Ver Fonte

Remove the selection rect for nodes that do not require it

Gilles Roudiere há 7 anos atrás
pai
commit
72ed1e4244

+ 270 - 196
editor/plugins/canvas_item_editor_plugin.cpp

@@ -196,11 +196,15 @@ void CanvasItemEditor::_snap_other_nodes(Point2 p_value, Point2 &r_current_snap,
 		Transform2D ci_transform = canvas_item->get_global_transform_with_canvas();
 		Transform2D to_snap_transform = p_to_snap ? p_to_snap->get_global_transform_with_canvas() : Transform2D();
 		if (fmod(ci_transform.get_rotation() - to_snap_transform.get_rotation(), (real_t)360.0) == 0.0) {
-			Point2 begin = ci_transform.xform(canvas_item->_edit_get_rect().get_position());
-			Point2 end = ci_transform.xform(canvas_item->_edit_get_rect().get_position() + canvas_item->_edit_get_rect().get_size());
-
-			_snap_if_closer_point(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation());
-			_snap_if_closer_point(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation());
+			if (canvas_item->_edit_use_rect()) {
+				Point2 begin = ci_transform.xform(canvas_item->_edit_get_rect().get_position());
+				Point2 end = ci_transform.xform(canvas_item->_edit_get_rect().get_position() + canvas_item->_edit_get_rect().get_size());
+				_snap_if_closer_point(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation());
+				_snap_if_closer_point(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation());
+			} else {
+				Point2 position = ci_transform.xform(Point2());
+				_snap_if_closer_point(p_value, position, r_current_snap, r_snapped, ci_transform.get_rotation());
+			}
 		}
 	}
 	for (int i = 0; i < p_current->get_child_count(); i++) {
@@ -221,23 +225,23 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
 
 		// Parent sides and center
 		if ((is_snap_active && snap_node_parent && (p_modes & SNAP_NODE_PARENT)) || (p_forced_modes & SNAP_NODE_PARENT)) {
-			Point2 begin;
-			Point2 end;
-			bool can_snap = false;
 			if (const Control *c = Object::cast_to<Control>(p_canvas_item)) {
-				begin = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(0, 0)));
-				end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(1, 1)));
-				can_snap = true;
-			} else if (const CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_canvas_item->get_parent())) {
-				begin = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position());
-				end = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position() + parent_ci->_edit_get_rect().get_size());
-				can_snap = true;
-			}
-
-			if (can_snap) {
+				Point2 begin = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(0, 0)));
+				Point2 end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(1, 1)));
 				_snap_if_closer_point(p_target, begin, output, snapped, rotation);
 				_snap_if_closer_point(p_target, (begin + end) / 2.0, output, snapped, rotation);
 				_snap_if_closer_point(p_target, end, output, snapped, rotation);
+			} else if (const CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_canvas_item->get_parent())) {
+				if (parent_ci->_edit_use_rect()) {
+					Point2 begin = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position());
+					Point2 end = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position() + parent_ci->_edit_get_rect().get_size());
+					_snap_if_closer_point(p_target, begin, output, snapped, rotation);
+					_snap_if_closer_point(p_target, (begin + end) / 2.0, output, snapped, rotation);
+					_snap_if_closer_point(p_target, end, output, snapped, rotation);
+				} else {
+					Point2 position = p_canvas_item->get_transform().affine_inverse().xform(Point2());
+					_snap_if_closer_point(p_target, position, output, snapped, rotation);
+				}
 			}
 		}
 
@@ -253,16 +257,23 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
 
 		// Self sides
 		if ((is_snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) {
-			Point2 begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position());
-			Point2 end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size());
-			_snap_if_closer_point(p_target, begin, output, snapped, rotation);
-			_snap_if_closer_point(p_target, end, output, snapped, rotation);
+			if (p_canvas_item->_edit_use_rect()) {
+				Point2 begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position());
+				Point2 end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size());
+				_snap_if_closer_point(p_target, begin, output, snapped, rotation);
+				_snap_if_closer_point(p_target, end, output, snapped, rotation);
+			}
 		}
 
 		// Self center
 		if ((is_snap_active && snap_node_center && (p_modes & SNAP_NODE_CENTER)) || (p_forced_modes & SNAP_NODE_CENTER)) {
-			Point2 center = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size() / 2.0);
-			_snap_if_closer_point(p_target, center, output, snapped, rotation);
+			if (p_canvas_item->_edit_use_rect()) {
+				Point2 center = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size() / 2.0);
+				_snap_if_closer_point(p_target, center, output, snapped, rotation);
+			} else {
+				Point2 position = p_canvas_item->get_global_transform_with_canvas().xform(Point2());
+				_snap_if_closer_point(p_target, position, output, snapped, rotation);
+			}
 		}
 	}
 
@@ -364,63 +375,85 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li
 
 	// Handles the first element
 	CanvasItem *canvas_item = p_list.front()->get();
-	Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
+	Rect2 rect;
+	if (canvas_item->_edit_use_rect()) {
+		rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
+	} else {
+		rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(Point2()), Size2());
+	}
 
