| … | … | @@ -288,7 +288,7 @@ void BoxContainer::_resort() { |
| 288 | 288 | } |
| 289 | 289 | } |
| 290 | 290 | |
| 291 | Size2 BoxContainer::get_minimum_size() const { | |
| 291 | Size2 BoxContainer::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 292 | 292 | /* Calculate MINIMUM SIZE */ |
| 293 | 293 | |
| 294 | 294 | Size2i minimum; |
| … | … | @@ -301,7 +301,7 @@ Size2 BoxContainer::get_minimum_size() const { |
| 301 | 301 | continue; |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | Size2i size = c->get_bound_minimum_size(); | |
| 304 | Size2i size = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); | |
| 305 | 305 | |
| 306 | 306 | if (vertical) { /* VERTICAL */ |
| 307 | 307 | |
| … | … | @@ -326,6 +326,14 @@ Size2 BoxContainer::get_minimum_size() const { |
| 326 | 326 | return minimum; |
| 327 | 327 | } |
| 328 | 328 | |
| 329 | Size2 BoxContainer::get_minimum_size() const { | |
| 330 | return _get_minimum_size(false); | |
| 331 | } | |
| 332 | ||
| 333 | Size2 BoxContainer::get_desired_size() const { | |
| 334 | return _get_minimum_size(true); | |
| 335 | } | |
| 336 | ||
| 329 | 337 | void BoxContainer::_notification(int p_what) { |
| 330 | 338 | switch (p_what) { |
| 331 | 339 | case NOTIFICATION_SORT_CHILDREN: { |
| … | … | @@ -51,6 +51,7 @@ private: |
| 51 | 51 | } theme_cache; |
| 52 | 52 | |
| 53 | 53 | void _resort(); |
| 54 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 54 | 55 | |
| 55 | 56 | protected: |
| 56 | 57 | bool is_fixed = false; |
| … | … | @@ -69,6 +70,7 @@ public: |
| 69 | 70 | bool is_vertical() const; |
| 70 | 71 | |
| 71 | 72 | virtual Size2 get_minimum_size() const override; |
| 73 | virtual Size2 get_desired_size() const override; | |
| 72 | 74 | |
| 73 | 75 | virtual Vector<int> get_allowed_size_flags_horizontal() const override; |
| 74 | 76 | virtual Vector<int> get_allowed_size_flags_vertical() const override; |
| … | … | @@ -49,6 +49,23 @@ Size2 CenterContainer::get_minimum_size() const { |
| 49 | 49 | return ms; |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | Size2 CenterContainer::get_desired_size() const { | |
| 53 | if (use_top_left) { | |
| 54 | return Size2(); | |
| 55 | } | |
| 56 | Size2 ds; | |
| 57 | for (int i = 0; i < get_child_count(); i++) { | |
| 58 | Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE); | |
| 59 | if (!c) { | |
| 60 | continue; | |
| 61 | } | |
| 62 | Size2 minsize = c->get_bound_desired_size(); | |
| 63 | ds = ds.max(minsize); | |
| 64 | } | |
| 65 | ||
| 66 | return ds; | |
| 67 | } | |
| 68 | ||
| 52 | 69 | void CenterContainer::set_use_top_left(bool p_enable) { |
| 53 | 70 | if (use_top_left == p_enable) { |
| 54 | 71 | return; |
| … | … | @@ -46,6 +46,7 @@ public: |
| 46 | 46 | bool is_using_top_left() const; |
| 47 | 47 | |
| 48 | 48 | virtual Size2 get_minimum_size() const override; |
| 49 | virtual Size2 get_desired_size() const override; | |
| 49 | 50 | |
| 50 | 51 | virtual Vector<int> get_allowed_size_flags_horizontal() const override; |
| 51 | 52 | virtual Vector<int> get_allowed_size_flags_vertical() const override; |
| … | … | @@ -39,6 +39,11 @@ void Container::_child_minsize_changed() { |
| 39 | 39 | queue_sort(); |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | void Container::_child_desired_size_changed() { | |
| 43 | update_desired_size(); | |
| 44 | queue_sort(); | |
| 45 | } | |
| 46 | ||
| 42 | 47 | void Container::add_child_notify(Node *p_child) { |
| 43 | 48 | Control::add_child_notify(p_child); |
| 44 | 49 | |
| … | … | @@ -50,6 +55,7 @@ void Container::add_child_notify(Node *p_child) { |
| 50 | 55 | control->connect(SceneStringName(size_flags_changed), callable_mp(this, &Container::queue_sort)); |
| 51 | 56 | control->connect(SceneStringName(minimum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); |
| 52 | 57 | control->connect(SceneStringName(maximum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); |
| 58 | control->connect("_desired_size_changed", callable_mp(this, &Container::_child_desired_size_changed)); | |
| 53 | 59 | control->connect(SceneStringName(visibility_changed), callable_mp(this, &Container::_child_minsize_changed)); |
| 54 | 60 | |
| 55 | 61 | update_minimum_size(); |
| … | … | @@ -78,6 +84,7 @@ void Container::remove_child_notify(Node *p_child) { |
| 78 | 84 | control->disconnect(SceneStringName(size_flags_changed), callable_mp(this, &Container::queue_sort)); |
| 79 | 85 | control->disconnect(SceneStringName(minimum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); |
| 80 | 86 | control->disconnect(SceneStringName(maximum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); |
| 87 | control->disconnect("_desired_size_changed", callable_mp(this, &Container::_child_desired_size_changed)); | |
| 81 | 88 | control->disconnect(SceneStringName(visibility_changed), callable_mp(this, &Container::_child_minsize_changed)); |
| 82 | 89 | |
| 83 | 90 | update_minimum_size(); |
| … | … | @@ -105,6 +112,7 @@ void Container::fit_child_in_rect(RequiredParam<Control> rp_child, const Rect2 & |
| 105 | 112 | |
| 106 | 113 | bool rtl = is_layout_rtl(); |
| 107 | 114 | Size2 minsize = p_child->get_combined_minimum_size(); |
| 115 | Size2 desired_size = p_child->get_bound_desired_size(); | |
| 108 | 116 | Size2 maxsize = p_child->get_combined_maximum_size(); |
| 109 | 117 | Rect2 r = p_rect; |
| 110 | 118 | BitField<SizeFlags> h_size_flags = p_child->get_h_size_flags(); |
| … | … | @@ -112,6 +120,7 @@ void Container::fit_child_in_rect(RequiredParam<Control> rp_child, const Rect2 & |
| 112 | 120 | |
| 113 | 121 | if (!h_size_flags.has_flag(SIZE_FILL)) { |
| 114 | 122 | float final_width = minsize.width; |
| 123 | final_width = MAX(MIN(desired_size.width, r.size.width), final_width); | |
| 115 | 124 | if (maxsize.width >= 0) { |
| 116 | 125 | final_width = MIN(final_width, maxsize.width); |
| 117 | 126 | } |
| … | … | @@ -127,6 +136,7 @@ void Container::fit_child_in_rect(RequiredParam<Control> rp_child, const Rect2 & |
| 127 | 136 | |
| 128 | 137 | if (!v_size_flags.has_flag(SIZE_FILL)) { |
| 129 | 138 | float final_height = minsize.y; |
| 139 | final_height = MAX(MIN(desired_size.y, r.size.y), final_height); | |
| 130 | 140 | if (maxsize.height >= 0) { |
| 131 | 141 | final_height = MIN(final_height, maxsize.height); |
| 132 | 142 | } |
| … | … | @@ -39,6 +39,7 @@ class Container : public Control { |
| 39 | 39 | bool accessibility_region = false; |
| 40 | 40 | void _sort_children(); |
| 41 | 41 | void _child_minsize_changed(); |
| 42 | void _child_desired_size_changed(); | |
| 42 | 43 | |
| 43 | 44 | protected: |
| 44 | 45 | enum class SortableVisibilityMode { |
| … | … | @@ -1550,6 +1550,8 @@ void Control::set_size(const Size2 &p_size, bool p_keep_offsets) { |
| 1550 | 1550 | } |
| 1551 | 1551 | #endif // TOOLS_ENABLED |
| 1552 | 1552 | |
| 1553 | data.expanded_by_desired_size = false; | |
| 1554 | ||
| 1553 | 1555 | if (p_keep_offsets) { |
| 1554 | 1556 | _compute_anchors(Rect2(data.pos_cache, new_size), data.offset, data.anchor); |
| 1555 | 1557 | } else { |
| … | … | @@ -1761,6 +1763,11 @@ void Control::update_maximum_size() { |
| 1761 | 1763 | data.updating_last_minimum_size = true; |
| 1762 | 1764 | callable_mp(this, &Control::_update_minimum_size).call_deferred(); |
| 1763 | 1765 | } |
| 1766 | // Same with desired size. | |
| 1767 | if (!data.updating_last_desired_size) { | |
| 1768 | data.updating_last_desired_size = true; | |
| 1769 | callable_mp(this, &Control::_update_desired_size).call_deferred(); | |
| 1770 | } | |
| 1764 | 1771 | |
| 1765 | 1772 | callable_mp(this, &Control::_update_maximum_size).call_deferred(); |
| 1766 | 1773 | } |
| … | … | @@ -1948,6 +1955,107 @@ Size2 Control::get_custom_minimum_size() const { |
| 1948 | 1955 | return data.custom_minimum_size; |
| 1949 | 1956 | } |
| 1950 | 1957 | |
| 1958 | void Control::_update_desired_size_cache() const { | |
| 1959 | Size2 desired_size = get_desired_size(); | |
| 1960 | ||
| 1961 | data.desired_size_cache = desired_size; | |
| 1962 | data.desired_size_valid = true; | |
| 1963 | } | |
| 1964 | ||
| 1965 | void Control::_update_desired_size() { | |
| 1966 | if (!is_inside_tree()) { | |
| 1967 | data.updating_last_desired_size = false; | |
| 1968 | return; | |
| 1969 | } | |
| 1970 | ||
| 1971 | Size2 desired_size = get_desired_size(); | |
| 1972 | data.updating_last_desired_size = false; | |
| 1973 | ||
| 1974 | if (desired_size != data.last_desired_size) { | |
| 1975 | data.last_desired_size = desired_size; | |
| 1976 | grow_to_desired_size(); | |
| 1977 | emit_signal("_desired_size_changed"); | |
| 1978 | } | |
| 1979 | } | |
| 1980 | ||
| 1981 | void Control::update_desired_size() { | |
| 1982 | ERR_MAIN_THREAD_GUARD; | |
| 1983 | if (!is_inside_tree()) { | |
| 1984 | return; | |
| 1985 | } | |
| 1986 | ||
| 1987 | // Invalidate cache upwards. | |
| 1988 | Control *invalidate = this; | |
| 1989 | while (invalidate && invalidate->data.desired_size_valid) { | |
| 1990 | invalidate->data.desired_size_valid = false; | |
| 1991 | if (invalidate->is_set_as_top_level()) { | |
| 1992 | break; // Do not go further up. | |
| 1993 | } | |
| 1994 | ||
| 1995 | Window *parent_window = invalidate->get_parent_window(); | |
| 1996 | if (parent_window && parent_window->is_wrapping_controls()) { | |
| 1997 | parent_window->child_controls_changed(); | |
| 1998 | break; // Stop on a window as well. | |
| 1999 | } | |
| 2000 | ||
| 2001 | invalidate = invalidate->get_parent_control(); | |
| 2002 | } | |
| 2003 | ||
| 2004 | if (!is_visible_in_tree()) { | |
| 2005 | // Invalidate the last desired size so it will update when made visible. | |
| 2006 | data.last_desired_size = Size2(-1, -1); | |
| 2007 | return; | |
| 2008 | } | |
| 2009 | ||
| 2010 | if (data.updating_last_desired_size) { | |
| 2011 | return; | |
| 2012 | } | |
| 2013 | data.updating_last_desired_size = true; | |
| 2014 | ||
| 2015 | callable_mp(this, &Control::_update_desired_size).call_deferred(); | |
| 2016 | } | |
| 2017 | ||
| 2018 | Size2 Control::get_bound_desired_size() const { | |
| 2019 | ERR_READ_THREAD_GUARD_V(Size2()); | |
| 2020 | if (!data.desired_size_valid) { | |
| 2021 | _update_desired_size_cache(); | |
| 2022 | } | |
| 2023 | Size2 desired_size = data.desired_size_cache; | |
| 2024 | desired_size = desired_size.max(get_combined_minimum_size()); | |
| 2025 | Size2 max_size = get_combined_maximum_size(); | |
| 2026 | if (max_size.x >= 0) { | |
| 2027 | desired_size.x = MIN(desired_size.x, max_size.x); | |
| 2028 | } | |
| 2029 | if (max_size.y >= 0) { | |
| 2030 | desired_size.y = MIN(desired_size.y, max_size.y); | |
| 2031 | } | |
| 2032 | return desired_size; | |
| 2033 | } | |
| 2034 | ||
| 2035 | Size2 Control::get_desired_size() const { | |
| 2036 | return Size2(); | |
| 2037 | } | |
| 2038 | ||
| 2039 | void Control::grow_to_desired_size() { | |
| 2040 | ERR_MAIN_THREAD_GUARD; | |
| 2041 | if (!is_inside_tree()) { | |
| 2042 | return; | |
| 2043 | } | |
| 2044 | ||
| 2045 | Size2 desired_size = get_bound_desired_size(); | |
| 2046 | if (desired_size <= get_combined_minimum_size()) { | |
| 2047 | return; | |
| 2048 | } | |
| 2049 | ||
| 2050 | if (data.expanded_by_desired_size) { | |
| 2051 | set_size(desired_size); | |
| 2052 | data.expanded_by_desired_size = true; | |
| 2053 | } else if (desired_size.x > get_size().x || desired_size.y > get_size().y) { | |
| 2054 | set_size(desired_size); | |
| 2055 | data.expanded_by_desired_size = true; | |
| 2056 | } | |
| 2057 | } | |
| 2058 | ||
| 1951 | 2059 | void Control::add_child_notify(Node *p_child) { |
| 1952 | 2060 | CanvasItem::add_child_notify(p_child); |
| 1953 | 2061 | |
| … | … | @@ -2021,6 +2129,9 @@ void Control::_update_minimum_size_cache() const { |
| 2021 | 2129 | |
| 2022 | 2130 | data.minimum_size_cache = minsize; |
| 2023 | 2131 | data.minimum_size_valid = true; |
| 2132 | ||
| 2133 | // 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. | |
| 2134 | data.desired_size_valid = false; | |
| 2024 | 2135 | } |
| 2025 | 2136 | |
| 2026 | 2137 | Size2 Control::get_combined_minimum_size() const { |
| … | … | @@ -5024,6 +5135,7 @@ void Control::_bind_methods() { |
| 5024 | 5135 | ADD_SIGNAL(MethodInfo("size_flags_changed")); |
| 5025 | 5136 | ADD_SIGNAL(MethodInfo("maximum_size_changed")); |
| 5026 | 5137 | ADD_SIGNAL(MethodInfo("minimum_size_changed")); |
| 5138 | ADD_SIGNAL(MethodInfo("_desired_size_changed")); | |
| 5027 | 5139 | ADD_SIGNAL(MethodInfo("theme_changed")); |
| 5028 | 5140 | |
| 5029 | 5141 | GDVIRTUAL_BIND(_has_point, "point"); |
| … | … | @@ -256,6 +256,14 @@ private: |
| 256 | 256 | bool updating_last_minimum_size = false; |
| 257 | 257 | bool block_minimum_size_adjust = false; |
| 258 | 258 | |
| 259 | mutable Size2 desired_size_cache; | |
| 260 | mutable bool desired_size_valid = false; | |
| 261 | ||
| 262 | Size2 last_desired_size; | |
| 263 | bool updating_last_desired_size = false; | |
| 264 | ||
| 265 | bool expanded_by_desired_size = false; | |
| 266 | ||
| 259 | 267 | bool layout_pending = false; |
| 260 | 268 | |
| 261 | 269 | bool size_warning = true; |
| … | … | @@ -371,6 +379,9 @@ private: |
| 371 | 379 | void _update_maximum_size(); |
| 372 | 380 | void _update_minimum_size_cache() const; |
| 373 | 381 | void _update_minimum_size(); |
| 382 | void _update_desired_size_cache() const; | |
| 383 | void _update_desired_size(); | |
| 384 | void _grow_to_desired_size(); | |
| 374 | 385 | void _size_changed(); |
| 375 | 386 | |
| 376 | 387 | void _top_level_changed() override {} // Controls don't need to do anything, only other CanvasItems. |
| … | … | @@ -603,6 +614,9 @@ public: |
| 603 | 614 | |
| 604 | 615 | void update_maximum_size(); |
| 605 | 616 | void update_minimum_size(); |
| 617 | void update_desired_size(); | |
| 618 | ||
| 619 | void grow_to_desired_size(); | |
| 606 | 620 | |
| 607 | 621 | void set_block_maximum_size_adjust(bool p_block); |
| 608 | 622 | void set_block_minimum_size_adjust(bool p_block); |
| … | … | @@ -624,6 +638,9 @@ public: |
| 624 | 638 | |
| 625 | 639 | virtual Size2 get_bound_minimum_size() const; |
| 626 | 640 | |
| 641 | Size2 get_bound_desired_size() const; | |
| 642 | virtual Size2 get_desired_size() const; | |
| 643 | ||
| 627 | 644 | bool is_layout_pending() const; |
| 628 | 645 | bool is_layout_pending_in_tree() const; |
| 629 | 646 | void layout_pending_start(); |
| … | … | @@ -347,7 +347,7 @@ void FlowContainer::_resort() { |
| 347 | 347 | cached_line_max_child_count = lines_data.size() > 0 ? lines_data[0].child_count : 0; |
| 348 | 348 | } |
| 349 | 349 | |
| 350 | Size2 FlowContainer::get_minimum_size() const { | |
| 350 | Size2 FlowContainer::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 351 | 351 | Size2i minimum; |
| 352 | 352 | |
| 353 | 353 | for (int i = 0; i < get_child_count(); i++) { |
| … | … | @@ -356,7 +356,7 @@ Size2 FlowContainer::get_minimum_size() const { |
| 356 | 356 | continue; |
| 357 | 357 | } |
| 358 | 358 | |
| 359 | Size2i size = c->get_bound_minimum_size(); | |
| 359 | Size2i size = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); | |
| 360 | 360 | |
| 361 | 361 | if (vertical) { /* VERTICAL */ |
| 362 | 362 | minimum.height = MAX(minimum.height, size.height); |
| … | … | @@ -371,6 +371,14 @@ Size2 FlowContainer::get_minimum_size() const { |
| 371 | 371 | return minimum; |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | Size2 FlowContainer::get_minimum_size() const { | |
| 375 | return _get_minimum_size(false); | |
| 376 | } | |
| 377 | ||
| 378 | Size2 FlowContainer::get_desired_size() const { | |
| 379 | return _get_minimum_size(true); | |
| 380 | } | |
| 381 | ||
| 374 | 382 | Vector<int> FlowContainer::get_allowed_size_flags_horizontal() const { |
| 375 | 383 | Vector<int> flags; |
| 376 | 384 | flags.append(SIZE_FILL); |
| … | … | @@ -64,6 +64,7 @@ private: |
| 64 | 64 | } theme_cache; |
| 65 | 65 | |
| 66 | 66 | void _resort(); |
| 67 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 67 | 68 | |
| 68 | 69 | protected: |
| 69 | 70 | bool is_fixed = false; |
| … | … | @@ -89,6 +90,7 @@ public: |
| 89 | 90 | bool is_reverse_fill() const; |
| 90 | 91 | |
| 91 | 92 | virtual Size2 get_minimum_size() const override; |
| 93 | virtual Size2 get_desired_size() const override; | |
| 92 | 94 | |
| 93 | 95 | virtual Vector<int> get_allowed_size_flags_horizontal() const override; |
| 94 | 96 | virtual Vector<int> get_allowed_size_flags_vertical() const override; |
| … | … | @@ -54,6 +54,26 @@ Size2 FoldableContainer::get_minimum_size() const { |
| 54 | 54 | return Size2(MAX(ms.width, title_minimum_size.width), ms.height + title_minimum_size.height); |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | Size2 FoldableContainer::get_desired_size() const { | |
| 58 | _update_title_min_size(); | |
| 59 | ||
| 60 | if (folded) { | |
| 61 | return title_minimum_size; | |
| 62 | } | |
| 63 | Size2 ds; | |
| 64 | ||
| 65 | for (int i = 0; i < get_child_count(); i++) { | |
| 66 | Control *c = as_sortable_control(get_child(i)); | |
| 67 | if (!c) { | |
| 68 | continue; | |
| 69 | } | |
| 70 | ds = ds.max(c->get_bound_desired_size()); | |
| 71 | } | |
| 72 | ds += theme_cache.panel_style->get_minimum_size(); | |
| 73 | ||
| 74 | return Size2(MAX(ds.width, title_minimum_size.width), ds.height + title_minimum_size.height); | |
| 75 | } | |
| 76 | ||
| 57 | 77 | Size2 FoldableContainer::get_inner_combined_maximum_size() const { |
| 58 | 78 | Size2 ms = Container::get_inner_combined_maximum_size(); |
| 59 | 79 |
| … | … | @@ -138,6 +138,7 @@ public: |
| 138 | 138 | void remove_title_bar_control(Control *p_control); |
| 139 | 139 | |
| 140 | 140 | virtual Size2 get_minimum_size() const override; |
| 141 | virtual Size2 get_desired_size() const override; | |
| 141 | 142 | virtual Size2 get_inner_combined_maximum_size() const override; |
| 142 | 143 | |
| 143 | 144 | virtual Vector<int> get_allowed_size_flags_horizontal() const override { return { SIZE_FILL, SIZE_SHRINK_BEGIN, SIZE_SHRINK_CENTER, SIZE_SHRINK_END }; } |
| … | … | @@ -323,11 +323,11 @@ bool GraphFrame::has_point(const Point2 &p_point) const { |
| 323 | 323 | return false; |
| 324 | 324 | } |
| 325 | 325 | |
| 326 | Size2 GraphFrame::get_minimum_size() const { | |
| 326 | Size2 GraphFrame::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 327 | 327 | Ref<StyleBox> sb_panel = theme_cache.panel; |
| 328 | 328 | Ref<StyleBox> sb_titlebar = theme_cache.titlebar; |
| 329 | 329 | |
| 330 | Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size(); | |
| 330 | Size2 minsize = (p_use_desired_sizes ? titlebar_hbox->get_bound_desired_size() : titlebar_hbox->get_minimum_size()) + sb_titlebar->get_minimum_size(); | |
| 331 | 331 | |
| 332 | 332 | for (int i = 0; i < get_child_count(false); i++) { |
| 333 | 333 | Control *child = as_sortable_control(get_child(i, false)); |
| … | … | @@ -335,7 +335,7 @@ Size2 GraphFrame::get_minimum_size() const { |
| 335 | 335 | continue; |
| 336 | 336 | } |
| 337 | 337 | |
| 338 | Size2i size = child->get_bound_minimum_size(); | |
| 338 | Size2i size = p_use_desired_sizes ? child->get_bound_desired_size() : child->get_bound_minimum_size(); | |
| 339 | 339 | size.width += sb_panel->get_minimum_size().width; |
| 340 | 340 | |
| 341 | 341 | minsize.x = MAX(minsize.x, size.x); |
| … | … | @@ -347,6 +347,14 @@ Size2 GraphFrame::get_minimum_size() const { |
| 347 | 347 | return minsize; |
| 348 | 348 | } |
| 349 | 349 | |
| 350 | Size2 GraphFrame::get_minimum_size() const { | |
| 351 | return _get_minimum_size(false); | |
| 352 | } | |
| 353 | ||
| 354 | Size2 GraphFrame::get_desired_size() const { | |
| 355 | return _get_minimum_size(true); | |
| 356 | } | |
| 357 | ||
| 350 | 358 | GraphFrame::GraphFrame() { |
| 351 | 359 | titlebar_hbox = memnew(HBoxContainer); |
| 352 | 360 | titlebar_hbox->set_h_size_flags(SIZE_EXPAND_FILL); |
| … | … | @@ -60,6 +60,8 @@ private: |
| 60 | 60 | bool tint_color_enabled = false; |
| 61 | 61 | Color tint_color = Color(0.3, 0.3, 0.3, 0.75); |
| 62 | 62 | |
| 63 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 64 | ||
| 63 | 65 | protected: |
| 64 | 66 | virtual void gui_input(const Ref<InputEvent> &p_event) override; |
| 65 | 67 | virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; |
| … | … | @@ -95,6 +97,7 @@ public: |
| 95 | 97 | |
| 96 | 98 | virtual bool has_point(const Point2 &p_point) const override; |
| 97 | 99 | virtual Size2 get_minimum_size() const override; |
| 100 | virtual Size2 get_desired_size() const override; | |
| 98 | 101 | |
| 99 | 102 | GraphFrame(); |
| 100 | 103 | }; |
| … | … | @@ -996,13 +996,13 @@ bool GraphNode::is_ignoring_valid_connection_type() const { |
| 996 | 996 | return ignore_invalid_connection_type; |
| 997 | 997 | } |
| 998 | 998 | |
| 999 | Size2 GraphNode::get_minimum_size() const { | |
| 999 | Size2 GraphNode::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 1000 | 1000 | Ref<StyleBox> sb_panel = theme_cache.panel; |
| 1001 | 1001 | Ref<StyleBox> sb_titlebar = theme_cache.titlebar; |
| 1002 | 1002 | Ref<StyleBox> sb_slot = theme_cache.slot; |
| 1003 | 1003 | |
| 1004 | 1004 | int separation = theme_cache.separation; |
| 1005 | Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size(); | |
| 1005 | Size2 minsize = (p_use_desired_sizes ? titlebar_hbox->get_bound_desired_size() : titlebar_hbox->get_minimum_size()) + sb_titlebar->get_minimum_size(); | |
| 1006 | 1006 | |
| 1007 | 1007 | for (int i = 0; i < get_child_count(false); i++) { |
| 1008 | 1008 | Control *child = as_sortable_control(get_child(i, false)); |
| … | … | @@ -1010,7 +1010,7 @@ Size2 GraphNode::get_minimum_size() const { |
| 1010 | 1010 | continue; |
| 1011 | 1011 | } |
| 1012 | 1012 | |
| 1013 | Size2i size = child->get_bound_minimum_size(); | |
| 1013 | Size2i size = p_use_desired_sizes ? child->get_bound_desired_size() : child->get_bound_minimum_size(); | |
| 1014 | 1014 | size.width += sb_panel->get_minimum_size().width; |
| 1015 | 1015 | if (slot_table.has(i)) { |
| 1016 | 1016 | size += slot_table[i].draw_stylebox ? sb_slot->get_minimum_size() : Size2(); |
| … | … | @@ -1029,6 +1029,14 @@ Size2 GraphNode::get_minimum_size() const { |
| 1029 | 1029 | return minsize; |
| 1030 | 1030 | } |
| 1031 | 1031 | |
| 1032 | Size2 GraphNode::get_minimum_size() const { | |
| 1033 | return _get_minimum_size(false); | |
| 1034 | } | |
| 1035 | ||
| 1036 | Size2 GraphNode::get_desired_size() const { | |
| 1037 | return _get_minimum_size(true); | |
| 1038 | } | |
| 1039 | ||
| 1032 | 1040 | void GraphNode::_port_pos_update() { |
| 1033 | 1041 | int edgeofs = theme_cache.port_h_offset; |
| 1034 | 1042 | int separation = theme_cache.separation; |
| … | … | @@ -115,6 +115,8 @@ class GraphNode : public GraphElement { |
| 115 | 115 | |
| 116 | 116 | void _port_pos_update(); |
| 117 | 117 | |
| 118 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 119 | ||
| 118 | 120 | protected: |
| 119 | 121 | void _notification(int p_what); |
| 120 | 122 | static void _bind_methods(); |
| … | … | @@ -195,6 +197,7 @@ public: |
| 195 | 197 | Control::FocusMode get_slots_focus_mode() const; |
| 196 | 198 | |
| 197 | 199 | virtual Size2 get_minimum_size() const override; |
| 200 | virtual Size2 get_desired_size() const override; | |
| 198 | 201 | |
| 199 | 202 | virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; |
| 200 | 203 |
| … | … | @@ -378,7 +378,7 @@ void GridContainer::_bind_methods() { |
| 378 | 378 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GridContainer, v_separation); |
| 379 | 379 | } |
| 380 | 380 | |
| 381 | Size2 GridContainer::get_minimum_size() const { | |
| 381 | Size2 GridContainer::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 382 | 382 | RBMap<int, int> col_minw; |
| 383 | 383 | RBMap<int, int> row_minh; |
| 384 | 384 | |
| … | … | @@ -395,7 +395,7 @@ Size2 GridContainer::get_minimum_size() const { |
| 395 | 395 | int col = valid_controls_index % columns; |
| 396 | 396 | valid_controls_index++; |
| 397 | 397 | |
| 398 | Size2i ms = c->get_bound_minimum_size(); | |
| 398 | Size2i ms = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); | |
| 399 | 399 | if (col_minw.has(col)) { |
| 400 | 400 | col_minw[col] = MAX(col_minw[col], ms.width); |
| 401 | 401 | } else { |
| … | … | @@ -426,3 +426,11 @@ Size2 GridContainer::get_minimum_size() const { |
| 426 | 426 | |
| 427 | 427 | return ms; |
| 428 | 428 | } |
| 429 | ||
| 430 | Size2 GridContainer::get_minimum_size() const { | |
| 431 | return _get_minimum_size(false); | |
| 432 | } | |
| 433 | ||
| 434 | Size2 GridContainer::get_desired_size() const { | |
| 435 | return _get_minimum_size(true); | |
| 436 | } |
| … | … | @@ -44,6 +44,7 @@ class GridContainer : public Container { |
| 44 | 44 | |
| 45 | 45 | private: |
| 46 | 46 | void _resort(); |
| 47 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 47 | 48 | |
| 48 | 49 | protected: |
| 49 | 50 | void _notification(int p_what); |
| … | … | @@ -53,6 +54,7 @@ public: |
| 53 | 54 | void set_columns(int p_columns); |
| 54 | 55 | int get_columns() const; |
| 55 | 56 | virtual Size2 get_minimum_size() const override; |
| 57 | virtual Size2 get_desired_size() const override; | |
| 56 | 58 | |
| 57 | 59 | int get_h_separation() const; |
| 58 | 60 | }; |
| … | … | @@ -53,6 +53,7 @@ void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) { |
| 53 | 53 | if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
| 54 | 54 | update_minimum_size(); |
| 55 | 55 | } |
| 56 | update_desired_size(); | |
| 56 | 57 | } |
| 57 | 58 | |
| 58 | 59 | TextServer::AutowrapMode Label::get_autowrap_mode() const { |
| … | … | @@ -74,6 +75,7 @@ void Label::set_autowrap_trim_flags(BitField<TextServer::LineBreakFlag> p_flags) |
| 74 | 75 | if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
| 75 | 76 | update_minimum_size(); |
| 76 | 77 | } |
| 78 | update_desired_size(); | |
| 77 | 79 | } |
| 78 | 80 | |
| 79 | 81 | BitField<TextServer::LineBreakFlag> Label::get_autowrap_trim_flags() const { |
| … | … | @@ -152,11 +154,7 @@ void Label::_shape() const { |
| 152 | 154 | if (maximum_width <= 0) { |
| 153 | 155 | maximum_width = 1; |
| 154 | 156 | } |
| 155 | if (width > 0) { | |
| 156 | width = MIN(width, maximum_width); | |
| 157 | } else { | |
| 158 | width = maximum_width; | |
| 159 | } | |
| 157 | width = maximum_width; | |
| 160 | 158 | } |
| 161 | 159 | |
| 162 | 160 | if (text_dirty) { |
| … | … | @@ -914,6 +912,7 @@ void Label::_notification(int p_what) { |
| 914 | 912 | case NOTIFICATION_THEME_CHANGED: { |
| 915 | 913 | font_dirty = true; |
| 916 | 914 | queue_redraw(); |
| 915 | update_desired_size(); | |
| 917 | 916 | update_configuration_warnings(); |
| 918 | 917 | } break; |
| 919 | 918 | |
| … | … | @@ -993,9 +992,6 @@ Size2 Label::get_minimum_size() const { |
| 993 | 992 | _ensure_shaped(); |
| 994 | 993 | |
| 995 | 994 | Size2 min_size = minsize; |
| 996 | Size2 combined_maximum_size = get_combined_maximum_size(); | |
| 997 | bool wrap_with_max_width = autowrap_mode != TextServer::AUTOWRAP_OFF && combined_maximum_size.x > 0; | |
| 998 | bool overrun_with_max_width = autowrap_mode == TextServer::AUTOWRAP_OFF && combined_maximum_size.x > 0 && (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING); | |
| 999 | 995 | |
| 1000 | 996 | const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font; |
| 1001 | 997 | int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size; |
| … | … | @@ -1010,28 +1006,29 @@ Size2 Label::get_minimum_size() const { |
| 1010 | 1006 | } else if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
| 1011 | 1007 | min_size.height = 1; |
| 1012 | 1008 | } |
| 1013 | if (wrap_with_max_width) { | |
| 1014 | min_size.width = MAX(1, min_size.width); | |
| 1015 | return min_size + min_style; | |
| 1016 | } else { | |
| 1017 | return Size2(1, min_size.height) + min_style; | |
| 1018 | } | |
| 1009 | return Size2(1, min_size.height) + min_style; | |
| 1019 | 1010 | } else { |
| 1020 | 1011 | if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
| 1021 | if (overrun_with_max_width) { | |
| 1022 | min_size.width = MAX(1, min_size.width); | |
| 1023 | } else { | |
| 1024 | min_size.width = 1; | |
| 1025 | } | |
| 1026 | } | |
| 1027 | Size2 computed_min_size = min_size + min_style; | |
| 1028 | if (overrun_with_max_width) { | |
| 1029 | computed_min_size.width = MIN(computed_min_size.width, combined_maximum_size.x); | |
| 1012 | min_size.width = 1; | |
| 1030 | 1013 | } |
| 1031 | return computed_min_size; | |
| 1014 | return min_size + min_style; | |
| 1032 | 1015 | } |
| 1033 | 1016 | } |
| 1034 | 1017 | |
| 1018 | Size2 Label::get_desired_size() const { | |
| 1019 | Size2 combined_max = get_combined_maximum_size(); | |
| 1020 | if (combined_max.width < 0) { | |
| 1021 | return Size2(); | |
| 1022 | } | |
| 1023 | ||
| 1024 | _ensure_shaped(); | |
| 1025 | Size2 min_style = theme_cache.normal_style->get_minimum_size(); | |
| 1026 | Size2 content_size = minsize + min_style; | |
| 1027 | content_size.width = MIN(content_size.width, int(combined_max.width)); | |
| 1028 | ||
| 1029 | return content_size; | |
| 1030 | } | |
| 1031 | ||
| 1035 | 1032 | #ifndef DISABLE_DEPRECATED |
| 1036 | 1033 | bool Label::_set(const StringName &p_name, const Variant &p_value) { |
| 1037 | 1034 | if (p_name == SNAME("valign")) { |
| … | … | @@ -1144,6 +1141,7 @@ void Label::set_text(const String &p_string) { |
| 1144 | 1141 | queue_accessibility_update(); |
| 1145 | 1142 | queue_redraw(); |
| 1146 | 1143 | update_minimum_size(); |
| 1144 | update_desired_size(); | |
| 1147 | 1145 | update_configuration_warnings(); |
| 1148 | 1146 | } |
| 1149 | 1147 | |
| … | … | @@ -1163,6 +1161,7 @@ void Label::_maximum_size_changed() { |
| 1163 | 1161 | } |
| 1164 | 1162 | queue_redraw(); |
| 1165 | 1163 | update_minimum_size(); |
| 1164 | update_desired_size(); | |
| 1166 | 1165 | update_configuration_warnings(); |
| 1167 | 1166 | } |
| 1168 | 1167 | |
| … | … | @@ -1264,6 +1263,7 @@ void Label::set_clip_text(bool p_clip) { |
| 1264 | 1263 | clip = p_clip; |
| 1265 | 1264 | queue_redraw(); |
| 1266 | 1265 | update_minimum_size(); |
| 1266 | update_desired_size(); | |
| 1267 | 1267 | } |
| 1268 | 1268 | |
| 1269 | 1269 | bool Label::is_clipping_text() const { |
| … | … | @@ -1297,6 +1297,7 @@ void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { |
| 1297 | 1297 | if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
| 1298 | 1298 | update_minimum_size(); |
| 1299 | 1299 | } |
| 1300 | update_desired_size(); | |
| 1300 | 1301 | } |
| 1301 | 1302 | |
| 1302 | 1303 | TextServer::OverrunBehavior Label::get_text_overrun_behavior() const { |
| … | … | @@ -1320,6 +1321,7 @@ void Label::set_ellipsis_char(const String &p_char) { |
| 1320 | 1321 | if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
| 1321 | 1322 | update_minimum_size(); |
| 1322 | 1323 | } |
| 1324 | update_desired_size(); | |
| 1323 | 1325 | } |
| 1324 | 1326 | |
| 1325 | 1327 | String Label::get_ellipsis_char() const { |
| … | … | @@ -116,6 +116,7 @@ protected: |
| 116 | 116 | |
| 117 | 117 | public: |
| 118 | 118 | virtual Size2 get_minimum_size() const override; |
| 119 | virtual Size2 get_desired_size() const override; | |
| 119 | 120 | virtual PackedStringArray get_configuration_warnings() const override; |
| 120 | 121 | |
| 121 | 122 | void set_horizontal_alignment(HorizontalAlignment p_alignment); |
| … | … | @@ -42,12 +42,7 @@ Size2 MarginContainer::get_minimum_size() const { |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | Size2 s = c->get_bound_minimum_size(); |
| 45 | if (s.width > max.width) { | |
| 46 | max.width = s.width; | |
| 47 | } | |
| 48 | if (s.height > max.height) { | |
| 49 | max.height = s.height; | |
| 50 | } | |
| 45 | max = max.max(s); | |
| 51 | 46 | } |
| 52 | 47 | |
| 53 | 48 | max.width += (theme_cache.margin_left + theme_cache.margin_right); |
| … | … | @@ -56,6 +51,25 @@ Size2 MarginContainer::get_minimum_size() const { |
| 56 | 51 | return max; |
| 57 | 52 | } |
| 58 | 53 | |
| 54 | Size2 MarginContainer::get_desired_size() const { | |
| 55 | Size2 ds; | |
| 56 | ||
| 57 | for (int i = 0; i < get_child_count(); i++) { | |
| 58 | Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE); | |
| 59 | if (!c) { | |
| 60 | continue; | |
| 61 | } | |
| 62 | ||
| 63 | Size2 s = c->get_desired_size(); | |
| 64 | ds = ds.max(s); | |
| 65 | } | |
| 66 | ||
| 67 | ds.width += (theme_cache.margin_left + theme_cache.margin_right); | |
| 68 | ds.height += (theme_cache.margin_top + theme_cache.margin_bottom); | |
| 69 | ||
| 70 | return ds; | |
| 71 | } | |
| 72 | ||
| 59 | 73 | Size2 MarginContainer::get_inner_combined_maximum_size() const { |
| 60 | 74 | Size2 ms = Container::get_inner_combined_maximum_size(); |
| 61 | 75 |
| … | … | @@ -48,6 +48,7 @@ protected: |
| 48 | 48 | |
| 49 | 49 | public: |
| 50 | 50 | virtual Size2 get_minimum_size() const override; |
| 51 | virtual Size2 get_desired_size() const override; | |
| 51 | 52 | virtual Size2 get_inner_combined_maximum_size() const override; |
| 52 | 53 | |
| 53 | 54 | virtual Vector<int> get_allowed_size_flags_horizontal() const override; |
| … | … | @@ -50,6 +50,24 @@ Size2 PanelContainer::get_minimum_size() const { |
| 50 | 50 | return ms; |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | Size2 PanelContainer::get_desired_size() const { | |
| 54 | Size2 ds; | |
| 55 | ||
| 56 | for (int i = 0; i < get_child_count(); i++) { | |
| 57 | Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE); | |
| 58 | if (!c) { | |
| 59 | continue; | |
| 60 | } | |
| 61 | ||
| 62 | Size2 minsize = c->get_desired_size(); | |
| 63 | ds = ds.max(minsize); | |
| 64 | } | |
| 65 | if (theme_cache.panel_style.is_valid()) { | |
| 66 | ds += theme_cache.panel_style->get_minimum_size(); | |
| 67 | } | |
| 68 | return ds; | |
| 69 | } | |
| 70 | ||
| 53 | 71 | Size2 PanelContainer::get_inner_combined_maximum_size() const { |
| 54 | 72 | Size2 ms = Container::get_inner_combined_maximum_size(); |
| 55 | 73 |
| … | … | @@ -45,6 +45,7 @@ protected: |
| 45 | 45 | |
| 46 | 46 | public: |
| 47 | 47 | virtual Size2 get_minimum_size() const override; |
| 48 | virtual Size2 get_desired_size() const override; | |
| 48 | 49 | virtual Size2 get_inner_combined_maximum_size() const override; |
| 49 | 50 | |
| 50 | 51 | virtual Vector<int> get_allowed_size_flags_horizontal() const override; |
| … | … | @@ -40,7 +40,7 @@ |
| 40 | 40 | #include "servers/display/accessibility_server.h" |
| 41 | 41 | #include "servers/display/display_server.h" |
| 42 | 42 | |
| 43 | Size2 ScrollContainer::get_minimum_size() const { | |
| 43 | Size2 ScrollContainer::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 44 | 44 | // Calculated in this function, as it needs to traverse all child controls once to calculate; |
| 45 | 45 | // and needs to be calculated before being used by `_update_scrollbars()`. |
| 46 | 46 | largest_child_min_size = Size2(); |
| … | … | @@ -51,7 +51,7 @@ Size2 ScrollContainer::get_minimum_size() const { |
| 51 | 51 | continue; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | Size2 child_min_size = c->get_bound_minimum_size(); | |
| 54 | Size2 child_min_size = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); | |
| 55 | 55 | largest_child_min_size = largest_child_min_size.max(child_min_size); |
| 56 | 56 | } |
| 57 | 57 | |
| … | … | @@ -93,6 +93,14 @@ Size2 ScrollContainer::get_minimum_size() const { |
| 93 | 93 | return min_size; |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | Size2 ScrollContainer::get_minimum_size() const { | |
| 97 | return _get_minimum_size(false); | |
| 98 | } | |
| 99 | ||
| 100 | Size2 ScrollContainer::get_desired_size() const { | |
| 101 | return _get_minimum_size(true); | |
| 102 | } | |
| 103 | ||
| 96 | 104 | Size2 ScrollContainer::get_inner_combined_maximum_size() const { |
| 97 | 105 | Size2 ms = Container::get_inner_combined_maximum_size(); |
| 98 | 106 |
| … | … | @@ -117,8 +117,11 @@ private: |
| 117 | 117 | bool focus_border_is_drawn = false; |
| 118 | 118 | bool child_has_focus(); |
| 119 | 119 | |
| 120 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 121 | ||
| 120 | 122 | protected: |
| 121 | 123 | Size2 get_minimum_size() const override; |
| 124 | Size2 get_desired_size() const override; | |
| 122 | 125 | Size2 get_inner_combined_maximum_size() const override; |
| 123 | 126 | |
| 124 | 127 | void _gui_focus_changed(Control *p_control); |
| … | … | @@ -1073,7 +1073,7 @@ void SplitContainer::_update_draggers() { |
| 1073 | 1073 | } |
| 1074 | 1074 | } |
| 1075 | 1075 | |
| 1076 | Size2 SplitContainer::get_minimum_size() const { | |
| 1076 | Size2 SplitContainer::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 1077 | 1077 | const int sep = _get_separation(); |
| 1078 | 1078 | const int axis = vertical ? 1 : 0; |
| 1079 | 1079 | const int other_axis = vertical ? 0 : 1; |
| … | … | @@ -1085,7 +1085,7 @@ Size2 SplitContainer::get_minimum_size() const { |
| 1085 | 1085 | } |
| 1086 | 1086 | |
| 1087 | 1087 | for (const Control *child : valid_children) { |
| 1088 | const Size2 min_size = child->get_bound_minimum_size(); | |
| 1088 | const Size2 min_size = p_use_desired_sizes ? child->get_bound_desired_size() : child->get_bound_minimum_size(); | |
| 1089 | 1089 | minimum[axis] += (int)min_size[axis]; |
| 1090 | 1090 | minimum[other_axis] = (int)MAX(minimum[other_axis], min_size[other_axis]); |
| 1091 | 1091 | } |
| … | … | @@ -1093,6 +1093,14 @@ Size2 SplitContainer::get_minimum_size() const { |
| 1093 | 1093 | return minimum; |
| 1094 | 1094 | } |
| 1095 | 1095 | |
| 1096 | Size2 SplitContainer::get_minimum_size() const { | |
| 1097 | return _get_minimum_size(false); | |
| 1098 | } | |
| 1099 | ||
| 1100 | Size2 SplitContainer::get_desired_size() const { | |
| 1101 | return _get_minimum_size(true); | |
| 1102 | } | |
| 1103 | ||
| 1096 | 1104 | void SplitContainer::_validate_property(PropertyInfo &p_property) const { |
| 1097 | 1105 | if (is_fixed && p_property.name == "vertical") { |
| 1098 | 1106 | p_property.usage = PROPERTY_USAGE_NONE; |
| … | … | @@ -169,6 +169,8 @@ private: |
| 169 | 169 | void _update_nested_ancestors(bool p_remove = false); |
| 170 | 170 | void _update_all_nested_descendents(Control *p_control, Control *p_first_child = nullptr); |
| 171 | 171 | |
| 172 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 173 | ||
| 172 | 174 | protected: |
| 173 | 175 | bool is_fixed = false; |
| 174 | 176 | |
| … | … | @@ -207,6 +209,7 @@ public: |
| 207 | 209 | bool is_dragging_enabled() const; |
| 208 | 210 | |
| 209 | 211 | virtual Size2 get_minimum_size() const override; |
| 212 | virtual Size2 get_desired_size() const override; | |
| 210 | 213 | |
| 211 | 214 | virtual Vector<int> get_allowed_size_flags_horizontal() const override; |
| 212 | 215 | virtual Vector<int> get_allowed_size_flags_vertical() const override; |
| … | … | @@ -50,8 +50,6 @@ static inline Color _select_color(const Color &p_override_color, const Color &p_ |
| 50 | 50 | Size2 TabBar::get_minimum_size() const { |
| 51 | 51 | Size2 ms; |
| 52 | 52 | Size2 combined_max = get_combined_maximum_size(); |
| 53 | int computed_max_width = 0; | |
| 54 | bool stop_adding = combined_max.width < 0; | |
| 55 | 53 | |
| 56 | 54 | int buttons_size = get_tab_count() > 1 ? theme_cache.decrement_icon->get_width() + theme_cache.increment_icon->get_width() : 0; |
| 57 | 55 | |
| … | … | @@ -120,31 +118,18 @@ Size2 TabBar::get_minimum_size() const { |
| 120 | 118 | ms.width += theme_cache.tab_separation; |
| 121 | 119 | } |
| 122 | 120 | |
| 123 | if (!stop_adding) { | |
| 124 | int buttons_eff_size = clip_tabs ? (i != tabs.size() - 1 ? buttons_size : 0) : 0; | |
| 125 | if (computed_max_width + ms.width - ofs + buttons_eff_size >= combined_max.width) { | |
| 126 | stop_adding = true; | |
| 127 | } else { | |
| 128 | computed_max_width += ms.width - ofs; | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | 121 | if (ms.width - ofs > max_tab_width) { |
| 133 | 122 | max_tab_width = ms.width - ofs; |
| 134 | 123 | } |
| 135 | 124 | } |
| 136 | 125 | |
| 137 | 126 | if (clip_tabs) { |
| 138 | int clip_min_width = max_tab_width + buttons_size; | |
| 127 | ms.width = max_tab_width + buttons_size; | |
| 139 | 128 | if (combined_max.width >= 0) { |
| 140 | int fitted_width = stop_adding ? (computed_max_width + buttons_size) : computed_max_width; | |
| 141 | ms.width = MAX(clip_min_width, fitted_width); | |
| 142 | 129 | ms.width = MIN(ms.width, int(combined_max.width)); |
| 143 | } else { | |
| 144 | ms.width = clip_min_width; | |
| 145 | 130 | } |
| 146 | 131 | } else if (combined_max.width >= 0) { |
| 147 | ms.width = stop_adding ? combined_max.width : MIN(computed_max_width, combined_max.width); | |
| 132 | ms.width = MIN(ms.width, int(combined_max.width)); | |
| 148 | 133 | } |
| 149 | 134 | |
| 150 | 135 | return ms; |
| … | … | @@ -507,10 +492,21 @@ void TabBar::_notification(int p_what) { |
| 507 | 492 | |
| 508 | 493 | queue_accessibility_update(); |
| 509 | 494 | queue_redraw(); |
| 495 | ||
| 496 | int ofs_old = offset; | |
| 497 | int max_old = max_drawn_tab; | |
| 498 | ||
| 499 | _update_cache(); | |
| 500 | _ensure_no_over_offset(); | |
| 501 | ||
| 502 | if (scroll_to_selected && (offset != ofs_old || max_drawn_tab != max_old)) { | |
| 503 | ensure_tab_visible(current); | |
| 504 | } | |
| 505 | ||
| 506 | update_desired_size(); | |
| 510 | 507 | update_minimum_size(); |
| 508 | } break; | |
| 511 | 509 | |
| 512 | [[fallthrough]]; | |
| 513 | } | |
| 514 | 510 | case NOTIFICATION_RESIZED: { |
| 515 | 511 | int ofs_old = offset; |
| 516 | 512 | int max_old = max_drawn_tab; |
| … | … | @@ -813,6 +809,7 @@ void TabBar::set_tab_count(int p_count) { |
| 813 | 809 | |
| 814 | 810 | queue_accessibility_update(); |
| 815 | 811 | queue_redraw(); |
| 812 | update_desired_size(); | |
| 816 | 813 | update_minimum_size(); |
| 817 | 814 | notify_property_list_changed(); |
| 818 | 815 | } |
| … | … | @@ -943,6 +940,7 @@ void TabBar::set_tab_title(int p_tab, const String &p_title) { |
| 943 | 940 | } |
| 944 | 941 | queue_accessibility_update(); |
| 945 | 942 | queue_redraw(); |
| 943 | update_desired_size(); | |
| 946 | 944 | update_minimum_size(); |
| 947 | 945 | } |
| 948 | 946 | |
| … | … | @@ -994,6 +992,7 @@ void TabBar::set_tab_language(int p_tab, const String &p_language) { |
| 994 | 992 | } |
| 995 | 993 | queue_accessibility_update(); |
| 996 | 994 | queue_redraw(); |
| 995 | update_desired_size(); | |
| 997 | 996 | update_minimum_size(); |
| 998 | 997 | } |
| 999 | 998 | } |
| … | … | @@ -1018,6 +1017,7 @@ void TabBar::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) { |
| 1018 | 1017 | ensure_tab_visible(current); |
| 1019 | 1018 | } |
| 1020 | 1019 | queue_redraw(); |
| 1020 | update_desired_size(); | |
| 1021 | 1021 | update_minimum_size(); |
| 1022 | 1022 | } |
| 1023 | 1023 | |
| … | … | @@ -1041,6 +1041,7 @@ void TabBar::set_tab_icon_max_width(int p_tab, int p_width) { |
| 1041 | 1041 | ensure_tab_visible(current); |
| 1042 | 1042 | } |
| 1043 | 1043 | queue_redraw(); |
| 1044 | update_desired_size(); | |
| 1044 | 1045 | update_minimum_size(); |
| 1045 | 1046 | } |
| 1046 | 1047 | |
| … | … | @@ -1096,6 +1097,7 @@ void TabBar::set_tab_disabled(int p_tab, bool p_disabled) { |
| 1096 | 1097 | } |
| 1097 | 1098 | queue_accessibility_update(); |
| 1098 | 1099 | queue_redraw(); |
| 1100 | update_desired_size(); | |
| 1099 | 1101 | update_minimum_size(); |
| 1100 | 1102 | } |
| 1101 | 1103 | |
| … | … | @@ -1120,6 +1122,7 @@ void TabBar::set_tab_hidden(int p_tab, bool p_hidden) { |
| 1120 | 1122 | } |
| 1121 | 1123 | queue_accessibility_update(); |
| 1122 | 1124 | queue_redraw(); |
| 1125 | update_desired_size(); | |
| 1123 | 1126 | update_minimum_size(); |
| 1124 | 1127 | } |
| 1125 | 1128 | |
| … | … | @@ -1153,6 +1156,7 @@ void TabBar::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) { |
| 1153 | 1156 | ensure_tab_visible(current); |
| 1154 | 1157 | } |
| 1155 | 1158 | queue_redraw(); |
| 1159 | update_desired_size(); | |
| 1156 | 1160 | update_minimum_size(); |
| 1157 | 1161 | } |
| 1158 | 1162 | |
| … | … | @@ -1232,7 +1236,7 @@ void TabBar::_update_cache(bool p_update_hover) { |
| 1232 | 1236 | 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; |
| 1233 | 1237 | int effective_max_width = max_width > 0 ? MIN(max_width, combined_max_width) : combined_max_width; |
| 1234 | 1238 | |
| 1235 | int limit = combined_max.width > 0 ? combined_max.width : get_size().width; | |
| 1239 | int limit = combined_max.width > 0 ? MIN(combined_max.width, get_size().width) : get_size().width; | |
| 1236 | 1240 | int limit_minus_buttons = limit - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); |
| 1237 | 1241 | |
| 1238 | 1242 | int w = 0; |
| … | … | @@ -1323,6 +1327,68 @@ void TabBar::_update_cache(bool p_update_hover) { |
| 1323 | 1327 | } |
| 1324 | 1328 | } |
| 1325 | 1329 | |
| 1330 | Size2 TabBar::get_desired_size() const { | |
| 1331 | if (!clip_tabs || tabs.is_empty()) { | |
| 1332 | return Size2(); | |
| 1333 | } | |
| 1334 | Size2 combined_max = get_combined_maximum_size(); | |
| 1335 | if (combined_max.width < 0) { | |
| 1336 | return Size2(); | |
| 1337 | } | |
| 1338 | ||
| 1339 | int buttons_size = tabs.size() > 1 ? theme_cache.decrement_icon->get_width() + theme_cache.increment_icon->get_width() : 0; | |
| 1340 | int limit = int(combined_max.width); | |
| 1341 | int limit_minus_buttons = limit - buttons_size; | |
| 1342 | ||
| 1343 | int w = 0; | |
| 1344 | bool overflowed = false; | |
| 1345 | ||
| 1346 | // First pass: check if all tabs fit without buttons. | |
| 1347 | for (int i = offset; i < tabs.size(); i++) { | |
| 1348 | if (tabs[i].hidden) { | |
| 1349 | continue; | |
| 1350 | } | |
| 1351 | ||
| 1352 | int next_w = w + tabs[i].size_cache; | |
| 1353 | if (i > offset) { | |
| 1354 | next_w += theme_cache.tab_separation; | |
| 1355 | } | |
| 1356 | ||
| 1357 | if (next_w > limit) { | |
| 1358 | overflowed = true; | |
| 1359 | break; | |
| 1360 | } | |
| 1361 | ||
| 1362 | w = next_w; | |
| 1363 | } | |
| 1364 | ||
| 1365 | // If buttons are needed, recompute against the reduced limit. | |
| 1366 | if (offset > 0 || overflowed) { | |
| 1367 | w = 0; | |
| 1368 | for (int i = offset; i < tabs.size(); i++) { | |
| 1369 | if (tabs[i].hidden) { | |
| 1370 | continue; | |
| 1371 | } | |
| 1372 | ||
| 1373 | int next_w = w + tabs[i].size_cache; | |
| 1374 | if (i > offset) { | |
| 1375 | next_w += theme_cache.tab_separation; | |
| 1376 | } | |
| 1377 | ||
| 1378 | if (next_w > limit_minus_buttons) { | |
| 1379 | break; | |
| 1380 | } | |
| 1381 | ||
| 1382 | w = next_w; | |
| 1383 | } | |
| 1384 | } | |
| 1385 | ||
| 1386 | int desired = (offset > 0 || overflowed) ? w + buttons_size : w; | |
| 1387 | desired = MIN(desired, limit); | |
| 1388 | ||
| 1389 | return Size2(desired, 0); | |
| 1390 | } | |
| 1391 | ||
| 1326 | 1392 | void TabBar::_hover_switch_timeout() { |
| 1327 | 1393 | set_current_tab(hover); |
| 1328 | 1394 | } |
| … | … | @@ -1352,6 +1418,7 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { |
| 1352 | 1418 | } |
| 1353 | 1419 | queue_accessibility_update(); |
| 1354 | 1420 | queue_redraw(); |
| 1421 | update_desired_size(); | |
| 1355 | 1422 | update_minimum_size(); |
| 1356 | 1423 | |
| 1357 | 1424 | if (!deselect_enabled && tabs.size() == 1) { |
| … | … | @@ -1383,6 +1450,7 @@ void TabBar::clear_tabs() { |
| 1383 | 1450 | |
| 1384 | 1451 | queue_accessibility_update(); |
| 1385 | 1452 | queue_redraw(); |
| 1453 | update_desired_size(); | |
| 1386 | 1454 | update_minimum_size(); |
| 1387 | 1455 | notify_property_list_changed(); |
| 1388 | 1456 | } |
| … | … | @@ -1445,6 +1513,7 @@ void TabBar::remove_tab(int p_idx) { |
| 1445 | 1513 | |
| 1446 | 1514 | queue_accessibility_update(); |
| 1447 | 1515 | queue_redraw(); |
| 1516 | update_desired_size(); | |
| 1448 | 1517 | update_minimum_size(); |
| 1449 | 1518 | notify_property_list_changed(); |
| 1450 | 1519 | |
| … | … | @@ -1653,6 +1722,7 @@ void TabBar::_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_in |
| 1653 | 1722 | } |
| 1654 | 1723 | |
| 1655 | 1724 | queue_accessibility_update(); |
| 1725 | update_desired_size(); | |
| 1656 | 1726 | update_minimum_size(); |
| 1657 | 1727 | } |
| 1658 | 1728 | |
| … | … | @@ -1733,6 +1803,7 @@ void TabBar::set_clip_tabs(bool p_clip_tabs) { |
| 1733 | 1803 | ensure_tab_visible(current); |
| 1734 | 1804 | } |
| 1735 | 1805 | queue_redraw(); |
| 1806 | update_desired_size(); | |
| 1736 | 1807 | update_minimum_size(); |
| 1737 | 1808 | } |
| 1738 | 1809 | |
| … | … | @@ -1988,6 +2059,7 @@ void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { |
| 1988 | 2059 | ensure_tab_visible(current); |
| 1989 | 2060 | } |
| 1990 | 2061 | queue_redraw(); |
| 2062 | update_desired_size(); | |
| 1991 | 2063 | update_minimum_size(); |
| 1992 | 2064 | } |
| 1993 | 2065 | |
| … | … | @@ -2010,6 +2082,7 @@ void TabBar::set_max_tab_width(int p_width) { |
| 2010 | 2082 | ensure_tab_visible(current); |
| 2011 | 2083 | } |
| 2012 | 2084 | queue_redraw(); |
| 2085 | update_desired_size(); | |
| 2013 | 2086 | update_minimum_size(); |
| 2014 | 2087 | } |
| 2015 | 2088 |
| … | … | @@ -334,6 +334,7 @@ public: |
| 334 | 334 | |
| 335 | 335 | Rect2 get_tab_rect(int p_tab) const; |
| 336 | 336 | Size2 get_minimum_size() const override; |
| 337 | Size2 get_desired_size() const override; | |
| 337 | 338 | |
| 338 | 339 | TabBar(); |
| 339 | 340 | }; |
| … | … | @@ -266,6 +266,7 @@ void TabContainer::_on_theme_changed() { |
| 266 | 266 | _repaint(); |
| 267 | 267 | } else { |
| 268 | 268 | update_minimum_size(); |
| 269 | update_desired_size(); | |
| 269 | 270 | } |
| 270 | 271 | queue_redraw(); |
| 271 | 272 | |
| … | … | @@ -933,6 +934,7 @@ void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) { |
| 933 | 934 | tab_bar->set_tab_disabled(p_tab, p_disabled); |
| 934 | 935 | |
| 935 | 936 | _update_margins(); |
| 937 | update_desired_size(); | |
| 936 | 938 | if (!get_clip_tabs()) { |
| 937 | 939 | update_minimum_size(); |
| 938 | 940 | } |
| … | … | @@ -958,6 +960,7 @@ void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) { |
| 958 | 960 | child->hide(); |
| 959 | 961 | |
| 960 | 962 | _update_margins(); |
| 963 | update_desired_size(); | |
| 961 | 964 | if (!get_clip_tabs()) { |
| 962 | 965 | update_minimum_size(); |
| 963 | 966 | } |
| … | … | @@ -987,16 +990,16 @@ Ref<Texture2D> TabContainer::get_tab_button_icon(int p_tab) const { |
| 987 | 990 | return tab_bar->get_tab_button_icon(p_tab); |
| 988 | 991 | } |
| 989 | 992 | |
| 990 | Size2 TabContainer::get_minimum_size() const { | |
| 993 | Size2 TabContainer::_get_minimum_size(bool p_use_desired_sizes) const { | |
| 991 | 994 | Size2 ms; |
| 992 | 995 | |
| 993 | 996 | if (tabs_visible) { |
| 994 | ms = tab_bar->get_minimum_size(); | |
| 997 | ms = p_use_desired_sizes ? tab_bar->get_bound_desired_size() : tab_bar->get_minimum_size(); | |
| 995 | 998 | ms.width += theme_cache.tabbar_style->get_margin(SIDE_LEFT) + theme_cache.tabbar_style->get_margin(SIDE_RIGHT); |
| 996 | 999 | ms.height += theme_cache.tabbar_style->get_margin(SIDE_TOP) + theme_cache.tabbar_style->get_margin(SIDE_BOTTOM); |
| 997 | 1000 | |
| 998 | 1001 | if (get_popup()) { |
| 999 | ms.width += popup_button->get_minimum_size().x; | |
| 1002 | ms.width += p_use_desired_sizes ? popup_button->get_bound_desired_size().x : popup_button->get_minimum_size().x; | |
| 1000 | 1003 | } |
| 1001 | 1004 | |
| 1002 | 1005 | if (theme_cache.side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER && |
| … | … | @@ -1014,7 +1017,7 @@ Size2 TabContainer::get_minimum_size() const { |
| 1014 | 1017 | continue; |
| 1015 | 1018 | } |
| 1016 | 1019 | |
| 1017 | Size2 cms = c->get_bound_minimum_size(); | |
| 1020 | Size2 cms = p_use_desired_sizes ? c->get_bound_desired_size() : c->get_bound_minimum_size(); | |
| 1018 | 1021 | largest_child_min_size = largest_child_min_size.max(cms); |
| 1019 | 1022 | } |
| 1020 | 1023 | ms.height += largest_child_min_size.height; |
| … | … | @@ -1027,6 +1030,14 @@ Size2 TabContainer::get_minimum_size() const { |
| 1027 | 1030 | return ms; |
| 1028 | 1031 | } |
| 1029 | 1032 | |
| 1033 | Size2 TabContainer::get_minimum_size() const { | |
| 1034 | return _get_minimum_size(false); | |
| 1035 | } | |
| 1036 | ||
| 1037 | Size2 TabContainer::get_desired_size() const { | |
| 1038 | return _get_minimum_size(true); | |
| 1039 | } | |
| 1040 | ||
| 1030 | 1041 | Size2 TabContainer::get_inner_combined_maximum_size() const { |
| 1031 | 1042 | Size2 ms = Container::get_inner_combined_maximum_size(); |
| 1032 | 1043 | |
| … | … | @@ -1105,6 +1116,7 @@ void TabContainer::set_popup(Node *p_popup) { |
| 1105 | 1116 | popup_button->set_visible(popup != nullptr); |
| 1106 | 1117 | _update_margins(); |
| 1107 | 1118 | update_minimum_size(); |
| 1119 | update_desired_size(); | |
| 1108 | 1120 | } |
| 1109 | 1121 | } |
| 1110 | 1122 | |
| … | … | @@ -1155,6 +1167,7 @@ void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { |
| 1155 | 1167 | |
| 1156 | 1168 | use_hidden_tabs_for_min_size = p_use_hidden_tabs; |
| 1157 | 1169 | update_minimum_size(); |
| 1170 | update_desired_size(); | |
| 1158 | 1171 | } |
| 1159 | 1172 | |
| 1160 | 1173 | bool TabContainer::get_use_hidden_tabs_for_min_size() const { |
| … | … | @@ -152,6 +152,8 @@ private: |
| 152 | 152 | void _popup_button_hovered(bool p_hover); |
| 153 | 153 | void _popup_button_pressed(); |
| 154 | 154 | |
| 155 | Size2 _get_minimum_size(bool p_use_desired_sizes) const; | |
| 156 | ||
| 155 | 157 | protected: |
| 156 | 158 | bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } |
| 157 | 159 | 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: |
| 236 | 238 | |
| 237 | 239 | virtual Size2 get_minimum_size() const override; |
| 238 | 240 | virtual Size2 get_inner_combined_maximum_size() const override; |
| 241 | virtual Size2 get_desired_size() const override; | |
| 239 | 242 | |
| 240 | 243 | void set_popup(Node *p_popup); |
| 241 | 244 | Popup *get_popup() const; |
| … | … | @@ -32,6 +32,8 @@ |
| 32 | 32 | |
| 33 | 33 | TEST_FORCE_LINK(test_label) |
| 34 | 34 | |
| 35 | #include "modules/modules_enabled.gen.h" // IWYU pragma: keep. Needed for MODULE_TEXT_SERVER_FB_ENABLED and MODULE_TEXT_SERVER_ADV_ENABLED definitions. | |
| 36 | ||
| 35 | 37 | #if defined(MODULE_TEXT_SERVER_FB_ENABLED) || defined(MODULE_TEXT_SERVER_ADV_ENABLED) |
| 36 | 38 | |
| 37 | 39 | #include "scene/gui/label.h" |
| … | … | @@ -139,7 +141,7 @@ TEST_CASE("[SceneTree][Label] Sizing") { |
| 139 | 141 | real_t max_width = 50; |
| 140 | 142 | real_t min_width = 25; |
| 141 | 143 | |
| 142 | test_label->set_custom_maximum_size(Size2(max_width, 0)); | |
| 144 | test_label->set_custom_maximum_size(Size2(max_width, -1)); | |
| 143 | 145 | test_label->set_custom_minimum_size(Size2(min_width, 0)); |
| 144 | 146 | test_label->set_text("This is a long text that should be wrapped and exceeds minimum size."); |
| 145 | 147 | SceneTree::get_singleton()->process(0); |