1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Fix #100536: Control set_position resizes offsets/anchors

The set_position method computes the anchors/offsets to match a
rectangle at the given position with size "size_cache". However, when
the Control's combined minimum size is larger than the size obtained
through the offsets and anchors, "size_cache" is set to be as large as
the combined minimum size. Therefore, when position is set while the
combined minimum size is larger than the rectangle given by the anchors
and offsets, it would resize these two fields, which would then stop
the Control from shrinking when its combined minimum size decreased. To
fix this, set_position now uses the size given by the offsets and
anchors instead of the "size_cache" field. This way, the rectangle
denoted by the offsets and anchors is simply moved, without being
resized, enabling the Control to shrink automatically when its combined
minimum size decreases. I also added a test case to ensure that the
Control shrinks correctly after setting its position while it has a
larger custom minimum size than the one obtained through the offsets
and anchors.
This commit is contained in:
Filipe Alexandre Francisco Costa
2025-03-17 10:33:41 +00:00
parent e585e6a3eb
commit ca57fe1db4
3 changed files with 46 additions and 9 deletions

View File

@@ -867,6 +867,13 @@ void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (
r_offsets[3] = p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y);
}
void Control::_compute_edge_positions(Rect2 p_rect, real_t (&r_edge_positions)[4]) {
for (int i = 0; i < 4; i++) {
real_t area = p_rect.size[i & 1];
r_edge_positions[i] = data.offset[i] + (data.anchor[i] * area);
}
}
/// Presets and layout modes.
void Control::_set_layout_mode(LayoutMode p_mode) {
@@ -1392,10 +1399,13 @@ void Control::set_position(const Point2 &p_point, bool p_keep_offsets) {
}
#endif // TOOLS_ENABLED
real_t edge_pos[4];
_compute_edge_positions(get_parent_anchorable_rect(), edge_pos);
Size2 offset_size(edge_pos[2] - edge_pos[0], edge_pos[3] - edge_pos[1]);
if (p_keep_offsets) {
_compute_anchors(Rect2(p_point, data.size_cache), data.offset, data.anchor);
_compute_anchors(Rect2(p_point, offset_size), data.offset, data.anchor);
} else {
_compute_offsets(Rect2(p_point, data.size_cache), data.anchor, data.offset);
_compute_offsets(Rect2(p_point, offset_size), data.anchor, data.offset);
}
_size_changed();
}
@@ -1682,14 +1692,8 @@ Size2 Control::get_combined_minimum_size() const {
void Control::_size_changed() {
Rect2 parent_rect = get_parent_anchorable_rect();
real_t edge_pos[4];
for (int i = 0; i < 4; i++) {
real_t area = parent_rect.size[i & 1];
edge_pos[i] = data.offset[i] + (data.anchor[i] * area);
}
_compute_edge_positions(parent_rect, edge_pos);
Point2 new_pos_cache = Point2(edge_pos[0], edge_pos[1]);
Size2 new_size_cache = Point2(edge_pos[2], edge_pos[3]) - new_pos_cache;