Skip to content

Commit 96a5791

Browse files
miheArnklit
andcommitted
Add ability to drag-toggle visibility in scene tree editor
Co-authored-by: Kasper Arnklit Frandsen <kasper.arnklit@gmail.com>
1 parent 3f63a40 commit 96a5791

2 files changed

Lines changed: 108 additions & 0 deletions

File tree

editor/scene/scene_tree_editor.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,90 @@ PackedStringArray SceneTreeEditor::_get_node_accessibility_configuration_warning
9292
return warnings;
9393
}
9494

95+
void SceneTreeEditor::_gui_input(const Ref<InputEvent> &p_event) {
96+
if (connect_to_script_mode) {
97+
return; // Don't do anything in this mode.
98+
}
99+
100+
Ref<InputEventMouseButton> mb = p_event;
101+
if (mb.is_valid()) {
102+
if (mb->get_button_index() == MouseButton::LEFT) {
103+
if (mb->is_pressed()) {
104+
Vector2 tree_mouse_pos = tree->get_transform().xform_inv(mb->get_position());
105+
int tree_button_id = tree->get_button_id_at_position(tree_mouse_pos);
106+
if (tree_button_id == BUTTON_VISIBILITY) {
107+
TreeItem *tree_item = tree->get_item_at_position(tree_mouse_pos);
108+
ERR_FAIL_NULL(tree_item);
109+
NodePath node_path = tree_item->get_metadata(0);
110+
Node *node = get_node_or_null(node_path);
111+
if (node != nullptr) {
112+
visibility_drag_value = !node->call("is_visible");
113+
visibility_drag_start_pos = tree_mouse_pos;
114+
visibility_drag_start_node = node->get_instance_id();
115+
}
116+
}
117+
} else if (mb->is_released() && visibility_drag_start_node.is_valid()) {
118+
if (!visibility_drag_nodes.is_empty()) {
119+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
120+
undo_redo->create_action(vformat(TTR("Toggle Visibility of %d Nodes"), visibility_drag_nodes.size()));
121+
122+
for (ObjectID id : visibility_drag_nodes) {
123+
Node *node = ObjectDB::get_instance<Node>(id);
124+
if (node != nullptr) {
125+
undo_redo->add_do_method(node, "set_visible", visibility_drag_value);
126+
undo_redo->add_undo_method(node, "set_visible", !visibility_drag_value);
127+
}
128+
}
129+
130+
undo_redo->commit_action(false);
131+
}
132+
133+
// Defer this so that `_cell_button_pressed` can still react to the dragging.
134+
callable_mp(this, &SceneTreeEditor::_reset_visibility_drag).call_deferred();
135+
}
136+
} else if (mb->get_button_index() == MouseButton::RIGHT && visibility_drag_start_node.is_valid()) {
137+
_reset_visibility_drag();
138+
accept_event();
139+
}
140+
141+
return;
142+
}
143+
144+
Ref<InputEventMouseMotion> mm = p_event;
145+
if (mm.is_valid()) {
146+
if (visibility_drag_start_node.is_valid()) {
147+
Vector2 tree_mouse_pos = tree->get_transform().xform_inv(mm->get_position());
148+
int tree_button_id = tree->get_button_id_at_position(tree_mouse_pos);
149+
bool crossed_drag_threshold = visibility_drag_start_pos.distance_to(tree_mouse_pos) > get_viewport()->get_drag_threshold();
150+
if (tree_button_id == BUTTON_VISIBILITY && (crossed_drag_threshold || !visibility_drag_nodes.is_empty())) {
151+
Node *start_node = ObjectDB::get_instance<Node>(visibility_drag_start_node);
152+
if (start_node != nullptr && (bool)start_node->call("is_visible") != visibility_drag_value) {
153+
start_node->call("set_visible", visibility_drag_value);
154+
visibility_drag_nodes.push_back(visibility_drag_start_node);
155+
}
156+
157+
TreeItem *tree_item = tree->get_item_at_position(tree_mouse_pos);
158+
ERR_FAIL_NULL(tree_item);
159+
NodePath node_path = tree_item->get_metadata(0);
160+
Node *node = get_node_or_null(node_path);
161+
if (node != nullptr && (bool)node->call("is_visible") != visibility_drag_value) {
162+
node->call("set_visible", visibility_drag_value);
163+
visibility_drag_nodes.push_back(node->get_instance_id());
164+
}
165+
}
166+
}
167+
168+
return;
169+
}
170+
171+
if (p_event->is_action_type()) {
172+
if (p_event->is_action_pressed(SNAME("ui_cancel")) && visibility_drag_start_node.is_valid()) {
173+
_reset_visibility_drag();
174+
accept_event();
175+
}
176+
}
177+
}
178+
95179
void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {
96180
if (p_button != MouseButton::LEFT) {
97181
return;
@@ -125,6 +209,10 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
125209
}
126210

127211
} else if (p_id == BUTTON_VISIBILITY) {
212+
if (!visibility_drag_nodes.is_empty()) {
213+
return;
214+
}
215+
128216
undo_redo->create_action(TTR("Toggle Visible"));
129217
_toggle_visible(n);
130218
List<Node *> selection = editor_selection->get_top_selected_node_list();
@@ -1367,6 +1455,13 @@ void SceneTreeEditor::_tree_scroll_to_item(ObjectID p_item_id) {
13671455
}
13681456
}
13691457

