Browse Source

Merge pull request #18634 from groud/fix_control_child_of_node2d

Fixes the bad calculation of margin & anchors when child of Node2D
Max Hilbrunner 7 years ago
parent
commit
b21c1f64cd

+ 11 - 9
editor/plugins/canvas_item_editor_plugin.cpp

@@ -543,7 +543,6 @@ void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResu
 
 
 	for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
 	for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
 		Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
 		Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
-		Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().to));
 
 
 		Vector<Vector2> bone_shape;
 		Vector<Vector2> bone_shape;
 		if (!_get_bone_shape(&bone_shape, NULL, E))
 		if (!_get_bone_shape(&bone_shape, NULL, E))
@@ -719,16 +718,17 @@ Vector2 CanvasItemEditor::_anchor_to_position(const Control *p_control, Vector2
 	ERR_FAIL_COND_V(!p_control, Vector2());
 	ERR_FAIL_COND_V(!p_control, Vector2());
 
 
 	Transform2D parent_transform = p_control->get_transform().affine_inverse();
 	Transform2D parent_transform = p_control->get_transform().affine_inverse();
-	Size2 parent_size = p_control->get_parent_area_size();
+	Rect2 parent_rect = p_control->get_parent_anchorable_rect();
 
 
-	return parent_transform.xform(Vector2(parent_size.x * anchor.x, parent_size.y * anchor.y));
+	return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
 }
 }
 
 
 Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 position) {
 Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 position) {
 	ERR_FAIL_COND_V(!p_control, Vector2());
 	ERR_FAIL_COND_V(!p_control, Vector2());
-	Size2 parent_size = p_control->get_parent_area_size();
 
 
-	return p_control->get_transform().xform(position) / parent_size;
+	Rect2 parent_rect = p_control->get_parent_anchorable_rect();
+
+	return (p_control->get_transform().xform(position) - parent_rect.position) / parent_rect.size;
 }
 }
 
 
 void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
 void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
@@ -2491,10 +2491,12 @@ void CanvasItemEditor::_draw_selection() {
 					Transform2D parent_transform = xform * control->get_transform().affine_inverse();
 					Transform2D parent_transform = xform * control->get_transform().affine_inverse();
 					float node_pos_in_parent[4];
 					float node_pos_in_parent[4];
 
 
-					node_pos_in_parent[0] = control->get_anchor(MARGIN_LEFT) * control->get_parent_area_size().width + control->get_margin(MARGIN_LEFT);
-					node_pos_in_parent[1] = control->get_anchor(MARGIN_TOP) * control->get_parent_area_size().height + control->get_margin(MARGIN_TOP);
-					node_pos_in_parent[2] = control->get_anchor(MARGIN_RIGHT) * control->get_parent_area_size().width + control->get_margin(MARGIN_RIGHT);
-					node_pos_in_parent[3] = control->get_anchor(MARGIN_BOTTOM) * control->get_parent_area_size().height + control->get_margin(MARGIN_BOTTOM);
+					Rect2 parent_rect = control->get_parent_anchorable_rect();
+
+					node_pos_in_parent[0] = control->get_anchor(MARGIN_LEFT) * parent_rect.size.width + control->get_margin(MARGIN_LEFT) + parent_rect.position.x;
+					node_pos_in_parent[1] = control->get_anchor(MARGIN_TOP) * parent_rect.size.height + control->get_margin(MARGIN_TOP) + parent_rect.position.y;
+					node_pos_in_parent[2] = control->get_anchor(MARGIN_RIGHT) * parent_rect.size.width + control->get_margin(MARGIN_RIGHT) + parent_rect.position.x;
+					node_pos_in_parent[3] = control->get_anchor(MARGIN_BOTTOM) * parent_rect.size.height + control->get_margin(MARGIN_BOTTOM) + parent_rect.position.y;
 
 
 					Point2 start, end;
 					Point2 start, end;
 					switch (drag_type) {
 					switch (drag_type) {

+ 23 - 6
scene/2d/animated_sprite.cpp

@@ -59,15 +59,36 @@ bool AnimatedSprite::_edit_use_pivot() const {
 }
 }
 
 
 Rect2 AnimatedSprite::_edit_get_rect() const {
 Rect2 AnimatedSprite::_edit_get_rect() const {
+	return _get_rect();
+}
+
+bool AnimatedSprite::_edit_use_rect() const {
 	if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
 	if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
-		return Node2D::_edit_get_rect();
+		return false;
+	}
+	Ref<Texture> t;
+	if (animation)
+		t = frames->get_frame(animation, frame);
+	if (t.is_null())
+		return false;
+
+	return true;
+}
+
+Rect2 AnimatedSprite::get_anchorable_rect() const {
+	return _get_rect();
+}
+
+Rect2 AnimatedSprite::_get_rect() const {
+	if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+		return Rect2();
 	}
 	}
 
 
 	Ref<Texture> t;
 	Ref<Texture> t;
 	if (animation)
 	if (animation)
 		t = frames->get_frame(animation, frame);
 		t = frames->get_frame(animation, frame);
 	if (t.is_null())
 	if (t.is_null())
-		return Node2D::_edit_get_rect();
+		return Rect2();
 	Size2 s = t->get_size();
 	Size2 s = t->get_size();
 
 
 	Point2 ofs = offset;
 	Point2 ofs = offset;
@@ -80,10 +101,6 @@ Rect2 AnimatedSprite::_edit_get_rect() const {
 	return Rect2(ofs, s);
 	return Rect2(ofs, s);
 }
 }
 
 
