From 36c1b019facba3c4928d7966670ff5ae5aba5a4f Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Fri, 7 Feb 2025 10:33:30 +0100 Subject: [PATCH 1/6] Highlight Node and NodePath properties as valid drop targets This was already done for Resource properties; this just makes things consistent. --- editor/editor_properties.cpp | 22 ++++++++++++++++++++++ editor/editor_properties.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 398f1383622..1aedb6ac361 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2732,6 +2732,13 @@ void EditorPropertyNodePath::_node_assign() { scene_tree->popup_scenetree_dialog(n, get_base_node()); } +void EditorPropertyNodePath::_assign_draw() { + if (dropping) { + Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor)); + assign->draw_rect(Rect2(Point2(), assign->get_size()), color, false); + } +} + void EditorPropertyNodePath::_update_menu() { const NodePath &np = _get_node_path(); @@ -2909,6 +2916,20 @@ void EditorPropertyNodePath::_notification(int p_what) { menu->get_popup()->set_item_icon(ACTION_EDIT, get_editor_theme_icon(SNAME("Edit"))); menu->get_popup()->set_item_icon(ACTION_SELECT, get_editor_theme_icon(SNAME("ExternalLink"))); } break; + + case NOTIFICATION_DRAG_BEGIN: { + if (!is_read_only() && is_drop_valid(get_viewport()->gui_get_drag_data())) { + dropping = true; + assign->queue_redraw(); + } + } break; + + case NOTIFICATION_DRAG_END: { + if (dropping) { + dropping = false; + assign->queue_redraw(); + } + } break; } } @@ -2949,6 +2970,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() { assign->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); assign->set_expand_icon(true); assign->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyNodePath::_node_assign)); + assign->connect(SceneStringName(draw), callable_mp(this, &EditorPropertyNodePath::_assign_draw)); SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath); hbc->add_child(assign); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 81415b7e100..6435825c676 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -628,10 +628,12 @@ class EditorPropertyNodePath : public EditorProperty { SceneTreeDialog *scene_tree = nullptr; bool use_path_from_scene_root = false; bool editing_node = false; + bool dropping = false; Vector valid_types; void _node_selected(const NodePath &p_path, bool p_absolute = true); void _node_assign(); + void _assign_draw(); Node *get_base_node(); void _update_menu(); void _menu_option(int p_idx); From cd8eaaa07bad670bed17bee248b75245999a56ed Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Sat, 8 Feb 2025 11:29:51 +0100 Subject: [PATCH 2/6] Fix resource property editor incorrectly accepting script files See discussion on #102534. Before this fix, it was possible to drag a file `CustomResource.gd` with `class_name CustomResource` onto a property of type `CustomResource`. Of course, the intention is that only `Resource`s with the `CustomResource` script attached are accepted. (Actually accepting the script, but creating a resource from it automatically, is left as a future improvement.) --- editor/editor_resource_picker.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 96fb8323704..1f3700c4802 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -686,9 +686,11 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { return true; } - StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res.ptr()); - if (_is_type_valid(custom_class, allowed_types)) { - return true; + if (res->get_script()) { + StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script()); + if (_is_type_valid(custom_class, allowed_types)) { + return true; + } } } From 0c46089d1b55b11f3daf6b16fba96465e90ffe39 Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Fri, 7 Feb 2025 12:13:12 +0100 Subject: [PATCH 3/6] Allow dragging custom resources onto array property editor This duplicates some of the logic in EditorResourcePicker, but that's unavoidable: EditorResourcePicker works on a single, loaded resource, whereas we'd like this to be efficient and not need to load all (potentially many) dragged resources. Instead, we use the EditorFileSystem cache to get the information we need. Note that EditorResourcePicker also supports some automatic conversions, such as from Shader to ShaderMaterial. This change does not attempt to make that work for arrays as well. --- editor/editor_properties_array_dict.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 99ad820bb3a..89b1253f4c9 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -33,6 +33,7 @@ #include "core/input/input.h" #include "core/io/marshalls.h" #include "editor/editor_file_system.h" +#include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_properties_vector.h" #include "editor/editor_settings.h" @@ -570,11 +571,18 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { PackedStringArray files = drag_data["files"]; for (const String &file : files) { - const String ftype = EditorFileSystem::get_singleton()->get_file_type(file); + int idx_in_dir; + EditorFileSystemDirectory const *dir = EditorFileSystem::get_singleton()->find_file(file, &idx_in_dir); + if (!dir) { + return false; + } + StringName ftype = dir->get_file_type(idx_in_dir); + String script_class = dir->get_file_resource_script_class(idx_in_dir); + for (String at : allowed_type.split(",")) { at = at.strip_edges(); // Fail if one of the files is not of allowed type. - if (!ClassDB::is_parent_class(ftype, at)) { + if (!ClassDB::is_parent_class(ftype, at) && !EditorNode::get_editor_data().script_class_is_parent(script_class, at)) { return false; } } From 11b3900a0e8c44a4efed41306305bf80693fa534 Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Fri, 7 Feb 2025 12:31:53 +0100 Subject: [PATCH 4/6] Allow dragging custom node types onto array property editor For example, an Array[MyScript] property now accepts any node with the script MyScript on it. This works for Node and NodePath arrays alike, and also with the @export_node_path annotation. --- editor/editor_properties_array_dict.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 89b1253f4c9..446bad76aad 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -614,7 +614,8 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { ERR_FAIL_NULL_V_MSG(dropped_node, false, "Could not get the dropped node by its path."); if (allowed_type != "NodePath") { - if (!ClassDB::is_parent_class(dropped_node->get_class_name(), allowed_type)) { + if (!ClassDB::is_parent_class(dropped_node->get_class_name(), allowed_type) && + !EditorNode::get_singleton()->is_object_of_custom_type(dropped_node, allowed_type)) { // Fail if one of the nodes is not of allowed type. return false; } @@ -625,7 +626,8 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { if (!allowed_subtype_array.has(dropped_node->get_class_name())) { // The dropped node type was not found in the allowed subtype array, we must check if it inherits one of them. for (const String &ast : allowed_subtype_array) { - if (ClassDB::is_parent_class(dropped_node->get_class_name(), ast)) { + if (ClassDB::is_parent_class(dropped_node->get_class_name(), ast) || + EditorNode::get_singleton()->is_object_of_custom_type(dropped_node, ast)) { is_drop_allowed = true; break; } else { From b557840af57130fbcc94b97d8d41a2568c3e5593 Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Fri, 7 Feb 2025 12:53:33 +0100 Subject: [PATCH 5/6] Allow dragging resources (not just files) onto array property editor The most common scenario is dragging a file from the filesystem dock, which drags it as type "file", not "resource". This already worked. This change also makes it possible to drag a resource from another property editor. --- editor/editor_properties_array_dict.cpp | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 446bad76aad..4f97b6b1fe5 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -592,6 +592,28 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { return true; } + if (drop_type == "resource") { + Ref res = drag_data["resource"]; + if (res.is_null()) { + return false; + } + + String res_type = res->get_class(); + StringName script_class; + if (res->get_script()) { + script_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script()); + } + + for (String at : allowed_type.split(",")) { + at = at.strip_edges(); + if (ClassDB::is_parent_class(res_type, at) || EditorNode::get_editor_data().script_class_is_parent(script_class, at)) { + return true; + } + } + + return false; + } + if (drop_type == "nodes") { Array node_paths = drag_data["nodes"]; @@ -679,6 +701,16 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d emit_changed(get_edited_property(), array); } + if (drop_type == "resource") { + Ref res = drag_data["resource"]; + + if (res.is_valid()) { + array.call("push_back", res); + + emit_changed(get_edited_property(), array); + } + } + if (drop_type == "nodes") { Array node_paths = drag_data["nodes"]; Node *base_node = get_base_node(); From 93d342b7450d2ec45ef2baa064499291d8f85929 Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Fri, 7 Feb 2025 15:17:06 +0100 Subject: [PATCH 6/6] Allow dragging items onto array property editor Add Element button Instead of having to first click the button, then drag the item into the new slot, this allows just dragging the item onto the button directly. The button is highlighted as a valid drop target to signal this. --- editor/editor_properties_array_dict.cpp | 15 +++++++++++++++ editor/editor_properties_array_dict.h | 1 + 2 files changed, 16 insertions(+) diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 4f97b6b1fe5..0c68f6c9245 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -460,6 +460,8 @@ void EditorPropertyArray::update_property() { button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element")); button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add"))); button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_add_element)); + button_add_item->connect(SceneStringName(draw), callable_mp(this, &EditorPropertyArray::_button_add_item_draw)); + SET_DRAG_FORWARDING_CD(button_add_item, EditorPropertyArray); button_add_item->set_disabled(is_read_only()); vbox->add_child(button_add_item); @@ -551,6 +553,13 @@ void EditorPropertyArray::_button_draw() { } } +void EditorPropertyArray::_button_add_item_draw() { + if (dropping) { + Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor)); + button_add_item->draw_rect(Rect2(Point2(), button_add_item->get_size()), color, false); + } +} + bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { if (is_read_only()) { return false; @@ -766,6 +775,9 @@ void EditorPropertyArray::_notification(int p_what) { if (_is_drop_valid(get_viewport()->gui_get_drag_data())) { dropping = true; edit->queue_redraw(); + if (button_add_item) { + button_add_item->queue_redraw(); + } } } } break; @@ -774,6 +786,9 @@ void EditorPropertyArray::_notification(int p_what) { if (dropping) { dropping = false; edit->queue_redraw(); + if (button_add_item) { + button_add_item->queue_redraw(); + } } } break; } diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index a7ec912e1a5..f5fcc59025c 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -163,6 +163,7 @@ protected: virtual void _remove_pressed(int p_index); virtual void _button_draw(); + virtual void _button_add_item_draw(); virtual bool _is_drop_valid(const Dictionary &p_drag_data) const; virtual bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; virtual void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);