1458+
void SceneTreeEditor::_reset_visibility_drag() {
1459+
visibility_drag_value = false;
1460+
visibility_drag_start_pos = Vector2();
1461+
visibility_drag_start_node = ObjectID();
1462+
visibility_drag_nodes.clear();
1463+
}
1464+
13701465
void SceneTreeEditor::_notification(int p_what) {
13711466
switch (p_what) {
13721467
case NOTIFICATION_ENTER_TREE: {
@@ -1430,6 +1525,11 @@ void SceneTreeEditor::_notification(int p_what) {
14301525
}
14311526
}
14321527
} break;
1528+
1529+
case NOTIFICATION_APPLICATION_FOCUS_OUT:
1530+
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
1531+
_reset_visibility_drag();
1532+
} break;
14331533
}
14341534
}
14351535

@@ -2194,6 +2294,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
21942294
tree->connect("multi_selected", callable_mp(this, &SceneTreeEditor::_cell_multi_selected));
21952295
tree->connect("button_clicked", callable_mp(this, &SceneTreeEditor::_cell_button_pressed));
21962296
tree->connect("nothing_selected", callable_mp(this, &SceneTreeEditor::_deselect_items));
2297+
tree->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeEditor::_gui_input));
21972298

21982299
error = memnew(AcceptDialog);
21992300
add_child(error);

editor/scene/scene_tree_editor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,14 @@ class SceneTreeEditor : public Control {
189189
bool pending_selection_update = false;
190190
Timer *update_node_tooltip_delay = nullptr;
191191

192+
bool visibility_drag_value = false;
193+
Vector2 visibility_drag_start_pos;
194+
ObjectID visibility_drag_start_node;
195+
LocalVector<ObjectID> visibility_drag_nodes;
196+
192197
static void _bind_methods();
193198

199+
void _gui_input(const Ref<InputEvent> &p_event);
194200
void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
195201
void _toggle_visible(Node *p_node);
196202
void _cell_multi_selected(Object *p_object, int p_cell, bool p_selected);
@@ -203,6 +209,7 @@ class SceneTreeEditor : public Control {
203209
void _update_node_tooltip(Node *p_node, TreeItem *p_item);
204210
void _queue_update_node_tooltip(Node *p_node, TreeItem *p_item);
205211
void _tree_scroll_to_item(ObjectID p_item_id);
212+
void _reset_visibility_drag();
206213

207214
void _selection_changed();
208215
Node *get_scene_node() const;

0 commit comments

Comments
 (0)