-bool AnimatedSprite::_edit_use_rect() const {
-	return true;
-}
-
 void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_frame, int p_at_pos) {
 void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_frame, int p_at_pos) {
 
 
 	Map<StringName, Anim>::Element *E = animations.find(p_anim);
 	Map<StringName, Anim>::Element *E = animations.find(p_anim);

+ 3 - 0
scene/2d/animated_sprite.h

@@ -145,6 +145,7 @@ class AnimatedSprite : public Node2D {
 	void _reset_timeout();
 	void _reset_timeout();
 	void _set_playing(bool p_playing);
 	void _set_playing(bool p_playing);
 	bool _is_playing() const;
 	bool _is_playing() const;
+	Rect2 _get_rect() const;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -161,6 +162,8 @@ public:
 	virtual Rect2 _edit_get_rect() const;
 	virtual Rect2 _edit_get_rect() const;
 	virtual bool _edit_use_rect() const;
 	virtual bool _edit_use_rect() const;
 
 
+	virtual Rect2 get_anchorable_rect() const;
+
 	void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
 	void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
 	Ref<SpriteFrames> get_sprite_frames() const;
 	Ref<SpriteFrames> get_sprite_frames() const;
 
 

+ 5 - 0
scene/2d/back_buffer_copy.cpp

@@ -59,6 +59,11 @@ bool BackBufferCopy::_edit_use_rect() const {
 	return true;
 	return true;
 }
 }
 
 
+Rect2 BackBufferCopy::get_anchorable_rect() const {
+
+	return rect;
+}
+
 void BackBufferCopy::set_rect(const Rect2 &p_rect) {
 void BackBufferCopy::set_rect(const Rect2 &p_rect) {
 
 
 	rect = p_rect;
 	rect = p_rect;

+ 1 - 0
scene/2d/back_buffer_copy.h

@@ -58,6 +58,7 @@ public:
 
 
 	void set_rect(const Rect2 &p_rect);
 	void set_rect(const Rect2 &p_rect);
 	Rect2 get_rect() const;
 	Rect2 get_rect() const;
+	Rect2 get_anchorable_rect() const;
 
 
 	void set_copy_mode(CopyMode p_mode);
 	void set_copy_mode(CopyMode p_mode);
 	CopyMode get_copy_mode() const;
 	CopyMode get_copy_mode() const;

+ 0 - 21
scene/2d/canvas_item.cpp

@@ -321,11 +321,6 @@ void CanvasItem::hide() {
 	_change_notify("visible");
 	_change_notify("visible");
 }
 }
 
 
-Size2 CanvasItem::_edit_get_minimum_size() const {
-
-	return Size2(-1, -1); //no limit
-}
-
 void CanvasItem::_update_callback() {
 void CanvasItem::_update_callback() {
 
 
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
@@ -994,7 +989,6 @@ void CanvasItem::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
 	ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
 	ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
 	ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
 	ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
 	ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
-	ClassDB::bind_method(D_METHOD("_edit_get_item_and_children_rect"), &CanvasItem::_edit_get_item_and_children_rect);
 	ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
 	ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
 	ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
 	ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
 	ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
 	ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
@@ -1175,21 +1169,6 @@ int CanvasItem::get_canvas_layer() const {
 		return 0;
 		return 0;
 }
 }
 
 
-Rect2 CanvasItem::_edit_get_item_and_children_rect() const {
-
-	Rect2 rect = _edit_get_rect();
-
-	for (int i = 0; i < get_child_count(); i++) {
-		CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
-		if (c) {
-			Rect2 sir = c->get_transform().xform(c->_edit_get_item_and_children_rect());
-			rect = rect.merge(sir);
-		}
-	}
-
-	return rect;
-}
-
 CanvasItem::CanvasItem() :
 CanvasItem::CanvasItem() :
 		xform_change(this) {
 		xform_change(this) {
 
 

+ 15 - 24
scene/2d/canvas_item.h

@@ -222,6 +222,9 @@ public:
 
 
 	/* EDITOR */
 	/* EDITOR */
 
 
+	// Select the node
+	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
 	// Save and restore a CanvasItem state
 	// Save and restore a CanvasItem state
 	virtual void _edit_set_state(const Dictionary &p_state){};
 	virtual void _edit_set_state(const Dictionary &p_state){};
 	virtual Dictionary _edit_get_state() const { return Dictionary(); };
 	virtual Dictionary _edit_get_state() const { return Dictionary(); };
@@ -234,36 +237,21 @@ public:
 	virtual void _edit_set_scale(const Size2 &p_scale) = 0;
 	virtual void _edit_set_scale(const Size2 &p_scale) = 0;
 	virtual Size2 _edit_get_scale() const = 0;
 	virtual Size2 _edit_get_scale() const = 0;
 
 
+	// Used to rotate the node
+	virtual bool _edit_use_rotation() const { return false; };
+	virtual void _edit_set_rotation(float p_rotation){};
+	virtual float _edit_get_rotation() const { return 0.0; };
+
 	// Used to resize/move the node
 	// Used to resize/move the node
+	virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
 	virtual void _edit_set_rect(const Rect2 &p_rect){};
 	virtual void _edit_set_rect(const Rect2 &p_rect){};
 	virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
 	virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
-	virtual bool _edit_use_rect() const { return false; };
-
-	Rect2 _edit_get_item_and_children_rect() const;
-
-	// used to select the node
-	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-
-	// Used to rotate the node
-	virtual void
-	_edit_set_rotation(float p_rotation){};
-	virtual float _edit_get_rotation() const {
-		return 0.0;
-	};
-	virtual bool _edit_use_rotation() const {
-		return false;
-	};
+	virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
 
 
 	// Used to set a pivot
 	// Used to set a pivot
+	virtual bool _edit_use_pivot() const { return false; };
 	virtual void _edit_set_pivot(const Point2 &p_pivot){};
 	virtual void _edit_set_pivot(const Point2 &p_pivot){};
-	virtual Point2 _edit_get_pivot() const {
-		return Point2();
-	};
-	virtual bool _edit_use_pivot() const {
-		return false;
-	};
-
-	virtual Size2 _edit_get_minimum_size() const;
+	virtual Point2 _edit_get_pivot() const { return Point2(); };
 
 
 	/* VISIBILITY */
 	/* VISIBILITY */
 
 
@@ -358,6 +346,9 @@ public:
 	void set_notify_transform(bool p_enable);
 	void set_notify_transform(bool p_enable);
 	bool is_transform_notification_enabled() const;
 	bool is_transform_notification_enabled() const;
 
 
+	// Used by control nodes to retreive the parent's anchorable area
+	virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
+
 	int get_canvas_layer() const;
 	int get_canvas_layer() const;
 
 
 	CanvasItem();
 	CanvasItem();

+ 10 - 2
scene/2d/light_2d.cpp

@@ -59,14 +59,22 @@ bool Light2D::_edit_use_pivot() const {
 
 
 Rect2 Light2D::_edit_get_rect() const {
 Rect2 Light2D::_edit_get_rect() const {
 	if (texture.is_null())
 	if (texture.is_null())
-		return Node2D::_edit_get_rect();
+		return Rect2();
 
 
 	Size2 s = texture->get_size() * _scale;
 	Size2 s = texture->get_size() * _scale;
 	return Rect2(texture_offset - s / 2.0, s);
 	return Rect2(texture_offset - s / 2.0, s);
 }
 }
 
 
 bool Light2D::_edit_use_rect() const {
 bool Light2D::_edit_use_rect() const {
-	return true;
+	return !texture.is_null();
+}
+
+Rect2 Light2D::get_anchorable_rect() const {
+	if (texture.is_null())
+		return Rect2();
+
+	Size2 s = texture->get_size() * _scale;
+	return Rect2(texture_offset - s / 2.0, s);
 }
 }
 
 
 void Light2D::_update_light_visibility() {
 void Light2D::_update_light_visibility() {

+ 2 - 0
scene/2d/light_2d.h

@@ -94,6 +94,8 @@ public:
 	virtual Rect2 _edit_get_rect() const;
 	virtual Rect2 _edit_get_rect() const;
 	virtual bool _edit_use_rect() const;
 	virtual bool _edit_use_rect() const;
 
 
+	virtual Rect2 get_anchorable_rect() const;
+
 	void set_enabled(bool p_enabled);
 	void set_enabled(bool p_enabled);
 	bool is_enabled() const;
 	bool is_enabled() const;
 
 

+ 8 - 6
scene/2d/screen_button.cpp

@@ -324,19 +324,21 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
 }
 }
 
 
 Rect2 TouchScreenButton::_edit_get_rect() const {
 Rect2 TouchScreenButton::_edit_get_rect() const {
-
-	if (texture.is_null())
-		return Rect2(0, 0, 1, 1);
-	/*
 	if (texture.is_null())
 	if (texture.is_null())
 		return CanvasItem::_edit_get_rect();
 		return CanvasItem::_edit_get_rect();
-	*/
 
 
 	return Rect2(Size2(), texture->get_size());
 	return Rect2(Size2(), texture->get_size());
 }
 }
 
 
 bool TouchScreenButton::_edit_use_rect() const {
 bool TouchScreenButton::_edit_use_rect() const {
-	return true;
+	return !texture.is_null();
+}
+
+Rect2 TouchScreenButton::get_anchorable_rect() const {
+	if (texture.is_null())
+		return CanvasItem::get_anchorable_rect();
+
+	return Rect2(Size2(), texture->get_size());
 }
 }
 
 
 void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
 void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {

+ 2 - 1
scene/2d/screen_button.h

@@ -103,8 +103,9 @@ public:
 
 
 	bool is_pressed() const;
 	bool is_pressed() const;
 
 
-	Rect2 _edit_get_rect() const;
+	virtual Rect2 _edit_get_rect() const;
 	virtual bool _edit_use_rect() const;
 	virtual bool _edit_use_rect() const;
+	virtual Rect2 get_anchorable_rect() const;
 
 
 	TouchScreenButton();
 	TouchScreenButton();
 };
 };

+ 7 - 4
scene/2d/sprite.cpp

@@ -63,9 +63,16 @@ Rect2 Sprite::_edit_get_rect() const {
 }
 }
 
 
 bool Sprite::_edit_use_rect() const {
 bool Sprite::_edit_use_rect() const {
+	if (texture.is_null())
+		return false;
+
 	return true;
 	return true;
 }
 }
 
 
+Rect2 Sprite::get_anchorable_rect() const {
+	return get_rect();
+}
+
 void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
 void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
 
 
 	Rect2 base_rect;
 	Rect2 base_rect;
@@ -367,10 +374,6 @@ Rect2 Sprite::get_rect() const {
 
 
 	if (texture.is_null())
 	if (texture.is_null())
 		return Rect2(0, 0, 1, 1);
 		return Rect2(0, 0, 1, 1);
-	/*
-	if (texture.is_null())
-		return CanvasItem::_edit_get_rect();
-	*/
 
 
 	Size2i s;
 	Size2i s;
 
 

+ 1 - 0
scene/2d/sprite.h

@@ -115,6 +115,7 @@ public:
 	int get_hframes() const;
 	int get_hframes() const;
 
 
 	Rect2 get_rect() const;
 	Rect2 get_rect() const;
+	virtual Rect2 get_anchorable_rect() const;
 
 
 	Sprite();
 	Sprite();
 	~Sprite();
 	~Sprite();

+ 0 - 10
scene/2d/tile_map.cpp

@@ -1152,16 +1152,6 @@ PoolVector<int> TileMap::_get_tile_data() const {
 	return data;
 	return data;
 }
 }
 
 
-Rect2 TileMap::_edit_get_rect() const {
-
-	const_cast<TileMap *>(this)->_update_dirty_quadrants();
-	return rect_cache;
-}
-
-bool TileMap::_edit_use_rect() const {
-	return true;
-}
-
 void TileMap::set_collision_layer(uint32_t p_layer) {
 void TileMap::set_collision_layer(uint32_t p_layer) {
 
 
 	collision_layer = p_layer;
 	collision_layer = p_layer;

+ 0 - 3
scene/2d/tile_map.h

@@ -245,9 +245,6 @@ public:
 	void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false);
 	void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false);
 	int get_cellv(const Vector2 &p_pos) const;
 	int get_cellv(const Vector2 &p_pos) const;
 
 
-	Rect2 _edit_get_rect() const;
-	virtual bool _edit_use_rect() const;
-
 	void make_bitmask_area_dirty(const Vector2 &p_pos);
 	void make_bitmask_area_dirty(const Vector2 &p_pos);
 	void update_bitmask_area(const Vector2 &p_pos);
 	void update_bitmask_area(const Vector2 &p_pos);
 	void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2());
 	void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2());

+ 62 - 105
scene/gui/control.cpp

@@ -1274,21 +1274,23 @@ bool Control::has_constant(const StringName &p_name, const StringName &p_type) c
 	return Theme::get_default()->has_constant(p_name, type);
 	return Theme::get_default()->has_constant(p_name, type);
 }
 }
 
 