-	// Handles the other ones
+	// Expand with the other ones
 	for (List<CanvasItem *>::Element *E = p_list.front(); E; E = E->next()) {
 		CanvasItem *canvas_item = E->get();
-		Rect2 current_rect = canvas_item->_edit_get_rect();
 		Transform2D xform = canvas_item->get_global_transform_with_canvas();
-		rect.expand_to(xform.xform(current_rect.position));
-		rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0)));
-		rect.expand_to(xform.xform(current_rect.position + current_rect.size));
-		rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y)));
+		if (canvas_item->_edit_use_rect()) {
+			Rect2 current_rect = canvas_item->_edit_get_rect();
+
+			rect.expand_to(xform.xform(current_rect.position));
+			rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0)));
+			rect.expand_to(xform.xform(current_rect.position + current_rect.size));
+			rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y)));
+		} else {
+			rect.expand_to(xform.xform(Point2()));
+		}
 	}
 
 	return rect;
 }
 
-void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
+void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
 	if (!p_node)
 		return;
 	if (Object::cast_to<Viewport>(p_node))
 		return;
 
-	CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
+	const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
 
-	bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != "";
-	bool editable = inherited && EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
+	/*bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != "";
+	bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
 	bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
 
-	if (!lock_children && (!inherited || editable)) {
-		for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
-			if (canvas_item && !canvas_item->is_set_as_toplevel()) {
-				_expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
-			} else {
-				CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
-				_expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
-			}
+	if (!lock_children && editable) {}*/
+
+	for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
+		if (canvas_item && !canvas_item->is_set_as_toplevel()) {
+			_expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+		} else {
+			const CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
+			_expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
 		}
 	}
 
 	if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) {
-		Rect2 rect = canvas_item->_edit_get_rect();
 		Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
-		if (r_first) {
-			r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
-			r_first = false;
+		if (canvas_item->_edit_use_rect()) {
+			Rect2 rect = canvas_item->_edit_get_rect();
+			if (r_first) {
+				r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
+				r_first = false;
+			}
+			if (r_rect.size != Size2()) {
+				r_rect.expand_to(xform.xform(rect.position));
+				r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0)));
+				r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y)));
+				r_rect.expand_to(xform.xform(rect.position + rect.size));
+			}
+		} else {
+			if (r_first) {
+				r_rect = Rect2(xform.xform(Point2()), Size2());
+				r_first = false;
+			} else {
+				r_rect.expand_to(xform.xform(Point2()));
+			}
 		}
-		r_rect.expand_to(xform.xform(rect.position));
-		r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0)));
-		r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y)));
-		r_rect.expand_to(xform.xform(rect.position + rect.size));
 	}
 }
 
-Rect2 CanvasItemEditor::_get_scene_encompassing_rect() {
+Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) {
 	Rect2 rect;
 	bool first = true;
-	_expand_encompassing_rect_using_children(rect, editor->get_edited_scene(), first);
+	_expand_encompassing_rect_using_children(rect, p_node, first);
+
 	return rect;
 }
 
@@ -463,7 +496,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
 	return;
 }
 
-void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
+void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
 	if (!p_node)
 		return;
 	if (Object::cast_to<Viewport>(p_node))
@@ -472,31 +505,37 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_n
 	CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
 
 	bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != "";
-	bool editable = inherited && EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
+	bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
 	bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
+	bool locked = p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
 
-	if (!lock_children && (!inherited || editable)) {
+	if (!lock_children && !locked && editable) {
 		for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
 			if (canvas_item && !canvas_item->is_set_as_toplevel()) {
-				_find_canvas_items_at_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+				_find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
 			} else {
 				CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
-				_find_canvas_items_at_rect(p_rect, p_node->get_child(i), r_items, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
+				_find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
 			}
 		}
 	}
 
 	if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) {
-
-		Rect2 rect = canvas_item->_edit_get_rect();
 		Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
 
-		if (p_rect.has_point(xform.xform(rect.position)) &&
-				p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, 0))) &&
-				p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, rect.size.y))) &&
-				p_rect.has_point(xform.xform(rect.position + Vector2(0, rect.size.y)))) {
+		if (canvas_item->_edit_use_rect()) {
+			Rect2 rect = canvas_item->_edit_get_rect();
+			if (p_rect.has_point(xform.xform(rect.position)) &&
+					p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, 0))) &&
+					p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, rect.size.y))) &&
+					p_rect.has_point(xform.xform(rect.position + Vector2(0, rect.size.y)))) {
 
-			r_items->push_back(canvas_item);
+				r_items->push_back(canvas_item);
+			}
+		} else {
+			if (p_rect.has_point(xform.xform(Point2()))) {
+				r_items->push_back(canvas_item);
+			}
 		}
 	}
 }
