1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-09 12:50:35 +00:00

Merge pull request #102534 from ttencate/feature/drag_drop_into_array

Improve drag and drop into array property editors
This commit is contained in:
Thaddeus Crews
2025-03-14 10:06:06 -05:00
5 changed files with 91 additions and 7 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -686,11 +686,13 @@ 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 (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)) { if (_is_type_valid(custom_class, allowed_types)) {
return true; return true;
} }
} }
}
return false; return false;
} }