-Size2 Control::get_parent_area_size() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), Size2());
-
-	Size2 parent_size;
+Rect2 Control::get_parent_anchorable_rect() const {
+	if (!is_inside_tree())
+		return Rect2();
 
 
+	Rect2 parent_rect;
 	if (data.parent_canvas_item) {
 	if (data.parent_canvas_item) {
-
-		parent_size = data.parent_canvas_item->_edit_get_rect().size;
+		parent_rect = data.parent_canvas_item->get_anchorable_rect();
 	} else {
 	} else {
-
-		parent_size = get_viewport()->get_visible_rect().size;
+		parent_rect = get_viewport()->get_visible_rect();
 	}
 	}
 
 
-	return parent_size;
+	return parent_rect;
+}
+
+Size2 Control::get_parent_area_size() const {
+
+	return get_parent_anchorable_rect().size;
 }
 }
 
 
 void Control::_size_changed() {
 void Control::_size_changed() {
@@ -1296,13 +1298,13 @@ void Control::_size_changed() {
 	if (!is_inside_tree())
 	if (!is_inside_tree())
 		return;
 		return;
 
 
-	Size2 parent_size = get_parent_area_size();
+	Rect2 parent_rect = get_parent_anchorable_rect();
 
 
 	float margin_pos[4];
 	float margin_pos[4];
 
 
 	for (int i = 0; i < 4; i++) {
 	for (int i = 0; i < 4; i++) {
 
 
-		float area = parent_size[i & 1];
+		float area = parent_rect.size[i & 1];
 		margin_pos[i] = data.margin[i] + (data.anchor[i] * area);
 		margin_pos[i] = data.margin[i] + (data.anchor[i] * area);
 	}
 	}
 
 
@@ -1356,43 +1358,9 @@ void Control::_size_changed() {
 	}
 	}
 }
 }
 
 