@@ -575,8 +614,11 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
 		if (se) {
 			se->undo_state = canvas_item->_edit_get_state();
 			se->pre_drag_xform = canvas_item->get_global_transform_with_canvas();
-			se->pre_drag_rect = canvas_item->_edit_get_rect();
-
+			if (canvas_item->_edit_use_rect()) {
+				se->pre_drag_rect = canvas_item->_edit_get_rect();
+			} else {
+				se->pre_drag_rect = Rect2();
+			}
 			se->pre_drag_bones_length = List<float>();
 			se->pre_drag_bones_undo_state = List<Dictionary>();
 
@@ -1290,54 +1332,55 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
 			List<CanvasItem *> selection = _get_edited_canvas_items();
 			if (selection.size() == 1) {
 				CanvasItem *canvas_item = selection[0];
+				if (canvas_item->_edit_use_rect()) {
+					Rect2 rect = canvas_item->_edit_get_rect();
+					Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
+
+					Vector2 endpoints[4] = {
+						xform.xform(rect.position),
+						xform.xform(rect.position + Vector2(rect.size.x, 0)),
+						xform.xform(rect.position + rect.size),
+						xform.xform(rect.position + Vector2(0, rect.size.y))
+					};
 
-				Rect2 rect = canvas_item->_edit_get_rect();
-				Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
-
-				Vector2 endpoints[4] = {
-					xform.xform(rect.position),
-					xform.xform(rect.position + Vector2(rect.size.x, 0)),
-					xform.xform(rect.position + rect.size),
-					xform.xform(rect.position + Vector2(0, rect.size.y))
-				};
-
-				DragType dragger[] = {
-					DRAG_TOP_LEFT,
-					DRAG_TOP,
-					DRAG_TOP_RIGHT,
-					DRAG_RIGHT,
-					DRAG_BOTTOM_RIGHT,
-					DRAG_BOTTOM,
-					DRAG_BOTTOM_LEFT,
-					DRAG_LEFT
-				};
-
-				DragType resize_drag = DRAG_NONE;
-				float radius = (select_handle->get_size().width / 2) * 1.5;
-
-				for (int i = 0; i < 4; i++) {
-					int prev = (i + 3) % 4;
-					int next = (i + 1) % 4;
+					DragType dragger[] = {
+						DRAG_TOP_LEFT,
+						DRAG_TOP,
+						DRAG_TOP_RIGHT,
+						DRAG_RIGHT,
+						DRAG_BOTTOM_RIGHT,
+						DRAG_BOTTOM,
+						DRAG_BOTTOM_LEFT,
+						DRAG_LEFT
+					};
 
-					Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
-					ofs *= (select_handle->get_size().width / 2);
-					ofs += endpoints[i];
-					if (ofs.distance_to(b->get_position()) < radius)
-						resize_drag = dragger[i * 2];
+					DragType resize_drag = DRAG_NONE;
+					float radius = (select_handle->get_size().width / 2) * 1.5;
 
-					ofs = (endpoints[i] + endpoints[next]) / 2;
-					ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2);
-					if (ofs.distance_to(b->get_position()) < radius)
-						resize_drag = dragger[i * 2 + 1];
-				}
+					for (int i = 0; i < 4; i++) {
+						int prev = (i + 3) % 4;
+						int next = (i + 1) % 4;
+
+						Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
+						ofs *= (select_handle->get_size().width / 2);
+						ofs += endpoints[i];
+						if (ofs.distance_to(b->get_position()) < radius)
+							resize_drag = dragger[i * 2];
+
+						ofs = (endpoints[i] + endpoints[next]) / 2;
+						ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2);
+						if (ofs.distance_to(b->get_position()) < radius)
+							resize_drag = dragger[i * 2 + 1];
+					}
 
-				if (resize_drag != DRAG_NONE) {
-					drag_type = resize_drag;
-					drag_from = transform.affine_inverse().xform(b->get_position());
-					drag_selection = List<CanvasItem *>();
-					drag_selection.push_back(canvas_item);
-					_save_canvas_item_state(drag_selection);
-					return true;
+					if (resize_drag != DRAG_NONE) {
+						drag_type = resize_drag;
+						drag_from = transform.affine_inverse().xform(b->get_position());
+						drag_selection = List<CanvasItem *>();
+						drag_selection.push_back(canvas_item);
+						_save_canvas_item_state(drag_selection);
+						return true;
+					}
 				}
 			}
 		}
@@ -1535,61 +1578,64 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
 			_save_canvas_item_state(drag_selection, true);
 		}
 
