From 5fa0f3124720c2f7653bff39340d7f6d818316db Mon Sep 17 00:00:00 2001 From: kobewi Date: Sat, 16 Aug 2025 17:28:23 -0400 Subject: [PATCH] Edit groups on multiple nodes Co-authored-by: Pablo Ibarz --- editor/docks/groups_editor.cpp | 103 ++++++++++++++++++++++------ editor/docks/groups_editor.h | 11 ++- editor/docks/node_dock.cpp | 54 +++------------ editor/docks/node_dock.h | 4 +- editor/docks/scene_tree_dock.cpp | 4 +- editor/editor_node.cpp | 19 +++-- editor/scene/connections_dialog.cpp | 43 +++++++++--- editor/scene/connections_dialog.h | 5 +- 8 files changed, 154 insertions(+), 89 deletions(-) diff --git a/editor/docks/groups_editor.cpp b/editor/docks/groups_editor.cpp index 9e0740b8b4f..d412c114b38 100644 --- a/editor/docks/groups_editor.cpp +++ b/editor/docks/groups_editor.cpp @@ -93,6 +93,41 @@ void GroupsEditor::_set_group_checked(const String &p_name, bool p_checked) { ti->set_checked(0, p_checked); } +void GroupsEditor::_add_to_group(const StringName &p_name, bool p_persist, const Array &p_nodes) { + for (const Variant &v : p_nodes) { + Node *node = Object::cast_to(v.get_validated_object()); + if (node) { + node->add_to_group(p_name, p_persist); + } + } +} + +void GroupsEditor::_remove_from_group(const StringName &p_name, const Array &p_nodes) { + for (const Variant &v : p_nodes) { + Node *node = Object::cast_to(v.get_validated_object()); + if (node) { + node->remove_from_group(p_name); + } + } +} + +void GroupsEditor::_get_group_mask(const StringName &p_name, Array &r_nodes, bool p_invert) { + for (Node *p_node : selection) { + if (p_invert != p_node->is_in_group(p_name)) { + r_nodes.push_back(p_node); + } + } +} + +bool GroupsEditor::_can_edit(const StringName &p_group) { + for (Node *p_node : selection) { + if (!can_edit(p_node, p_group)) { + return false; + } + } + return true; +} + bool GroupsEditor::_has_group(const String &p_name) { return global_groups.has(p_name) || scene_groups.has(p_name); } @@ -102,7 +137,7 @@ void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseBu return; } - if (!node) { + if (selection.is_empty()) { return; } @@ -177,7 +212,7 @@ void GroupsEditor::_update_tree() { return; } - if (!node) { + if (selection.is_empty()) { return; } @@ -190,7 +225,9 @@ void GroupsEditor::_update_tree() { tree->clear(); List groups; - node->get_groups(&groups); + for (Node *p_node : selection) { + p_node->get_groups(&groups); + } groups.sort_custom<_GroupInfoComparator>(); List current_groups; @@ -220,7 +257,7 @@ void GroupsEditor::_update_tree() { TreeItem *item = tree->create_item(local_root); item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0, can_edit(node, E)); + item->set_editable(0, _can_edit(E)); item->set_checked(0, current_groups.find(E) != nullptr); item->set_text(0, E); item->set_meta("__local", true); @@ -252,7 +289,7 @@ void GroupsEditor::_update_tree() { TreeItem *item = tree->create_item(global_root); item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0, can_edit(node, E)); + item->set_editable(0, _can_edit(E)); item->set_checked(0, current_groups.find(E) != nullptr); item->set_text(0, E); item->set_meta("__local", false); @@ -307,15 +344,18 @@ void GroupsEditor::_cache_scene_groups(const ObjectID &p_id) { } } -void GroupsEditor::set_current(Node *p_node) { - if (node == p_node) { +void GroupsEditor::set_selection(const Vector &p_nodes) { + if (p_nodes.is_empty()) { + holder->hide(); + select_a_node->show(); + selection.clear(); return; } - node = p_node; - if (!node) { - return; - } + selection = p_nodes; + + holder->show(); + select_a_node->hide(); if (scene_tree->get_edited_scene_root() != scene_root_node) { scene_root_node = scene_tree->get_edited_scene_root(); @@ -338,8 +378,10 @@ void GroupsEditor::_item_edited() { if (ti->is_checked(0)) { undo_redo->create_action(TTR("Add to Group")); - undo_redo->add_do_method(node, "add_to_group", name, true); - undo_redo->add_undo_method(node, "remove_from_group", name); + Array nodes; + _get_group_mask(name, nodes, true); + undo_redo->add_do_method(this, "_add_to_group", name, true, nodes); + undo_redo->add_undo_method(this, "_remove_from_group", name, nodes); undo_redo->add_do_method(this, "_set_group_checked", name, true); undo_redo->add_undo_method(this, "_set_group_checked", name, false); @@ -353,8 +395,10 @@ void GroupsEditor::_item_edited() { } else { undo_redo->create_action(TTR("Remove from Group")); - undo_redo->add_do_method(node, "remove_from_group", name); - undo_redo->add_undo_method(node, "add_to_group", name, true); + Array nodes; + _get_group_mask(name, nodes, false); + undo_redo->add_do_method(this, "_remove_from_group", name, nodes); + undo_redo->add_undo_method(this, "_add_to_group", name, true, nodes); undo_redo->add_do_method(this, "_set_group_checked", name, false); undo_redo->add_undo_method(this, "_set_group_checked", name, true); @@ -489,8 +533,10 @@ void GroupsEditor::_confirm_add() { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add to Group")); - undo_redo->add_do_method(node, "add_to_group", name, true); - undo_redo->add_undo_method(node, "remove_from_group", name); + Array nodes; + _get_group_mask(name, nodes, true); + undo_redo->add_do_method(this, "_add_to_group", name, true, nodes); + undo_redo->add_undo_method(this, "_remove_from_group", name, nodes); bool is_local = !global_group_button->is_pressed(); if (is_local) { @@ -819,6 +865,9 @@ void GroupsEditor::_bind_methods() { ClassDB::bind_method("_rename_scene_group", &GroupsEditor::_rename_scene_group); ClassDB::bind_method("_remove_scene_group", &GroupsEditor::_remove_scene_group); ClassDB::bind_method("_set_group_checked", &GroupsEditor::_set_group_checked); + + ClassDB::bind_method("_add_to_group", &GroupsEditor::_add_to_group); + ClassDB::bind_method("_remove_from_group", &GroupsEditor::_remove_from_group); } void GroupsEditor::_node_removed(Node *p_node) { @@ -834,15 +883,19 @@ void GroupsEditor::_node_removed(Node *p_node) { } GroupsEditor::GroupsEditor() { - node = nullptr; scene_tree = SceneTree::get_singleton(); ED_SHORTCUT("groups_editor/delete", TTRC("Delete"), Key::KEY_DELETE); ED_SHORTCUT("groups_editor/rename", TTRC("Rename"), Key::F2); ED_SHORTCUT_OVERRIDE("groups_editor/rename", "macos", Key::ENTER); + holder = memnew(VBoxContainer); + holder->set_v_size_flags(SIZE_EXPAND_FILL); + holder->hide(); + add_child(holder); + HBoxContainer *hbc = memnew(HBoxContainer); - add_child(hbc); + holder->add_child(hbc); add = memnew(Button); add->set_theme_type_variation("FlatMenuButton"); @@ -867,11 +920,21 @@ GroupsEditor::GroupsEditor() { tree->connect("button_clicked", callable_mp(this, &GroupsEditor::_modify_group)); tree->connect("item_mouse_selected", callable_mp(this, &GroupsEditor::_item_mouse_selected)); tree->connect(SceneStringName(gui_input), callable_mp(this, &GroupsEditor::_groups_gui_input)); - add_child(tree); + holder->add_child(tree); menu = memnew(PopupMenu); menu->connect(SceneStringName(id_pressed), callable_mp(this, &GroupsEditor::_menu_id_pressed)); tree->add_child(menu); + select_a_node = memnew(Label); + select_a_node->set_focus_mode(FOCUS_ACCESSIBILITY); + select_a_node->set_text(TTRC("Select one or more nodes to edit their groups.")); + select_a_node->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); + select_a_node->set_v_size_flags(SIZE_EXPAND_FILL); + select_a_node->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + select_a_node->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + select_a_node->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + add_child(select_a_node); + ProjectSettingsEditor::get_singleton()->get_group_settings()->connect("group_changed", callable_mp(this, &GroupsEditor::_update_groups_and_tree)); } diff --git a/editor/docks/groups_editor.h b/editor/docks/groups_editor.h index ae61772efd3..59ac961a1e6 100644 --- a/editor/docks/groups_editor.h +++ b/editor/docks/groups_editor.h @@ -52,7 +52,7 @@ class GroupsEditor : public VBoxContainer { bool groups_dirty = false; bool update_groups_and_tree_queued = false; - Node *node = nullptr; + LocalVector selection; Node *scene_root_node = nullptr; SceneTree *scene_tree = nullptr; @@ -73,9 +73,11 @@ class GroupsEditor : public VBoxContainer { PopupMenu *menu = nullptr; + VBoxContainer *holder = nullptr; LineEdit *filter = nullptr; Button *add = nullptr; Tree *tree = nullptr; + Label *select_a_node = nullptr; HashMap> scene_groups_cache; HashMap scene_groups_for_caching; @@ -122,6 +124,11 @@ class GroupsEditor : public VBoxContainer { void _node_removed(Node *p_node); + void _add_to_group(const StringName &p_name, bool p_persist, const Array &p_nodes); + void _remove_from_group(const StringName &p_name, const Array &p_nodes); + void _get_group_mask(const StringName &p_name, Array &r_nodes, bool p_invert); + bool _can_edit(const StringName &p_group); + protected: void _notification(int p_what); static void _bind_methods(); @@ -134,7 +141,7 @@ public: CONVERT_GROUP, }; - void set_current(Node *p_node); + void set_selection(const Vector &p_nodes); GroupsEditor(); }; diff --git a/editor/docks/node_dock.cpp b/editor/docks/node_dock.cpp index 6de79672e02..70c243f0c74 100644 --- a/editor/docks/node_dock.cpp +++ b/editor/docks/node_dock.cpp @@ -55,15 +55,7 @@ void NodeDock::save_layout_to_config(Ref &p_layout, const String &p_ void NodeDock::load_layout_from_config(const Ref &p_layout, const String &p_section) { const int current_tab = p_layout->get_value(p_section, "current_tab", 0); - if (select_a_node->is_visible()) { - if (current_tab == 0) { - groups_button->set_pressed_no_signal(false); - connections_button->set_pressed_no_signal(true); - } else if (current_tab == 1) { - groups_button->set_pressed_no_signal(true); - connections_button->set_pressed_no_signal(false); - } - } else if (current_tab == 0) { + if (current_tab == 0) { show_connections(); } else if (current_tab == 1) { show_groups(); @@ -83,32 +75,17 @@ void NodeDock::update_lists() { connections->update_tree(); } -void NodeDock::set_object(Object *p_object) { - connections->set_object(p_object); - groups->set_current(Object::cast_to(p_object)); +void NodeDock::set_selection(const Vector &p_objects) { + connections->set_selection(p_objects); - if (p_object) { - if (connections_button->is_pressed()) { - connections->show(); - } else { - groups->show(); + Vector nodes; + for (Object *obj : p_objects) { + Node *n = Object::cast_to(obj); + if (n) { + nodes.append(n); } - - if (Object::cast_to(p_object)) { - show_connections(); - groups_button->set_disabled(true); - } else { - groups_button->set_disabled(false); - } - - mode_hb->show(); - select_a_node->hide(); - } else { - connections->hide(); - groups->hide(); - mode_hb->hide(); - select_a_node->show(); } + groups->set_selection(nodes); } NodeDock::NodeDock() { @@ -123,13 +100,11 @@ NodeDock::NodeDock() { mode_hb = memnew(HBoxContainer); main_vb->add_child(mode_hb); - mode_hb->hide(); connections_button = memnew(Button); connections_button->set_theme_type_variation(SceneStringName(FlatButton)); connections_button->set_text(TTRC("Signals")); connections_button->set_toggle_mode(true); - connections_button->set_pressed(true); connections_button->set_h_size_flags(SIZE_EXPAND_FILL); connections_button->set_clip_text(true); mode_hb->add_child(connections_button); @@ -139,7 +114,6 @@ NodeDock::NodeDock() { groups_button->set_theme_type_variation(SceneStringName(FlatButton)); groups_button->set_text(TTRC("Groups")); groups_button->set_toggle_mode(true); - groups_button->set_pressed(false); groups_button->set_h_size_flags(SIZE_EXPAND_FILL); groups_button->set_clip_text(true); mode_hb->add_child(groups_button); @@ -155,15 +129,7 @@ NodeDock::NodeDock() { groups->set_v_size_flags(SIZE_EXPAND_FILL); groups->hide(); - select_a_node = memnew(Label); - select_a_node->set_focus_mode(FOCUS_ACCESSIBILITY); - select_a_node->set_text(TTRC("Select a single node to edit its signals and groups, or select an independent resource to view its signals.")); - select_a_node->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - select_a_node->set_v_size_flags(SIZE_EXPAND_FILL); - select_a_node->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - select_a_node->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - select_a_node->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); - main_vb->add_child(select_a_node); + show_connections(); } NodeDock::~NodeDock() { diff --git a/editor/docks/node_dock.h b/editor/docks/node_dock.h index 380f152e216..aca2705f327 100644 --- a/editor/docks/node_dock.h +++ b/editor/docks/node_dock.h @@ -47,8 +47,6 @@ class NodeDock : public EditorDock { HBoxContainer *mode_hb = nullptr; - Label *select_a_node = nullptr; - private: inline static NodeDock *singleton = nullptr; @@ -62,7 +60,7 @@ protected: virtual void load_layout_from_config(const Ref &p_layout, const String &p_section) override; public: - void set_object(Object *p_object); + void set_selection(const Vector &p_objects); void show_groups(); void show_connections(); diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp index eab86edfd26..7db0e0b0e63 100644 --- a/editor/docks/scene_tree_dock.cpp +++ b/editor/docks/scene_tree_dock.cpp @@ -1361,7 +1361,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { undo_redo->add_undo_method(node, "set_scene_file_path", node->get_scene_file_path()); _node_replace_owner(node, node, root); _node_strip_signal_inheritance(node); - NodeDock::get_singleton()->set_object(node); // Refresh. + NodeDock::get_singleton()->set_selection(Vector{ node }); // Refresh. undo_redo->add_do_method(scene_tree, "update_tree"); undo_redo->add_undo_method(scene_tree, "update_tree"); undo_redo->commit_action(); @@ -2865,7 +2865,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { editor_history->cleanup_history(); InspectorDock::get_singleton()->call("_prepare_history"); InspectorDock::get_singleton()->update(nullptr); - NodeDock::get_singleton()->set_object(nullptr); + NodeDock::get_singleton()->set_selection(Vector{}); } void SceneTreeDock::_update_script_button() { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d8110a0a863..3792391c62e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2844,7 +2844,7 @@ void EditorNode::push_node_item(Node *p_node) { void EditorNode::push_item(Object *p_object, const String &p_property, bool p_inspector_only) { if (!p_object) { InspectorDock::get_inspector_singleton()->edit(nullptr); - NodeDock::get_singleton()->set_object(nullptr); + NodeDock::get_singleton()->set_selection(Vector()); SceneTreeDock::get_singleton()->set_selected(nullptr); InspectorDock::get_singleton()->update(nullptr); hide_unused_editors(); @@ -2955,7 +2955,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update if (!current_obj) { SceneTreeDock::get_singleton()->set_selected(nullptr); InspectorDock::get_inspector_singleton()->edit(nullptr); - NodeDock::get_singleton()->set_object(nullptr); + NodeDock::get_singleton()->set_selection(Vector()); InspectorDock::get_singleton()->update(nullptr); EditorDebuggerNode::get_singleton()->clear_remote_tree_selection(); hide_unused_editors(); @@ -2989,7 +2989,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update if (!p_skip_inspector_update) { InspectorDock::get_inspector_singleton()->edit(current_res); SceneTreeDock::get_singleton()->set_selected(nullptr); - NodeDock::get_singleton()->set_object(current_res); + NodeDock::get_singleton()->set_selection(Vector{ current_res }); InspectorDock::get_singleton()->update(nullptr); EditorDebuggerNode::get_singleton()->clear_remote_tree_selection(); ImportDock::get_singleton()->set_edit_path(current_res->get_path()); @@ -3019,7 +3019,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update InspectorDock::get_inspector_singleton()->edit(current_node); if (current_node->is_inside_tree()) { - NodeDock::get_singleton()->set_object(current_node); + NodeDock::get_singleton()->set_selection(Vector{ current_node }); SceneTreeDock::get_singleton()->set_selected(current_node); SceneTreeDock::get_singleton()->set_selection({ current_node }); InspectorDock::get_singleton()->update(current_node); @@ -3031,7 +3031,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update } } } else { - NodeDock::get_singleton()->set_object(nullptr); + NodeDock::get_singleton()->set_selection(Vector()); SceneTreeDock::get_singleton()->set_selected(nullptr); InspectorDock::get_singleton()->update(nullptr); } @@ -3078,8 +3078,15 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update EditorDebuggerNode::get_singleton()->clear_remote_tree_selection(); } + // TODO: This can be replaced by some casting operator. + Vector nodes_as_objects; + nodes_as_objects.reserve_exact(multi_nodes.size()); + for (Node *n : multi_nodes) { + nodes_as_objects.append(n); + } + InspectorDock::get_inspector_singleton()->edit(current_obj); - NodeDock::get_singleton()->set_object(nullptr); + NodeDock::get_singleton()->set_selection(nodes_as_objects); SceneTreeDock::get_singleton()->set_selected(selected_node); SceneTreeDock::get_singleton()->set_selection(multi_nodes); InspectorDock::get_singleton()->update(nullptr); diff --git a/editor/scene/connections_dialog.cpp b/editor/scene/connections_dialog.cpp index a49670aa0cd..4b736b4ef56 100644 --- a/editor/scene/connections_dialog.cpp +++ b/editor/scene/connections_dialog.cpp @@ -1523,8 +1523,16 @@ void ConnectionsDock::_bind_methods() { ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree); } -void ConnectionsDock::set_object(Object *p_obj) { - selected_object = p_obj; +void ConnectionsDock::set_selection(const Vector &p_objects) { + if (p_objects.size() != 1) { + select_a_node->show(); + holder->hide(); + selected_object = nullptr; + } else { + select_a_node->hide(); + holder->show(); + selected_object = p_objects[0]; + } is_editing_resource = (Object::cast_to(selected_object) != nullptr); update_tree(); } @@ -1718,7 +1726,10 @@ void ConnectionsDock::update_tree() { ConnectionsDock::ConnectionsDock() { set_name(TTR("Signals")); - VBoxContainer *vbc = this; + holder = memnew(VBoxContainer); + holder->set_v_size_flags(SIZE_EXPAND_FILL); + holder->hide(); + add_child(holder); search_box = memnew(LineEdit); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -1726,7 +1737,7 @@ ConnectionsDock::ConnectionsDock() { search_box->set_accessibility_name(TTRC("Filter Signals")); search_box->set_clear_button_enabled(true); search_box->connect(SceneStringName(text_changed), callable_mp(this, &ConnectionsDock::_filter_changed)); - vbc->add_child(search_box); + holder->add_child(search_box); tree = memnew(ConnectionsDockTree); tree->set_accessibility_name(TTRC("Connections")); @@ -1735,24 +1746,24 @@ ConnectionsDock::ConnectionsDock() { tree->set_select_mode(Tree::SELECT_ROW); tree->set_hide_root(true); tree->set_column_clip_content(0, true); - vbc->add_child(tree); + holder->add_child(tree); tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); tree->set_allow_rmb_select(true); connect_button = memnew(Button); connect_button->set_accessibility_name(TTRC("Connect")); HBoxContainer *hb = memnew(HBoxContainer); - vbc->add_child(hb); + holder->add_child(hb); hb->add_spacer(); hb->add_child(connect_button); connect_button->connect(SceneStringName(pressed), callable_mp(this, &ConnectionsDock::_connect_pressed)); connect_dialog = memnew(ConnectDialog); connect_dialog->set_process_shortcut_input(true); - add_child(connect_dialog); + holder->add_child(connect_dialog); disconnect_all_dialog = memnew(ConfirmationDialog); - add_child(disconnect_all_dialog); + holder->add_child(disconnect_all_dialog); disconnect_all_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ConnectionsDock::_disconnect_all)); disconnect_all_dialog->set_text(TTR("Are you sure you want to remove all connections from this signal?")); @@ -1760,7 +1771,7 @@ ConnectionsDock::ConnectionsDock() { class_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_class_menu_option)); class_menu->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_class_menu_about_to_popup)); class_menu->add_item(TTR("Open Documentation"), CLASS_MENU_OPEN_DOCS); - add_child(class_menu); + holder->add_child(class_menu); signal_menu = memnew(PopupMenu); signal_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_signal_menu_option)); @@ -1770,7 +1781,7 @@ ConnectionsDock::ConnectionsDock() { signal_menu->add_item(TTR("Copy Name"), SIGNAL_MENU_COPY_NAME); signal_menu->add_separator(); signal_menu->add_item(TTR("Open Documentation"), SIGNAL_MENU_OPEN_DOCS); - add_child(signal_menu); + holder->add_child(signal_menu); slot_menu = memnew(PopupMenu); slot_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_slot_menu_option)); @@ -1778,7 +1789,7 @@ ConnectionsDock::ConnectionsDock() { slot_menu->add_item(TTR("Edit..."), SLOT_MENU_EDIT); slot_menu->add_item(TTR("Go to Method"), SLOT_MENU_GO_TO_METHOD); slot_menu->add_shortcut(ED_SHORTCUT("connections_editor/disconnect", TTRC("Disconnect"), Key::KEY_DELETE), SLOT_MENU_DISCONNECT); - add_child(slot_menu); + holder->add_child(slot_menu); connect_dialog->connect("connected", callable_mp(this, &ConnectionsDock::_make_or_edit_connection)); tree->connect(SceneStringName(item_selected), callable_mp(this, &ConnectionsDock::_tree_item_selected)); @@ -1786,4 +1797,14 @@ ConnectionsDock::ConnectionsDock() { tree->connect(SceneStringName(gui_input), callable_mp(this, &ConnectionsDock::_tree_gui_input)); add_theme_constant_override("separation", 3 * EDSCALE); + + select_a_node = memnew(Label); + select_a_node->set_focus_mode(FOCUS_ACCESSIBILITY); + select_a_node->set_text(TTRC("Select a single node or resource to edit its signals.")); + select_a_node->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); + select_a_node->set_v_size_flags(SIZE_EXPAND_FILL); + select_a_node->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + select_a_node->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + select_a_node->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + add_child(select_a_node); } diff --git a/editor/scene/connections_dialog.h b/editor/scene/connections_dialog.h index fbfe32cd50d..af5baa08ab4 100644 --- a/editor/scene/connections_dialog.h +++ b/editor/scene/connections_dialog.h @@ -231,6 +231,9 @@ class ConnectionsDock : public VBoxContainer { SLOT_MENU_DISCONNECT, }; + VBoxContainer *holder = nullptr; + Label *select_a_node = nullptr; + Object *selected_object = nullptr; ConnectionsDockTree *tree = nullptr; @@ -276,7 +279,7 @@ protected: static void _bind_methods(); public: - void set_object(Object *p_obj); + void set_selection(const Vector &p_objects); void update_tree(); ConnectionsDock();