Skip to content

Commit 5fa0f31

Browse files
KoBeWiRoboticy3
andcommitted
Edit groups on multiple nodes
Co-authored-by: Pablo Ibarz <[email protected]>
1 parent e6aa06d commit 5fa0f31

File tree

8 files changed

+154
-89
lines changed

8 files changed

+154
-89
lines changed

editor/docks/groups_editor.cpp

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,41 @@ void GroupsEditor::_set_group_checked(const String &p_name, bool p_checked) {
9393
ti->set_checked(0, p_checked);
9494
}
9595

96+
void GroupsEditor::_add_to_group(const StringName &p_name, bool p_persist, const Array &p_nodes) {
97+
for (const Variant &v : p_nodes) {
98+
Node *node = Object::cast_to<Node>(v.get_validated_object());
99+
if (node) {
100+
node->add_to_group(p_name, p_persist);
101+
}
102+
}
103+
}
104+
105+
void GroupsEditor::_remove_from_group(const StringName &p_name, const Array &p_nodes) {
106+
for (const Variant &v : p_nodes) {
107+
Node *node = Object::cast_to<Node>(v.get_validated_object());
108+
if (node) {
109+
node->remove_from_group(p_name);
110+
}
111+
}
112+
}
113+
114+
void GroupsEditor::_get_group_mask(const StringName &p_name, Array &r_nodes, bool p_invert) {
115+
for (Node *p_node : selection) {
116+
if (p_invert != p_node->is_in_group(p_name)) {
117+
r_nodes.push_back(p_node);
118+
}
119+
}
120+
}
121+
122+
bool GroupsEditor::_can_edit(const StringName &p_group) {
123+
for (Node *p_node : selection) {
124+
if (!can_edit(p_node, p_group)) {
125+
return false;
126+
}
127+
}
128+
return true;
129+
}
130+
96131
bool GroupsEditor::_has_group(const String &p_name) {
97132
return global_groups.has(p_name) || scene_groups.has(p_name);
98133
}
@@ -102,7 +137,7 @@ void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseBu
102137
return;
103138
}
104139

