From 05737cd4498ca2fc69e3f5d54c9eb600948ea77f Mon Sep 17 00:00:00 2001 From: StarryWorm <41305715+StarryWorm@users.noreply.github.com> Date: Sat, 11 Apr 2026 18:18:18 -0400 Subject: [PATCH] Add "desired size" to `Control` A `Control` can define `get_desired_size()` which allows it to grow based on its content without increasing its minimum size. This new size will be respected by parent `Container`s. Currently used by `Label` and `TabBar`. --- scene/gui/box_container.cpp | 12 +++- scene/gui/box_container.h | 2 + scene/gui/center_container.cpp | 17 +++++ scene/gui/center_container.h | 1 + scene/gui/container.cpp | 10 +++ scene/gui/container.h | 1 + scene/gui/control.cpp | 112 ++++++++++++++++++++++++++++++ scene/gui/control.h | 17 +++++ scene/gui/flow_container.cpp | 12 +++- scene/gui/flow_container.h | 2 + scene/gui/foldable_container.cpp | 20 ++++++ scene/gui/foldable_container.h | 1 + scene/gui/graph_frame.cpp | 14 +++- scene/gui/graph_frame.h | 3 + scene/gui/graph_node.cpp | 14 +++- scene/gui/graph_node.h | 3 + scene/gui/grid_container.cpp | 12 +++- scene/gui/grid_container.h | 2 + scene/gui/label.cpp | 50 +++++++------- scene/gui/label.h | 1 + scene/gui/margin_container.cpp | 26 +++++-- scene/gui/margin_container.h | 1 + scene/gui/panel_container.cpp | 18 +++++ scene/gui/panel_container.h | 1 + scene/gui/scroll_container.cpp | 12 +++- scene/gui/scroll_container.h | 3 + scene/gui/split_container.cpp | 12 +++- scene/gui/split_container.h | 3 + scene/gui/tab_bar.cpp | 115 +++++++++++++++++++++++++------ scene/gui/tab_bar.h | 1 + scene/gui/tab_container.cpp | 21 ++++-- scene/gui/tab_container.h | 3 + tests/scene/test_label.cpp | 4 +- 33 files changed, 454 insertions(+), 72 deletions(-) diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 7aaa4cb41a..89a7e27b56 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -288,7 +288,7 @@ void BoxContainer::_resort() { } } -Size2 BoxContainer::get_minimum_size() const { +Size2 BoxContainer::_get_minimum_size(bool p_use_desired_sizes) const { /* Calculate MINIMUM SIZE */ Size2i minimum; @@ -301,7 +301,7 @@ Size2 BoxContainer::get_minimum_size() const { continue; } - Size2i size = c->get_bound_minimum_size(); + Size2i size = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); if (vertical) { /* VERTICAL */ @@ -326,6 +326,14 @@ Size2 BoxContainer::get_minimum_size() const { return minimum; } +Size2 BoxContainer::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 BoxContainer::get_desired_size() const { + return _get_minimum_size(true); +} + void BoxContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h index 028a0ac205..51d59e4f0f 100644 --- a/scene/gui/box_container.h +++ b/scene/gui/box_container.h @@ -51,6 +51,7 @@ private: } theme_cache; void _resort(); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; protected: bool is_fixed = false; @@ -69,6 +70,7 @@ public: bool is_vertical() const; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; virtual Vector get_allowed_size_flags_vertical() const override; diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index 7b7641efcc..1a7a17b547 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -49,6 +49,23 @@ Size2 CenterContainer::get_minimum_size() const { return ms; } +Size2 CenterContainer::get_desired_size() const { + if (use_top_left) { + return Size2(); + } + Size2 ds; + for (int i = 0; i < get_child_count(); i++) { + Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE); + if (!c) { + continue; + } + Size2 minsize = c->get_bound_desired_size(); + ds = ds.max(minsize); + } + + return ds; +} + void CenterContainer::set_use_top_left(bool p_enable) { if (use_top_left == p_enable) { return; diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h index aed17d25cf..05fb9189c4 100644 --- a/scene/gui/center_container.h +++ b/scene/gui/center_container.h @@ -46,6 +46,7 @@ public: bool is_using_top_left() const; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; virtual Vector get_allowed_size_flags_vertical() const override; diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index a269944bd4..a158c01af0 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -39,6 +39,11 @@ void Container::_child_minsize_changed() { queue_sort(); } +void Container::_child_desired_size_changed() { + update_desired_size(); + queue_sort(); +} + void Container::add_child_notify(Node *p_child) { Control::add_child_notify(p_child); @@ -50,6 +55,7 @@ void Container::add_child_notify(Node *p_child) { control->connect(SceneStringName(size_flags_changed), callable_mp(this, &Container::queue_sort)); control->connect(SceneStringName(minimum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); control->connect(SceneStringName(maximum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); + control->connect("_desired_size_changed", callable_mp(this, &Container::_child_desired_size_changed)); control->connect(SceneStringName(visibility_changed), callable_mp(this, &Container::_child_minsize_changed)); update_minimum_size(); @@ -78,6 +84,7 @@ void Container::remove_child_notify(Node *p_child) { control->disconnect(SceneStringName(size_flags_changed), callable_mp(this, &Container::queue_sort)); control->disconnect(SceneStringName(minimum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); control->disconnect(SceneStringName(maximum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); + control->disconnect("_desired_size_changed", callable_mp(this, &Container::_child_desired_size_changed)); control->disconnect(SceneStringName(visibility_changed), callable_mp(this, &Container::_child_minsize_changed)); update_minimum_size(); @@ -105,6 +112,7 @@ void Container::fit_child_in_rect(RequiredParam rp_child, const Rect2 & bool rtl = is_layout_rtl(); Size2 minsize = p_child->get_combined_minimum_size(); + Size2 desired_size = p_child->get_bound_desired_size(); Size2 maxsize = p_child->get_combined_maximum_size(); Rect2 r = p_rect; BitField h_size_flags = p_child->get_h_size_flags(); @@ -112,6 +120,7 @@ void Container::fit_child_in_rect(RequiredParam rp_child, const Rect2 & if (!h_size_flags.has_flag(SIZE_FILL)) { float final_width = minsize.width; + final_width = MAX(MIN(desired_size.width, r.size.width), final_width); if (maxsize.width >= 0) { final_width = MIN(final_width, maxsize.width); } @@ -127,6 +136,7 @@ void Container::fit_child_in_rect(RequiredParam rp_child, const Rect2 & if (!v_size_flags.has_flag(SIZE_FILL)) { float final_height = minsize.y; + final_height = MAX(MIN(desired_size.y, r.size.y), final_height); if (maxsize.height >= 0) { final_height = MIN(final_height, maxsize.height); } diff --git a/scene/gui/container.h b/scene/gui/container.h index af9fbc7fe9..19945a79f1 100644 --- a/scene/gui/container.h +++ b/scene/gui/container.h @@ -39,6 +39,7 @@ class Container : public Control { bool accessibility_region = false; void _sort_children(); void _child_minsize_changed(); + void _child_desired_size_changed(); protected: enum class SortableVisibilityMode { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index b4eb000598..51048bf29f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1550,6 +1550,8 @@ void Control::set_size(const Size2 &p_size, bool p_keep_offsets) { } #endif // TOOLS_ENABLED + data.expanded_by_desired_size = false; + if (p_keep_offsets) { _compute_anchors(Rect2(data.pos_cache, new_size), data.offset, data.anchor); } else { @@ -1761,6 +1763,11 @@ void Control::update_maximum_size() { data.updating_last_minimum_size = true; callable_mp(this, &Control::_update_minimum_size).call_deferred(); } + // Same with desired size. + if (!data.updating_last_desired_size) { + data.updating_last_desired_size = true; + callable_mp(this, &Control::_update_desired_size).call_deferred(); + } callable_mp(this, &Control::_update_maximum_size).call_deferred(); } @@ -1948,6 +1955,107 @@ Size2 Control::get_custom_minimum_size() const { return data.custom_minimum_size; } +void Control::_update_desired_size_cache() const { + Size2 desired_size = get_desired_size(); + + data.desired_size_cache = desired_size; + data.desired_size_valid = true; +} + +void Control::_update_desired_size() { + if (!is_inside_tree()) { + data.updating_last_desired_size = false; + return; + } + + Size2 desired_size = get_desired_size(); + data.updating_last_desired_size = false; + + if (desired_size != data.last_desired_size) { + data.last_desired_size = desired_size; + grow_to_desired_size(); + emit_signal("_desired_size_changed"); + } +} + +void Control::update_desired_size() { + ERR_MAIN_THREAD_GUARD; + if (!is_inside_tree()) { + return; + } + + // Invalidate cache upwards. + Control *invalidate = this; + while (invalidate && invalidate->data.desired_size_valid) { + invalidate->data.desired_size_valid = false; + if (invalidate->is_set_as_top_level()) { + break; // Do not go further up. + } + + Window *parent_window = invalidate->get_parent_window(); + if (parent_window && parent_window->is_wrapping_controls()) { + parent_window->child_controls_changed(); + break; // Stop on a window as well. + } + + invalidate = invalidate->get_parent_control(); + } + + if (!is_visible_in_tree()) { + // Invalidate the last desired size so it will update when made visible. + data.last_desired_size = Size2(-1, -1); + return; + } + + if (data.updating_last_desired_size) { + return; + } + data.updating_last_desired_size = true; + + callable_mp(this, &Control::_update_desired_size).call_deferred(); +} + +Size2 Control::get_bound_desired_size() const { + ERR_READ_THREAD_GUARD_V(Size2()); + if (!data.desired_size_valid) { + _update_desired_size_cache(); + } + Size2 desired_size = data.desired_size_cache; + desired_size = desired_size.max(get_combined_minimum_size()); + Size2 max_size = get_combined_maximum_size(); + if (max_size.x >= 0) { + desired_size.x = MIN(desired_size.x, max_size.x); + } + if (max_size.y >= 0) { + desired_size.y = MIN(desired_size.y, max_size.y); + } + return desired_size; +} + +Size2 Control::get_desired_size() const { + return Size2(); +} + +void Control::grow_to_desired_size() { + ERR_MAIN_THREAD_GUARD; + if (!is_inside_tree()) { + return; + } + + Size2 desired_size = get_bound_desired_size(); + if (desired_size <= get_combined_minimum_size()) { + return; + } + + if (data.expanded_by_desired_size) { + set_size(desired_size); + data.expanded_by_desired_size = true; + } else if (desired_size.x > get_size().x || desired_size.y > get_size().y) { + set_size(desired_size); + data.expanded_by_desired_size = true; + } +} + void Control::add_child_notify(Node *p_child) { CanvasItem::add_child_notify(p_child); @@ -2021,6 +2129,9 @@ void Control::_update_minimum_size_cache() const { data.minimum_size_cache = minsize; data.minimum_size_valid = true; + + // Keep the desired size cache in sync so it will update if needed when the minimum size changes. This is needed for get_bound_desired_size to work correctly. + data.desired_size_valid = false; } Size2 Control::get_combined_minimum_size() const { @@ -5024,6 +5135,7 @@ void Control::_bind_methods() { ADD_SIGNAL(MethodInfo("size_flags_changed")); ADD_SIGNAL(MethodInfo("maximum_size_changed")); ADD_SIGNAL(MethodInfo("minimum_size_changed")); + ADD_SIGNAL(MethodInfo("_desired_size_changed")); ADD_SIGNAL(MethodInfo("theme_changed")); GDVIRTUAL_BIND(_has_point, "point"); diff --git a/scene/gui/control.h b/scene/gui/control.h index 32b218a04a..11710cfe7b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -256,6 +256,14 @@ private: bool updating_last_minimum_size = false; bool block_minimum_size_adjust = false; + mutable Size2 desired_size_cache; + mutable bool desired_size_valid = false; + + Size2 last_desired_size; + bool updating_last_desired_size = false; + + bool expanded_by_desired_size = false; + bool layout_pending = false; bool size_warning = true; @@ -371,6 +379,9 @@ private: void _update_maximum_size(); void _update_minimum_size_cache() const; void _update_minimum_size(); + void _update_desired_size_cache() const; + void _update_desired_size(); + void _grow_to_desired_size(); void _size_changed(); void _top_level_changed() override {} // Controls don't need to do anything, only other CanvasItems. @@ -603,6 +614,9 @@ public: void update_maximum_size(); void update_minimum_size(); + void update_desired_size(); + + void grow_to_desired_size(); void set_block_maximum_size_adjust(bool p_block); void set_block_minimum_size_adjust(bool p_block); @@ -624,6 +638,9 @@ public: virtual Size2 get_bound_minimum_size() const; + Size2 get_bound_desired_size() const; + virtual Size2 get_desired_size() const; + bool is_layout_pending() const; bool is_layout_pending_in_tree() const; void layout_pending_start(); diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp index a1b7708928..081c8766a4 100644 --- a/scene/gui/flow_container.cpp +++ b/scene/gui/flow_container.cpp @@ -347,7 +347,7 @@ void FlowContainer::_resort() { cached_line_max_child_count = lines_data.size() > 0 ? lines_data[0].child_count : 0; } -Size2 FlowContainer::get_minimum_size() const { +Size2 FlowContainer::_get_minimum_size(bool p_use_desired_sizes) const { Size2i minimum; for (int i = 0; i < get_child_count(); i++) { @@ -356,7 +356,7 @@ Size2 FlowContainer::get_minimum_size() const { continue; } - Size2i size = c->get_bound_minimum_size(); + Size2i size = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); if (vertical) { /* VERTICAL */ minimum.height = MAX(minimum.height, size.height); @@ -371,6 +371,14 @@ Size2 FlowContainer::get_minimum_size() const { return minimum; } +Size2 FlowContainer::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 FlowContainer::get_desired_size() const { + return _get_minimum_size(true); +} + Vector FlowContainer::get_allowed_size_flags_horizontal() const { Vector flags; flags.append(SIZE_FILL); diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h index 81258fb51f..f2a84cbf38 100644 --- a/scene/gui/flow_container.h +++ b/scene/gui/flow_container.h @@ -64,6 +64,7 @@ private: } theme_cache; void _resort(); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; protected: bool is_fixed = false; @@ -89,6 +90,7 @@ public: bool is_reverse_fill() const; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; virtual Vector get_allowed_size_flags_vertical() const override; diff --git a/scene/gui/foldable_container.cpp b/scene/gui/foldable_container.cpp index 216b7fb650..2f3c2614f3 100644 --- a/scene/gui/foldable_container.cpp +++ b/scene/gui/foldable_container.cpp @@ -54,6 +54,26 @@ Size2 FoldableContainer::get_minimum_size() const { return Size2(MAX(ms.width, title_minimum_size.width), ms.height + title_minimum_size.height); } +Size2 FoldableContainer::get_desired_size() const { + _update_title_min_size(); + + if (folded) { + return title_minimum_size; + } + Size2 ds; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = as_sortable_control(get_child(i)); + if (!c) { + continue; + } + ds = ds.max(c->get_bound_desired_size()); + } + ds += theme_cache.panel_style->get_minimum_size(); + + return Size2(MAX(ds.width, title_minimum_size.width), ds.height + title_minimum_size.height); +} + Size2 FoldableContainer::get_inner_combined_maximum_size() const { Size2 ms = Container::get_inner_combined_maximum_size(); diff --git a/scene/gui/foldable_container.h b/scene/gui/foldable_container.h index 584e9a9d76..097fbe4b72 100644 --- a/scene/gui/foldable_container.h +++ b/scene/gui/foldable_container.h @@ -138,6 +138,7 @@ public: void remove_title_bar_control(Control *p_control); virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Size2 get_inner_combined_maximum_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override { return { SIZE_FILL, SIZE_SHRINK_BEGIN, SIZE_SHRINK_CENTER, SIZE_SHRINK_END }; } diff --git a/scene/gui/graph_frame.cpp b/scene/gui/graph_frame.cpp index a0c47702b5..23461525f8 100644 --- a/scene/gui/graph_frame.cpp +++ b/scene/gui/graph_frame.cpp @@ -323,11 +323,11 @@ bool GraphFrame::has_point(const Point2 &p_point) const { return false; } -Size2 GraphFrame::get_minimum_size() const { +Size2 GraphFrame::_get_minimum_size(bool p_use_desired_sizes) const { Ref sb_panel = theme_cache.panel; Ref sb_titlebar = theme_cache.titlebar; - Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size(); + Size2 minsize = (p_use_desired_sizes ? titlebar_hbox->get_bound_desired_size() : titlebar_hbox->get_minimum_size()) + sb_titlebar->get_minimum_size(); for (int i = 0; i < get_child_count(false); i++) { Control *child = as_sortable_control(get_child(i, false)); @@ -335,7 +335,7 @@ Size2 GraphFrame::get_minimum_size() const { continue; } - Size2i size = child->get_bound_minimum_size(); + Size2i size = p_use_desired_sizes ? child->get_bound_desired_size() : child->get_bound_minimum_size(); size.width += sb_panel->get_minimum_size().width; minsize.x = MAX(minsize.x, size.x); @@ -347,6 +347,14 @@ Size2 GraphFrame::get_minimum_size() const { return minsize; } +Size2 GraphFrame::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 GraphFrame::get_desired_size() const { + return _get_minimum_size(true); +} + GraphFrame::GraphFrame() { titlebar_hbox = memnew(HBoxContainer); titlebar_hbox->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/scene/gui/graph_frame.h b/scene/gui/graph_frame.h index 4542ddbcd7..0aad4ed592 100644 --- a/scene/gui/graph_frame.h +++ b/scene/gui/graph_frame.h @@ -60,6 +60,8 @@ private: bool tint_color_enabled = false; Color tint_color = Color(0.3, 0.3, 0.3, 0.75); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; + protected: virtual void gui_input(const Ref &p_event) override; virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; @@ -95,6 +97,7 @@ public: virtual bool has_point(const Point2 &p_point) const override; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; GraphFrame(); }; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 5f48e4219b..477995bf6c 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -996,13 +996,13 @@ bool GraphNode::is_ignoring_valid_connection_type() const { return ignore_invalid_connection_type; } -Size2 GraphNode::get_minimum_size() const { +Size2 GraphNode::_get_minimum_size(bool p_use_desired_sizes) const { Ref sb_panel = theme_cache.panel; Ref sb_titlebar = theme_cache.titlebar; Ref sb_slot = theme_cache.slot; int separation = theme_cache.separation; - Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size(); + Size2 minsize = (p_use_desired_sizes ? titlebar_hbox->get_bound_desired_size() : titlebar_hbox->get_minimum_size()) + sb_titlebar->get_minimum_size(); for (int i = 0; i < get_child_count(false); i++) { Control *child = as_sortable_control(get_child(i, false)); @@ -1010,7 +1010,7 @@ Size2 GraphNode::get_minimum_size() const { continue; } - Size2i size = child->get_bound_minimum_size(); + Size2i size = p_use_desired_sizes ? child->get_bound_desired_size() : child->get_bound_minimum_size(); size.width += sb_panel->get_minimum_size().width; if (slot_table.has(i)) { size += slot_table[i].draw_stylebox ? sb_slot->get_minimum_size() : Size2(); @@ -1029,6 +1029,14 @@ Size2 GraphNode::get_minimum_size() const { return minsize; } +Size2 GraphNode::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 GraphNode::get_desired_size() const { + return _get_minimum_size(true); +} + void GraphNode::_port_pos_update() { int edgeofs = theme_cache.port_h_offset; int separation = theme_cache.separation; diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 36606f85d3..c14aa1eb60 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -115,6 +115,8 @@ class GraphNode : public GraphElement { void _port_pos_update(); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; + protected: void _notification(int p_what); static void _bind_methods(); @@ -195,6 +197,7 @@ public: Control::FocusMode get_slots_focus_mode() const; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index a9399f5e86..e4b9558cb3 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -378,7 +378,7 @@ void GridContainer::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GridContainer, v_separation); } -Size2 GridContainer::get_minimum_size() const { +Size2 GridContainer::_get_minimum_size(bool p_use_desired_sizes) const { RBMap col_minw; RBMap row_minh; @@ -395,7 +395,7 @@ Size2 GridContainer::get_minimum_size() const { int col = valid_controls_index % columns; valid_controls_index++; - Size2i ms = c->get_bound_minimum_size(); + Size2i ms = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); if (col_minw.has(col)) { col_minw[col] = MAX(col_minw[col], ms.width); } else { @@ -426,3 +426,11 @@ Size2 GridContainer::get_minimum_size() const { return ms; } + +Size2 GridContainer::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 GridContainer::get_desired_size() const { + return _get_minimum_size(true); +} diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h index aa3b0f1a5c..c16f7174d1 100644 --- a/scene/gui/grid_container.h +++ b/scene/gui/grid_container.h @@ -44,6 +44,7 @@ class GridContainer : public Container { private: void _resort(); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; protected: void _notification(int p_what); @@ -53,6 +54,7 @@ public: void set_columns(int p_columns); int get_columns() const; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; int get_h_separation() const; }; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 345c1fff8f..87138e5dd7 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -53,6 +53,7 @@ void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) { if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); } + update_desired_size(); } TextServer::AutowrapMode Label::get_autowrap_mode() const { @@ -74,6 +75,7 @@ void Label::set_autowrap_trim_flags(BitField p_flags) if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); } + update_desired_size(); } BitField Label::get_autowrap_trim_flags() const { @@ -152,11 +154,7 @@ void Label::_shape() const { if (maximum_width <= 0) { maximum_width = 1; } - if (width > 0) { - width = MIN(width, maximum_width); - } else { - width = maximum_width; - } + width = maximum_width; } if (text_dirty) { @@ -914,6 +912,7 @@ void Label::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { font_dirty = true; queue_redraw(); + update_desired_size(); update_configuration_warnings(); } break; @@ -993,9 +992,6 @@ Size2 Label::get_minimum_size() const { _ensure_shaped(); Size2 min_size = minsize; - Size2 combined_maximum_size = get_combined_maximum_size(); - bool wrap_with_max_width = autowrap_mode != TextServer::AUTOWRAP_OFF && combined_maximum_size.x > 0; - bool overrun_with_max_width = autowrap_mode == TextServer::AUTOWRAP_OFF && combined_maximum_size.x > 0 && (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING); const Ref &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font; int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size; @@ -1010,28 +1006,29 @@ Size2 Label::get_minimum_size() const { } else if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { min_size.height = 1; } - if (wrap_with_max_width) { - min_size.width = MAX(1, min_size.width); - return min_size + min_style; - } else { - return Size2(1, min_size.height) + min_style; - } + return Size2(1, min_size.height) + min_style; } else { if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { - if (overrun_with_max_width) { - min_size.width = MAX(1, min_size.width); - } else { - min_size.width = 1; - } + min_size.width = 1; } - Size2 computed_min_size = min_size + min_style; - if (overrun_with_max_width) { - computed_min_size.width = MIN(computed_min_size.width, combined_maximum_size.x); - } - return computed_min_size; + return min_size + min_style; } } +Size2 Label::get_desired_size() const { + Size2 combined_max = get_combined_maximum_size(); + if (combined_max.width < 0) { + return Size2(); + } + + _ensure_shaped(); + Size2 min_style = theme_cache.normal_style->get_minimum_size(); + Size2 content_size = minsize + min_style; + content_size.width = MIN(content_size.width, int(combined_max.width)); + + return content_size; +} + #ifndef DISABLE_DEPRECATED bool Label::_set(const StringName &p_name, const Variant &p_value) { if (p_name == SNAME("valign")) { @@ -1144,6 +1141,7 @@ void Label::set_text(const String &p_string) { queue_accessibility_update(); queue_redraw(); update_minimum_size(); + update_desired_size(); update_configuration_warnings(); } @@ -1163,6 +1161,7 @@ void Label::_maximum_size_changed() { } queue_redraw(); update_minimum_size(); + update_desired_size(); update_configuration_warnings(); } @@ -1264,6 +1263,7 @@ void Label::set_clip_text(bool p_clip) { clip = p_clip; queue_redraw(); update_minimum_size(); + update_desired_size(); } bool Label::is_clipping_text() const { @@ -1297,6 +1297,7 @@ void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); } + update_desired_size(); } TextServer::OverrunBehavior Label::get_text_overrun_behavior() const { @@ -1320,6 +1321,7 @@ void Label::set_ellipsis_char(const String &p_char) { if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); } + update_desired_size(); } String Label::get_ellipsis_char() const { diff --git a/scene/gui/label.h b/scene/gui/label.h index 472c709afb..cd17fe4572 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -116,6 +116,7 @@ protected: public: virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual PackedStringArray get_configuration_warnings() const override; void set_horizontal_alignment(HorizontalAlignment p_alignment); diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index 4f2589009d..6e9e22acfc 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -42,12 +42,7 @@ Size2 MarginContainer::get_minimum_size() const { } Size2 s = c->get_bound_minimum_size(); - if (s.width > max.width) { - max.width = s.width; - } - if (s.height > max.height) { - max.height = s.height; - } + max = max.max(s); } max.width += (theme_cache.margin_left + theme_cache.margin_right); @@ -56,6 +51,25 @@ Size2 MarginContainer::get_minimum_size() const { return max; } +Size2 MarginContainer::get_desired_size() const { + Size2 ds; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE); + if (!c) { + continue; + } + + Size2 s = c->get_desired_size(); + ds = ds.max(s); + } + + ds.width += (theme_cache.margin_left + theme_cache.margin_right); + ds.height += (theme_cache.margin_top + theme_cache.margin_bottom); + + return ds; +} + Size2 MarginContainer::get_inner_combined_maximum_size() const { Size2 ms = Container::get_inner_combined_maximum_size(); diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h index a573190f6c..4265648154 100644 --- a/scene/gui/margin_container.h +++ b/scene/gui/margin_container.h @@ -48,6 +48,7 @@ protected: public: virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Size2 get_inner_combined_maximum_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index 318d732a1a..3087a51af9 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -50,6 +50,24 @@ Size2 PanelContainer::get_minimum_size() const { return ms; } +Size2 PanelContainer::get_desired_size() const { + Size2 ds; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE); + if (!c) { + continue; + } + + Size2 minsize = c->get_desired_size(); + ds = ds.max(minsize); + } + if (theme_cache.panel_style.is_valid()) { + ds += theme_cache.panel_style->get_minimum_size(); + } + return ds; +} + Size2 PanelContainer::get_inner_combined_maximum_size() const { Size2 ms = Container::get_inner_combined_maximum_size(); diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h index b435e3dea6..ac0818a938 100644 --- a/scene/gui/panel_container.h +++ b/scene/gui/panel_container.h @@ -45,6 +45,7 @@ protected: public: virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Size2 get_inner_combined_maximum_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 25b5c522f1..ec77c2f956 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -40,7 +40,7 @@ #include "servers/display/accessibility_server.h" #include "servers/display/display_server.h" -Size2 ScrollContainer::get_minimum_size() const { +Size2 ScrollContainer::_get_minimum_size(bool p_use_desired_sizes) const { // Calculated in this function, as it needs to traverse all child controls once to calculate; // and needs to be calculated before being used by `_update_scrollbars()`. largest_child_min_size = Size2(); @@ -51,7 +51,7 @@ Size2 ScrollContainer::get_minimum_size() const { continue; } - Size2 child_min_size = c->get_bound_minimum_size(); + Size2 child_min_size = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); largest_child_min_size = largest_child_min_size.max(child_min_size); } @@ -93,6 +93,14 @@ Size2 ScrollContainer::get_minimum_size() const { return min_size; } +Size2 ScrollContainer::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 ScrollContainer::get_desired_size() const { + return _get_minimum_size(true); +} + Size2 ScrollContainer::get_inner_combined_maximum_size() const { Size2 ms = Container::get_inner_combined_maximum_size(); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 1ce299ed56..b7c0b356d7 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -117,8 +117,11 @@ private: bool focus_border_is_drawn = false; bool child_has_focus(); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; + protected: Size2 get_minimum_size() const override; + Size2 get_desired_size() const override; Size2 get_inner_combined_maximum_size() const override; void _gui_focus_changed(Control *p_control); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index c978df72d6..62030a3360 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -1073,7 +1073,7 @@ void SplitContainer::_update_draggers() { } } -Size2 SplitContainer::get_minimum_size() const { +Size2 SplitContainer::_get_minimum_size(bool p_use_desired_sizes) const { const int sep = _get_separation(); const int axis = vertical ? 1 : 0; const int other_axis = vertical ? 0 : 1; @@ -1085,7 +1085,7 @@ Size2 SplitContainer::get_minimum_size() const { } for (const Control *child : valid_children) { - const Size2 min_size = child->get_bound_minimum_size(); + const Size2 min_size = p_use_desired_sizes ? child->get_bound_desired_size() : child->get_bound_minimum_size(); minimum[axis] += (int)min_size[axis]; minimum[other_axis] = (int)MAX(minimum[other_axis], min_size[other_axis]); } @@ -1093,6 +1093,14 @@ Size2 SplitContainer::get_minimum_size() const { return minimum; } +Size2 SplitContainer::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 SplitContainer::get_desired_size() const { + return _get_minimum_size(true); +} + void SplitContainer::_validate_property(PropertyInfo &p_property) const { if (is_fixed && p_property.name == "vertical") { p_property.usage = PROPERTY_USAGE_NONE; diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index 7acc752ed0..414e3d3735 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -169,6 +169,8 @@ private: void _update_nested_ancestors(bool p_remove = false); void _update_all_nested_descendents(Control *p_control, Control *p_first_child = nullptr); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; + protected: bool is_fixed = false; @@ -207,6 +209,7 @@ public: bool is_dragging_enabled() const; virtual Size2 get_minimum_size() const override; + virtual Size2 get_desired_size() const override; virtual Vector get_allowed_size_flags_horizontal() const override; virtual Vector get_allowed_size_flags_vertical() const override; diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 63ad4fc561..02ece24916 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -50,8 +50,6 @@ static inline Color _select_color(const Color &p_override_color, const Color &p_ Size2 TabBar::get_minimum_size() const { Size2 ms; Size2 combined_max = get_combined_maximum_size(); - int computed_max_width = 0; - bool stop_adding = combined_max.width < 0; int buttons_size = get_tab_count() > 1 ? theme_cache.decrement_icon->get_width() + theme_cache.increment_icon->get_width() : 0; @@ -120,31 +118,18 @@ Size2 TabBar::get_minimum_size() const { ms.width += theme_cache.tab_separation; } - if (!stop_adding) { - int buttons_eff_size = clip_tabs ? (i != tabs.size() - 1 ? buttons_size : 0) : 0; - if (computed_max_width + ms.width - ofs + buttons_eff_size >= combined_max.width) { - stop_adding = true; - } else { - computed_max_width += ms.width - ofs; - } - } - if (ms.width - ofs > max_tab_width) { max_tab_width = ms.width - ofs; } } if (clip_tabs) { - int clip_min_width = max_tab_width + buttons_size; + ms.width = max_tab_width + buttons_size; if (combined_max.width >= 0) { - int fitted_width = stop_adding ? (computed_max_width + buttons_size) : computed_max_width; - ms.width = MAX(clip_min_width, fitted_width); ms.width = MIN(ms.width, int(combined_max.width)); - } else { - ms.width = clip_min_width; } } else if (combined_max.width >= 0) { - ms.width = stop_adding ? combined_max.width : MIN(computed_max_width, combined_max.width); + ms.width = MIN(ms.width, int(combined_max.width)); } return ms; @@ -507,10 +492,21 @@ void TabBar::_notification(int p_what) { queue_accessibility_update(); queue_redraw(); - update_minimum_size(); - [[fallthrough]]; - } + int ofs_old = offset; + int max_old = max_drawn_tab; + + _update_cache(); + _ensure_no_over_offset(); + + if (scroll_to_selected && (offset != ofs_old || max_drawn_tab != max_old)) { + ensure_tab_visible(current); + } + + update_desired_size(); + update_minimum_size(); + } break; + case NOTIFICATION_RESIZED: { int ofs_old = offset; int max_old = max_drawn_tab; @@ -813,6 +809,7 @@ void TabBar::set_tab_count(int p_count) { queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); notify_property_list_changed(); } @@ -943,6 +940,7 @@ void TabBar::set_tab_title(int p_tab, const String &p_title) { } queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -994,6 +992,7 @@ void TabBar::set_tab_language(int p_tab, const String &p_language) { } queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); } } @@ -1018,6 +1017,7 @@ void TabBar::set_tab_icon(int p_tab, const Ref &p_icon) { ensure_tab_visible(current); } queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -1041,6 +1041,7 @@ void TabBar::set_tab_icon_max_width(int p_tab, int p_width) { ensure_tab_visible(current); } queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -1096,6 +1097,7 @@ void TabBar::set_tab_disabled(int p_tab, bool p_disabled) { } queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -1120,6 +1122,7 @@ void TabBar::set_tab_hidden(int p_tab, bool p_hidden) { } queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -1153,6 +1156,7 @@ void TabBar::set_tab_button_icon(int p_tab, const Ref &p_icon) { ensure_tab_visible(current); } queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -1232,7 +1236,7 @@ void TabBar::_update_cache(bool p_update_hover) { int combined_max_width = combined_max.width >= 0 ? int(combined_max.width) - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width() : INT_MAX; int effective_max_width = max_width > 0 ? MIN(max_width, combined_max_width) : combined_max_width; - int limit = combined_max.width > 0 ? combined_max.width : get_size().width; + int limit = combined_max.width > 0 ? MIN(combined_max.width, get_size().width) : get_size().width; int limit_minus_buttons = limit - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); int w = 0; @@ -1323,6 +1327,68 @@ void TabBar::_update_cache(bool p_update_hover) { } } +Size2 TabBar::get_desired_size() const { + if (!clip_tabs || tabs.is_empty()) { + return Size2(); + } + Size2 combined_max = get_combined_maximum_size(); + if (combined_max.width < 0) { + return Size2(); + } + + int buttons_size = tabs.size() > 1 ? theme_cache.decrement_icon->get_width() + theme_cache.increment_icon->get_width() : 0; + int limit = int(combined_max.width); + int limit_minus_buttons = limit - buttons_size; + + int w = 0; + bool overflowed = false; + + // First pass: check if all tabs fit without buttons. + for (int i = offset; i < tabs.size(); i++) { + if (tabs[i].hidden) { + continue; + } + + int next_w = w + tabs[i].size_cache; + if (i > offset) { + next_w += theme_cache.tab_separation; + } + + if (next_w > limit) { + overflowed = true; + break; + } + + w = next_w; + } + + // If buttons are needed, recompute against the reduced limit. + if (offset > 0 || overflowed) { + w = 0; + for (int i = offset; i < tabs.size(); i++) { + if (tabs[i].hidden) { + continue; + } + + int next_w = w + tabs[i].size_cache; + if (i > offset) { + next_w += theme_cache.tab_separation; + } + + if (next_w > limit_minus_buttons) { + break; + } + + w = next_w; + } + } + + int desired = (offset > 0 || overflowed) ? w + buttons_size : w; + desired = MIN(desired, limit); + + return Size2(desired, 0); +} + void TabBar::_hover_switch_timeout() { set_current_tab(hover); } @@ -1352,6 +1418,7 @@ void TabBar::add_tab(const String &p_str, const Ref &p_icon) { } queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); if (!deselect_enabled && tabs.size() == 1) { @@ -1383,6 +1450,7 @@ void TabBar::clear_tabs() { queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); notify_property_list_changed(); } @@ -1445,6 +1513,7 @@ void TabBar::remove_tab(int p_idx) { queue_accessibility_update(); queue_redraw(); + update_desired_size(); update_minimum_size(); notify_property_list_changed(); @@ -1653,6 +1722,7 @@ void TabBar::_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_in } queue_accessibility_update(); + update_desired_size(); update_minimum_size(); } @@ -1733,6 +1803,7 @@ void TabBar::set_clip_tabs(bool p_clip_tabs) { ensure_tab_visible(current); } queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -1988,6 +2059,7 @@ void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { ensure_tab_visible(current); } queue_redraw(); + update_desired_size(); update_minimum_size(); } @@ -2010,6 +2082,7 @@ void TabBar::set_max_tab_width(int p_width) { ensure_tab_visible(current); } queue_redraw(); + update_desired_size(); update_minimum_size(); } diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index c22c578732..8c4602e43d 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -334,6 +334,7 @@ public: Rect2 get_tab_rect(int p_tab) const; Size2 get_minimum_size() const override; + Size2 get_desired_size() const override; TabBar(); }; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 0a3d6188d8..980ae1fe66 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -266,6 +266,7 @@ void TabContainer::_on_theme_changed() { _repaint(); } else { update_minimum_size(); + update_desired_size(); } queue_redraw(); @@ -933,6 +934,7 @@ void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) { tab_bar->set_tab_disabled(p_tab, p_disabled); _update_margins(); + update_desired_size(); if (!get_clip_tabs()) { update_minimum_size(); } @@ -958,6 +960,7 @@ void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) { child->hide(); _update_margins(); + update_desired_size(); if (!get_clip_tabs()) { update_minimum_size(); } @@ -987,16 +990,16 @@ Ref TabContainer::get_tab_button_icon(int p_tab) const { return tab_bar->get_tab_button_icon(p_tab); } -Size2 TabContainer::get_minimum_size() const { +Size2 TabContainer::_get_minimum_size(bool p_use_desired_sizes) const { Size2 ms; if (tabs_visible) { - ms = tab_bar->get_minimum_size(); + ms = p_use_desired_sizes ? tab_bar->get_bound_desired_size() : tab_bar->get_minimum_size(); ms.width += theme_cache.tabbar_style->get_margin(SIDE_LEFT) + theme_cache.tabbar_style->get_margin(SIDE_RIGHT); ms.height += theme_cache.tabbar_style->get_margin(SIDE_TOP) + theme_cache.tabbar_style->get_margin(SIDE_BOTTOM); if (get_popup()) { - ms.width += popup_button->get_minimum_size().x; + ms.width += p_use_desired_sizes ? popup_button->get_bound_desired_size().x : popup_button->get_minimum_size().x; } if (theme_cache.side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER && @@ -1014,7 +1017,7 @@ Size2 TabContainer::get_minimum_size() const { continue; } - Size2 cms = c->get_bound_minimum_size(); + Size2 cms = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); largest_child_min_size = largest_child_min_size.max(cms); } ms.height += largest_child_min_size.height; @@ -1027,6 +1030,14 @@ Size2 TabContainer::get_minimum_size() const { return ms; } +Size2 TabContainer::get_minimum_size() const { + return _get_minimum_size(false); +} + +Size2 TabContainer::get_desired_size() const { + return _get_minimum_size(true); +} + Size2 TabContainer::get_inner_combined_maximum_size() const { Size2 ms = Container::get_inner_combined_maximum_size(); @@ -1105,6 +1116,7 @@ void TabContainer::set_popup(Node *p_popup) { popup_button->set_visible(popup != nullptr); _update_margins(); update_minimum_size(); + update_desired_size(); } } @@ -1155,6 +1167,7 @@ void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { use_hidden_tabs_for_min_size = p_use_hidden_tabs; update_minimum_size(); + update_desired_size(); } bool TabContainer::get_use_hidden_tabs_for_min_size() const { diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 09dcf67fba..f9010b23ac 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -152,6 +152,8 @@ private: void _popup_button_hovered(bool p_hover); void _popup_button_pressed(); + Size2 _get_minimum_size(bool p_use_desired_sizes) const; + protected: bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } @@ -236,6 +238,7 @@ public: virtual Size2 get_minimum_size() const override; virtual Size2 get_inner_combined_maximum_size() const override; + virtual Size2 get_desired_size() const override; void set_popup(Node *p_popup); Popup *get_popup() const; diff --git a/tests/scene/test_label.cpp b/tests/scene/test_label.cpp index 3a634bd893..24e617d4a7 100644 --- a/tests/scene/test_label.cpp +++ b/tests/scene/test_label.cpp @@ -32,6 +32,8 @@ TEST_FORCE_LINK(test_label) +#include "modules/modules_enabled.gen.h" // IWYU pragma: keep. Needed for MODULE_TEXT_SERVER_FB_ENABLED and MODULE_TEXT_SERVER_ADV_ENABLED definitions. + #if defined(MODULE_TEXT_SERVER_FB_ENABLED) || defined(MODULE_TEXT_SERVER_ADV_ENABLED) #include "scene/gui/label.h" @@ -139,7 +141,7 @@ TEST_CASE("[SceneTree][Label] Sizing") { real_t max_width = 50; real_t min_width = 25; - test_label->set_custom_maximum_size(Size2(max_width, 0)); + test_label->set_custom_maximum_size(Size2(max_width, -1)); test_label->set_custom_minimum_size(Size2(min_width, 0)); test_label->set_text("This is a long text that should be wrapped and exceeds minimum size."); SceneTree::get_singleton()->process(0);