-float Control::_get_parent_range(int p_idx) const {
-
-	if (!is_inside_tree()) {
-
-		return 0;
-	}
-	if (data.parent_canvas_item) {
-
-		return data.parent_canvas_item->_edit_get_rect().size[p_idx & 1];
-	} else {
-		return get_viewport()->get_visible_rect().size[p_idx & 1];
-	}
-
-	return 0;
-}
-
-float Control::_get_range(int p_idx) const {
-
-	p_idx &= 1;
-
-	float parent_range = _get_parent_range(p_idx);
-	float from = _a2s(data.margin[p_idx], data.anchor[p_idx], parent_range);
-	float to = _a2s(data.margin[p_idx + 2], data.anchor[p_idx + 2], parent_range);
-
-	return to - from;
-}
-
-float Control::_s2a(float p_val, float p_anchor, float p_range) const {
-	return p_val - (p_anchor * p_range);
-}
-
-float Control::_a2s(float p_val, float p_anchor, float p_range) const {
-	return Math::floor(p_val + (p_anchor * p_range));
-}
-
 void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) {
 void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) {
-	float parent_range = _get_parent_range((p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? 0 : 1);
+	Rect2 parent_rect = get_parent_anchorable_rect();
+	float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
 	float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range;
 	float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range;
 	float previous_opposite_margin_pos = data.margin[(p_margin + 2) % 4] + data.anchor[(p_margin + 2) % 4] * parent_range;
 	float previous_opposite_margin_pos = data.margin[(p_margin + 2) % 4] + data.anchor[(p_margin + 2) % 4] * parent_range;
 
 
@@ -1408,9 +1376,9 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo
 	}
 	}
 
 
 	if (!p_keep_margin) {
 	if (!p_keep_margin) {
-		data.margin[p_margin] = _s2a(previous_margin_pos, data.anchor[p_margin], parent_range);
+		data.margin[p_margin] = previous_margin_pos - data.anchor[p_margin] * parent_range;
 		if (p_push_opposite_anchor) {
 		if (p_push_opposite_anchor) {
-			data.margin[(p_margin + 2) % 4] = _s2a(previous_opposite_margin_pos, data.anchor[(p_margin + 2) % 4], parent_range);
+			data.margin[(p_margin + 2) % 4] = previous_opposite_margin_pos - data.anchor[(p_margin + 2) % 4] * parent_range;
 		}
 		}
 	}
 	}
 	if (is_inside_tree()) {
 	if (is_inside_tree()) {
@@ -1564,8 +1532,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		new_size.y = min_size.y;
 		new_size.y = min_size.y;
 	}
 	}
 
 