105-
if (!node) {
140+
if (selection.is_empty()) {
106141
return;
107142
}
108143

@@ -177,7 +212,7 @@ void GroupsEditor::_update_tree() {
177212
return;
178213
}
179214

180-
if (!node) {
215+
if (selection.is_empty()) {
181216
return;
182217
}
183218

@@ -190,7 +225,9 @@ void GroupsEditor::_update_tree() {
190225
tree->clear();
191226

192227
List<Node::GroupInfo> groups;
193-
node->get_groups(&groups);
228+
for (Node *p_node : selection) {
229+
p_node->get_groups(&groups);
230+
}
194231
groups.sort_custom<_GroupInfoComparator>();
195232

196233
List<StringName> current_groups;
@@ -220,7 +257,7 @@ void GroupsEditor::_update_tree() {
220257

221258
TreeItem *item = tree->create_item(local_root);
222259
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
223-
item->set_editable(0, can_edit(node, E));
260+
item->set_editable(0, _can_edit(E));
224261
item->set_checked(0, current_groups.find(E) != nullptr);
225262
item->set_text(0, E);
226263
item->set_meta("__local", true);
@@ -252,7 +289,7 @@ void GroupsEditor::_update_tree() {
252289

253290
TreeItem *item = tree->create_item(global_root);
254291
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
255-
item->set_editable(0, can_edit(node, E));
292+
item->set_editable(0, _can_edit(E));
256293
item->set_checked(0, current_groups.find(E) != nullptr);
257294
item->set_text(0, E);
258295
item->set_meta("__local", false);
@@ -307,15 +344,18 @@ void GroupsEditor::_cache_scene_groups(const ObjectID &p_id) {
307344
}
308345
}
309346

310-
void GroupsEditor::set_current(Node *p_node) {
311-
if (node == p_node) {
347+
void GroupsEditor::set_selection(const Vector<Node *> &p_nodes) {
348+
if (p_nodes.is_empty()) {
349+
holder->hide();
350+
select_a_node->show();
351+
selection.clear();
312352
return;
313353
}
314-
node = p_node;
315354

316-
if (!node) {
317-
return;
318-
}
355+
selection = p_nodes;
356+
357+
holder->show();
358+
select_a_node->hide();
319359

320360
if (scene_tree->get_edited_scene_root() != scene_root_node) {
321361
scene_root_node = scene_tree->get_edited_scene_root();
@@ -338,8 +378,10 @@ void GroupsEditor::_item_edited() {
338378
if (ti->is_checked(0)) {
339379
undo_redo->create_action(TTR("Add to Group"));
340380

341-
undo_redo->add_do_method(node, "add_to_group", name, true);
342-
undo_redo->add_undo_method(node, "remove_from_group", name);
381+
Array nodes;
382+
_get_group_mask(name, nodes, true);
383+
undo_redo->add_do_method(this, "_add_to_group", name, true, nodes);
384+
undo_redo->add_undo_method(this, "_remove_from_group", name, nodes);
343385

344386
undo_redo->add_do_method(this, "_set_group_checked", name, true);
345387
undo_redo->add_undo_method(this, "_set_group_checked", name, false);
@@ -353,8 +395,10 @@ void GroupsEditor::_item_edited() {
353395
} else {
354396
undo_redo->create_action(TTR("Remove from Group"));
355397

356-
undo_redo->add_do_method(node, "remove_from_group", name);
357-
undo_redo->add_undo_method(node, "add_to_group", name, true);
398+
Array nodes;
399+
_get_group_mask(name, nodes, false);
400+
undo_redo->add_do_method(this, "_remove_from_group", name, nodes);
401+
undo_redo->add_undo_method(this, "_add_to_group", name, true, nodes);
358402

359403
undo_redo->add_do_method(this, "_set_group_checked", name, false);
360404
undo_redo->add_undo_method(this, "_set_group_checked", name, true);
@@ -489,8 +533,10 @@ void GroupsEditor::_confirm_add() {
489533
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
490534
undo_redo->create_action(TTR("Add to Group"));
491535

492-
undo_redo->add_do_method(node, "add_to_group", name, true);
493-
undo_redo->add_undo_method(node, "remove_from_group", name);
536+
Array nodes;
537+
_get_group_mask(name, nodes, true);
538+
undo_redo->add_do_method(this, "_add_to_group", name, true, nodes);
539+
undo_redo->add_undo_method(this, "_remove_from_group", name, nodes);
494540

495541
bool is_local = !global_group_button->is_pressed();
496542
if (is_local) {
@@ -819,6 +865,9 @@ void GroupsEditor::_bind_methods() {
819865
ClassDB::bind_method("_rename_scene_group", &GroupsEditor::_rename_scene_group);
820866
ClassDB::bind_method("_remove_scene_group", &GroupsEditor::_remove_scene_group);
821867
ClassDB::bind_method("_set_group_checked", &GroupsEditor::_set_group_checked);
868+
869+
ClassDB::bind_method("_add_to_group", &GroupsEditor::_add_to_group);
870+
ClassDB::bind_method("_remove_from_group", &GroupsEditor::_remove_from_group);
822871
}
823872

824873
void GroupsEditor::_node_removed(Node *p_node) {
@@ -834,15 +883,19 @@ void GroupsEditor::_node_removed(Node *p_node) {
834883
}
835884

836885
GroupsEditor::GroupsEditor() {
837-
node = nullptr;
838886
scene_tree = SceneTree::get_singleton();
839887

840888
ED_SHORTCUT("groups_editor/delete", TTRC("Delete"), Key::KEY_DELETE);
841889
ED_SHORTCUT("groups_editor/rename", TTRC("Rename"), Key::F2);
842890
ED_SHORTCUT_OVERRIDE("groups_editor/rename", "macos", Key::ENTER);
843891

892+
holder = memnew(VBoxContainer);
893+
holder->set_v_size_flags(SIZE_EXPAND_FILL);
894+
holder->hide();
895+
add_child(holder);
896+
844897
HBoxContainer *hbc = memnew(HBoxContainer);
845-
add_child(hbc);
898+
holder->add_child(hbc);
846899

847900
add = memnew(Button);
848901
add->set_theme_type_variation("FlatMenuButton");
@@ -867,11 +920,21 @@ GroupsEditor::GroupsEditor() {
867920
tree->connect("button_clicked", callable_mp(this, &GroupsEditor::_modify_group));
868921
tree->connect("item_mouse_selected", callable_mp(this, &GroupsEditor::_item_mouse_selected));
869922
tree->connect(SceneStringName(gui_input), callable_mp(this, &GroupsEditor::_groups_gui_input));
870-
add_child(tree);
923+
holder->add_child(tree);
871924

872925
menu = memnew(PopupMenu);
873926
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GroupsEditor::_menu_id_pressed));
874927
tree->add_child(menu);
875928

929+
select_a_node = memnew(Label);
930+
select_a_node->set_focus_mode(FOCUS_ACCESSIBILITY);
931+
select_a_node->set_text(TTRC("Select one or more nodes to edit their groups."));
932+
select_a_node->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
933+
select_a_node->set_v_size_flags(SIZE_EXPAND_FILL);
934+
select_a_node->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
935+
select_a_node->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
936+
select_a_node->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
937+
add_child(select_a_node);
938+
876939
ProjectSettingsEditor::get_singleton()->get_group_settings()->connect("group_changed", callable_mp(this, &GroupsEditor::_update_groups_and_tree));
877940
}

editor/docks/groups_editor.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class GroupsEditor : public VBoxContainer {
5252
bool groups_dirty = false;
5353
bool update_groups_and_tree_queued = false;
5454

55-
Node *node = nullptr;
55+
LocalVector<Node *> selection;
5656
Node *scene_root_node = nullptr;
5757
SceneTree *scene_tree = nullptr;
5858

@@ -73,9 +73,11 @@ class GroupsEditor : public VBoxContainer {
7373

7474
PopupMenu *menu = nullptr;
7575

76+
VBoxContainer *holder = nullptr;
7677
LineEdit *filter = nullptr;
7778
Button *add = nullptr;
7879
Tree *tree = nullptr;
80+
Label *select_a_node = nullptr;
7981

8082
HashMap<ObjectID, HashMap<StringName, bool>> scene_groups_cache;
8183
HashMap<StringName, bool> scene_groups_for_caching;
@@ -122,6 +124,11 @@ class GroupsEditor : public VBoxContainer {
122124

123125
void _node_removed(Node *p_node);
124126

127+
void _add_to_group(const StringName &p_name, bool p_persist, const Array &p_nodes);
128+
void _remove_from_group(const StringName &p_name, const Array &p_nodes);
129+
void _get_group_mask(const StringName &p_name, Array &r_nodes, bool p_invert);
130+
bool _can_edit(const StringName &p_group);
131+
125132
protected:
126133
void _notification(int p_what);
127134
static void _bind_methods();
@@ -134,7 +141,7 @@ class GroupsEditor : public VBoxContainer {
134141
CONVERT_GROUP,
135142
};
136143

137-
void set_current(Node *p_node);
144+
void set_selection(const Vector<Node *> &p_nodes);
138145

139146
GroupsEditor();
140147
};

editor/docks/node_dock.cpp

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,7 @@ void NodeDock::save_layout_to_config(Ref<ConfigFile> &p_layout, const String &p_
5555

5656
void NodeDock::load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) {
5757
const int current_tab = p_layout->get_value(p_section, "current_tab", 0);
58-
if (select_a_node->is_visible()) {
59-
if (current_tab == 0) {
60-
groups_button->set_pressed_no_signal(false);
61-
connections_button->set_pressed_no_signal(true);
62-
} else if (current_tab == 1) {
63-
groups_button->set_pressed_no_signal(true);
64-
connections_button->set_pressed_no_signal(false);
65-
}
66-
} else if (current_tab == 0) {
58+
if (current_tab == 0) {
6759
show_connections();
6860
} else if (current_tab == 1) {
6961
show_groups();
@@ -83,32 +75,17 @@ void NodeDock::update_lists() {
8375
connections->update_tree();
8476
}
8577

86-
void NodeDock::set_object(Object *p_object) {
87-
connections->set_object(p_object);
88-
groups->set_current(Object::cast_to<Node>(p_object));
89-
90-
if (p_object) {
91-
if (connections_button->is_pressed()) {
92-
connections->show();
93-
} else {
94-
groups->show();
95-
}
78+
void NodeDock::set_selection(const Vector<Object *> &p_objects) {
79+
connections->set_selection(p_objects);
9680

97-
if (Object::cast_to<Resource>(p_object)) {
98-
show_connections();
99-
groups_button->set_disabled(true);
100-
} else {
101-
groups_button->set_disabled(false);
81+
Vector<Node *> nodes;
82+
for (Object *obj : p_objects) {
83+
Node *n = Object::cast_to<Node>(obj);
84+
if (n) {
85+
nodes.append(n);
10286
}
103-
104-
mode_hb->show();
105-
select_a_node->hide();
106-
} else {
107-
connections->hide();
108-
groups->hide();
109-
mode_hb->hide();
110-
select_a_node->show();
11187
}
88+
groups->set_selection(nodes);
11289
}
11390

11491
NodeDock::NodeDock() {
@@ -123,13 +100,11 @@ NodeDock::NodeDock() {
123100

124101
mode_hb = memnew(HBoxContainer);
125102
main_vb->add_child(mode_hb);
126-
mode_hb->hide();
127103

128104
connections_button = memnew(Button);
129105
connections_button->set_theme_type_variation(SceneStringName(FlatButton));
130106
connections_button->set_text(TTRC("Signals"));
131107
connections_button->set_toggle_mode(true);
132-
connections_button->set_pressed(true);
133108
connections_button->set_h_size_flags(SIZE_EXPAND_FILL);
134109
connections_button->set_clip_text(true);
135110
mode_hb->add_child(connections_button);
@@ -139,7 +114,6 @@ NodeDock::NodeDock() {
139114
groups_button->set_theme_type_variation(SceneStringName(FlatButton));
140115
groups_button->set_text(TTRC("Groups"));
141116
groups_button->set_toggle_mode(true);
142-
groups_button->set_pressed(false);
143117
groups_button->set_h_size_flags(SIZE_EXPAND_FILL);
144118
groups_button->set_clip_text(true);
145119
mode_hb->add_child(groups_button);
@@ -155,15 +129,7 @@ NodeDock::NodeDock() {
155129
groups->set_v_size_flags(SIZE_EXPAND_FILL);
156130
groups->hide();
157131

158-
select_a_node = memnew(Label);
159-
select_a_node->set_focus_mode(FOCUS_ACCESSIBILITY);
160-
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."));
161-
select_a_node->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
162-
select_a_node->set_v_size_flags(SIZE_EXPAND_FILL);
163-
select_a_node->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
164-
select_a_node->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
165-
select_a_node->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
166-
main_vb->add_child(select_a_node);
132+
show_connections();
167133
}
168134

169135
NodeDock::~NodeDock() {

editor/docks/node_dock.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ class NodeDock : public EditorDock {
4747

4848
HBoxContainer *mode_hb = nullptr;
4949

50-
Label *select_a_node = nullptr;
51-
5250
private:
5351
inline static NodeDock *singleton = nullptr;
5452

@@ -62,7 +60,7 @@ class NodeDock : public EditorDock {
6260
virtual void load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) override;
6361

6462
public:
65-
void set_object(Object *p_object);
63+
void set_selection(const Vector<Object *> &p_objects);
6664

6765
void show_groups();
6866
void show_connections();

editor/docks/scene_tree_dock.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
13611361
undo_redo->add_undo_method(node, "set_scene_file_path", node->get_scene_file_path());
13621362
_node_replace_owner(node, node, root);
13631363
_node_strip_signal_inheritance(node);
1364-
NodeDock::get_singleton()->set_object(node); // Refresh.
1364+
NodeDock::get_singleton()->set_selection(Vector<Object *>{ node }); // Refresh.
13651365
undo_redo->add_do_method(scene_tree, "update_tree");
13661366
undo_redo->add_undo_method(scene_tree, "update_tree");
13671367
undo_redo->commit_action();
@@ -2865,7 +2865,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
28652865
editor_history->cleanup_history();
28662866
InspectorDock::get_singleton()->call("_prepare_history");
28672867
InspectorDock::get_singleton()->update(nullptr);
2868-
NodeDock::get_singleton()->set_object(nullptr);
2868+
NodeDock::get_singleton()->set_selection(Vector<Object *>{});
28692869
}
28702870

28712871
void SceneTreeDock::_update_script_button() {

0 commit comments

Comments
 (0)