diff options
author | groud <gilles.roudiere@gmail.com> | 2018-09-10 14:39:46 +0200 |
---|---|---|
committer | groud <gilles.roudiere@gmail.com> | 2018-09-11 17:48:57 +0200 |
commit | 2f316bc608567b9c9dea8b5ecb1c2889fbcf2dfb (patch) | |
tree | 6068814d5b6e37cb6455c007bf9d2a60863f10ef | |
parent | c320d9394d82b755e2ccffb0d8fac3e9df61396b (diff) |
Add a scale mode to the 2D editor
-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); |