-	float pw = _get_parent_range(0);
-	float ph = _get_parent_range(1);
+	Rect2 parent_rect = get_parent_anchorable_rect();
 
 
 	//Left
 	//Left
 	switch (p_preset) {
 	switch (p_preset) {
@@ -1577,21 +1544,21 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		case PRESET_LEFT_WIDE:
 		case PRESET_LEFT_WIDE:
 		case PRESET_HCENTER_WIDE:
 		case PRESET_HCENTER_WIDE:
 		case PRESET_WIDE:
 		case PRESET_WIDE:
-			data.margin[0] = pw * (0.0 - data.anchor[0]) + p_margin;
+			data.margin[0] = parent_rect.size.x * (0.0 - data.anchor[0]) + p_margin + parent_rect.position.x;
 			break;
 			break;
 
 
 		case PRESET_CENTER_TOP:
 		case PRESET_CENTER_TOP:
 		case PRESET_CENTER_BOTTOM:
 		case PRESET_CENTER_BOTTOM:
 		case PRESET_CENTER:
 		case PRESET_CENTER:
 		case PRESET_VCENTER_WIDE:
 		case PRESET_VCENTER_WIDE:
-			data.margin[0] = pw * (0.5 - data.anchor[0]) - new_size.x / 2;
+			data.margin[0] = parent_rect.size.x * (0.5 - data.anchor[0]) - new_size.x / 2 + parent_rect.position.x;
 			break;
 			break;
 
 
 		case PRESET_TOP_RIGHT:
 		case PRESET_TOP_RIGHT:
 		case PRESET_BOTTOM_RIGHT:
 		case PRESET_BOTTOM_RIGHT:
 		case PRESET_CENTER_RIGHT:
 		case PRESET_CENTER_RIGHT:
 		case PRESET_RIGHT_WIDE:
 		case PRESET_RIGHT_WIDE:
-			data.margin[0] = pw * (1.0 - data.anchor[0]) - new_size.x - p_margin;
+			data.margin[0] = parent_rect.size.x * (1.0 - data.anchor[0]) - new_size.x - p_margin + parent_rect.position.x;
 			break;
 			break;
 	}
 	}
 
 
