Browse Source

Ability to set rotation and scaling pivot for controls.

Juan Linietsky 8 years ago
parent
commit
bd9d98c172

+ 54 - 4
editor/plugins/canvas_item_editor_plugin.cpp

@@ -199,6 +199,25 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) {
 				undo_redo->add_undo_method(n2dc, "set_global_position", n2dc->get_global_position());
 			}
 		}
+
+		Control *cnt = E->get()->cast_to<Control>();
+		if (cnt) {
+
+			Vector2 old_pivot = cnt->get_pivot_offset();
+			Vector2 new_pivot = cnt->get_global_transform_with_canvas().affine_inverse().xform(mouse_pos);
+			Vector2 old_pos = cnt->get_position();
+
+			Vector2 top_pos = cnt->get_transform().get_origin(); //remember where top pos was
+			cnt->set_pivot_offset(new_pivot);
+			Vector2 new_top_pos = cnt->get_transform().get_origin(); //check where it is now
+
+			Vector2 new_pos = old_pos - (new_top_pos - top_pos); //offset it back
+
+			undo_redo->add_do_method(cnt, "set_pivot_offset", new_pivot);
+			undo_redo->add_do_method(cnt, "set_position", new_pos);
+			undo_redo->add_undo_method(cnt, "set_pivot_offset", old_pivot);
+			undo_redo->add_undo_method(cnt, "set_position", old_pos);
+		}
 	}
 
 	undo_redo->commit_action();
@@ -842,6 +861,8 @@ void CanvasItemEditor::_prepare_drag(const Point2 &p_click_pos) {
 		se->undo_state = canvas_item->edit_get_state();
 		if (canvas_item->cast_to<Node2D>())
 			se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot();
+		if (canvas_item->cast_to<Control>())
+			se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset();
 	}
 
 	if (selection.size() == 1 && selection[0]->cast_to<Node2D>()) {
@@ -1149,6 +1170,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
 						canvas_item->edit_set_state(se->undo_state);
 						if (canvas_item->cast_to<Node2D>())
 							canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot);
+						if (canvas_item->cast_to<Node2D>())
+							canvas_item->cast_to<Control>()->set_pivot_offset(se->undo_pivot);
 					}
 				}
 
@@ -1238,12 +1261,18 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
 							Variant state = canvas_item->edit_get_state();
 							undo_redo->add_do_method(canvas_item, "edit_set_state", state);
 							undo_redo->add_undo_method(canvas_item, "edit_set_state", se->undo_state);
-							if (canvas_item->cast_to<Node2D>()) {
+							{
 								Node2D *pvt = canvas_item->cast_to<Node2D>();
-								if (pvt->edit_has_pivot()) {
+								if (pvt && pvt->edit_has_pivot()) {
 									undo_redo->add_do_method(canvas_item, "edit_set_pivot", pvt->edit_get_pivot());
 									undo_redo->add_undo_method(canvas_item, "edit_set_pivot", se->undo_pivot);
 								}
+
+								Control *cnt = canvas_item->cast_to<Control>();
+								if (cnt) {
+									undo_redo->add_do_method(canvas_item, "set_pivot_offset", cnt->get_pivot_offset());
+									undo_redo->add_undo_method(canvas_item, "set_pivot_offset", se->undo_pivot);
+								}
 							}
 						}
 						undo_redo->commit_action();
@@ -1380,7 +1409,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
 				if (canvas_item->cast_to<Node2D>())
 					se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot();
 				if (canvas_item->cast_to<Control>())
-					se->undo_pivot = Vector2();
+					se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset();
 				return;
 			}
 
@@ -1405,6 +1434,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
 					se->undo_state = canvas_item->edit_get_state();
 					if (canvas_item->cast_to<Node2D>())
 						se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot();
+					if (canvas_item->cast_to<Control>())
+						se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset();
 
 					return;
 				}
@@ -1522,6 +1553,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
 				canvas_item->edit_set_state(se->undo_state); //reset state and reapply
 				if (canvas_item->cast_to<Node2D>())
 					canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot);
+				if (canvas_item->cast_to<Control>())
+					canvas_item->cast_to<Control>()->set_pivot_offset(se->undo_pivot);
 			}
 
 			Vector2 dfrom = drag_from;
@@ -1659,6 +1692,9 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
 						Node2D *n2d = canvas_item->cast_to<Node2D>();
 						n2d->edit_set_pivot(se->undo_pivot + drag_vector);
 					}
+					if (canvas_item->cast_to<Control>()) {
+						canvas_item->cast_to<Control>()->set_pivot_offset(se->undo_pivot + drag_vector);
+					}
 					continue;
 				} break;
 				case DRAG_NODE_2D: {
@@ -1920,6 +1956,14 @@ void CanvasItemEditor::_viewport_draw() {
 					pivot_found = true;
 				}
 			}
