Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exported script properties and sub-resource scripts will now be properly treated as Scripts #30738

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/string_name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ bool StringName::operator!=(const String &p_name) const {
return !(operator==(p_name));
}

bool StringName::operator!=(const char *p_name) const {

return !(operator==(p_name));
}

bool StringName::operator!=(const StringName &p_name) const {

// the real magic of all this mess happens here.
Expand Down
1 change: 1 addition & 0 deletions core/string_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class StringName {
bool operator==(const String &p_name) const;
bool operator==(const char *p_name) const;
bool operator!=(const String &p_name) const;
bool operator!=(const char *p_name) const;
_FORCE_INLINE_ bool operator<(const StringName &p_name) const {

return _data < p_name._data;
Expand Down
3 changes: 3 additions & 0 deletions editor/editor_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2317,6 +2317,9 @@ EditorInspector::EditorInspector() {
set_enable_h_scroll(false);
set_enable_v_scroll(true);

script_create_dialog = memnew(ScriptCreateDialog);
add_child(script_create_dialog);

show_categories = false;
hide_script = true;
use_doc_hints = false;
Expand Down
5 changes: 5 additions & 0 deletions editor/editor_inspector.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#ifndef EDITOR_INSPECTOR_H
#define EDITOR_INSPECTOR_H

#include "editor/script_create_dialog.h"
#include "scene/gui/box_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/scroll_container.h"
Expand Down Expand Up @@ -268,6 +269,8 @@ class EditorInspector : public ScrollContainer {
void _clear();
Object *object;

ScriptCreateDialog *script_create_dialog;

//

LineEdit *search_box;
Expand Down Expand Up @@ -351,6 +354,8 @@ class EditorInspector : public ScrollContainer {
void edit(Object *p_object);
Object *get_edited_object();

ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }

void set_keying(bool p_active);
void set_read_only(bool p_read_only);

Expand Down
107 changes: 105 additions & 2 deletions editor/editor_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2182,8 +2182,97 @@ void EditorPropertyResource::_menu_option(int p_which) {
} break;
case OBJ_MENU_NEW_SCRIPT: {

if (Object::cast_to<Node>(get_edited_object())) {
if (Object::cast_to<Node>(get_edited_object()) &&
EditorNode::get_singleton()->get_editor_data().get_edited_scene_root()->is_a_parent_of(Object::cast_to<Node>(get_edited_object())) &&
get_edited_property() == "script") {
// This is a script property of a node in the scene tree, so we should defer to the SceneTreeDock's script creation code
EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(Object::cast_to<Node>(get_edited_object()));
} else {

// Based upon editor/scene_tree_dock.cpp#_tool_selected (case TOOL_ATTACH_SCRIPT); edited
// to account for exported script properties, resources, and sub-resources
Copy link
Contributor Author

@LikeLakers2 LikeLakers2 Jul 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would want to try to merge this again, but instead of merging it back into the mentioned function (as I tried with my first attempt), I would prefer to merge this and the above-mentioned function into editor/editor_node.cpp (or another editor class that's a bit more "global", if you get what I mean) in some manner.

That said, the reason I have not done so already is that I don't think that's within the scope of this PR -- but if it can be considered within the scope, I might try my hand at it.


Ref<Script> existing = get_edited_object()->get(get_edited_property());

String inherits;
if (existing.is_valid()) {
// A script already exists in this property, so inherit from that script
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *l = ScriptServer::get_language(i);
if (l->get_type() == existing->get_class()) {
String name = l->get_global_class_name(existing->get_path());
if (ScriptServer::is_global_class(name) && EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) {
inherits = name;
} else if (l->can_inherit_from_file()) {
inherits = "\"" + existing->get_path() + "\"";
}
break;
}
}
} else if (get_edited_property() == "script") {
// This is the script property of an object's sub-property, so inherit from that object's class
inherits = get_edited_object()->get_class();
} else {
inherits = "Reference";
}

String path;
// Path creation:
// Get the object's basename
// If the object has no basename, get the scene root's filename
// If the scene root has a filename, append the object's name/class to it
// If it does not, append the object's name/class to "res://"
// If the property we're editing is not "script", append the property name to the filename
if (Object::cast_to<Node>(get_edited_object()) &&
EditorNode::get_singleton()->get_editor_data().get_edited_scene_root()->is_a_parent_of(Object::cast_to<Node>(get_edited_object()))) {
// This is a node in the scene tree, but it is not the script property
Node *edited_node = Object::cast_to<Node>(get_edited_object());

path = edited_node->get_filename().get_basename();
if (path == "") {
String root_path = EditorNode::get_singleton()->get_editor_data().get_edited_scene_root()->get_filename();
if (root_path == "") {
path = String("res://").plus_file(edited_node->get_name());
} else {
path = root_path.get_base_dir().plus_file(edited_node->get_name());
}
}
} else if (Object::cast_to<Resource>(get_edited_object())) {
RES edited_res = Object::cast_to<Resource>(get_edited_object());

path = edited_res->get_path().get_basename();
if (path == "") {
String root_path = EditorNode::get_singleton()->get_editor_data().get_edited_scene_root()->get_filename();
if (root_path == "") {
path = String("res://").plus_file(edited_res->get_name());
} else {
path = root_path.get_base_dir().plus_file(edited_res->get_name());
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be more appropriate to put this section of code (as well as the copies for Node and the else statement) in a macro, for re-use in all three cases? I would normally just go ahead and do so, but I'm not sure if such a move would be appreciated (considering the only macros I ever see in the engine are the error macros), or if there is perhaps a better way of doing that.

}
} else {
String root_path = EditorNode::get_singleton()->get_editor_data().get_edited_scene_root()->get_filename();
if (root_path == "") {
path = String("res://").plus_file(get_edited_object()->get_class());
} else {
path = root_path.get_base_dir().plus_file(get_edited_object()->get_class());
}
}

// If we're editing an object that isn't in the scene tree, we still have the script property,
// so we don't want to accidentally add the property name to the end of the script path.
if (get_edited_property() != "script") {
// path = <node_or_scene_name>.<property_name>.
// The extra period at the end is to prevent the property name from being seen as the type by ScriptCreateDialog
String path_property_name = get_edited_property();
path_property_name = path_property_name.replace(":", ".").replace("/", ".").replace("\\", ".");
path = path + "." + path_property_name + ".";
Copy link
Contributor Author

@LikeLakers2 LikeLakers2 Jul 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if it could get a NodePath to the current property. For example, if the path to the property is MyCSGMesh:material:albedo_texture:script, the path could generated as "res://scenes/MyCSGMesh.material.albedo_texture.gd". Preliminary testing seems to show that this would be a bit harder than I initially thought, however, and might be better served as its own PR anyways (since from what I can tell, I'd need to implement additional functionality into the Inspector or something).

}

ScriptCreateDialog *script_create_dialog = EditorNode::get_singleton()->get_inspector()->get_script_create_dialog();
script_create_dialog->connect("script_created", this, "_script_created");
script_create_dialog->connect("popup_hide", this, "_script_creation_closed", varray(), CONNECT_ONESHOT);
script_create_dialog->config(inherits, path);
script_create_dialog->popup_centered();
}

} break;
Expand Down Expand Up @@ -2308,14 +2397,26 @@ void EditorPropertyResource::_resource_preview(const String &p_path, const Ref<T
}
}

void EditorPropertyResource::_script_created(Ref<Script> p_script) {

// Based partially upon editor/scene_tree_dock.cpp#_script_created
emit_changed(get_edited_property(), p_script);
update_property();
}

void EditorPropertyResource::_script_creation_closed() {
ScriptCreateDialog *script_create_dialog = EditorNode::get_singleton()->get_inspector()->get_script_create_dialog();
script_create_dialog->disconnect("script_created", this, "_script_created");
}

void EditorPropertyResource::_update_menu_items() {

//////////////////// UPDATE MENU //////////////////////////
RES res = get_edited_object()->get(get_edited_property());

menu->clear();

if (get_edited_property() == "script" && base_type == "Script" && Object::cast_to<Node>(get_edited_object())) {
if (base_type == "Script") {
menu->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
menu->add_separator();
} else if (base_type != "") {
Expand Down Expand Up @@ -2833,6 +2934,8 @@ void EditorPropertyResource::_bind_methods() {
ClassDB::bind_method(D_METHOD("_resource_preview"), &EditorPropertyResource::_resource_preview);
ClassDB::bind_method(D_METHOD("_resource_selected"), &EditorPropertyResource::_resource_selected);
ClassDB::bind_method(D_METHOD("_viewport_selected"), &EditorPropertyResource::_viewport_selected);
ClassDB::bind_method(D_METHOD("_script_created"), &EditorPropertyResource::_script_created);
ClassDB::bind_method(D_METHOD("_script_creation_closed"), &EditorPropertyResource::_script_creation_closed);
ClassDB::bind_method(D_METHOD("_sub_inspector_property_keyed"), &EditorPropertyResource::_sub_inspector_property_keyed);
ClassDB::bind_method(D_METHOD("_sub_inspector_resource_selected"), &EditorPropertyResource::_sub_inspector_resource_selected);
ClassDB::bind_method(D_METHOD("_sub_inspector_object_id_selected"), &EditorPropertyResource::_sub_inspector_object_id_selected);
Expand Down
2 changes: 2 additions & 0 deletions editor/editor_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,8 @@ class EditorPropertyResource : public EditorProperty {
void _resource_preview(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, ObjectID p_obj);
void _resource_selected();
void _viewport_selected(const NodePath &p_path);
void _script_created(Ref<Script> p_script);
void _script_creation_closed();

void _update_menu_items();

Expand Down