@@ -1605,21 +1572,21 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		case PRESET_TOP_WIDE:
 		case PRESET_TOP_WIDE:
 		case PRESET_VCENTER_WIDE:
 		case PRESET_VCENTER_WIDE:
 		case PRESET_WIDE:
 		case PRESET_WIDE:
-			data.margin[1] = ph * (0.0 - data.anchor[1]) + p_margin;
+			data.margin[1] = parent_rect.size.y * (0.0 - data.anchor[1]) + p_margin + parent_rect.position.y;
 			break;
 			break;
 
 
 		case PRESET_CENTER_LEFT:
 		case PRESET_CENTER_LEFT:
 		case PRESET_CENTER_RIGHT:
 		case PRESET_CENTER_RIGHT:
 		case PRESET_CENTER:
 		case PRESET_CENTER:
 		case PRESET_HCENTER_WIDE:
 		case PRESET_HCENTER_WIDE:
-			data.margin[1] = ph * (0.5 - data.anchor[1]) - new_size.y / 2;
+			data.margin[1] = parent_rect.size.y * (0.5 - data.anchor[1]) - new_size.y / 2 + parent_rect.position.y;
 			break;
 			break;
 
 
 		case PRESET_BOTTOM_LEFT:
 		case PRESET_BOTTOM_LEFT:
 		case PRESET_BOTTOM_RIGHT:
 		case PRESET_BOTTOM_RIGHT:
 		case PRESET_CENTER_BOTTOM:
 		case PRESET_CENTER_BOTTOM:
 		case PRESET_BOTTOM_WIDE:
 		case PRESET_BOTTOM_WIDE:
-			data.margin[1] = ph * (1.0 - data.anchor[1]) - new_size.y - p_margin;
+			data.margin[1] = parent_rect.size.y * (1.0 - data.anchor[1]) - new_size.y - p_margin + parent_rect.position.y;
 			break;
 			break;
 	}
 	}
 
 
@@ -1629,14 +1596,14 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		case PRESET_BOTTOM_LEFT:
 		case PRESET_BOTTOM_LEFT:
 		case PRESET_CENTER_LEFT:
 		case PRESET_CENTER_LEFT:
 		case PRESET_LEFT_WIDE:
 		case PRESET_LEFT_WIDE:
-			data.margin[2] = pw * (0.0 - data.anchor[2]) + new_size.x + p_margin;
+			data.margin[2] = parent_rect.size.x * (0.0 - data.anchor[2]) + new_size.x + p_margin + parent_rect.position.x;
 			break;
 			break;
 
 
 		case PRESET_CENTER_TOP:
 		case PRESET_CENTER_TOP:
 		case PRESET_CENTER_BOTTOM:
 		case PRESET_CENTER_BOTTOM:
 		case PRESET_CENTER:
 		case PRESET_CENTER:
 		case PRESET_VCENTER_WIDE:
 		case PRESET_VCENTER_WIDE:
-			data.margin[2] = pw * (0.5 - data.anchor[2]) + new_size.x / 2;
+			data.margin[2] = parent_rect.size.x * (0.5 - data.anchor[2]) + new_size.x / 2 + parent_rect.position.x;
 			break;
 			break;
 
 
 		case PRESET_TOP_RIGHT:
 		case PRESET_TOP_RIGHT:
@@ -1647,7 +1614,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		case PRESET_BOTTOM_WIDE:
 		case PRESET_BOTTOM_WIDE:
 		case PRESET_HCENTER_WIDE:
 		case PRESET_HCENTER_WIDE:
 		case PRESET_WIDE:
 		case PRESET_WIDE:
-			data.margin[2] = pw * (1.0 - data.anchor[2]) - p_margin;
+			data.margin[2] = parent_rect.size.x * (1.0 - data.anchor[2]) - p_margin + parent_rect.position.x;
 			break;
 			break;
 	}
 	}
 
 
