@@ -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+
95169void 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+
13701455void 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);
0 commit comments