diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index bce4f8454e..baa85b3701 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1115,10 +1115,10 @@ The node's global position, relative to the world (usually to the [CanvasLayer]). - Controls the direction on the horizontal axis in which the control should grow if its horizontal minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size. + Controls the direction on the horizontal axis in which the control should grow or shrink if its horizontal size is changed. - Controls the direction on the vertical axis in which the control should grow if its vertical minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size. + Controls the direction on the vertical axis in which the control should grow or shrink if its vertical size is changed. Controls layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew). See also [method is_layout_rtl]. @@ -1568,13 +1568,13 @@ [b]Note:[/b] If the control has received [signal mouse_entered] but not [signal mouse_exited], changing the [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] will cause [signal mouse_exited] to be emitted. - The control will grow to the left or top to make up if its minimum size is changed to be greater than its current size on the respective axis. + The control will grow/shrink to the left or top if its size is changed to be larger/smaller than its current size on the respective axis. - The control will grow to the right or bottom to make up if its minimum size is changed to be greater than its current size on the respective axis. + The control will grow/shrink to the right or bottom if its size is changed to be larger/smaller than its current size on the respective axis. - The control will grow in both directions equally to make up if its minimum size is changed to be greater than its current size. + The control will grow/shrink in both directions equally if its size is changed to be larger/smaller than its current size. Snaps one of the 4 anchor's sides to the origin of the node's [code]Rect[/code], in the top left. Use it with one of the [code]anchor_*[/code] member variables, like [member anchor_left]. To change all 4 anchors at once, use [method set_anchors_preset]. diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 51048bf29f..248f0ad840 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -918,32 +918,49 @@ Control::GrowDirection Control::get_v_grow_direction() const { return data.v_grow; } -void Control::_compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]) { +void Control::_compute_layout_rect(Rect2 p_rect, bool p_keep_offsets) { Size2 parent_rect_size = get_parent_anchorable_rect().size; - ERR_FAIL_COND(parent_rect_size.x == 0.0); - ERR_FAIL_COND(parent_rect_size.y == 0.0); + + if (p_keep_offsets) { + // If computing anchors, we need to ensure the parent rect size is valid to avoid division by zero. + ERR_FAIL_COND(parent_rect_size.x == 0.0); + ERR_FAIL_COND(parent_rect_size.y == 0.0); + } real_t x = p_rect.position.x; + real_t y = p_rect.position.y; + + if (_get_layout_mode() != LayoutMode::LAYOUT_MODE_CONTAINER) { + float left_grow_factor = + (data.h_grow == GROW_DIRECTION_BEGIN) ? 1.0f + : (data.h_grow == GROW_DIRECTION_END) ? 0.0f + : 0.5f; + float top_grow_factor = + (data.v_grow == GROW_DIRECTION_BEGIN) ? 1.0f + : (data.v_grow == GROW_DIRECTION_END) ? 0.0f + : 0.5f; + + Size2 size_diff = p_rect.size - data.size_cache; + + x -= size_diff.x * (is_layout_rtl() ? (1.0f - left_grow_factor) : left_grow_factor); + y -= size_diff.y * top_grow_factor; + } + if (is_layout_rtl()) { x = parent_rect_size.x - x - p_rect.size.x; } - r_anchors[0] = (x - p_offsets[0]) / parent_rect_size.x; - r_anchors[1] = (p_rect.position.y - p_offsets[1]) / parent_rect_size.y; - r_anchors[2] = (x + p_rect.size.x - p_offsets[2]) / parent_rect_size.x; - r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_offsets[3]) / parent_rect_size.y; -} -void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]) { - Size2 parent_rect_size = get_parent_anchorable_rect().size; - - real_t x = p_rect.position.x; - if (is_layout_rtl()) { - x = parent_rect_size.x - x - p_rect.size.x; + if (p_keep_offsets) { + data.anchor[0] = (x - data.offset[0]) / parent_rect_size.x; + data.anchor[1] = (y - data.offset[1]) / parent_rect_size.y; + data.anchor[2] = (x + p_rect.size.x - data.offset[2]) / parent_rect_size.x; + data.anchor[3] = (y + p_rect.size.y - data.offset[3]) / parent_rect_size.y; + } else { + data.offset[0] = x - (data.anchor[0] * parent_rect_size.x); + data.offset[1] = y - (data.anchor[1] * parent_rect_size.y); + data.offset[2] = x + p_rect.size.x - (data.anchor[2] * parent_rect_size.x); + data.offset[3] = y + p_rect.size.y - (data.anchor[3] * parent_rect_size.y); } - r_offsets[0] = x - (p_anchors[0] * parent_rect_size.x); - r_offsets[1] = p_rect.position.y - (p_anchors[1] * parent_rect_size.y); - r_offsets[2] = x + p_rect.size.x - (p_anchors[2] * parent_rect_size.x); - r_offsets[3] = p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y); } /// Presets and layout modes. @@ -1476,11 +1493,7 @@ void Control::set_position(const Point2 &p_point, bool p_keep_offsets) { } #endif // TOOLS_ENABLED - if (p_keep_offsets) { - _compute_anchors(Rect2(p_point, data.size_cache), data.offset, data.anchor); - } else { - _compute_offsets(Rect2(p_point, data.size_cache), data.anchor, data.offset); - } + _compute_layout_rect(Rect2(p_point, data.size_cache), p_keep_offsets); _size_changed(); } @@ -1552,11 +1565,7 @@ void Control::set_size(const Size2 &p_size, bool p_keep_offsets) { data.expanded_by_desired_size = false; - if (p_keep_offsets) { - _compute_anchors(Rect2(data.pos_cache, new_size), data.offset, data.anchor); - } else { - _compute_offsets(Rect2(data.pos_cache, new_size), data.anchor, data.offset); - } + _compute_layout_rect(Rect2(data.pos_cache, new_size), p_keep_offsets); _size_changed(); } @@ -1576,7 +1585,7 @@ void Control::set_rect(const Rect2 &p_rect) { data.anchor[i] = ANCHOR_BEGIN; } - _compute_offsets(p_rect, data.anchor, data.offset); + _compute_layout_rect(p_rect); if (is_inside_tree()) { _size_changed(); } diff --git a/scene/gui/control.h b/scene/gui/control.h index 9f3d248e29..44709c6508 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -365,8 +365,7 @@ private: void _set_global_position(const Point2 &p_point); void _set_size(const Size2 &p_size); - void _compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]); - void _compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]); + void _compute_layout_rect(Rect2 p_rect, bool p_keep_offsets = false); void _set_layout_mode(LayoutMode p_mode); void _update_layout_mode();