From 409c71bdfd8e0a08fd726225ebdce16bc60a4570 Mon Sep 17 00:00:00 2001 From: AeioMuch <75151379+AeioMuch@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:13:36 +0100 Subject: [PATCH] Allow batch drag and drop in typed array of Node and NodePath. --- editor/editor_properties_array_dict.cpp | 102 +++++++++++++++++++++--- editor/editor_properties_array_dict.h | 2 + 2 files changed, 92 insertions(+), 12 deletions(-) diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index a6c7d6b617d..00fe42cb0af 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -483,9 +483,10 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { } Dictionary drag_data = p_drag_data; + const String drop_type = drag_data.get("type", ""); - if (drag_data.has("type") && String(drag_data["type"]) == "files") { - Vector files = drag_data["files"]; + if (drop_type == "files") { + PackedStringArray files = drag_data["files"]; for (int i = 0; i < files.size(); i++) { const String &file = files[i]; @@ -504,6 +505,56 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { return true; } + if (drop_type == "nodes") { + Array node_paths = drag_data["nodes"]; + + PackedStringArray allowed_subtype_array; + if (allowed_type == "NodePath") { + if (subtype_hint_string == "NodePath") { + return true; + } else { + for (int j = 0; j < subtype_hint_string.get_slice_count(","); j++) { + String ast = subtype_hint_string.get_slice(",", j).strip_edges(); + allowed_subtype_array.append(ast); + } + } + } + + bool is_drop_allowed = true; + + for (int i = 0; i < node_paths.size(); i++) { + const Node *dropped_node = get_node_or_null(node_paths[i]); + 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)) { + // Fail if one of the nodes is not of allowed type. + return false; + } + } + + // The array of NodePaths is restricted to specific types using @export_node_path(). + if (allowed_type == "NodePath" && subtype_hint_string != "NodePath") { + 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)) { + is_drop_allowed = true; + break; + } else { + is_drop_allowed = false; + } + } + if (!is_drop_allowed) { + break; + } + } + } + } + + return is_drop_allowed; + } + return false; } @@ -515,18 +566,18 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d ERR_FAIL_COND(!_is_drop_valid(p_data)); Dictionary drag_data = p_data; + const String drop_type = drag_data.get("type", ""); + Variant array = object->get_array(); - if (drag_data.has("type") && String(drag_data["type"]) == "files") { - Vector files = drag_data["files"]; + // Handle the case where array is not initialized yet. + if (!array.is_array()) { + initialize_array(array); + } else { + array = array.duplicate(); + } - Variant array = object->get_array(); - - // Handle the case where array is not initialized yet. - if (!array.is_array()) { - initialize_array(array); - } else { - array = array.duplicate(); - } + if (drop_type == "files") { + PackedStringArray files = drag_data["files"]; // Loop the file array and add to existing array. for (int i = 0; i < files.size(); i++) { @@ -540,6 +591,33 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d emit_changed(get_edited_property(), array); } + + if (drop_type == "nodes") { + Array node_paths = drag_data["nodes"]; + Node *base_node = get_base_node(); + + for (int i = 0; i < node_paths.size(); i++) { + const NodePath &path = node_paths[i]; + + if (subtype == Variant::OBJECT) { + array.call("push_back", get_node(path)); + } else if (subtype == Variant::NODE_PATH) { + array.call("push_back", base_node->get_path().rel_path_to(path)); + } + } + + emit_changed(get_edited_property(), array); + } +} + +Node *EditorPropertyArray::get_base_node() { + Node *base_node = Object::cast_to(InspectorDock::get_inspector_singleton()->get_edited_object()); + + if (!base_node) { + base_node = get_tree()->get_edited_scene_root(); + } + + return base_node; } void EditorPropertyArray::_notification(int p_what) { diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index b1bf45f1b76..dae0fc52a64 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -135,6 +135,8 @@ class EditorPropertyArray : public EditorProperty { void _reorder_button_up(); void _create_new_property_slot(); + Node *get_base_node(); + protected: Ref object;