-		_restore_canvas_item_state(drag_selection, true);
-
-		bool move_local_base = k->get_alt();
-		bool move_local_base_rotated = k->get_control() || k->get_metakey();
-
-		Vector2 dir;
-		if (k->get_scancode() == KEY_UP)
-			dir += Vector2(0, -1);
-		else if (k->get_scancode() == KEY_DOWN)
-			dir += Vector2(0, 1);
-		else if (k->get_scancode() == KEY_LEFT)
-			dir += Vector2(-1, 0);
-		else if (k->get_scancode() == KEY_RIGHT)
-			dir += Vector2(1, 0);
-		if (k->get_shift())
-			dir *= grid_step * Math::pow(2.0, grid_step_multiplier);
-
-		drag_to += dir;
-		if (k->get_shift())
-			drag_to = drag_to.snapped(grid_step * Math::pow(2.0, grid_step_multiplier));
-
-		Point2 previous_pos;
-		if (drag_selection.size() == 1) {
-			Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
-			previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
-		} else {
-			previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
-		}
+		if (drag_selection.size() > 0) {
+
+			_restore_canvas_item_state(drag_selection, true);
+
+			bool move_local_base = k->get_alt();
+			bool move_local_base_rotated = k->get_control() || k->get_metakey();
+
+			Vector2 dir;
+			if (k->get_scancode() == KEY_UP)
+				dir += Vector2(0, -1);
+			else if (k->get_scancode() == KEY_DOWN)
+				dir += Vector2(0, 1);
+			else if (k->get_scancode() == KEY_LEFT)
+				dir += Vector2(-1, 0);
+			else if (k->get_scancode() == KEY_RIGHT)
+				dir += Vector2(1, 0);
+			if (k->get_shift())
+				dir *= grid_step * Math::pow(2.0, grid_step_multiplier);
+
+			drag_to += dir;
+			if (k->get_shift())
+				drag_to = drag_to.snapped(grid_step * Math::pow(2.0, grid_step_multiplier));
+
+			Point2 previous_pos;
+			if (drag_selection.size() == 1) {
+				Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
+				previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
+			} else {
+				previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
+			}
 
-		Point2 new_pos;
-		if (drag_selection.size() == 1) {
-			Node2D *node_2d = Object::cast_to<Node2D>(drag_selection[0]);
-			if (node_2d && move_local_base_rotated) {
-				Transform2D m;
-				m.rotate(node_2d->get_rotation());
-				new_pos += m.xform(drag_to);
-			} else if (move_local_base) {
-				new_pos += drag_to;
+			Point2 new_pos;
+			if (drag_selection.size() == 1) {
+				Node2D *node_2d = Object::cast_to<Node2D>(drag_selection[0]);
+				if (node_2d && move_local_base_rotated) {
+					Transform2D m;
+					m.rotate(node_2d->get_rotation());
+					new_pos += m.xform(drag_to);
+				} else if (move_local_base) {
+					new_pos += drag_to;
+				} else {
+					new_pos = previous_pos + (drag_to - drag_from);
+				}
 			} else {
 				new_pos = previous_pos + (drag_to - drag_from);
 			}
-		} else {
-			new_pos = previous_pos + (drag_to - drag_from);
-		}
 
-		for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
-			CanvasItem *canvas_item = E->get();
-			CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
-			Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+			for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
+				CanvasItem *canvas_item = E->get();
+				CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+				Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
 
-			Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
-			if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
-				_solve_IK(node2d, new_pos);
-			} else {
-				canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+				Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
+				if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
+					_solve_IK(node2d, new_pos);
+				} else {
+					canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+				}
 			}
 		}
 		return true;
