1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-03 16:55:53 +00:00

Merge pull request #112729 from KoBeWi/multi_group_yoink

Edit groups on multiple nodes
This commit is contained in:
Thaddeus Crews
2025-11-20 16:47:07 -06:00
8 changed files with 154 additions and 89 deletions

View File

@@ -93,6 +93,41 @@ void GroupsEditor::_set_group_checked(const String &p_name, bool p_checked) {
ti->set_checked(0, 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<Node>(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<Node>(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) { bool GroupsEditor::_has_group(const String &p_name) {
return global_groups.has(p_name) || scene_groups.has(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; return;
} }
if (!node) { if (selection.is_empty()) {
return; return;
} }
@@ -177,7 +212,7 @@ void GroupsEditor::_update_tree() {
return; return;
} }
if (!node) { if (selection.is_empty()) {
return; return;
} }
@@ -190,7 +225,9 @@ void GroupsEditor::_update_tree() {
tree->clear(); tree->clear();
List<Node::GroupInfo> groups; List<Node::GroupInfo> groups;
node->get_groups(&groups); for (Node *p_node : selection) {
p_node->get_groups(&groups);
}
groups.sort_custom<_GroupInfoComparator>(); groups.sort_custom<_GroupInfoComparator>();
List<StringName> current_groups; List<StringName> current_groups;
@@ -220,7 +257,7 @@ void GroupsEditor::_update_tree() {
TreeItem *item = tree->create_item(local_root); TreeItem *item = tree->create_item(local_root);
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); 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_checked(0, current_groups.find(E) != nullptr);
item->set_text(0, E); item->set_text(0, E);
item->set_meta("__local", true); item->set_meta("__local", true);
@@ -252,7 +289,7 @@ void GroupsEditor::_update_tree() {
TreeItem *item = tree->create_item(global_root); TreeItem *item = tree->create_item(global_root);
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); 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_checked(0, current_groups.find(E) != nullptr);
item->set_text(0, E); item->set_text(0, E);
item->set_meta("__local", false); 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) { void GroupsEditor::set_selection(const Vector<Node *> &p_nodes) {
if (node == p_node) { if (p_nodes.is_empty()) {
holder->hide();
select_a_node->show();
selection.clear();
return; return;
} }
node = p_node;
if (!node) { selection = p_nodes;
return;
} holder->show();
select_a_node->hide();
if (scene_tree->get_edited_scene_root() != scene_root_node) { if (scene_tree->get_edited_scene_root() != scene_root_node) {
scene_root_node = scene_tree->get_edited_scene_root(); scene_root_node = scene_tree->get_edited_scene_root();
@@ -338,8 +378,10 @@ void GroupsEditor::_item_edited() {
if (ti->is_checked(0)) { if (ti->is_checked(0)) {
undo_redo->create_action(TTR("Add to Group")); undo_redo->create_action(TTR("Add to Group"));
undo_redo->add_do_method(node, "add_to_group", name, true); Array nodes;
undo_redo->add_undo_method(node, "remove_from_group", name); _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_do_method(this, "_set_group_checked", name, true);
undo_redo->add_undo_method(this, "_set_group_checked", name, false); undo_redo->add_undo_method(this, "_set_group_checked", name, false);
@@ -353,8 +395,10 @@ void GroupsEditor::_item_edited() {
} else { } else {
undo_redo->create_action(TTR("Remove from Group")); undo_redo->create_action(TTR("Remove from Group"));
undo_redo->add_do_method(node, "remove_from_group", name); Array nodes;
undo_redo->add_undo_method(node, "add_to_group", name, true); _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_do_method(this, "_set_group_checked", name, false);
undo_redo->add_undo_method(this, "_set_group_checked", name, true); 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(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add to Group")); undo_redo->create_action(TTR("Add to Group"));
undo_redo->add_do_method(node, "add_to_group", name, true); Array nodes;
undo_redo->add_undo_method(node, "remove_from_group", name); _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(); bool is_local = !global_group_button->is_pressed();
if (is_local) { if (is_local) {
@@ -819,6 +865,9 @@ void GroupsEditor::_bind_methods() {
ClassDB::bind_method("_rename_scene_group", &GroupsEditor::_rename_scene_group); ClassDB::bind_method("_rename_scene_group", &GroupsEditor::_rename_scene_group);
ClassDB::bind_method("_remove_scene_group", &GroupsEditor::_remove_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("_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) { void GroupsEditor::_node_removed(Node *p_node) {
@@ -834,15 +883,19 @@ void GroupsEditor::_node_removed(Node *p_node) {
} }
GroupsEditor::GroupsEditor() { GroupsEditor::GroupsEditor() {
node = nullptr;
scene_tree = SceneTree::get_singleton(); scene_tree = SceneTree::get_singleton();
ED_SHORTCUT("groups_editor/delete", TTRC("Delete"), Key::KEY_DELETE); ED_SHORTCUT("groups_editor/delete", TTRC("Delete"), Key::KEY_DELETE);
ED_SHORTCUT("groups_editor/rename", TTRC("Rename"), Key::F2); ED_SHORTCUT("groups_editor/rename", TTRC("Rename"), Key::F2);
ED_SHORTCUT_OVERRIDE("groups_editor/rename", "macos", Key::ENTER); 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); HBoxContainer *hbc = memnew(HBoxContainer);
add_child(hbc); holder->add_child(hbc);
add = memnew(Button); add = memnew(Button);
add->set_theme_type_variation("FlatMenuButton"); add->set_theme_type_variation("FlatMenuButton");
@@ -867,11 +920,21 @@ GroupsEditor::GroupsEditor() {
tree->connect("button_clicked", callable_mp(this, &GroupsEditor::_modify_group)); tree->connect("button_clicked", callable_mp(this, &GroupsEditor::_modify_group));
tree->connect("item_mouse_selected", callable_mp(this, &GroupsEditor::_item_mouse_selected)); tree->connect("item_mouse_selected", callable_mp(this, &GroupsEditor::_item_mouse_selected));
tree->connect(SceneStringName(gui_input), callable_mp(this, &GroupsEditor::_groups_gui_input)); tree->connect(SceneStringName(gui_input), callable_mp(this, &GroupsEditor::_groups_gui_input));
add_child(tree); holder->add_child(tree);
menu = memnew(PopupMenu); menu = memnew(PopupMenu);
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GroupsEditor::_menu_id_pressed)); menu->connect(SceneStringName(id_pressed), callable_mp(this, &GroupsEditor::_menu_id_pressed));
tree->add_child(menu); 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)); ProjectSettingsEditor::get_singleton()->get_group_settings()->connect("group_changed", callable_mp(this, &GroupsEditor::_update_groups_and_tree));
} }

View File

@@ -52,7 +52,7 @@ class GroupsEditor : public VBoxContainer {
bool groups_dirty = false; bool groups_dirty = false;
bool update_groups_and_tree_queued = false; bool update_groups_and_tree_queued = false;
Node *node = nullptr; LocalVector<Node *> selection;
Node *scene_root_node = nullptr; Node *scene_root_node = nullptr;
SceneTree *scene_tree = nullptr; SceneTree *scene_tree = nullptr;
@@ -73,9 +73,11 @@ class GroupsEditor : public VBoxContainer {
PopupMenu *menu = nullptr; PopupMenu *menu = nullptr;
VBoxContainer *holder = nullptr;
LineEdit *filter = nullptr; LineEdit *filter = nullptr;
Button *add = nullptr; Button *add = nullptr;
Tree *tree = nullptr; Tree *tree = nullptr;
Label *select_a_node = nullptr;
HashMap<ObjectID, HashMap<StringName, bool>> scene_groups_cache; HashMap<ObjectID, HashMap<StringName, bool>> scene_groups_cache;
HashMap<StringName, bool> scene_groups_for_caching; HashMap<StringName, bool> scene_groups_for_caching;
@@ -122,6 +124,11 @@ class GroupsEditor : public VBoxContainer {
void _node_removed(Node *p_node); 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: protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();
@@ -134,7 +141,7 @@ public:
CONVERT_GROUP, CONVERT_GROUP,
}; };
void set_current(Node *p_node); void set_selection(const Vector<Node *> &p_nodes);
GroupsEditor(); GroupsEditor();
}; };

View File

@@ -55,15 +55,7 @@ void NodeDock::save_layout_to_config(Ref<ConfigFile> &p_layout, const String &p_
void NodeDock::load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) { void NodeDock::load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) {
const int current_tab = p_layout->get_value(p_section, "current_tab", 0); const int current_tab = p_layout->get_value(p_section, "current_tab", 0);
if (select_a_node->is_visible()) {
if (current_tab == 0) { 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) {
show_connections(); show_connections();
} else if (current_tab == 1) { } else if (current_tab == 1) {
show_groups(); show_groups();
@@ -83,32 +75,17 @@ void NodeDock::update_lists() {
connections->update_tree(); connections->update_tree();
} }
void NodeDock::set_object(Object *p_object) { void NodeDock::set_selection(const Vector<Object *> &p_objects) {
connections->set_object(p_object); connections->set_selection(p_objects);
groups->set_current(Object::cast_to<Node>(p_object));
if (p_object) { Vector<Node *> nodes;
if (connections_button->is_pressed()) { for (Object *obj : p_objects) {
connections->show(); Node *n = Object::cast_to<Node>(obj);
} else { if (n) {
groups->show(); nodes.append(n);
} }
if (Object::cast_to<Resource>(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() { NodeDock::NodeDock() {
@@ -123,13 +100,11 @@ NodeDock::NodeDock() {
mode_hb = memnew(HBoxContainer); mode_hb = memnew(HBoxContainer);
main_vb->add_child(mode_hb); main_vb->add_child(mode_hb);
mode_hb->hide();
connections_button = memnew(Button); connections_button = memnew(Button);
connections_button->set_theme_type_variation(SceneStringName(FlatButton)); connections_button->set_theme_type_variation(SceneStringName(FlatButton));
connections_button->set_text(TTRC("Signals")); connections_button->set_text(TTRC("Signals"));
connections_button->set_toggle_mode(true); connections_button->set_toggle_mode(true);
connections_button->set_pressed(true);
connections_button->set_h_size_flags(SIZE_EXPAND_FILL); connections_button->set_h_size_flags(SIZE_EXPAND_FILL);
connections_button->set_clip_text(true); connections_button->set_clip_text(true);
mode_hb->add_child(connections_button); mode_hb->add_child(connections_button);
@@ -139,7 +114,6 @@ NodeDock::NodeDock() {
groups_button->set_theme_type_variation(SceneStringName(FlatButton)); groups_button->set_theme_type_variation(SceneStringName(FlatButton));
groups_button->set_text(TTRC("Groups")); groups_button->set_text(TTRC("Groups"));
groups_button->set_toggle_mode(true); groups_button->set_toggle_mode(true);
groups_button->set_pressed(false);
groups_button->set_h_size_flags(SIZE_EXPAND_FILL); groups_button->set_h_size_flags(SIZE_EXPAND_FILL);
groups_button->set_clip_text(true); groups_button->set_clip_text(true);
mode_hb->add_child(groups_button); mode_hb->add_child(groups_button);
@@ -155,15 +129,7 @@ NodeDock::NodeDock() {
groups->set_v_size_flags(SIZE_EXPAND_FILL); groups->set_v_size_flags(SIZE_EXPAND_FILL);
groups->hide(); groups->hide();
select_a_node = memnew(Label); show_connections();
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);
} }
NodeDock::~NodeDock() { NodeDock::~NodeDock() {

View File

@@ -47,8 +47,6 @@ class NodeDock : public EditorDock {
HBoxContainer *mode_hb = nullptr; HBoxContainer *mode_hb = nullptr;
Label *select_a_node = nullptr;
private: private:
inline static NodeDock *singleton = nullptr; inline static NodeDock *singleton = nullptr;
@@ -62,7 +60,7 @@ protected:
virtual void load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) override; virtual void load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) override;
public: public:
void set_object(Object *p_object); void set_selection(const Vector<Object *> &p_objects);
void show_groups(); void show_groups();
void show_connections(); void show_connections();

View File

@@ -1351,7 +1351,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()); undo_redo->add_undo_method(node, "set_scene_file_path", node->get_scene_file_path());
_node_replace_owner(node, node, root); _node_replace_owner(node, node, root);
_node_strip_signal_inheritance(node); _node_strip_signal_inheritance(node);
NodeDock::get_singleton()->set_object(node); // Refresh. NodeDock::get_singleton()->set_selection(Vector<Object *>{ node }); // Refresh.
undo_redo->add_do_method(scene_tree, "update_tree"); undo_redo->add_do_method(scene_tree, "update_tree");
undo_redo->add_undo_method(scene_tree, "update_tree"); undo_redo->add_undo_method(scene_tree, "update_tree");
undo_redo->commit_action(); undo_redo->commit_action();
@@ -2855,7 +2855,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
editor_history->cleanup_history(); editor_history->cleanup_history();
InspectorDock::get_singleton()->call("_prepare_history"); InspectorDock::get_singleton()->call("_prepare_history");
InspectorDock::get_singleton()->update(nullptr); InspectorDock::get_singleton()->update(nullptr);
NodeDock::get_singleton()->set_object(nullptr); NodeDock::get_singleton()->set_selection(Vector<Object *>{});
} }
void SceneTreeDock::_update_script_button() { void SceneTreeDock::_update_script_button() {

View File

@@ -2888,7 +2888,7 @@ void EditorNode::push_node_item(Node *p_node) {
void EditorNode::push_item(Object *p_object, const String &p_property, bool p_inspector_only) { void EditorNode::push_item(Object *p_object, const String &p_property, bool p_inspector_only) {
if (!p_object) { if (!p_object) {
InspectorDock::get_inspector_singleton()->edit(nullptr); InspectorDock::get_inspector_singleton()->edit(nullptr);
NodeDock::get_singleton()->set_object(nullptr); NodeDock::get_singleton()->set_selection(Vector<Object *>());
SceneTreeDock::get_singleton()->set_selected(nullptr); SceneTreeDock::get_singleton()->set_selected(nullptr);
InspectorDock::get_singleton()->update(nullptr); InspectorDock::get_singleton()->update(nullptr);
hide_unused_editors(); hide_unused_editors();
@@ -2999,7 +2999,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
if (!current_obj) { if (!current_obj) {
SceneTreeDock::get_singleton()->set_selected(nullptr); SceneTreeDock::get_singleton()->set_selected(nullptr);
InspectorDock::get_inspector_singleton()->edit(nullptr); InspectorDock::get_inspector_singleton()->edit(nullptr);
NodeDock::get_singleton()->set_object(nullptr); NodeDock::get_singleton()->set_selection(Vector<Object *>());
InspectorDock::get_singleton()->update(nullptr); InspectorDock::get_singleton()->update(nullptr);
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection(); EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
hide_unused_editors(); hide_unused_editors();
@@ -3033,7 +3033,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
if (!p_skip_inspector_update) { if (!p_skip_inspector_update) {
InspectorDock::get_inspector_singleton()->edit(current_res); InspectorDock::get_inspector_singleton()->edit(current_res);
SceneTreeDock::get_singleton()->set_selected(nullptr); SceneTreeDock::get_singleton()->set_selected(nullptr);
NodeDock::get_singleton()->set_object(current_res); NodeDock::get_singleton()->set_selection(Vector<Object *>{ current_res });
InspectorDock::get_singleton()->update(nullptr); InspectorDock::get_singleton()->update(nullptr);
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection(); EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
ImportDock::get_singleton()->set_edit_path(current_res->get_path()); ImportDock::get_singleton()->set_edit_path(current_res->get_path());
@@ -3063,7 +3063,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
InspectorDock::get_inspector_singleton()->edit(current_node); InspectorDock::get_inspector_singleton()->edit(current_node);
if (current_node->is_inside_tree()) { if (current_node->is_inside_tree()) {
NodeDock::get_singleton()->set_object(current_node); NodeDock::get_singleton()->set_selection(Vector<Object *>{ current_node });
SceneTreeDock::get_singleton()->set_selected(current_node); SceneTreeDock::get_singleton()->set_selected(current_node);
SceneTreeDock::get_singleton()->set_selection({ current_node }); SceneTreeDock::get_singleton()->set_selection({ current_node });
InspectorDock::get_singleton()->update(current_node); InspectorDock::get_singleton()->update(current_node);
@@ -3075,7 +3075,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
} }
} }
} else { } else {
NodeDock::get_singleton()->set_object(nullptr); NodeDock::get_singleton()->set_selection(Vector<Object *>());
SceneTreeDock::get_singleton()->set_selected(nullptr); SceneTreeDock::get_singleton()->set_selected(nullptr);
InspectorDock::get_singleton()->update(nullptr); InspectorDock::get_singleton()->update(nullptr);
} }
@@ -3122,8 +3122,15 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection(); EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
} }
// TODO: This can be replaced by some casting operator.
Vector<Object *> 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); 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_selected(selected_node);
SceneTreeDock::get_singleton()->set_selection(multi_nodes); SceneTreeDock::get_singleton()->set_selection(multi_nodes);
InspectorDock::get_singleton()->update(nullptr); InspectorDock::get_singleton()->update(nullptr);

View File

@@ -1503,8 +1503,16 @@ void ConnectionsDock::_bind_methods() {
ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree); ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree);
} }
void ConnectionsDock::set_object(Object *p_obj) { void ConnectionsDock::set_selection(const Vector<Object *> &p_objects) {
selected_object = p_obj; 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<Resource>(selected_object) != nullptr); is_editing_resource = (Object::cast_to<Resource>(selected_object) != nullptr);
update_tree(); update_tree();
} }
@@ -1699,7 +1707,10 @@ void ConnectionsDock::update_tree() {
ConnectionsDock::ConnectionsDock() { ConnectionsDock::ConnectionsDock() {
set_name(TTR("Signals")); 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 = memnew(LineEdit);
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -1707,7 +1718,7 @@ ConnectionsDock::ConnectionsDock() {
search_box->set_accessibility_name(TTRC("Filter Signals")); search_box->set_accessibility_name(TTRC("Filter Signals"));
search_box->set_clear_button_enabled(true); search_box->set_clear_button_enabled(true);
search_box->connect(SceneStringName(text_changed), callable_mp(this, &ConnectionsDock::_filter_changed)); 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 = memnew(ConnectionsDockTree);
tree->set_accessibility_name(TTRC("Connections")); tree->set_accessibility_name(TTRC("Connections"));
@@ -1716,24 +1727,24 @@ ConnectionsDock::ConnectionsDock() {
tree->set_select_mode(Tree::SELECT_ROW); tree->set_select_mode(Tree::SELECT_ROW);
tree->set_hide_root(true); tree->set_hide_root(true);
tree->set_column_clip_content(0, 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_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->set_allow_rmb_select(true); tree->set_allow_rmb_select(true);
connect_button = memnew(Button); connect_button = memnew(Button);
connect_button->set_accessibility_name(TTRC("Connect")); connect_button->set_accessibility_name(TTRC("Connect"));
HBoxContainer *hb = memnew(HBoxContainer); HBoxContainer *hb = memnew(HBoxContainer);
vbc->add_child(hb); holder->add_child(hb);
hb->add_spacer(); hb->add_spacer();
hb->add_child(connect_button); hb->add_child(connect_button);
connect_button->connect(SceneStringName(pressed), callable_mp(this, &ConnectionsDock::_connect_pressed)); connect_button->connect(SceneStringName(pressed), callable_mp(this, &ConnectionsDock::_connect_pressed));
connect_dialog = memnew(ConnectDialog); connect_dialog = memnew(ConnectDialog);
connect_dialog->set_process_shortcut_input(true); connect_dialog->set_process_shortcut_input(true);
add_child(connect_dialog); holder->add_child(connect_dialog);
disconnect_all_dialog = memnew(ConfirmationDialog); 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->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?")); disconnect_all_dialog->set_text(TTR("Are you sure you want to remove all connections from this signal?"));
@@ -1741,7 +1752,7 @@ ConnectionsDock::ConnectionsDock() {
class_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_class_menu_option)); 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->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_class_menu_about_to_popup));
class_menu->add_item(TTR("Open Documentation"), CLASS_MENU_OPEN_DOCS); 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 = memnew(PopupMenu);
signal_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_signal_menu_option)); signal_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_signal_menu_option));
@@ -1751,7 +1762,7 @@ ConnectionsDock::ConnectionsDock() {
signal_menu->add_item(TTR("Copy Name"), SIGNAL_MENU_COPY_NAME); signal_menu->add_item(TTR("Copy Name"), SIGNAL_MENU_COPY_NAME);
signal_menu->add_separator(); signal_menu->add_separator();
signal_menu->add_item(TTR("Open Documentation"), SIGNAL_MENU_OPEN_DOCS); 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 = memnew(PopupMenu);
slot_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_slot_menu_option)); slot_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ConnectionsDock::_handle_slot_menu_option));
@@ -1759,7 +1770,7 @@ ConnectionsDock::ConnectionsDock() {
slot_menu->add_item(TTR("Edit..."), SLOT_MENU_EDIT); 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_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); 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)); connect_dialog->connect("connected", callable_mp(this, &ConnectionsDock::_make_or_edit_connection));
tree->connect(SceneStringName(item_selected), callable_mp(this, &ConnectionsDock::_tree_item_selected)); tree->connect(SceneStringName(item_selected), callable_mp(this, &ConnectionsDock::_tree_item_selected));
@@ -1767,4 +1778,14 @@ ConnectionsDock::ConnectionsDock() {
tree->connect(SceneStringName(gui_input), callable_mp(this, &ConnectionsDock::_tree_gui_input)); tree->connect(SceneStringName(gui_input), callable_mp(this, &ConnectionsDock::_tree_gui_input));
add_theme_constant_override("separation", 3 * EDSCALE); 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);
} }

View File

@@ -237,6 +237,9 @@ class ConnectionsDock : public VBoxContainer {
SLOT_MENU_DISCONNECT, SLOT_MENU_DISCONNECT,
}; };
VBoxContainer *holder = nullptr;
Label *select_a_node = nullptr;
Object *selected_object = nullptr; Object *selected_object = nullptr;
ConnectionsDockTree *tree = nullptr; ConnectionsDockTree *tree = nullptr;
@@ -282,7 +285,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: public:
void set_object(Object *p_obj); void set_selection(const Vector<Object *> &p_objects);
void update_tree(); void update_tree();
ConnectionsDock(); ConnectionsDock();