diff options
| -rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 530 | ||||
| -rw-r--r-- | editor/plugins/canvas_item_editor_plugin.h | 15 | 
2 files changed, 349 insertions, 196 deletions
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index fbf4671165..7d82394887 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -55,6 +55,7 @@  #define MAX_ZOOM 100  #define RULER_WIDTH 15 * EDSCALE +#define SCALE_HANDLE_DISTANCE 25  class SnapDialog : public ConfirmationDialog { @@ -335,10 +336,11 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {  	if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())  		return; -	if (k->get_control()) -		return; +	if (k->get_scancode() == KEY_CONTROL || k->get_scancode() == KEY_ALT || k->get_scancode() == KEY_SHIFT) { +		viewport->update(); +	} -	if (k->is_pressed() && !k->is_echo()) { +	if (k->is_pressed() && !k->get_control() && !k->is_echo()) {  		if ((snap_grid || show_grid) && multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->is_shortcut(p_ev)) {  			// Multiply the grid size  			grid_step_multiplier = MIN(grid_step_multiplier + 1, 12); @@ -1267,7 +1269,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {  	if (drag_type == DRAG_NONE) {  		if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {  			drag_selection = _get_edited_canvas_items(); -			if (drag_selection.size() > 0 && ((b->get_control() && tool == TOOL_SELECT) || tool == TOOL_ROTATE)) { +			if (drag_selection.size() > 0 && ((b->get_control() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE)) {  				drag_type = DRAG_ROTATE;  				drag_from = transform.affine_inverse().xform(b->get_position());  				CanvasItem *canvas_item = drag_selection[0]; @@ -1615,6 +1617,89 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {  	return false;  } +bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { + +	Ref<InputEventMouseButton> b = p_event; +	Ref<InputEventMouseMotion> m = p_event; + +	// Drag resize handles +	if (drag_type == DRAG_NONE) { +		if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) { +			List<CanvasItem *> selection = _get_edited_canvas_items(); +			if (selection.size() == 1) { +				CanvasItem *canvas_item = selection[0]; + +				Transform2D xform = transform * canvas_item->get_global_transform_with_canvas(); +				Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized(); +				Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + +				Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); +				Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); +				if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { +					drag_type = DRAG_SCALE_X; +				} +				Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); +				if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { +					drag_type = DRAG_SCALE_Y; +				} +				if (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { +					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 (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { +		// Resize the node +		if (m.is_valid()) { +			_restore_canvas_item_state(drag_selection, true); +			CanvasItem *canvas_item = drag_selection[0]; + +			drag_to = transform.affine_inverse().xform(m->get_position()); + +			bool uniform = m->get_shift(); +			Point2 offset = drag_to - drag_from; +			Size2 scale = canvas_item->call("get_scale"); +			float ratio = scale.y / scale.x; +			if (drag_type == DRAG_SCALE_X) { +				scale.x += offset.x / SCALE_HANDLE_DISTANCE; +				if (uniform) { +					scale.y = scale.x * ratio; +				} +				canvas_item->call("set_scale", scale); + +			} else if (drag_type == DRAG_SCALE_Y) { +				scale.y -= offset.y / SCALE_HANDLE_DISTANCE; +				if (uniform) { +					scale.x = scale.y / ratio; +				} +				canvas_item->call("set_scale", scale); +			} +		} + +		// Confirm resize +		if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { +			_commit_canvas_item_state(drag_selection, TTR("Scale CanvasItem")); +			drag_type = DRAG_NONE; +			viewport->update(); +			return true; +		} + +		// Cancel a drag +		if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) { +			_restore_canvas_item_state(drag_selection); +			drag_type = DRAG_NONE; +			viewport->update(); +			return true; +		} +	} +	return false; +} +  bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {  	Ref<InputEventMouseButton> b = p_event;  	Ref<InputEventMouseMotion> m = p_event; @@ -1624,7 +1709,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {  		//Start moving the nodes  		if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {  			List<CanvasItem *> selection = _get_edited_canvas_items(); -			if ((b->get_alt() || tool == TOOL_MOVE) && selection.size() > 0) { +			if (((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) && selection.size() > 0) {  				drag_type = DRAG_MOVE;  				drag_from = transform.affine_inverse().xform(b->get_position());  				drag_selection = selection; @@ -2019,6 +2104,8 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {  		//printf("Open scene on double click\n");  	} else if ((accepted = _gui_input_anchors(p_event))) {  		//printf("Anchors\n"); +	} else if ((accepted = _gui_input_scale(p_event))) { +		//printf("Set scale\n");  	} else if ((accepted = _gui_input_pivot(p_event))) {  		//printf("Set pivot\n");  	} else if ((accepted = _gui_input_resize(p_event))) { @@ -2301,6 +2388,188 @@ void CanvasItemEditor::_draw_grid() {  	}  } +void CanvasItemEditor::_draw_control_helpers(Control *control) { +	Transform2D xform = transform * control->get_global_transform_with_canvas(); +	RID ci = viewport->get_canvas_item(); +	if (tool == TOOL_SELECT && show_helpers && !Object::cast_to<Container>(control->get_parent())) { +		// Draw the helpers +		Color color_base = Color(0.8, 0.8, 0.8, 0.5); + +		float anchors_values[4]; +		anchors_values[0] = control->get_anchor(MARGIN_LEFT); +		anchors_values[1] = control->get_anchor(MARGIN_TOP); +		anchors_values[2] = control->get_anchor(MARGIN_RIGHT); +		anchors_values[3] = control->get_anchor(MARGIN_BOTTOM); + +		// Draw the anchors +		Vector2 anchors[4]; +		Vector2 anchors_pos[4]; +		for (int i = 0; i < 4; i++) { +			anchors[i] = Vector2((i % 2 == 0) ? anchors_values[i] : anchors_values[(i + 1) % 4], (i % 2 == 1) ? anchors_values[i] : anchors_values[(i + 1) % 4]); +			anchors_pos[i] = xform.xform(_anchor_to_position(control, anchors[i])); +		} + +		// Get which anchor is dragged +		int dragged_anchor = -1; +		switch (drag_type) { +			case DRAG_ANCHOR_ALL: +			case DRAG_ANCHOR_TOP_LEFT: +				dragged_anchor = 0; +				break; +			case DRAG_ANCHOR_TOP_RIGHT: +				dragged_anchor = 1; +				break; +			case DRAG_ANCHOR_BOTTOM_RIGHT: +				dragged_anchor = 2; +				break; +			case DRAG_ANCHOR_BOTTOM_LEFT: +				dragged_anchor = 3; +				break; +			default: +				break; +		} + +		if (dragged_anchor >= 0) { +			// Draw the 4 lines when dragged +			bool snapped; +			Color color_snapped = Color(0.64, 0.93, 0.67, 0.5); + +			Vector2 corners_pos[4]; +			for (int i = 0; i < 4; i++) { +				corners_pos[i] = xform.xform(_anchor_to_position(control, Vector2((i == 0 || i == 3) ? ANCHOR_BEGIN : ANCHOR_END, (i <= 1) ? ANCHOR_BEGIN : ANCHOR_END))); +			} + +			Vector2 line_starts[4]; +			Vector2 line_ends[4]; +			for (int i = 0; i < 4; i++) { +				float anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i]; +				line_starts[i] = Vector2::linear_interpolate(corners_pos[i], corners_pos[(i + 1) % 4], anchor_val); +				line_ends[i] = Vector2::linear_interpolate(corners_pos[(i + 3) % 4], corners_pos[(i + 2) % 4], anchor_val); +				snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0; +				viewport->draw_line(line_starts[i], line_ends[i], snapped ? color_snapped : color_base, (i == dragged_anchor || (i + 3) % 4 == dragged_anchor) ? 2 : 1); +			} + +			// Display the percentages next to the lines +			float percent_val; +			percent_val = anchors_values[(dragged_anchor + 2) % 4] - anchors_values[dragged_anchor]; +			percent_val = (dragged_anchor >= 2) ? -percent_val : percent_val; +			_draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Margin)((dragged_anchor + 1) % 4)); + +			percent_val = anchors_values[(dragged_anchor + 3) % 4] - anchors_values[(dragged_anchor + 1) % 4]; +			percent_val = ((dragged_anchor + 1) % 4 >= 2) ? -percent_val : percent_val; +			_draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 3) % 4]) / 2, (Margin)(dragged_anchor)); + +			percent_val = anchors_values[(dragged_anchor + 1) % 4]; +			percent_val = ((dragged_anchor + 1) % 4 >= 2) ? ANCHOR_END - percent_val : percent_val; +			_draw_percentage_at_position(percent_val, (line_starts[dragged_anchor] + anchors_pos[dragged_anchor]) / 2, (Margin)(dragged_anchor)); + +			percent_val = anchors_values[dragged_anchor]; +			percent_val = (dragged_anchor >= 2) ? ANCHOR_END - percent_val : percent_val; +			_draw_percentage_at_position(percent_val, (line_ends[(dragged_anchor + 1) % 4] + anchors_pos[dragged_anchor]) / 2, (Margin)((dragged_anchor + 1) % 4)); +		} + +		Rect2 anchor_rects[4]; +		anchor_rects[0] = Rect2(anchors_pos[0] - anchor_handle->get_size(), anchor_handle->get_size()); +		anchor_rects[1] = Rect2(anchors_pos[1] - Vector2(0.0, anchor_handle->get_size().y), Point2(-anchor_handle->get_size().x, anchor_handle->get_size().y)); +		anchor_rects[2] = Rect2(anchors_pos[2], -anchor_handle->get_size()); +		anchor_rects[3] = Rect2(anchors_pos[3] - Vector2(anchor_handle->get_size().x, 0.0), Point2(anchor_handle->get_size().x, -anchor_handle->get_size().y)); + +		for (int i = 0; i < 4; i++) { +			anchor_handle->draw_rect(ci, anchor_rects[i]); +		} + +		// Draw the margin values and the node width/height when dragging control side +		float ratio = 0.33; +		Transform2D parent_transform = xform * control->get_transform().affine_inverse(); +		float node_pos_in_parent[4]; + +		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; +		switch (drag_type) { +			case DRAG_LEFT: +			case DRAG_TOP_LEFT: +			case DRAG_BOTTOM_LEFT: +				_draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); +			case DRAG_MOVE: +				start = Vector2(node_pos_in_parent[0], Math::lerp(node_pos_in_parent[1], node_pos_in_parent[3], ratio)); +				end = start - Vector2(control->get_margin(MARGIN_LEFT), 0); +				_draw_margin_at_position(control->get_margin(MARGIN_LEFT), parent_transform.xform((start + end) / 2), MARGIN_TOP); +				viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); +				break; +			default: +				break; +		} +		switch (drag_type) { +			case DRAG_RIGHT: +			case DRAG_TOP_RIGHT: +			case DRAG_BOTTOM_RIGHT: +				_draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); +			case DRAG_MOVE: +				start = Vector2(node_pos_in_parent[2], Math::lerp(node_pos_in_parent[3], node_pos_in_parent[1], ratio)); +				end = start - Vector2(control->get_margin(MARGIN_RIGHT), 0); +				_draw_margin_at_position(control->get_margin(MARGIN_RIGHT), parent_transform.xform((start + end) / 2), MARGIN_BOTTOM); +				viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); +				break; +			default: +				break; +		} +		switch (drag_type) { +			case DRAG_TOP: +			case DRAG_TOP_LEFT: +			case DRAG_TOP_RIGHT: +				_draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), MARGIN_RIGHT); +			case DRAG_MOVE: +				start = Vector2(Math::lerp(node_pos_in_parent[0], node_pos_in_parent[2], ratio), node_pos_in_parent[1]); +				end = start - Vector2(0, control->get_margin(MARGIN_TOP)); +				_draw_margin_at_position(control->get_margin(MARGIN_TOP), parent_transform.xform((start + end) / 2), MARGIN_LEFT); +				viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); +				break; +			default: +				break; +		} +		switch (drag_type) { +			case DRAG_BOTTOM: +			case DRAG_BOTTOM_LEFT: +			case DRAG_BOTTOM_RIGHT: +				_draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), MARGIN_RIGHT); +			case DRAG_MOVE: +				start = Vector2(Math::lerp(node_pos_in_parent[2], node_pos_in_parent[0], ratio), node_pos_in_parent[3]); +				end = start - Vector2(0, control->get_margin(MARGIN_BOTTOM)); +				_draw_margin_at_position(control->get_margin(MARGIN_BOTTOM), parent_transform.xform((start + end) / 2), MARGIN_RIGHT); +				viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); +				break; +			default: +				break; +		} + +		switch (drag_type) { +			//Draw the ghost rect if the node if rotated/scaled +			case DRAG_LEFT: +			case DRAG_TOP_LEFT: +			case DRAG_TOP: +			case DRAG_TOP_RIGHT: +			case DRAG_RIGHT: +			case DRAG_BOTTOM_RIGHT: +			case DRAG_BOTTOM: +			case DRAG_BOTTOM_LEFT: +			case DRAG_MOVE: +				if (control->get_rotation() != 0.0 || control->get_scale() != Vector2(1, 1)) { +					Rect2 rect = Rect2(Vector2(node_pos_in_parent[0], node_pos_in_parent[1]), control->get_size()); +					viewport->draw_rect(parent_transform.xform(rect), color_base, false); +				} +				break; +			default: +				break; +		} +	} +} +  void CanvasItemEditor::_draw_selection() {  	Ref<Texture> pivot_icon = get_icon("EditorPivot", "EditorIcons");  	Ref<Texture> position_icon = get_icon("EditorPosition", "EditorIcons"); @@ -2359,199 +2628,26 @@ void CanvasItemEditor::_draw_selection() {  			}  		} else { -			Transform2D transform = Transform2D(xform.get_rotation(), xform.get_origin()); -			viewport->draw_set_transform_matrix(transform); +			Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized(); +			Transform2D simple_xform = viewport->get_transform() * unscaled_transform; +			viewport->draw_set_transform_matrix(simple_xform);  			viewport->draw_texture(position_icon, -(position_icon->get_size() / 2)); -			viewport->draw_set_transform_matrix(Transform2D()); +			viewport->draw_set_transform_matrix(viewport->get_transform());  		} -		if (single && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks +		if (single && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || 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());  			} +			// Draw control-related helpers  			Control *control = Object::cast_to<Control>(canvas_item);  			if (control) { -				if (tool == TOOL_SELECT && show_helpers && !Object::cast_to<Container>(control->get_parent())) { -					// Draw the helpers -					Color color_base = Color(0.8, 0.8, 0.8, 0.5); - -					float anchors_values[4]; -					anchors_values[0] = control->get_anchor(MARGIN_LEFT); -					anchors_values[1] = control->get_anchor(MARGIN_TOP); -					anchors_values[2] = control->get_anchor(MARGIN_RIGHT); -					anchors_values[3] = control->get_anchor(MARGIN_BOTTOM); - -					// Draw the anchors -					Vector2 anchors[4]; -					Vector2 anchors_pos[4]; -					for (int i = 0; i < 4; i++) { -						anchors[i] = Vector2((i % 2 == 0) ? anchors_values[i] : anchors_values[(i + 1) % 4], (i % 2 == 1) ? anchors_values[i] : anchors_values[(i + 1) % 4]); -						anchors_pos[i] = xform.xform(_anchor_to_position(control, anchors[i])); -					} - -					// Get which anchor is dragged -					int dragged_anchor = -1; -					switch (drag_type) { -						case DRAG_ANCHOR_ALL: -						case DRAG_ANCHOR_TOP_LEFT: -							dragged_anchor = 0; -							break; -						case DRAG_ANCHOR_TOP_RIGHT: -							dragged_anchor = 1; -							break; -						case DRAG_ANCHOR_BOTTOM_RIGHT: -							dragged_anchor = 2; -							break; -						case DRAG_ANCHOR_BOTTOM_LEFT: -							dragged_anchor = 3; -							break; -						default: -							break; -					} - -					if (dragged_anchor >= 0) { -						// Draw the 4 lines when dragged -						bool snapped; -						Color color_snapped = Color(0.64, 0.93, 0.67, 0.5); - -						Vector2 corners_pos[4]; -						for (int i = 0; i < 4; i++) { -							corners_pos[i] = xform.xform(_anchor_to_position(control, Vector2((i == 0 || i == 3) ? ANCHOR_BEGIN : ANCHOR_END, (i <= 1) ? ANCHOR_BEGIN : ANCHOR_END))); -						} - -						Vector2 line_starts[4]; -						Vector2 line_ends[4]; -						for (int i = 0; i < 4; i++) { -							float anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i]; -							line_starts[i] = Vector2::linear_interpolate(corners_pos[i], corners_pos[(i + 1) % 4], anchor_val); -							line_ends[i] = Vector2::linear_interpolate(corners_pos[(i + 3) % 4], corners_pos[(i + 2) % 4], anchor_val); -							snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0; -							viewport->draw_line(line_starts[i], line_ends[i], snapped ? color_snapped : color_base, (i == dragged_anchor || (i + 3) % 4 == dragged_anchor) ? 2 : 1); -						} - -						// Display the percentages next to the lines -						float percent_val; -						percent_val = anchors_values[(dragged_anchor + 2) % 4] - anchors_values[dragged_anchor]; -						percent_val = (dragged_anchor >= 2) ? -percent_val : percent_val; -						_draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Margin)((dragged_anchor + 1) % 4)); - -						percent_val = anchors_values[(dragged_anchor + 3) % 4] - anchors_values[(dragged_anchor + 1) % 4]; -						percent_val = ((dragged_anchor + 1) % 4 >= 2) ? -percent_val : percent_val; -						_draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 3) % 4]) / 2, (Margin)(dragged_anchor)); - -						percent_val = anchors_values[(dragged_anchor + 1) % 4]; -						percent_val = ((dragged_anchor + 1) % 4 >= 2) ? ANCHOR_END - percent_val : percent_val; -						_draw_percentage_at_position(percent_val, (line_starts[dragged_anchor] + anchors_pos[dragged_anchor]) / 2, (Margin)(dragged_anchor)); - -						percent_val = anchors_values[dragged_anchor]; -						percent_val = (dragged_anchor >= 2) ? ANCHOR_END - percent_val : percent_val; -						_draw_percentage_at_position(percent_val, (line_ends[(dragged_anchor + 1) % 4] + anchors_pos[dragged_anchor]) / 2, (Margin)((dragged_anchor + 1) % 4)); -					} - -					Rect2 anchor_rects[4]; -					anchor_rects[0] = Rect2(anchors_pos[0] - anchor_handle->get_size(), anchor_handle->get_size()); -					anchor_rects[1] = Rect2(anchors_pos[1] - Vector2(0.0, anchor_handle->get_size().y), Point2(-anchor_handle->get_size().x, anchor_handle->get_size().y)); -					anchor_rects[2] = Rect2(anchors_pos[2], -anchor_handle->get_size()); -					anchor_rects[3] = Rect2(anchors_pos[3] - Vector2(anchor_handle->get_size().x, 0.0), Point2(anchor_handle->get_size().x, -anchor_handle->get_size().y)); - -					for (int i = 0; i < 4; i++) { -						anchor_handle->draw_rect(ci, anchor_rects[i]); -					} - -					// Draw the margin values and the node width/height when dragging control side -					float ratio = 0.33; -					Transform2D parent_transform = xform * control->get_transform().affine_inverse(); -					float node_pos_in_parent[4]; - -					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; -					switch (drag_type) { -						case DRAG_LEFT: -						case DRAG_TOP_LEFT: -						case DRAG_BOTTOM_LEFT: -							_draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); -						case DRAG_MOVE: -							start = Vector2(node_pos_in_parent[0], Math::lerp(node_pos_in_parent[1], node_pos_in_parent[3], ratio)); -							end = start - Vector2(control->get_margin(MARGIN_LEFT), 0); -							_draw_margin_at_position(control->get_margin(MARGIN_LEFT), parent_transform.xform((start + end) / 2), MARGIN_TOP); -							viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); -							break; -						default: -							break; -					} -					switch (drag_type) { -						case DRAG_RIGHT: -						case DRAG_TOP_RIGHT: -						case DRAG_BOTTOM_RIGHT: -							_draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); -						case DRAG_MOVE: -							start = Vector2(node_pos_in_parent[2], Math::lerp(node_pos_in_parent[3], node_pos_in_parent[1], ratio)); -							end = start - Vector2(control->get_margin(MARGIN_RIGHT), 0); -							_draw_margin_at_position(control->get_margin(MARGIN_RIGHT), parent_transform.xform((start + end) / 2), MARGIN_BOTTOM); -							viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); -							break; -						default: -							break; -					} -					switch (drag_type) { -						case DRAG_TOP: -						case DRAG_TOP_LEFT: -						case DRAG_TOP_RIGHT: -							_draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), MARGIN_RIGHT); -						case DRAG_MOVE: -							start = Vector2(Math::lerp(node_pos_in_parent[0], node_pos_in_parent[2], ratio), node_pos_in_parent[1]); -							end = start - Vector2(0, control->get_margin(MARGIN_TOP)); -							_draw_margin_at_position(control->get_margin(MARGIN_TOP), parent_transform.xform((start + end) / 2), MARGIN_LEFT); -							viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); -							break; -						default: -							break; -					} -					switch (drag_type) { -						case DRAG_BOTTOM: -						case DRAG_BOTTOM_LEFT: -						case DRAG_BOTTOM_RIGHT: -							_draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), MARGIN_RIGHT); -						case DRAG_MOVE: -							start = Vector2(Math::lerp(node_pos_in_parent[2], node_pos_in_parent[0], ratio), node_pos_in_parent[3]); -							end = start - Vector2(0, control->get_margin(MARGIN_BOTTOM)); -							_draw_margin_at_position(control->get_margin(MARGIN_BOTTOM), parent_transform.xform((start + end) / 2), MARGIN_RIGHT); -							viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, 1); -							break; -						default: -							break; -					} - -					switch (drag_type) { -						//Draw the ghost rect if the node if rotated/scaled -						case DRAG_LEFT: -						case DRAG_TOP_LEFT: -						case DRAG_TOP: -						case DRAG_TOP_RIGHT: -						case DRAG_RIGHT: -						case DRAG_BOTTOM_RIGHT: -						case DRAG_BOTTOM: -						case DRAG_BOTTOM_LEFT: -						case DRAG_MOVE: -							if (control->get_rotation() != 0.0 || control->get_scale() != Vector2(1, 1)) { -								Rect2 rect = Rect2(Vector2(node_pos_in_parent[0], node_pos_in_parent[1]), control->get_size()); -								viewport->draw_rect(parent_transform.xform(rect), color_base, false); -							} -							break; -						default: -							break; -					} -				} +				_draw_control_helpers(control);  			} +			// Draw the resize handles  			if (tool == TOOL_SELECT && canvas_item->_edit_use_rect()) {  				Rect2 rect = canvas_item->_edit_get_rect();  				Vector2 endpoints[4] = { @@ -2561,7 +2657,6 @@ void CanvasItemEditor::_draw_selection() {  					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;  					int next = (i + 1) % 4; @@ -2576,6 +2671,46 @@ void CanvasItemEditor::_draw_selection() {  					select_handle->draw(ci, (ofs - (select_handle->get_size() / 2)).floor());  				}  			} + +			// Draw the rescale handles +			bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL); +			bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); +			if ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { + +				Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized(); +				Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + +				Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); +				bool uniform = Input::get_singleton()->is_key_pressed(KEY_SHIFT); +				Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom; + +				if (drag_type == DRAG_SCALE_X) { +					scale_factor.x += offset.x; +					if (uniform) { +						scale_factor.y += offset.x; +					} +				} else if (drag_type == DRAG_SCALE_Y) { +					scale_factor.y -= offset.y; +					if (uniform) { +						scale_factor.x -= offset.y; +					} +				} + +				//scale_factor *= zoom; + +				viewport->draw_set_transform_matrix(simple_xform); +				Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); +				Color x_axis_color(1.0, 0.4, 0.4, 0.6); +				viewport->draw_rect(x_handle_rect, x_axis_color); +				viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), x_axis_color); + +				Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); +				Color y_axis_color(0.4, 1.0, 0.4, 0.6); +				viewport->draw_rect(y_handle_rect, y_axis_color); +				viewport->draw_line(Point2(), Point2(0, -scale_factor.y * EDSCALE), y_axis_color); + +				viewport->draw_set_transform_matrix(viewport->get_transform()); +			}  		}  	} @@ -2750,15 +2885,16 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans  		_draw_invisible_nodes_positions(p_node->get_child(i), parent_xform, canvas_xform);  	} -	if (canvas_item && !canvas_item->_edit_use_rect() && (!editor_selection->is_selected(canvas_item) || canvas_item->get_meta("_edit_lock_"))) { +	if (canvas_item && !canvas_item->_edit_use_rect() && (!editor_selection->is_selected(canvas_item) || (canvas_item->has_meta("_edit_lock_") && canvas_item->get_meta("_edit_lock_")))) {  		Transform2D xform = transform * canvas_xform * parent_xform;  		// Draw the node's position  		Ref<Texture> position_icon = get_icon("EditorPositionUnselected", "EditorIcons"); -		Transform2D transform = Transform2D(xform.get_rotation(), xform.get_origin()); -		viewport->draw_set_transform_matrix(transform); +		Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized(); +		Transform2D simple_xform = viewport->get_transform() * unscaled_transform; +		viewport->draw_set_transform_matrix(simple_xform);  		viewport->draw_texture(position_icon, -position_icon->get_size() / 2, Color(1.0, 1.0, 1.0, 0.5)); -		viewport->draw_set_transform_matrix(Transform2D()); +		viewport->draw_set_transform_matrix(viewport->get_transform());  	}  } @@ -3086,6 +3222,7 @@ void CanvasItemEditor::_notification(int p_what) {  		select_button->set_icon(get_icon("ToolSelect", "EditorIcons"));  		list_select_button->set_icon(get_icon("ListSelect", "EditorIcons"));  		move_button->set_icon(get_icon("ToolMove", "EditorIcons")); +		scale_button->set_icon(get_icon("ToolScale", "EditorIcons"));  		rotate_button->set_icon(get_icon("ToolRotate", "EditorIcons"));  		snap_button->set_icon(get_icon("Snap", "EditorIcons"));  		snap_config_menu->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons")); @@ -3394,7 +3531,7 @@ void CanvasItemEditor::_button_toggle_snap(bool p_status) {  void CanvasItemEditor::_button_tool_select(int p_index) { -	ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, rotate_button, pivot_button, pan_button }; +	ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button };  	for (int i = 0; i < TOOL_MAX; i++) {  		tb[i]->set_pressed(i == p_index);  	} @@ -4286,6 +4423,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {  	select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), KEY_Q));  	select_button->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate") + "\n" + TTR("Alt+Drag: Move") + "\n" + TTR("Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).") + "\n" + TTR("Alt+RMB: Depth list selection")); +	hb->add_child(memnew(VSeparator)); +  	move_button = memnew(ToolButton);  	hb->add_child(move_button);  	move_button->set_toggle_mode(true); @@ -4293,6 +4432,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {  	move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W));  	move_button->set_tooltip(TTR("Move Mode")); +	scale_button = memnew(ToolButton); +	hb->add_child(scale_button); +	scale_button->set_toggle_mode(true); +	scale_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SCALE)); +	scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S)); +	scale_button->set_tooltip(TTR("Scale Mode")); +  	rotate_button = memnew(ToolButton);  	hb->add_child(rotate_button);  	rotate_button->set_toggle_mode(true); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index dd6c94eb60..61d77581d3 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -77,6 +77,7 @@ class CanvasItemEditor : public VBoxContainer {  		TOOL_SELECT,  		TOOL_LIST_SELECT,  		TOOL_MOVE, +		TOOL_SCALE,  		TOOL_ROTATE,  		TOOL_EDIT_PIVOT,  		TOOL_PAN, @@ -189,6 +190,8 @@ class CanvasItemEditor : public VBoxContainer {  		DRAG_ANCHOR_BOTTOM_LEFT,  		DRAG_ANCHOR_ALL,  		DRAG_MOVE, +		DRAG_SCALE_X, +		DRAG_SCALE_Y,  		DRAG_ROTATE,  		DRAG_PIVOT,  		DRAG_V_GUIDE, @@ -298,17 +301,19 @@ class CanvasItemEditor : public VBoxContainer {  	List<PoseClipboard> pose_clipboard;  	ToolButton *select_button; -	ToolButton *list_select_button; +  	ToolButton *move_button; +	ToolButton *scale_button;  	ToolButton *rotate_button; +	ToolButton *list_select_button; +	ToolButton *pivot_button; +	ToolButton *pan_button; +  	ToolButton *snap_button;  	MenuButton *snap_config_menu;  	PopupMenu *smartsnap_config_popup; -	ToolButton *pivot_button; -	ToolButton *pan_button; -  	ToolButton *lock_button;  	ToolButton *unlock_button; @@ -408,6 +413,7 @@ class CanvasItemEditor : public VBoxContainer {  	void _draw_guides();  	void _draw_focus();  	void _draw_grid(); +	void _draw_control_helpers(Control *control);  	void _draw_selection();  	void _draw_axis();  	void _draw_bones(); @@ -420,6 +426,7 @@ class CanvasItemEditor : public VBoxContainer {  	bool _gui_input_anchors(const Ref<InputEvent> &p_event);  	bool _gui_input_move(const Ref<InputEvent> &p_event);  	bool _gui_input_open_scene_on_double_click(const Ref<InputEvent> &p_event); +	bool _gui_input_scale(const Ref<InputEvent> &p_event);  	bool _gui_input_pivot(const Ref<InputEvent> &p_event);  	bool _gui_input_resize(const Ref<InputEvent> &p_event);  	bool _gui_input_rotate(const Ref<InputEvent> &p_event);  |