+			if (canvas_item->cast_to<Control>()) {
+				Vector2 pivot_ofs = canvas_item->cast_to<Control>()->get_pivot_offset();
+				if (pivot_ofs != Vector2()) {
+					viewport->draw_texture(pivot, xform.xform(pivot_ofs) + (-pivot->get_size() / 2).floor());
+				}
+				can_move_pivot = true;
+				pivot_found = true;
+			}
 
 			if (tool == TOOL_SELECT) {
 
@@ -2108,10 +2152,16 @@ void CanvasItemEditor::_notification(int p_what) {
 
 			Transform2D xform = canvas_item->get_transform();
 
-			if (r != se->prev_rect || xform != se->prev_xform) {
+			Vector2 pivot;
+			if (canvas_item->cast_to<Control>()) {
+				pivot = canvas_item->cast_to<Control>()->get_pivot_offset();
+			}
+
+			if (r != se->prev_rect || xform != se->prev_xform || pivot != se->prev_pivot) {
 				viewport->update();
 				se->prev_rect = r;
 				se->prev_xform = xform;
+				se->prev_pivot = pivot;
 			}
 		}
 

+ 1 - 0
editor/plugins/canvas_item_editor_plugin.h

@@ -56,6 +56,7 @@ public:
 	Transform2D prev_xform;
 	float prev_rot;
 	Rect2 prev_rect;
+	Vector2 prev_pivot;
 
 	CanvasItemEditorSelectedItem() { prev_rot = 0; }
 };

+ 35 - 7
scene/gui/control.cpp

@@ -90,11 +90,22 @@ Size2 Control::edit_get_minimum_size() const {
 	return get_combined_minimum_size();
 }
 
+Transform2D Control::_get_internal_transform() const {
+
+	Transform2D rot_scale;
+	rot_scale.set_rotation_and_scale(data.rotation, data.scale);
+	Transform2D offset;
+	offset.set_origin(-data.pivot_offset);
+
+	return offset.affine_inverse() * (rot_scale * offset);
+}
 void Control::edit_set_rect(const Rect2 &p_edit_rect) {
 
-	Transform2D postxf;
-	postxf.set_rotation_and_scale(data.rotation, data.scale);
-	Vector2 new_pos = postxf.xform(p_edit_rect.position);
+	Transform2D xform = _get_internal_transform();
+
+	//	xform[2] += get_position();
+
+	Vector2 new_pos = xform.basis_xform(p_edit_rect.position);
 
 	Vector2 pos = get_position() + new_pos;
 
@@ -353,8 +364,9 @@ void Control::remove_child_notify(Node *p_child) {
 
 void Control::_update_canvas_item_transform() {
 
-	Transform2D xform = Transform2D(data.rotation, get_position());
-	xform.scale_basis(data.scale);
+	Transform2D xform = _get_internal_transform();
+	xform[2] += get_position();
+
 	VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), xform);
 }
 
@@ -1903,8 +1915,8 @@ Control::CursorShape Control::get_cursor_shape(const Point2 &p_pos) const {
 
 Transform2D Control::get_transform() const {
 
-	Transform2D xform = Transform2D(data.rotation, get_position());
-	xform.scale_basis(data.scale);
+	Transform2D xform = _get_internal_transform();
+	xform[2] += get_position();
 	return xform;
 }
 
@@ -2230,6 +2242,19 @@ void Control::_font_changed() {
 	minimum_size_changed(); //fonts affect minimum size pretty much almost always
 }
 
+void Control::set_pivot_offset(const Vector2 &p_pivot) {
+
+	data.pivot_offset = p_pivot;
+	update();
+	_notify_transform();
+	_change_notify("rect_pivot_offset");
+}
+
+Vector2 Control::get_pivot_offset() const {
+
+	return data.pivot_offset;
+}
+
 void Control::set_scale(const Vector2 &p_scale) {
 
 	data.scale = p_scale;
@@ -2362,6 +2387,7 @@ void Control::_bind_methods() {
 	// TODO: Obsolete this method (old name) properly (GH-4397)
 	ClassDB::bind_method(D_METHOD("_set_rotation_deg", "degrees"), &Control::_set_rotation_deg);
 	ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Control::set_scale);
+	ClassDB::bind_method(D_METHOD("set_pivot_offset", "pivot_offset"), &Control::set_pivot_offset);
 	ClassDB::bind_method(D_METHOD("get_margin", "margin"), &Control::get_margin);
 	ClassDB::bind_method(D_METHOD("get_begin"), &Control::get_begin);
 	ClassDB::bind_method(D_METHOD("get_end"), &Control::get_end);
@@ -2372,6 +2398,7 @@ void Control::_bind_methods() {
 	// TODO: Obsolete this method (old name) properly (GH-4397)
 	ClassDB::bind_method(D_METHOD("_get_rotation_deg"), &Control::_get_rotation_deg);
 	ClassDB::bind_method(D_METHOD("get_scale"), &Control::get_scale);
+	ClassDB::bind_method(D_METHOD("get_pivot_offset"), &Control::get_pivot_offset);
 	ClassDB::bind_method(D_METHOD("get_custom_minimum_size"), &Control::get_custom_minimum_size);
 	ClassDB::bind_method(D_METHOD("get_parent_area_size"), &Control::get_size);
 	ClassDB::bind_method(D_METHOD("get_global_position"), &Control::get_global_position);
@@ -2491,6 +2518,7 @@ void Control::_bind_methods() {
 	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size");
 	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_deg", "get_rotation_deg");
 	ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale");
+	ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset");
 	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents");
 
 	ADD_GROUP("Hint", "hint_");

+ 6 - 0
scene/gui/control.h

@@ -127,6 +127,7 @@ private:
 
 		float rotation;
 		Vector2 scale;
+		Vector2 pivot_offset;
 
 		bool pending_resize;
 
@@ -207,6 +208,8 @@ private:
 
 	void _update_canvas_item_transform();
 
+	Transform2D _get_internal_transform() const;
+
 	friend class Viewport;
 	void _modal_stack_remove();
 	void _modal_set_prev_focus_owner(ObjectID p_prev);
@@ -306,6 +309,9 @@ public:
 	float get_rotation() const;
 	float get_rotation_deg() const;
 
+	void set_pivot_offset(const Vector2 &p_pivot);
+	Vector2 get_pivot_offset() const;
+
 	void set_scale(const Vector2 &p_scale);
 	Vector2 get_scale() const;