Skip to content

Commit c52838a

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 c52838a

2 files changed

Lines changed: 98 additions & 0 deletions

File tree

editor/scene/scene_tree_editor.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,80 @@ 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() && mb->get_button_index() == MouseButton::LEFT) {
102+
if (mb->is_pressed()) {
103+
Vector2 tree_mouse_pos = tree->get_transform().xform_inv(mb->get_position());
104+
int tree_button_id = tree->get_button_id_at_position(tree_mouse_pos);
105+
if (tree_button_id == BUTTON_VISIBILITY) {
106+
TreeItem *tree_item = tree->get_item_at_position(tree_mouse_pos);
107+
ERR_FAIL_NULL(tree_item);
108+
NodePath node_path = tree_item->get_metadata(0);
109+
Node *node = get_node_or_null(node_path);
110+
if (node != nullptr) {
111+
visibility_drag_value = !node->call("is_visible");
112+
visibility_drag_start_pos = tree_mouse_pos;
113+
visibility_drag_start_node = node->get_instance_id();
114+
}
115+
}
116+
} else if (mb->is_released() && visibility_drag_start_node.is_valid()) {
117+
if (!visibility_drag_nodes.is_empty()) {
118+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
119+
undo_redo->create_action(vformat(TTR("Toggle Visibility of %d Nodes"), visibility_drag_nodes.size()));
120+
121+
for (ObjectID id : visibility_drag_nodes) {
122+
Node *node = ObjectDB::get_instance<Node>(id);
123+
if (node != nullptr) {
124+
undo_redo->add_do_method(node, "set_visible", visibility_drag_value);
125+
undo_redo->add_undo_method(node, "set_visible", !visibility_drag_value);
126+
}
127+
}
128+
129+
undo_redo->commit_action(false);
130+
}
131+
132+
// Defer this so that `_cell_button_pressed` can still react to the dragging.
133+
callable_mp(this, &SceneTreeEditor::_reset_visibility_drag).call_deferred();
134+
}
135+
}
136+
137+
Ref<InputEventMouseMotion> mm = p_event;
138+
if (mm.is_valid() && visibility_drag_start_node.is_valid()) {
139+
Vector2 tree_mouse_pos = tree->get_transform().xform_inv(mm->get_position());
140+
int tree_button_id = tree->get_button_id_at_position(tree_mouse_pos);
141+
bool crossed_drag_threshold = visibility_drag_start_pos.distance_to(tree_mouse_pos) > get_viewport()->get_drag_threshold();
142+
if (tree_button_id == BUTTON_VISIBILITY && (crossed_drag_threshold || !visibility_drag_nodes.is_empty())) {
143+
Node *start_node = ObjectDB::get_instance<Node>(visibility_drag_start_node);
144+
if (start_node != nullptr && (bool)start_node->call("is_visible") != visibility_drag_value) {
145+
start_node->call("set_visible", visibility_drag_value);
146+
visibility_drag_nodes.push_back(visibility_drag_start_node);
147+
}
148+
149+
TreeItem *tree_item = tree->get_item_at_position(tree_mouse_pos);
150+
ERR_FAIL_NULL(tree_item);
151+
NodePath node_path = tree_item->get_metadata(0);
152+
Node *node = get_node_or_null(node_path);
153+
if (node != nullptr && (bool)node->call("is_visible") != visibility_drag_value) {
154+
node->call("set_visible", visibility_drag_value);
155+
visibility_drag_nodes.push_back(node->get_instance_id());
156+
}
157+
}
158+
}
159+
160+
Ref<InputEventKey> k = p_event;
161+
if (k.is_valid()) {
162+
if (k->is_action_pressed(SNAME("ui_cancel")) && visibility_drag_start_node.is_valid()) {
163+
_reset_visibility_drag();
164+
accept_event();
165+
}
166+
}
167+
}
168+
95169
void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {
96170
if (p_button != MouseButton::LEFT) {
97171
return;
@@ -125,6 +199,10 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
125199
}
126200

127201
} else if (p_id == BUTTON_VISIBILITY) {
202+
if (!visibility_drag_nodes.is_empty()) {
203+
return;
204+
}
205+
128206
undo_redo->create_action(TTR("Toggle Visible"));
129207
_toggle_visible(n);
130208
List<Node *> selection = editor_selection->get_top_selected_node_list();
@@ -1367,6 +1445,13 @@ void SceneTreeEditor::_tree_scroll_to_item(ObjectID p_item_id) {
13671445
}
13681446
}
13691447

1448+
void SceneTreeEditor::_reset_visibility_drag() {
1449+
visibility_drag_value = false;
1450+
visibility_drag_start_pos = Vector2();
1451+
visibility_drag_start_node = ObjectID();
1452+
visibility_drag_nodes.clear();
1453+
}
1454+
13701455
void SceneTreeEditor::_notification(int p_what) {
13711456
switch (p_what) {
13721457
case NOTIFICATION_ENTER_TREE: {
@@ -1430,6 +1515,11 @@ void SceneTreeEditor::_notification(int p_what) {
14301515
}
14311516
}
14321517
} break;
1518+
1519+
case NOTIFICATION_APPLICATION_FOCUS_OUT:
1520+
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
1521+
_reset_visibility_drag();
1522+
} break;
14331523
}
14341524
}
14351525

@@ -2194,6 +2284,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
21942284
tree->connect("multi_selected", callable_mp(this, &SceneTreeEditor::_cell_multi_selected));
21952285
tree->connect("button_clicked", callable_mp(this, &SceneTreeEditor::_cell_button_pressed));
21962286
tree->connect("nothing_selected", callable_mp(this, &SceneTreeEditor::_deselect_items));
2287+
tree->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeEditor::_gui_input));
21972288

21982289
error = memnew(AcceptDialog);
21992290
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)