@@ -1657,14 +1624,14 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		case PRESET_TOP_RIGHT:
 		case PRESET_TOP_RIGHT:
 		case PRESET_CENTER_TOP:
 		case PRESET_CENTER_TOP:
 		case PRESET_TOP_WIDE:
 		case PRESET_TOP_WIDE:
-			data.margin[3] = ph * (0.0 - data.anchor[3]) + new_size.y + p_margin;
+			data.margin[3] = parent_rect.size.y * (0.0 - data.anchor[3]) + new_size.y + p_margin + parent_rect.position.y;
 			break;
 			break;
 
 
 		case PRESET_CENTER_LEFT:
 		case PRESET_CENTER_LEFT:
 		case PRESET_CENTER_RIGHT:
 		case PRESET_CENTER_RIGHT:
 		case PRESET_CENTER:
 		case PRESET_CENTER:
 		case PRESET_HCENTER_WIDE:
 		case PRESET_HCENTER_WIDE:
-			data.margin[3] = ph * (0.5 - data.anchor[3]) + new_size.y / 2;
+			data.margin[3] = parent_rect.size.y * (0.5 - data.anchor[3]) + new_size.y / 2 + parent_rect.position.y;
 			break;
 			break;
 
 
 		case PRESET_BOTTOM_LEFT:
 		case PRESET_BOTTOM_LEFT:
@@ -1675,7 +1642,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
 		case PRESET_BOTTOM_WIDE:
 		case PRESET_BOTTOM_WIDE:
 		case PRESET_VCENTER_WIDE:
 		case PRESET_VCENTER_WIDE:
 		case PRESET_WIDE:
 		case PRESET_WIDE:
-			data.margin[3] = ph * (1.0 - data.anchor[3]) - p_margin;
+			data.margin[3] = parent_rect.size.y * (1.0 - data.anchor[3]) - p_margin + parent_rect.position.y;
 			break;
 			break;
 	}
 	}
 
 
@@ -1754,31 +1721,29 @@ void Control::set_global_position(const Point2 &p_point) {
 	set_position(inv.xform(p_point));
 	set_position(inv.xform(p_point));
 }
 }
 
 
-void Control::set_position(const Size2 &p_point) {
-
-	float pw = _get_parent_range(0);
-	float ph = _get_parent_range(1);
+Rect2 Control::_compute_child_rect(const float p_anchors[4], const float p_margins[4]) const {
 
 
-	float x = _a2s(data.margin[0], data.anchor[0], pw);
-	float y = _a2s(data.margin[1], data.anchor[1], ph);
-	float x2 = _a2s(data.margin[2], data.anchor[2], pw);
-	float y2 = _a2s(data.margin[3], data.anchor[3], ph);
+	Rect2 anchorable = get_parent_anchorable_rect();
+	Rect2 result = anchorable;
+	for (int i = 0; i < 4; i++) {
+		result.grow_margin((Margin)i, p_anchors[i] * anchorable.get_size()[i % 2] + p_margins[i]);
+	}
 
 
-	Size2 ret = Size2(x2 - x, y2 - y);
-	Size2 min = get_combined_minimum_size();
+	return result;
+}
 
 
-	Size2 size = Size2(MAX(min.width, ret.width), MAX(min.height, ret.height));
-	float w = size.x;
-	float h = size.y;
+void Control::_compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]) {
 
 
-	x = p_point.x;
-	y = p_point.y;
+	Size2 parent_rect_size = get_parent_anchorable_rect().size;
+	r_margins[0] = Math::floor(p_rect.position.x - (p_anchors[0] * parent_rect_size.x));
+	r_margins[1] = Math::floor(p_rect.position.y - (p_anchors[1] * parent_rect_size.y));
+	r_margins[2] = Math::floor(p_rect.position.x + p_rect.size.x - (p_anchors[2] * parent_rect_size.x));
+	r_margins[3] = Math::floor(p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y));
+}
 
 
-	data.margin[0] = _s2a(x, data.anchor[0], pw);
-	data.margin[1] = _s2a(y, data.anchor[1], ph);
-	data.margin[2] = _s2a(x + w, data.anchor[2], pw);
-	data.margin[3] = _s2a(y + h, data.anchor[3], ph);
+void Control::set_position(const Size2 &p_point) {
 
 
+	_compute_margins(Rect2(p_point, data.size_cache), data.anchor, data.margin);
 	_size_changed();
 	_size_changed();
 }
 }
 
 
@@ -1791,18 +1756,7 @@ void Control::set_size(const Size2 &p_size) {
 	if (new_size.y < min.y)
 	if (new_size.y < min.y)
 		new_size.y = min.y;
 		new_size.y = min.y;
 
 
-	float pw = _get_parent_range(0);
-	float ph = _get_parent_range(1);
-
-	float x = _a2s(data.margin[0], data.anchor[0], pw);
-	float y = _a2s(data.margin[1], data.anchor[1], ph);
-
-	float w = new_size.width;
-	float h = new_size.height;
-
-	data.margin[2] = _s2a(x + w, data.anchor[2], pw);
-	data.margin[3] = _s2a(y + h, data.anchor[3], ph);
-
+	_compute_margins(Rect2(data.pos_cache, new_size), data.anchor, data.margin);
 	_size_changed();
 	_size_changed();
 }
 }
 
 
