Fix layout rectangle computations

Makes use of growth directions for all size changes, not just minimum ones.
This commit is contained in:
Enzo Novoselic
2026-06-18 15:45:32 -04:00
parent 5b4e0cb0fd
commit d7d7baee8a
3 changed files with 44 additions and 36 deletions
+38 -29
View File
@@ -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();
}