Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add temporary pivot for rotating multiple 2D nodes #58375

Merged
merged 1 commit into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 66 additions & 15 deletions editor/plugins/canvas_item_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,22 +1344,33 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {

// Drag the pivot (in pivot mode / with V key)
if (drag_type == DRAG_NONE) {
bool move_temp_pivot = ((b.is_valid() && b->is_shift_pressed()) || (k.is_valid() && k->is_shift_pressed()));

if ((b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::LEFT && tool == TOOL_EDIT_PIVOT) ||
(k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::V && tool == TOOL_SELECT && k->get_modifiers_mask().is_empty())) {
(k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::V && tool == TOOL_SELECT && (k->get_modifiers_mask().is_empty() || move_temp_pivot))) {
List<CanvasItem *> selection = _get_edited_canvas_items();

// Filters the selection with nodes that allow setting the pivot
drag_selection = List<CanvasItem *>();
for (CanvasItem *ci : selection) {
if (ci->_edit_use_pivot()) {
if (ci->_edit_use_pivot() || move_temp_pivot) {
drag_selection.push_back(ci);
}
}

// Start dragging if we still have nodes
if (drag_selection.size() > 0) {
Vector2 event_pos = (b.is_valid()) ? b->get_position() : viewport->get_local_mouse_position();

if (move_temp_pivot) {
drag_type = DRAG_TEMP_PIVOT;
temp_pivot = transform.affine_inverse().xform(event_pos);
viewport->queue_redraw();
return true;
}

_save_canvas_item_state(drag_selection);
drag_from = transform.affine_inverse().xform((b.is_valid()) ? b->get_position() : viewport->get_local_mouse_position());
drag_from = transform.affine_inverse().xform(event_pos);
Vector2 new_pos;
if (drag_selection.size() == 1) {
new_pos = snap_point(drag_from, SNAP_NODE_SIDES | SNAP_NODE_CENTER | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, drag_selection[0]);
Expand Down Expand Up @@ -1416,6 +1427,20 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
return true;
}
}

if (drag_type == DRAG_TEMP_PIVOT) {
if (m.is_valid()) {
temp_pivot = transform.affine_inverse().xform(m->get_position());
viewport->queue_redraw();
return true;
}

if ((b.is_valid() && !b->is_pressed() && b->get_button_index() == MouseButton::LEFT && tool == TOOL_EDIT_PIVOT) ||
(k.is_valid() && !k->is_pressed() && k->get_keycode() == Key::V)) {
drag_type = DRAG_NONE;
return true;
}
}
return false;
}

Expand All @@ -1441,7 +1466,9 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
drag_type = DRAG_ROTATE;
drag_from = transform.affine_inverse().xform(b->get_position());
CanvasItem *ci = drag_selection[0];
if (ci->_edit_use_pivot()) {
if (!Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y)) {
drag_rotation_center = temp_pivot;
} else if (ci->_edit_use_pivot()) {
drag_rotation_center = ci->get_global_transform_with_canvas().xform(ci->_edit_get_pivot());
} else {
drag_rotation_center = ci->get_global_transform_with_canvas().get_origin();
Expand All @@ -1461,7 +1488,16 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
drag_to = transform.affine_inverse().xform(m->get_position());
//Rotate the opposite way if the canvas item's compounded scale has an uneven number of negative elements
bool opposite = (ci->get_global_transform().get_scale().sign().dot(ci->get_transform().get_scale().sign()) == 0);
ci->_edit_set_rotation(snap_angle(ci->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), ci->_edit_get_rotation()));
real_t prev_rotation = ci->_edit_get_rotation();
real_t new_rotation = snap_angle(ci->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), prev_rotation);

ci->_edit_set_rotation(new_rotation);
if (!Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y)) {
Transform2D xform = ci->get_global_transform_with_canvas() * ci->get_transform().affine_inverse();
Vector2 radius = xform.xform(ci->_edit_get_position()) - temp_pivot;
radius = radius.rotated(new_rotation - prev_rotation);
ci->_edit_set_position(xform.affine_inverse().xform(temp_pivot + radius));
}
viewport->queue_redraw();
}
return true;
Expand Down Expand Up @@ -3161,7 +3197,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
} else {
if (grid_snap_active) {
Ref<Texture2D> position_icon = get_editor_theme_icon(SNAME("EditorPosition"));
viewport->draw_texture(get_editor_theme_icon(SNAME("EditorPosition")), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
viewport->draw_texture(position_icon, (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
}
}
}
Expand Down Expand Up @@ -3583,6 +3619,10 @@ void CanvasItemEditor::_draw_selection() {
get_theme_color(SNAME("accent_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.6),
Math::round(2 * EDSCALE));
}

if (!Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y)) {
viewport->draw_texture(pivot_icon, (temp_pivot - view_offset) * zoom - (pivot_icon->get_size() / 2).floor(), get_theme_color(SNAME("accent_color"), SNAME("Editor")));
}
}

void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_color) {
Expand Down Expand Up @@ -3931,8 +3971,6 @@ void CanvasItemEditor::_notification(int p_what) {
} break;

case NOTIFICATION_PROCESS: {
int nb_having_pivot = 0;

// Update the viewport if the canvas_item changes
List<CanvasItem *> selection = _get_edited_canvas_items(true);
for (CanvasItem *ci : selection) {
Expand Down Expand Up @@ -3972,14 +4010,10 @@ void CanvasItemEditor::_notification(int p_what) {
viewport->queue_redraw();
}
}

if (ci->_edit_use_pivot()) {
nb_having_pivot++;
}
}

// Activate / Deactivate the pivot tool
pivot_button->set_disabled(nb_having_pivot == 0);
// Activate / Deactivate the pivot tool.
pivot_button->set_disabled(selection.is_empty());

// Update the viewport if bones changes
for (KeyValue<BoneKey, BoneList> &E : bone_list) {
Expand Down Expand Up @@ -4048,6 +4082,11 @@ void CanvasItemEditor::_selection_changed() {
_reset_drag();
}
selected_from_canvas = false;

if (temp_pivot != Vector2(INFINITY, INFINITY)) {
temp_pivot = Vector2(INFINITY, INFINITY);
viewport->queue_redraw();
}
}

void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
Expand Down Expand Up @@ -4202,6 +4241,18 @@ void CanvasItemEditor::_button_tool_select(int p_index) {

tool = (Tool)p_index;

if (p_index == TOOL_EDIT_PIVOT && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Special action that places temporary rotation pivot in the middle of the selection.
List<CanvasItem *> selection = _get_edited_canvas_items();
if (!selection.is_empty()) {
Vector2 center;
for (const CanvasItem *ci : selection) {
center += ci->_edit_get_position();
}
temp_pivot = center / selection.size();
}
}

viewport->queue_redraw();
_update_cursor();
}
Expand Down Expand Up @@ -5279,7 +5330,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_EDIT_PIVOT));
pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot."));
pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot.") + "\n" + TTR("Shift: Set temporary rotation pivot.") + "\n" + TTR("Click this button while holding Shift to put the rotation pivot in the center of the selected nodes."));

pan_button = memnew(Button);
pan_button->set_theme_type_variation("FlatButton");
Expand Down
2 changes: 2 additions & 0 deletions editor/plugins/canvas_item_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class CanvasItemEditor : public VBoxContainer {
DRAG_SCALE_BOTH,
DRAG_ROTATE,
DRAG_PIVOT,
DRAG_TEMP_PIVOT,
DRAG_V_GUIDE,
DRAG_H_GUIDE,
DRAG_DOUBLE_GUIDE,
Expand Down Expand Up @@ -251,6 +252,7 @@ class CanvasItemEditor : public VBoxContainer {
bool key_scale = false;

bool pan_pressed = false;
Vector2 temp_pivot = Vector2(INFINITY, INFINITY);

bool ruler_tool_active = false;
Point2 ruler_tool_origin;
Expand Down
Loading