From 357caceca6a8e4dbdb54606f0630a25632003969 Mon Sep 17 00:00:00 2001 From: Mike Precup Date: Sun, 21 Sep 2025 11:43:24 -0700 Subject: [PATCH] Optimize tree size computation and the scene tree dock filter --- editor/scene/scene_tree_editor.cpp | 24 ++++++++++++++++++++---- editor/scene/scene_tree_editor.h | 1 + scene/gui/tree.cpp | 7 +++++-- scene/gui/tree.h | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/editor/scene/scene_tree_editor.cpp b/editor/scene/scene_tree_editor.cpp index 4f85224f73c..760e8f5a7dc 100644 --- a/editor/scene/scene_tree_editor.cpp +++ b/editor/scene/scene_tree_editor.cpp @@ -972,6 +972,17 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) { } bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_selected) { + TreeItem *last_selected = nullptr; + bool result = _update_filter_helper(p_parent, p_scroll_to_selected, last_selected); + if (p_scroll_to_selected && last_selected) { + // Scrolling to the first selected in the _update_filter call above followed by the last + // selected here is enough to frame all selected items as well as possible. + callable_mp(tree, &Tree::scroll_to_item).call_deferred(last_selected, false); + } + return result; +} + +bool SceneTreeEditor::_update_filter_helper(TreeItem *p_parent, bool p_scroll_to_selected, TreeItem *&r_last_selected) { if (!p_parent) { p_parent = tree->get_root(); filter_term_warning.clear(); @@ -1026,7 +1037,8 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select bool keep_for_children = false; for (TreeItem *child = p_parent->get_first_child(); child; child = child->get_next()) { // Always keep if at least one of the children are kept. - keep_for_children = _update_filter(child, p_scroll_to_selected) || keep_for_children; + // Only scroll if we haven't already found a child to scroll to. + keep_for_children = _update_filter_helper(child, p_scroll_to_selected && !keep_for_children, r_last_selected) || keep_for_children; } if (!is_root) { @@ -1099,9 +1111,13 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select if (editor_selection) { Node *n = get_node(p_parent->get_metadata(0)); if (selectable) { - if (p_scroll_to_selected && n && editor_selection->is_selected(n)) { - // Needs to be deferred to account for possible root visibility change. - callable_mp(tree, &Tree::scroll_to_item).call_deferred(p_parent, false); + if (n && editor_selection->is_selected(n)) { + if (p_scroll_to_selected) { + // Needs to be deferred to account for possible root visibility change. + callable_mp(tree, &Tree::scroll_to_item).call_deferred(p_parent, false); + } else { + r_last_selected = p_parent; + } } } else if (n) { editor_selection->remove_node(n); diff --git a/editor/scene/scene_tree_editor.h b/editor/scene/scene_tree_editor.h index 2b30707d293..e11d148b6fc 100644 --- a/editor/scene/scene_tree_editor.h +++ b/editor/scene/scene_tree_editor.h @@ -146,6 +146,7 @@ class SceneTreeEditor : public Control { void _test_update_tree(); bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false); + bool _update_filter_helper(TreeItem *p_parent, bool p_scroll_to_selected, TreeItem *&r_last_selected); bool _node_matches_class_term(const Node *p_item_node, const String &p_term); bool _item_matches_all_terms(TreeItem *p_item, const PackedStringArray &p_terms); void _tree_changed(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index adb9f3a6b85..f74d6ba06c5 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2008,7 +2008,8 @@ int Tree::compute_item_height(TreeItem *p_item) const { for (int i = 0; i < columns.size(); i++) { height = MAX(height, p_item->get_minimum_size(i).y); } - int item_min_height = MAX(theme_cache.font->get_height(theme_cache.font_size), p_item->get_custom_minimum_height()); + int font_height = cache.font_height != -1 ? cache.font_height : theme_cache.font->get_height(theme_cache.font_size); + int item_min_height = MAX(font_height, p_item->get_custom_minimum_height()); if (height < item_min_height) { height = item_min_height; } @@ -5024,7 +5025,8 @@ void Tree::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - v_scroll->set_custom_step(theme_cache.font->get_height(theme_cache.font_size)); + int font_height = cache.font_height != -1 ? cache.font_height : theme_cache.font->get_height(theme_cache.font_size); + v_scroll->set_custom_step(font_height); update_scrollbars(); RID ci = get_canvas_item(); @@ -5120,6 +5122,7 @@ void Tree::_notification(int p_what) { } void Tree::_update_all() { + cache.font_height = theme_cache.font->get_height(theme_cache.font_size); for (int i = 0; i < columns.size(); i++) { update_column(i); } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index b65e5197fdb..0bf385680d4 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -688,6 +688,7 @@ private: int hover_button_index_in_column = -1; bool rtl = false; + int font_height = -1; } cache; int _get_title_button_height() const;