Merge pull request #104357 from FilipeAlexCosta/control-set-position

Fix `Control.set_position` resizes offsets/anchors
This commit is contained in:
Thaddeus Crews
2025-04-09 18:11:55 -05:00
3 changed files with 46 additions and 9 deletions

View File

@@ -883,6 +883,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) {
@@ -1413,10 +1420,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();
}
@@ -1706,14 +1716,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;

View File

@@ -301,6 +301,7 @@ private:
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_edge_positions(Rect2 p_rect, real_t (&r_edge_positions)[4]);
void _set_layout_mode(LayoutMode p_mode);
void _update_layout_mode();

View File

@@ -993,6 +993,38 @@ TEST_CASE("[SceneTree][Control] Anchoring") {
memdelete(test_control);
}
TEST_CASE("[SceneTree][Control] Set position does not cause size side-effects") {
Control *test_control = memnew(Control);
test_control->set_size(Size2(1, 1));
test_control->set_custom_minimum_size(Size2(2, 2));
Window *root = SceneTree::get_singleton()->get_root();
root->add_child(test_control);
SUBCASE("Shrinks after setting position and smaller custom minimum size (without keeping offsets)") {
test_control->set_position(Point2(10, 10), false);
SceneTree::get_singleton()->process(0);
test_control->set_custom_minimum_size(Size2(0, 0));
SceneTree::get_singleton()->process(0);
CHECK_MESSAGE(
test_control->get_size().is_equal_approx(Vector2(1, 1)),
"Should shrink to original size after setting a smaller custom minimum size.");
}
SUBCASE("Shrinks after setting position and smaller custom minimum size (while keeping offsets)") {
test_control->set_position(Point2(10, 10), true);
SceneTree::get_singleton()->process(0);
test_control->set_custom_minimum_size(Size2(0, 0));
SceneTree::get_singleton()->process(0);
CHECK_MESSAGE(
test_control->get_size().is_equal_approx(Vector2(1, 1)),
"Should shrink to original size after setting a smaller custom minimum size.");
}
memdelete(test_control);
}
TEST_CASE("[SceneTree][Control] Custom minimum size") {
Control *test_control = memnew(Control);
test_control->set_custom_minimum_size(Size2(4, 2));