Browse Source

Merge pull request #102534 from ttencate/feature/drag_drop_into_array

Improve drag and drop into array property editors
Thaddeus Crews 5 months ago
parent
commit
409fe3c944

+ 22 - 0
editor/editor_properties.cpp

@@ -2732,6 +2732,13 @@ void EditorPropertyNodePath::_node_assign() {
 	scene_tree->popup_scenetree_dialog(n, get_base_node());
 	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() {
 void EditorPropertyNodePath::_update_menu() {
 	const NodePath &np = _get_node_path();
 	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_EDIT, get_editor_theme_icon(SNAME("Edit")));
 			menu->get_popup()->set_item_icon(ACTION_SELECT, get_editor_theme_icon(SNAME("ExternalLink")));
 			menu->get_popup()->set_item_icon(ACTION_SELECT, get_editor_theme_icon(SNAME("ExternalLink")));
 		} break;
 		} 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_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
 	assign->set_expand_icon(true);
 	assign->set_expand_icon(true);
 	assign->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyNodePath::_node_assign));
 	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);
 	SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath);
 	hbc->add_child(assign);
 	hbc->add_child(assign);
 
 

+ 2 - 0
editor/editor_properties.h

@@ -628,10 +628,12 @@ class EditorPropertyNodePath : public EditorProperty {
 	SceneTreeDialog *scene_tree = nullptr;
 	SceneTreeDialog *scene_tree = nullptr;
 	bool use_path_from_scene_root = false;
 	bool use_path_from_scene_root = false;
 	bool editing_node = false;
 	bool editing_node = false;
+	bool dropping = false;
 
 
 	Vector<StringName> valid_types;
 	Vector<StringName> valid_types;
 	void _node_selected(const NodePath &p_path, bool p_absolute = true);
 	void _node_selected(const NodePath &p_path, bool p_absolute = true);
 	void _node_assign();
 	void _node_assign();
+	void _assign_draw();
 	Node *get_base_node();
 	Node *get_base_node();
 	void _update_menu();
 	void _update_menu();
 	void _menu_option(int p_idx);
 	void _menu_option(int p_idx);

+ 61 - 4
editor/editor_properties_array_dict.cpp

@@ -33,6 +33,7 @@
 #include "core/input/input.h"
 #include "core/input/input.h"
 #include "core/io/marshalls.h"
 #include "core/io/marshalls.h"
 #include "editor/editor_file_system.h"
 #include "editor/editor_file_system.h"
+#include "editor/editor_node.h"
 #include "editor/editor_properties.h"
 #include "editor/editor_properties.h"
 #include "editor/editor_properties_vector.h"
 #include "editor/editor_properties_vector.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"
@@ -459,6 +460,8 @@ void EditorPropertyArray::update_property() {
 			button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element"));
 			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->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(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());
 			button_add_item->set_disabled(is_read_only());
 			vbox->add_child(button_add_item);
 			vbox->add_child(button_add_item);
 
 
@@ -550,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 {
 bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
 	if (is_read_only()) {
 	if (is_read_only()) {
 		return false;
 		return false;
@@ -570,11 +580,18 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
 		PackedStringArray files = drag_data["files"];
 		PackedStringArray files = drag_data["files"];
 
 
 		for (const String &file : 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(",")) {
 			for (String at : allowed_type.split(",")) {
 				at = at.strip_edges();
 				at = at.strip_edges();
 				// Fail if one of the files is not of allowed type.
 				// 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;
 					return false;
 				}
 				}
 			}
 			}
@@ -584,6 +601,28 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
 		return true;
 		return true;
 	}
 	}
 
 
+	if (drop_type == "resource") {
+		Ref<Resource> 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") {
 	if (drop_type == "nodes") {
 		Array node_paths = drag_data["nodes"];
 		Array node_paths = drag_data["nodes"];
 
 
@@ -606,7 +645,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.");
 			ERR_FAIL_NULL_V_MSG(dropped_node, false, "Could not get the dropped node by its path.");
 
 
 			if (allowed_type != "NodePath") {
 			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.
 					// Fail if one of the nodes is not of allowed type.
 					return false;
 					return false;
 				}
 				}
@@ -617,7 +657,8 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
 				if (!allowed_subtype_array.has(dropped_node->get_class_name())) {
 				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.
 					// 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) {
 					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;
 							is_drop_allowed = true;
 							break;
 							break;
 						} else {
 						} else {
@@ -669,6 +710,16 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d
 		emit_changed(get_edited_property(), array);
 		emit_changed(get_edited_property(), array);
 	}
 	}
 
 
+	if (drop_type == "resource") {
+		Ref<Resource> res = drag_data["resource"];
+
+		if (res.is_valid()) {
+			array.call("push_back", res);
+
+			emit_changed(get_edited_property(), array);
+		}
+	}
+
 	if (drop_type == "nodes") {
 	if (drop_type == "nodes") {
 		Array node_paths = drag_data["nodes"];
 		Array node_paths = drag_data["nodes"];
 		Node *base_node = get_base_node();
 		Node *base_node = get_base_node();
@@ -724,6 +775,9 @@ void EditorPropertyArray::_notification(int p_what) {
 				if (_is_drop_valid(get_viewport()->gui_get_drag_data())) {
 				if (_is_drop_valid(get_viewport()->gui_get_drag_data())) {
 					dropping = true;
 					dropping = true;
 					edit->queue_redraw();
 					edit->queue_redraw();
+					if (button_add_item) {
+						button_add_item->queue_redraw();
+					}
 				}
 				}
 			}
 			}
 		} break;
 		} break;
@@ -732,6 +786,9 @@ void EditorPropertyArray::_notification(int p_what) {
 			if (dropping) {
 			if (dropping) {
 				dropping = false;
 				dropping = false;
 				edit->queue_redraw();
 				edit->queue_redraw();
+				if (button_add_item) {
+					button_add_item->queue_redraw();
+				}
 			}
 			}
 		} break;
 		} break;
 	}
 	}

+ 1 - 0
editor/editor_properties_array_dict.h

@@ -163,6 +163,7 @@ protected:
 	virtual void _remove_pressed(int p_index);
 	virtual void _remove_pressed(int p_index);
 
 
 	virtual void _button_draw();
 	virtual void _button_draw();
+	virtual void _button_add_item_draw();
 	virtual bool _is_drop_valid(const Dictionary &p_drag_data) const;
 	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 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);
 	virtual void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);

+ 5 - 3
editor/editor_resource_picker.cpp

@@ -686,9 +686,11 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
 			return true;
 			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;
+			}
 		}
 		}
 	}
 	}