From 7aa9174bc4656aefbc656c0be9db10f7e6f9b9eb Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Mon, 19 May 2025 15:59:48 +0800 Subject: [PATCH] Lazy create menu and slider nodes in `Tree` --- scene/gui/tree.cpp | 89 +++++++++++++++++++++++----------------------- scene/gui/tree.h | 4 +++ 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index a8e0ead8010..8a6a05c42b6 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3197,12 +3197,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int } break; case TreeItem::CELL_MODE_RANGE: { if (!c.text.is_empty()) { - popup_menu->clear(); - for (int i = 0; i < c.text.get_slice_count(","); i++) { - String s = c.text.get_slicec(',', i); - popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).is_empty() ? i : s.get_slicec(':', 1).to_int()); - } - + _update_popup_menu(c); popup_menu->set_size(Size2(col_width, 0)); popup_menu->set_position(get_screen_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h) - theme_cache.offset); popup_menu->popup(); @@ -3332,7 +3327,7 @@ void Tree::_text_editor_popup_modal_close() { return; // ESC pressed, app focus lost, or forced close from code. } - if (value_editor->has_point(value_editor->get_local_mouse_position())) { + if (value_editor && value_editor->has_point(value_editor->get_local_mouse_position())) { return; } @@ -3449,6 +3444,37 @@ void Tree::value_editor_changed(double p_value) { queue_redraw(); } +void Tree::_update_popup_menu(const TreeItem::Cell &p_cell) { + if (popup_menu == nullptr) { + popup_menu = memnew(PopupMenu); + popup_menu->hide(); + add_child(popup_menu, false, INTERNAL_MODE_FRONT); + popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &Tree::popup_select)); + } + popup_menu->clear(); + for (int i = 0; i < p_cell.text.get_slice_count(","); i++) { + String s = p_cell.text.get_slicec(',', i); + popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).is_empty() ? i : s.get_slicec(':', 1).to_int()); + } +} + +void Tree::_update_value_editor(const TreeItem::Cell &p_cell) { + if (value_editor == nullptr) { + value_editor = memnew(HSlider); + value_editor->set_v_size_flags(SIZE_EXPAND_FILL); + value_editor->hide(); + popup_editor_vb->add_child(value_editor); + value_editor->connect(SceneStringName(value_changed), callable_mp(this, &Tree::value_editor_changed)); + } + updating_value_editor = true; + value_editor->set_min(p_cell.min); + value_editor->set_max(p_cell.max); + value_editor->set_step(p_cell.step); + value_editor->set_value(p_cell.val); + value_editor->set_exp_ratio(p_cell.expr); + updating_value_editor = false; +} + void Tree::popup_select(int p_option) { if (!popup_edited_item) { return; @@ -4308,12 +4334,7 @@ bool Tree::edit_selected(bool p_force_edit) { return true; } else if (c.mode == TreeItem::CELL_MODE_RANGE && !c.text.is_empty()) { - popup_menu->clear(); - for (int i = 0; i < c.text.get_slice_count(","); i++) { - String s2 = c.text.get_slicec(',', i); - popup_menu->add_item(s2.get_slicec(':', 0), s2.get_slicec(':', 1).is_empty() ? i : s2.get_slicec(':', 1).to_int()); - } - + _update_popup_menu(c); popup_menu->set_size(Size2(rect.size.width, 0)); popup_menu->set_position(get_screen_position() + rect.position + Point2i(0, rect.size.height)); popup_menu->popup(); @@ -4322,9 +4343,16 @@ bool Tree::edit_selected(bool p_force_edit) { return true; } else if ((c.mode == TreeItem::CELL_MODE_STRING && !c.edit_multiline) || c.mode == TreeItem::CELL_MODE_RANGE) { - Rect2 popup_rect; + int value_editor_height = 0; + if (c.mode == TreeItem::CELL_MODE_RANGE) { + _update_value_editor(c); + value_editor_height = value_editor->get_minimum_size().height; + value_editor->show(); + } else if (value_editor) { + value_editor->hide(); + } - int value_editor_height = c.mode == TreeItem::CELL_MODE_RANGE ? value_editor->get_minimum_size().height : 0; + Rect2 popup_rect; // `floor()` centers vertically. Vector2 ofs(0, Math::floor((MAX(line_editor->get_minimum_size().height, rect.size.height - value_editor_height) - rect.size.height) / 2)); @@ -4334,8 +4362,7 @@ bool Tree::edit_selected(bool p_force_edit) { icon_ofs = _get_cell_icon_size(c).x * popup_scale + theme_cache.h_separation; } - popup_rect.size = rect.size; - popup_rect.size.x -= icon_ofs; + popup_rect.size = rect.size + Vector2(-icon_ofs, value_editor_height); popup_rect.position = rect.position - ofs; popup_rect.position.x += icon_ofs; @@ -4351,21 +4378,6 @@ bool Tree::edit_selected(bool p_force_edit) { text_editor->hide(); - if (c.mode == TreeItem::CELL_MODE_RANGE) { - popup_rect.size.y += value_editor_height; - - value_editor->show(); - updating_value_editor = true; - value_editor->set_min(c.min); - value_editor->set_max(c.max); - value_editor->set_step(c.step); - value_editor->set_value(c.val); - value_editor->set_exp_ratio(c.expr); - updating_value_editor = false; - } else { - value_editor->hide(); - } - popup_editor->set_position(popup_rect.position); popup_editor->set_size(popup_rect.size * popup_scale); if (!popup_editor->is_embedded()) { @@ -6634,14 +6646,10 @@ Tree::Tree() { set_focus_mode(FOCUS_ALL); - popup_menu = memnew(PopupMenu); - popup_menu->hide(); - add_child(popup_menu, false, INTERNAL_MODE_FRONT); - popup_editor = memnew(Popup); add_child(popup_editor, false, INTERNAL_MODE_FRONT); - VBoxContainer *popup_editor_vb = memnew(VBoxContainer); + popup_editor_vb = memnew(VBoxContainer); popup_editor_vb->add_theme_constant_override("separation", 0); popup_editor_vb->set_anchors_and_offsets_preset(PRESET_FULL_RECT); popup_editor->add_child(popup_editor_vb); @@ -6656,11 +6664,6 @@ Tree::Tree() { text_editor->hide(); popup_editor_vb->add_child(text_editor); - value_editor = memnew(HSlider); - value_editor->set_v_size_flags(SIZE_EXPAND_FILL); - value_editor->hide(); - popup_editor_vb->add_child(value_editor); - h_scroll = memnew(HScrollBar); v_scroll = memnew(VScrollBar); @@ -6676,8 +6679,6 @@ Tree::Tree() { line_editor->connect(SceneStringName(text_submitted), callable_mp(this, &Tree::_line_editor_submit)); text_editor->connect(SceneStringName(gui_input), callable_mp(this, &Tree::_text_editor_gui_input)); popup_editor->connect("popup_hide", callable_mp(this, &Tree::_text_editor_popup_modal_close)); - popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &Tree::popup_select)); - value_editor->connect(SceneStringName(value_changed), callable_mp(this, &Tree::value_editor_changed)); set_notify_transform(true); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 31ea1f43a9a..63b73386987 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -33,6 +33,7 @@ #include "scene/gui/control.h" #include "scene/resources/text_paragraph.h" +class VBoxContainer; class HScrollBar; class HSlider; class LineEdit; @@ -529,6 +530,7 @@ private: bool popup_edit_committed = true; RID accessibility_scroll_element; + VBoxContainer *popup_editor_vb = nullptr; Popup *popup_editor = nullptr; LineEdit *line_editor = nullptr; TextEdit *text_editor = nullptr; @@ -559,6 +561,8 @@ private: void _text_editor_popup_modal_close(); void _text_editor_gui_input(const Ref &p_event); void value_editor_changed(double p_value); + void _update_popup_menu(const TreeItem::Cell &p_cell); + void _update_value_editor(const TreeItem::Cell &p_cell); void popup_select(int p_option);