@@ -1833,6 +1787,11 @@ Rect2 Control::get_rect() const {
 	return Rect2(get_position(), get_size());
 	return Rect2(get_position(), get_size());
 }
 }
 
 
+Rect2 Control::get_anchorable_rect() const {
+
+	return Rect2(Point2(), get_size());
+}
+
 void Control::add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon) {
 void Control::add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon) {
 
 
 	ERR_FAIL_COND(p_icon.is_null());
 	ERR_FAIL_COND(p_icon.is_null());
@@ -2332,12 +2291,11 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
 	Point2 points[4];
 	Point2 points[4];
 
 
 	Transform2D xform = get_global_transform();
 	Transform2D xform = get_global_transform();
-	Rect2 rect = _edit_get_rect();
 
 
-	points[0] = xform.xform(rect.position);
-	points[1] = xform.xform(rect.position + Point2(rect.size.x, 0));
-	points[2] = xform.xform(rect.position + rect.size);
-	points[3] = xform.xform(rect.position + Point2(0, rect.size.y));
+	points[0] = xform.xform(Point2());
+	points[1] = xform.xform(Point2(get_size().x, 0));
+	points[2] = xform.xform(get_size());
+	points[3] = xform.xform(Point2(0, get_size().y));
 
 
 	const Vector2 dir[4] = {
 	const Vector2 dir[4] = {
 		Vector2(-1, 0),
 		Vector2(-1, 0),
@@ -2391,12 +2349,11 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con
 		Point2 points[4];
 		Point2 points[4];
 
 
 		Transform2D xform = c->get_global_transform();
 		Transform2D xform = c->get_global_transform();
-		Rect2 rect = c->_edit_get_rect();
 
 
-		points[0] = xform.xform(rect.position);
-		points[1] = xform.xform(rect.position + Point2(rect.size.x, 0));
-		points[2] = xform.xform(rect.position + rect.size);
-		points[3] = xform.xform(rect.position + Point2(0, rect.size.y));
+		points[0] = xform.xform(Point2());
+		points[1] = xform.xform(Point2(get_size().x, 0));
+		points[2] = xform.xform(get_size());
+		points[3] = xform.xform(Point2(0, get_size().y));
 
 
 		float min = 1e7;
 		float min = 1e7;
 
 

+ 6 - 4
scene/gui/control.h

@@ -220,10 +220,6 @@ private:
 
 
 	void _set_anchor(Margin p_margin, float p_anchor);
 	void _set_anchor(Margin p_margin, float p_anchor);
 
 
-	float _get_parent_range(int p_idx) const;
-	float _get_range(int p_idx) const;
-	float _s2a(float p_val, float p_anchor, float p_range) const;
-	float _a2s(float p_val, float p_anchor, float p_range) const;
 	void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign = true);
 	void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign = true);
 	void _theme_changed();
 	void _theme_changed();
 
 
@@ -233,6 +229,9 @@ private:
 	void _update_scroll();
 	void _update_scroll();
 	void _resize(const Size2 &p_size);
 	void _resize(const Size2 &p_size);
 
 
+	Rect2 _compute_child_rect(const float p_anchors[4], const float p_margins[4]) const;
+	void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]);
+
 	void _size_changed();
 	void _size_changed();
 	String _get_tooltip() const;
 	String _get_tooltip() const;
 
 
@@ -283,6 +282,7 @@ public:
 
 
 	};
 	};
 
 
+	/* EDITOR */
 	virtual Dictionary _edit_get_state() const;
 	virtual Dictionary _edit_get_state() const;
 	virtual void _edit_set_state(const Dictionary &p_state);
 	virtual void _edit_set_state(const Dictionary &p_state);
 
 
@@ -358,6 +358,7 @@ public:
 	Rect2 get_rect() const;
 	Rect2 get_rect() const;
 	Rect2 get_global_rect() const;
 	Rect2 get_global_rect() const;
 	Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server
 	Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server
+	Rect2 get_anchorable_rect() const;
 
 
 	void set_rotation(float p_radians);
 	void set_rotation(float p_radians);
 	void set_rotation_degrees(float p_degrees);
 	void set_rotation_degrees(float p_degrees);
@@ -465,6 +466,7 @@ public:
 	bool is_toplevel_control() const;
 	bool is_toplevel_control() const;
 
 
 	Size2 get_parent_area_size() const;
 	Size2 get_parent_area_size() const;
+	Rect2 get_parent_anchorable_rect() const;
 
 
 	void grab_click_focus();
 	void grab_click_focus();