@@ -1648,6 +1694,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
 
 				return true;
 			} else if (!selection_results.empty()) {
+				// Sorts items according the their z-index
 				selection_results.sort();
 
 				NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
@@ -1709,16 +1756,17 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
 				canvas_item = selection[0].item;
 
 			// Check if the canvas item is in a group, and select the group instead if it is the case
-			CanvasItem *canvas_item_tmp = canvas_item;
-			while (canvas_item_tmp) {
-				if (canvas_item->has_meta("_edit_group_")) {
+			Node *node = canvas_item;
+			while (node && node != scene) {
+				CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
+				if (canvas_item_tmp && node->has_meta("_edit_group_")) {
 					canvas_item = canvas_item_tmp;
 				}
-				canvas_item_tmp = canvas_item_tmp->get_parent_item();
+				node = node->get_parent();
 			}
 
 			// Make sure the selected node is in the current scene
-			Node *node = canvas_item;
+			node = canvas_item;
 			while (node && ((node != scene && node->get_owner() != scene) || !node->is_class("CanvasItem"))) {
 				node = node->get_parent();
 			};
@@ -1768,7 +1816,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
 				if (bsfrom.y > bsto.y)
 					SWAP(bsfrom.y, bsto.y);
 
-				_find_canvas_items_at_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
+				_find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
 				for (List<CanvasItem *>::Element *E = selitems.front(); E; E = E->next()) {
 					editor_selection->add_node(E->get());
 				}
@@ -2095,6 +2143,7 @@ void CanvasItemEditor::_draw_grid() {
 
 void CanvasItemEditor::_draw_selection() {
 	Ref<Texture> pivot_icon = get_icon("EditorPivot", "EditorIcons");
+	Ref<Texture> position_icon = get_icon("EditorPivot", "EditorIcons");
 	RID ci = viewport->get_canvas_item();
 
 	List<CanvasItem *> selection = _get_edited_canvas_items(false, false);
@@ -2104,8 +2153,6 @@ void CanvasItemEditor::_draw_selection() {
 		CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
 		CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
 
-		Rect2 rect = canvas_item->_edit_get_rect();
-
 		// Draw the previous position if we are dragging the node
 		if (show_helpers &&
 				(drag_type == DRAG_ALL || drag_type == DRAG_ROTATE ||
@@ -2114,42 +2161,52 @@ void CanvasItemEditor::_draw_selection() {
 			const Transform2D pre_drag_xform = transform * se->pre_drag_xform;
 			const Color pre_drag_color = Color(0.4, 0.6, 1, 0.7);
 
-			Vector2 pre_drag_endpoints[4] = {
+			if (canvas_item->_edit_use_rect()) {
+				Vector2 pre_drag_endpoints[4] = {
 
-				pre_drag_xform.xform(se->pre_drag_rect.position),
-				pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(se->pre_drag_rect.size.x, 0)),
-				pre_drag_xform.xform(se->pre_drag_rect.position + se->pre_drag_rect.size),
-				pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(0, se->pre_drag_rect.size.y))
-			};
+					pre_drag_xform.xform(se->pre_drag_rect.position),
+					pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(se->pre_drag_rect.size.x, 0)),
+					pre_drag_xform.xform(se->pre_drag_rect.position + se->pre_drag_rect.size),
+					pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(0, se->pre_drag_rect.size.y))
+				};
 
-			for (int i = 0; i < 4; i++) {
-				viewport->draw_line(pre_drag_endpoints[i], pre_drag_endpoints[(i + 1) % 4], pre_drag_color, 2);
+				for (int i = 0; i < 4; i++) {
+					viewport->draw_line(pre_drag_endpoints[i], pre_drag_endpoints[(i + 1) % 4], pre_drag_color, 2);
+				}
+			} else {
+				viewport->draw_texture(position_icon, (pre_drag_xform.xform(Point2()) - (position_icon->get_size() / 2)).floor(), Color(0.5, 1.0, 2.0));
 			}
 		}
 
 		Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
-		VisualServer::get_singleton()->canvas_item_add_set_transform(ci, xform);
-
-		// Draw the selected items surrounding boxes
-		Vector2 endpoints[4] = {
-			xform.xform(rect.position),
-			xform.xform(rect.position + Vector2(rect.size.x, 0)),
-			xform.xform(rect.position + rect.size),
-			xform.xform(rect.position + Vector2(0, rect.size.y))
-		};
 
-		Color c = Color(1, 0.6, 0.4, 0.7);
+		// Draw the selected items position / surrounding boxes
+		if (canvas_item->_edit_use_rect()) {
+			Rect2 rect = canvas_item->_edit_get_rect();
+			Vector2 endpoints[4] = {
+				xform.xform(rect.position),
+				xform.xform(rect.position + Vector2(rect.size.x, 0)),
+				xform.xform(rect.position + rect.size),
+				xform.xform(rect.position + Vector2(0, rect.size.y))
+			};
+
+			Color c = Color(1, 0.6, 0.4, 0.7);
 
-		VisualServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D());
+			for (int i = 0; i < 4; i++) {
+				viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, 2);
+			}
+		} else {
 
-		for (int i = 0; i < 4; i++) {
-			viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, 2);
+			Transform2D transform = Transform2D(xform.get_rotation(), xform.get_origin());
+			viewport->draw_set_transform_matrix(transform);
+			viewport->draw_texture(position_icon, -(position_icon->get_size() / 2));
+			viewport->draw_set_transform_matrix(Transform2D());
 		}
 
 		if (single && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks
 			// Draw the pivot
 			if (canvas_item->_edit_get_pivot() != Vector2() || drag_type == DRAG_PIVOT || tool == TOOL_EDIT_PIVOT) { // This is not really clean :/
-				viewport->draw_texture(pivot_icon, xform.xform(canvas_item->_edit_get_pivot()) + (-pivot_icon->get_size() / 2).floor());
+				viewport->draw_texture(pivot_icon, (xform.xform(canvas_item->_edit_get_pivot()) - (pivot_icon->get_size() / 2)).floor());
 			}
 
 			Control *control = Object::cast_to<Control>(canvas_item);
@@ -2331,7 +2388,14 @@ void CanvasItemEditor::_draw_selection() {
 				}
 			}
 
-			if (tool == TOOL_SELECT) {
+			if (tool == TOOL_SELECT && canvas_item->_edit_use_rect()) {
+				Rect2 rect = canvas_item->_edit_get_rect();
+				Vector2 endpoints[4] = {
+					xform.xform(rect.position),
+					xform.xform(rect.position + Vector2(rect.size.x, 0)),
+					xform.xform(rect.position + rect.size),
+					xform.xform(rect.position + Vector2(0, rect.size.y))
+				};
 				for (int i = 0; i < 4; i++) {
 					// Draw the resize handles
 					int prev = (i + 3) % 4;
@@ -2648,12 +2712,17 @@ void CanvasItemEditor::_notification(int p_what) {
 			CanvasItem *canvas_item = E->get();
 			CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
 
-			Rect2 r = canvas_item->_edit_get_rect();
+			Rect2 rect;
+			if (canvas_item->_edit_use_rect()) {
+				rect = canvas_item->_edit_get_rect();
+			} else {
+				rect = Rect2();
+			}
 			Transform2D xform = canvas_item->get_transform();
 
-			if (r != se->prev_rect || xform != se->prev_xform) {
+			if (rect != se->prev_rect || xform != se->prev_xform) {
 				viewport->update();
-				se->prev_rect = r;
+				se->prev_rect = rect;
 				se->prev_xform = xform;
 			}
 
@@ -2855,7 +2924,7 @@ void CanvasItemEditor::_update_scrollbars() {
 	// Calculate scrollable area
 	Rect2 canvas_item_rect = Rect2(Point2(), screen_rect);
 	if (editor->get_edited_scene()) {
-		Rect2 content_rect = _get_scene_encompassing_rect();
+		Rect2 content_rect = _get_encompassing_rect(editor->get_edited_scene());
 		canvas_item_rect.expand_to(content_rect.position);
 		canvas_item_rect.expand_to(content_rect.position + content_rect.size);
 	}
@@ -3554,7 +3623,12 @@ void CanvasItemEditor::_focus_selection(int p_op) {
 		//if (!canvas_item->is_visible_in_tree()) continue;
 		++count;
 
-		Rect2 item_rect = canvas_item->_edit_get_rect();
+		Rect2 item_rect;
+		if (canvas_item->_edit_use_rect()) {
+			item_rect = canvas_item->_edit_get_rect();
+		} else {
+			item_rect = Rect2();
+		}
 
 		Vector2 pos = canvas_item->get_global_transform().get_origin();
 		Vector2 scale = canvas_item->get_global_transform().get_scale();

+ 3 - 3
editor/plugins/canvas_item_editor_plugin.h

@@ -336,7 +336,7 @@ class CanvasItemEditor : public VBoxContainer {
 	Ref<ShortCut> divide_grid_step_shortcut;
 
 	void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
-	void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
+	void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
 	bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append);
 
 	ConfirmationDialog *snap_dialog;
@@ -366,8 +366,8 @@ class CanvasItemEditor : public VBoxContainer {
 
 	List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
 	Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
-	void _expand_encompassing_rect_using_children(Rect2 &p_rect, Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
-	Rect2 _get_scene_encompassing_rect();
+	void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
+	Rect2 _get_encompassing_rect(const Node *p_node);
 
 	Object *_get_editor_data(Object *p_what);
 

+ 4 - 0
scene/2d/animated_sprite.cpp

@@ -80,6 +80,10 @@ Rect2 AnimatedSprite::_edit_get_rect() const {
 	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) {
 
 	Map<StringName, Anim>::Element *E = animations.find(p_anim);

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

@@ -157,6 +157,7 @@ public:
 	virtual Point2 _edit_get_pivot() const;
 	virtual bool _edit_use_pivot() const;
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
 	Ref<SpriteFrames> get_sprite_frames() const;

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

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

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

@@ -54,6 +54,7 @@ protected:
 
 public:
 	Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	void set_rect(const Rect2 &p_rect);
 	Rect2 get_rect() const;

+ 10 - 1
scene/2d/canvas_item.cpp

@@ -245,6 +245,14 @@ CanvasItemMaterial::~CanvasItemMaterial() {
 
 ///////////////////////////////////////////////////////////////////
 
+bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+	if (_edit_use_rect()) {
+		return _edit_get_rect().has_point(p_point);
+	} else {
+		return p_point.length() < p_tolerance;
+	}
+}
+
 bool CanvasItem::is_visible_in_tree() const {
 
 	if (!is_inside_tree())
@@ -976,7 +984,8 @@ void CanvasItem::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
 	ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
-	ClassDB::bind_method(D_METHOD("_edit_use_position"), &CanvasItem::_edit_use_position);
+	ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
+	ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
 	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_use_rect"), &CanvasItem::_edit_use_rect);

+ 32 - 14
scene/2d/canvas_item.h

@@ -220,30 +220,46 @@ public:
 
 	/* EDITOR */
 
+	// Save and restore a CanvasItem state
 	virtual void _edit_set_state(const Dictionary &p_state){};
 	virtual Dictionary _edit_get_state() const { return Dictionary(); };
 
-	// Used to move/select the node
-	virtual void _edit_set_position(const Point2 &p_position){};
-	virtual Point2 _edit_get_position() const { return Point2(); };
-	virtual bool _edit_use_position() const { return false; };
+	// Used to move the node
+	virtual void _edit_set_position(const Point2 &p_position) = 0;
+	virtual Point2 _edit_get_position() const = 0;
 
-	// Used to resize/move/select the node
+	// Used to scale the node
+	virtual void _edit_set_scale(const Size2 &p_scale) = 0;
+	virtual Size2 _edit_get_scale() const = 0;
+
+	// Used to resize/move the node
 	virtual void _edit_set_rect(const Rect2 &p_rect){};
-	virtual Rect2 _edit_get_rect() const { return Rect2(-32, -32, 64, 64); };
-	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return _edit_get_rect().has_point(p_point); }
-	Rect2 _edit_get_item_and_children_rect() const;
+	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 void
+	_edit_set_rotation(float p_rotation){};
+	virtual float _edit_get_rotation() const {
+		return 0.0;
+	};
+	virtual bool _edit_use_rotation() const {
+		return false;
+	};
 
 	// Used to set a 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 Point2 _edit_get_pivot() const {
+		return Point2();
+	};
+	virtual bool _edit_use_pivot() const {
+		return false;
+	};
 
 	virtual Size2 _edit_get_minimum_size() const;
 
@@ -308,7 +324,9 @@ public:
 	virtual Transform2D get_global_transform_with_canvas() const;
 
 	CanvasItem *get_toplevel() const;
-	_FORCE_INLINE_ RID get_canvas_item() const { return canvas_item; }
+	_FORCE_INLINE_ RID get_canvas_item() const {
+		return canvas_item;
+	}
 
 	void set_block_transform_notify(bool p_enable);
 	bool is_block_transform_notify_enabled() const;

+ 4 - 0
scene/2d/collision_polygon_2d.cpp

@@ -264,6 +264,10 @@ Rect2 CollisionPolygon2D::_edit_get_rect() const {
 	return aabb;
 }
 
+bool CollisionPolygon2D::_edit_use_rect() const {
+	return true;
+}
+
 bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
 
 	return Geometry::is_point_in_polygon(p_point, Variant(polygon));

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

@@ -73,6 +73,7 @@ public:
 	Vector<Point2> get_polygon() const;
 
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
 
 	virtual String get_configuration_warning() const;

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

@@ -173,11 +173,6 @@ Ref<Shape2D> CollisionShape2D::get_shape() const {
 	return shape;
 }
 
-Rect2 CollisionShape2D::_edit_get_rect() const {
-
-	return rect;
-}
-
 bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
 
 	if (!shape.is_valid())

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

@@ -54,7 +54,6 @@ protected:
 	static void _bind_methods();
 
 public:
-	virtual Rect2 _edit_get_rect() const;
 	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
 
 	void set_shape(const Ref<Shape2D> &p_shape);

+ 4 - 0
scene/2d/light_2d.cpp

@@ -65,6 +65,10 @@ Rect2 Light2D::_edit_get_rect() const {
 	return Rect2(texture_offset - s / 2.0, s);
 }
 
+bool Light2D::_edit_use_rect() const {
+	return true;
+}
+
 void Light2D::_update_light_visibility() {
 
 	if (!is_inside_tree())

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

@@ -92,6 +92,7 @@ public:
 	virtual Point2 _edit_get_pivot() const;
 	virtual bool _edit_use_pivot() const;
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	void set_enabled(bool p_enabled);
 	bool is_enabled() const;

+ 4 - 0
scene/2d/line_2d.cpp

@@ -62,6 +62,10 @@ Rect2 Line2D::_edit_get_rect() const {
 	return aabb;
 }
 
+bool Line2D::_edit_use_rect() const {
+	return true;
+}
+
 bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
 
 	const real_t d = _width / 2 + p_tolerance;

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

@@ -59,6 +59,7 @@ public:
 	Line2D();
 
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
 
 	void set_points(const PoolVector<Vector2> &p_points);

+ 27 - 23
scene/2d/node_2d.cpp

@@ -58,16 +58,39 @@ void Node2D::_edit_set_state(const Dictionary &p_state) {
 }
 
 void Node2D::_edit_set_position(const Point2 &p_position) {
-	pos = p_position;
-	_update_transform();
-	_change_notify("position");
+	set_position(p_position);
 }
 
 Point2 Node2D::_edit_get_position() const {
 	return pos;
 }
 
+void Node2D::_edit_set_scale(const Size2 &p_scale) {
+	set_scale(p_scale);
+}
+
+Size2 Node2D::_edit_get_scale() const {
+	return _scale;
+}
+
+void Node2D::_edit_set_rotation(float p_rotation) {
+	angle = p_rotation;
+	_update_transform();
+	_change_notify("rotation");
+	_change_notify("rotation_degrees");
+}
+
+float Node2D::_edit_get_rotation() const {
+	return angle;
+}
+
+bool Node2D::_edit_use_rotation() const {
+	return true;
+}
+
 void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
+	ERR_FAIL_COND(!_edit_use_rect());
+
 	Rect2 r = _edit_get_rect();
 
 	Vector2 zero_offset;
@@ -83,7 +106,7 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
 	if (r.size.y != 0)
 		new_scale.y = p_edit_rect.size.y / r.size.y;
 
-	Point2 new_pos = p_edit_rect.position + p_edit_rect.size * zero_offset; //p_edit_rect.pos - r.pos;
+	Point2 new_pos = p_edit_rect.position + p_edit_rect.size * zero_offset;
 
 	Transform2D postxf;
 	postxf.set_rotation_and_scale(angle, _scale);
@@ -97,25 +120,6 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
 	_change_notify("position");
 }
 
-bool Node2D::_edit_use_rect() const {
-	return true;
-}
-
-void Node2D::_edit_set_rotation(float p_rotation) {
-	angle = p_rotation;
-	_update_transform();
-	_change_notify("rotation");
-	_change_notify("rotation_degrees");
-}
-
-float Node2D::_edit_get_rotation() const {
-	return angle;
-}
-
-bool Node2D::_edit_use_rotation() const {
-	return true;
-}
-
 void Node2D::_update_xform_values() {
 
 	pos = _mat.elements[2];

+ 6 - 2
scene/2d/node_2d.h

@@ -62,12 +62,16 @@ public:
 
 	virtual void _edit_set_position(const Point2 &p_position);
 	virtual Point2 _edit_get_position() const;
-	virtual void _edit_set_rect(const Rect2 &p_edit_rect);
-	virtual bool _edit_use_rect() const;
+
+	virtual void _edit_set_scale(const Size2 &p_scale);
+	virtual Size2 _edit_get_scale() const;
+
 	virtual void _edit_set_rotation(float p_rotation);
 	virtual float _edit_get_rotation() const;
 	virtual bool _edit_use_rotation() const;
 
+	virtual void _edit_set_rect(const Rect2 &p_edit_rect);
+
 	void set_position(const Point2 &p_pos);
 	void set_rotation(float p_radians);
 	void set_rotation_degrees(float p_degrees);

+ 4 - 0
scene/2d/path_2d.cpp

@@ -57,6 +57,10 @@ Rect2 Path2D::_edit_get_rect() const {
 	return aabb;
 }
 
+bool Path2D::_edit_use_rect() const {
+	return true;
+}
+
 bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
 
 	for (int i = 0; i < curve->get_point_count(); i++) {

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

@@ -48,6 +48,7 @@ protected:
 
 public:
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
 
 	void set_curve(const Ref<Curve2D> &p_curve);

+ 4 - 0
scene/2d/polygon_2d.cpp

@@ -73,6 +73,10 @@ Rect2 Polygon2D::_edit_get_rect() const {
 	return item_rect;
 }
 
+bool Polygon2D::_edit_use_rect() const {
+	return true;
+}
+
 bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
 
 	return Geometry::is_point_in_polygon(p_point - get_offset(), Variant(polygon));

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

@@ -68,6 +68,7 @@ public:
 	virtual Point2 _edit_get_pivot() const;
 	virtual bool _edit_use_pivot() const;
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
 

+ 4 - 0
scene/2d/position_2d.cpp

@@ -44,6 +44,10 @@ Rect2 Position2D::_edit_get_rect() const {
 	return Rect2(Point2(-10, -10), Size2(20, 20));
 }
 
+bool Position2D::_edit_use_rect() const {
+	return false;
+}
+
 void Position2D::_notification(int p_what) {
 
 	switch (p_what) {

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

@@ -44,6 +44,7 @@ protected:
 
 public:
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 	Position2D();
 };
 

+ 4 - 0
scene/2d/screen_button.cpp

@@ -335,6 +335,10 @@ Rect2 TouchScreenButton::_edit_get_rect() const {
 	return Rect2(Size2(), texture->get_size());
 }
 
+bool TouchScreenButton::_edit_use_rect() const {
+	return true;
+}
+
 void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
 	visibility = p_mode;
 	update();

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

@@ -104,6 +104,7 @@ public:
 	bool is_pressed() const;
 
 	Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	TouchScreenButton();
 };

+ 8 - 0
scene/2d/sprite.cpp

@@ -58,6 +58,14 @@ bool Sprite::_edit_use_pivot() const {
 	return true;
 }
 
+Rect2 Sprite::_edit_get_rect() const {
+	return get_rect();
+}
+
+bool Sprite::_edit_use_rect() const {
+	return true;
+}
+
 void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
 
 	Size2 s;

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

@@ -74,7 +74,9 @@ public:
 	virtual Point2 _edit_get_pivot() const;
 	virtual bool _edit_use_pivot() const;
 	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-	virtual Rect2 _edit_get_rect() const { return get_rect(); }
+
+	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	void set_texture(const Ref<Texture> &p_texture);
 	Ref<Texture> get_texture() const;

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

@@ -1119,6 +1119,10 @@ Rect2 TileMap::_edit_get_rect() const {
 	return rect_cache;
 }
 
+bool TileMap::_edit_use_rect() const {
+	return true;
+}
+
 void TileMap::set_collision_layer(uint32_t p_layer) {
 
 	collision_layer = p_layer;

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

@@ -245,6 +245,7 @@ public:
 	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 update_bitmask_area(const Vector2 &p_pos);

+ 4 - 0
scene/2d/visibility_notifier_2d.cpp

@@ -89,6 +89,10 @@ Rect2 VisibilityNotifier2D::_edit_get_rect() const {
 	return rect;
 }
 
+bool VisibilityNotifier2D::_edit_use_rect() const {
+	return true;
+}
+
 Rect2 VisibilityNotifier2D::get_rect() const {
 
 	return rect;

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

@@ -56,6 +56,7 @@ protected:
 
 public:
 	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_use_rect() const;
 
 	void set_rect(const Rect2 &p_rect);
 	Rect2 get_rect() const;

+ 8 - 0
scene/gui/control.cpp

@@ -94,6 +94,14 @@ Point2 Control::_edit_get_position() const {
 	return get_position();
 };
 
+void Control::_edit_set_scale(const Size2 &p_scale) {
+	set_scale(p_scale);
+}
+
+Size2 Control::_edit_get_scale() const {
+	return data.scale;
+}
+
 void Control::_edit_set_rect(const Rect2 &p_edit_rect) {
 	set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1)));
 	set_size(p_edit_rect.size.snapped(Vector2(1, 1)));

+ 3 - 0
scene/gui/control.h

@@ -280,6 +280,9 @@ public:
 	virtual void _edit_set_position(const Point2 &p_position);
 	virtual Point2 _edit_get_position() const;
 
+	virtual void _edit_set_scale(const Size2 &p_scale);
+	virtual Size2 _edit_get_scale() const;
+
 	virtual void _edit_set_rect(const Rect2 &p_edit_rect);
 	virtual Rect2 _edit_get_rect() const;
 	virtual bool _edit_use_rect() const;