diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 8473230758d..07544e8b238 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -31,6 +31,7 @@ #include "scene_tree_dock.h" #include "core/io/resource_saver.h" +#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" @@ -88,6 +89,8 @@ void SceneTreeDock::_unhandled_key_input(Ref p_event) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { _tool_selected(TOOL_INSTANCE); + } else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) { + _tool_selected(TOOL_EXPAND_COLLAPSE); } else if (ED_IS_SHORTCUT("scene_tree/change_node_type", p_event)) { _tool_selected(TOOL_REPLACE); } else if (ED_IS_SHORTCUT("scene_tree/duplicate", p_event)) { @@ -341,6 +344,23 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { quick_open->popup_dialog("PackedScene", true); quick_open->set_title(TTR("Instance Child Scene")); + } break; + case TOOL_EXPAND_COLLAPSE: { + + if (!scene_tree->get_selected()) + break; + + Tree *tree = scene_tree->get_scene_tree(); + TreeItem *selected_item = tree->get_selected(); + + if (!selected_item) + selected_item = tree->get_root(); + + bool collapsed = _is_collapsed_recursive(selected_item); + _set_collapsed_recursive(selected_item, !collapsed); + + tree->ensure_cursor_is_visible(); + } break; case TOOL_REPLACE: { @@ -965,6 +985,17 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } +void SceneTreeDock::_node_collapsed(Object *p_obj) { + + TreeItem *ti = Object::cast_to(p_obj); + if (!ti) + return; + + if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + _set_collapsed_recursive(ti, ti->is_collapsed()); + } +} + void SceneTreeDock::_notification(int p_what) { switch (p_what) { @@ -997,6 +1028,7 @@ void SceneTreeDock::_notification(int p_what) { filter->set_clear_button_enabled(true); EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); + scene_tree->get_scene_tree()->connect("item_collapsed", this, "_node_collapsed"); // create_root_dialog HBoxContainer *top_row = memnew(HBoxContainer); @@ -1591,6 +1623,52 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V editor_data->get_undo_redo().commit_action(); } +bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const { + + bool is_branch_collapsed = false; + + List needs_check; + needs_check.push_back(p_item); + + while (!needs_check.empty()) { + + TreeItem *item = needs_check.back()->get(); + needs_check.pop_back(); + + TreeItem *child = item->get_children(); + is_branch_collapsed = item->is_collapsed() && child; + + if (is_branch_collapsed) { + break; + } + while (child) { + needs_check.push_back(child); + child = child->get_next(); + } + } + return is_branch_collapsed; +} + +void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) { + + List to_collapse; + to_collapse.push_back(p_item); + + while (!to_collapse.empty()) { + + TreeItem *item = to_collapse.back()->get(); + to_collapse.pop_back(); + + item->set_collapsed(p_collapsed); + + TreeItem *child = item->get_children(); + while (child) { + to_collapse.push_back(child); + child = child->get_next(); + } + } +} + void SceneTreeDock::_script_created(Ref