mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 09:16:35 +08:00
Implement smart snapping. Fixes a bug with anchors single-axis move (when they were rotated).
This commit is contained in:
parent
a6f577a9f2
commit
ee61d5d04b
@ -222,6 +222,133 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) {
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_snap_if_closer(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation, float p_radius) {
|
||||
float radius = p_radius / zoom;
|
||||
float dist;
|
||||
|
||||
Transform2D rot_trans = Transform2D(rotation, Point2());
|
||||
p_value = rot_trans.inverse().xform(p_value);
|
||||
p_target_snap = rot_trans.inverse().xform(p_target_snap);
|
||||
r_current_snap = rot_trans.inverse().xform(r_current_snap);
|
||||
|
||||
dist = Math::abs(p_value.x - p_target_snap.x);
|
||||
if (p_radius < 0 || dist < radius && (!r_snapped[0] || dist < Math::abs(r_current_snap.x - p_value.x))) {
|
||||
r_current_snap.x = p_target_snap.x;
|
||||
r_snapped[0] = true;
|
||||
}
|
||||
|
||||
dist = Math::abs(p_value.y - p_target_snap.y);
|
||||
if (p_radius < 0 || dist < radius && (!r_snapped[1] || dist < Math::abs(r_current_snap.y - p_value.y))) {
|
||||
r_current_snap.y = p_target_snap.y;
|
||||
r_snapped[1] = true;
|
||||
}
|
||||
|
||||
r_current_snap = rot_trans.xform(r_current_snap);
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap) {
|
||||
const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_current);
|
||||
if (canvas_item && p_current != p_to_snap) {
|
||||
Transform2D ci_transform = canvas_item->get_global_transform_with_canvas();
|
||||
Transform2D to_snap_transform = p_to_snap->get_global_transform_with_canvas();
|
||||
if (ci_transform.get_rotation() == to_snap_transform.get_rotation()) {
|
||||
Point2 begin = ci_transform.xform(canvas_item->get_item_rect().get_position());
|
||||
Point2 end = ci_transform.xform(canvas_item->get_item_rect().get_position() + canvas_item->get_item_rect().get_size());
|
||||
|
||||
_snap_if_closer(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation());
|
||||
_snap_if_closer(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation());
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < p_current->get_child_count(); i++) {
|
||||
_snap_other_nodes(p_value, r_current_snap, r_snapped, p_current->get_child(i), p_to_snap);
|
||||
}
|
||||
}
|
||||
|
||||
Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const CanvasItem *p_canvas_item) {
|
||||
Point2 dist[2];
|
||||
bool snapped[2] = { false, false };
|
||||
|
||||
// Smart snap using the canvas position
|
||||
Vector2 output = p_target;
|
||||
real_t rotation = 0.0;
|
||||
|
||||
if (p_canvas_item) {
|
||||
Point2 begin;
|
||||
Point2 end;
|
||||
rotation = p_canvas_item->get_global_transform_with_canvas().get_rotation();
|
||||
|
||||
if (p_modes & SNAP_NODE_PARENT) {
|
||||
// Parent sides and center
|
||||
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->get_item_rect().get_position());
|
||||
end = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->get_item_rect().get_position() + parent_ci->get_item_rect().get_size());
|
||||
can_snap = true;
|
||||
}
|
||||
|
||||
if (can_snap) {
|
||||
_snap_if_closer(p_target, begin, output, snapped, rotation);
|
||||
_snap_if_closer(p_target, (begin + end) / 2.0, output, snapped, rotation);
|
||||
_snap_if_closer(p_target, end, output, snapped, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
// Self anchors (for sides)
|
||||
if (p_modes & SNAP_NODE_ANCHORS) {
|
||||
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(c->get_anchor(MARGIN_LEFT), c->get_anchor(MARGIN_TOP))));
|
||||
end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_RIGHT), c->get_anchor(MARGIN_BOTTOM))));
|
||||
_snap_if_closer(p_target, begin, output, snapped, rotation);
|
||||
_snap_if_closer(p_target, end, output, snapped, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
// Self sides (for anchors)
|
||||
if (p_modes & SNAP_NODE_SIDES) {
|
||||
begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position());
|
||||
end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position() + p_canvas_item->get_item_rect().get_size());
|
||||
_snap_if_closer(p_target, begin, output, snapped, rotation);
|
||||
_snap_if_closer(p_target, end, output, snapped, rotation);
|
||||
}
|
||||
|
||||
// Other nodes sides
|
||||
if (p_modes & SNAP_OTHER_NODES) {
|
||||
_snap_other_nodes(p_target, output, snapped, get_tree()->get_edited_scene_root(), p_canvas_item);
|
||||
}
|
||||
}
|
||||
|
||||
if ((p_modes & SNAP_GRID) && snap_grid && rotation == 0.0) {
|
||||
// Grid
|
||||
Point2 offset = grid_offset;
|
||||
if (snap_relative) {
|
||||
List<Node *> &selection = editor_selection->get_selected_node_list();
|
||||
if (selection.size() == 1 && Object::cast_to<Node2D>(selection[0])) {
|
||||
offset = Object::cast_to<Node2D>(selection[0])->get_global_position();
|
||||
} else {
|
||||
offset = _find_topleftmost_point();
|
||||
}
|
||||
}
|
||||
Point2 grid_output;
|
||||
grid_output.x = Math::stepify(p_target.x - offset.x, grid_step.x * Math::pow(2.0, grid_step_multiplier)) + offset.x;
|
||||
grid_output.y = Math::stepify(p_target.y - offset.y, grid_step.y * Math::pow(2.0, grid_step_multiplier)) + offset.y;
|
||||
_snap_if_closer(p_target, grid_output, output, snapped, 0.0, -1.0);
|
||||
} else if ((p_modes & SNAP_PIXEL) && snap_pixel && rotation == 0.0) {
|
||||
// Pixel
|
||||
output = p_target.snapped(Size2(1, 1));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
|
||||
float offset = snap_relative ? p_start : p_target;
|
||||
return (snap_rotation && snap_rotation_step != 0) ? Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset : p_target;
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
|
||||
|
||||
Ref<InputEventKey> k = p_ev;
|
||||
@ -243,7 +370,7 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
|
||||
if (selection.size() && viewport->get_rect().has_point(mouse_pos)) {
|
||||
//just in case, make it work if over viewport
|
||||
mouse_pos = transform.affine_inverse().xform(mouse_pos);
|
||||
mouse_pos = snap_point(mouse_pos);
|
||||
mouse_pos = snap_point(mouse_pos, SNAP_DEFAULT, _get_single_item());
|
||||
|
||||
_edit_set_pivot(mouse_pos);
|
||||
}
|
||||
@ -284,26 +411,6 @@ Object *CanvasItemEditor::_get_editor_data(Object *p_what) {
|
||||
return memnew(CanvasItemEditorSelectedItem);
|
||||
}
|
||||
|
||||
inline float _snap_scalar(float p_offset, float p_step, bool p_snap_relative, float p_target, float p_start) {
|
||||
float offset = p_snap_relative ? p_start : p_offset;
|
||||
return p_step != 0 ? Math::stepify(p_target - offset, p_step) + offset : p_target;
|
||||
}
|
||||
|
||||
Vector2 CanvasItemEditor::snap_point(Vector2 p_target, Vector2 p_start) const {
|
||||
if (snap_grid) {
|
||||
p_target.x = _snap_scalar(grid_offset.x, grid_step.x * Math::pow(2.0, grid_step_multiplier), snap_relative, p_target.x, p_start.x);
|
||||
p_target.y = _snap_scalar(grid_offset.y, grid_step.y * Math::pow(2.0, grid_step_multiplier), snap_relative, p_target.y, p_start.y);
|
||||
}
|
||||
if (snap_pixel)
|
||||
p_target = p_target.snapped(Size2(1, 1));
|
||||
|
||||
return p_target;
|
||||
}
|
||||
|
||||
float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
|
||||
return snap_rotation ? _snap_scalar(snap_rotation_offset, snap_rotation_step, snap_relative, p_target, p_start) : p_target;
|
||||
}
|
||||
|
||||
Dictionary CanvasItemEditor::get_state() const {
|
||||
|
||||
Dictionary state;
|
||||
@ -677,7 +784,7 @@ int CanvasItemEditor::get_item_count() {
|
||||
return ic;
|
||||
}
|
||||
|
||||
CanvasItem *CanvasItemEditor::get_single_item() {
|
||||
CanvasItem *CanvasItemEditor::_get_single_item() {
|
||||
|
||||
Map<Node *, Object *> &selection = editor_selection->get_selection();
|
||||
|
||||
@ -702,7 +809,7 @@ CanvasItem *CanvasItemEditor::get_single_item() {
|
||||
|
||||
CanvasItemEditor::DragType CanvasItemEditor::_get_resize_handle_drag_type(const Point2 &p_click, Vector2 &r_point) {
|
||||
// Returns a drag type if a resize handle is clicked
|
||||
CanvasItem *canvas_item = get_single_item();
|
||||
CanvasItem *canvas_item = _get_single_item();
|
||||
|
||||
ERR_FAIL_COND_V(!canvas_item, DRAG_NONE);
|
||||
|
||||
@ -766,35 +873,7 @@ CanvasItemEditor::DragType CanvasItemEditor::_get_resize_handle_drag_type(const
|
||||
return DRAG_NONE;
|
||||
}
|
||||
|
||||
float CanvasItemEditor::_anchor_snap(float p_anchor, bool *p_snapped, float p_opposite_anchor) {
|
||||
bool snapped = false;
|
||||
float dist, dist_min = 0.0;
|
||||
float radius = 0.05 / zoom;
|
||||
float basic_anchors[3] = { 0.0, 0.5, 1.0 };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
dist = fabs(p_anchor - basic_anchors[i]);
|
||||
if (dist < radius) {
|
||||
if (!snapped || dist <= dist_min) {
|
||||
p_anchor = basic_anchors[i];
|
||||
dist_min = dist;
|
||||
snapped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
dist = fabs(p_anchor - p_opposite_anchor);
|
||||
if (p_opposite_anchor >= 0 && dist < radius) {
|
||||
if (!snapped || dist <= dist_min) {
|
||||
p_anchor = p_opposite_anchor;
|
||||
dist_min = dist;
|
||||
snapped = true;
|
||||
}
|
||||
}
|
||||
if (p_snapped)
|
||||
*p_snapped = snapped;
|
||||
return p_anchor;
|
||||
}
|
||||
|
||||
Vector2 CanvasItemEditor::_anchor_to_position(Control *p_control, Vector2 anchor) {
|
||||
Vector2 CanvasItemEditor::_anchor_to_position(const Control *p_control, Vector2 anchor) {
|
||||
ERR_FAIL_COND_V(!p_control, Vector2());
|
||||
|
||||
Transform2D parent_transform = p_control->get_transform().affine_inverse();
|
||||
@ -803,7 +882,7 @@ Vector2 CanvasItemEditor::_anchor_to_position(Control *p_control, Vector2 anchor
|
||||
return parent_transform.xform(Vector2(parent_size.x * anchor.x, parent_size.y * anchor.y));
|
||||
}
|
||||
|
||||
Vector2 CanvasItemEditor::_position_to_anchor(Control *p_control, Vector2 position) {
|
||||
Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 position) {
|
||||
ERR_FAIL_COND_V(!p_control, Vector2());
|
||||
Size2 parent_size = p_control->get_parent_area_size();
|
||||
|
||||
@ -812,7 +891,7 @@ Vector2 CanvasItemEditor::_position_to_anchor(Control *p_control, Vector2 positi
|
||||
|
||||
CanvasItemEditor::DragType CanvasItemEditor::_get_anchor_handle_drag_type(const Point2 &p_click, Vector2 &r_point) {
|
||||
// Returns a drag type if an anchor handle is clicked
|
||||
CanvasItem *canvas_item = get_single_item();
|
||||
CanvasItem *canvas_item = _get_single_item();
|
||||
ERR_FAIL_COND_V(!canvas_item, DRAG_NONE);
|
||||
|
||||
Control *control = Object::cast_to<Control>(canvas_item);
|
||||
@ -1230,7 +1309,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
|
||||
// Set the pivot point
|
||||
Point2 mouse_pos = viewport_scrollable->get_transform().affine_inverse().xform(b->get_position());
|
||||
mouse_pos = transform.affine_inverse().xform(mouse_pos);
|
||||
mouse_pos = snap_point(mouse_pos);
|
||||
mouse_pos = snap_point(mouse_pos, SNAP_DEFAULT, _get_single_item());
|
||||
_edit_set_pivot(mouse_pos);
|
||||
}
|
||||
return;
|
||||
@ -1409,7 +1488,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
|
||||
}
|
||||
|
||||
// Single selected item
|
||||
CanvasItem *canvas_item = get_single_item();
|
||||
CanvasItem *canvas_item = _get_single_item();
|
||||
if (canvas_item) {
|
||||
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
||||
ERR_FAIL_COND(!se);
|
||||
@ -1614,6 +1693,10 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
|
||||
bool uniform = m->get_shift();
|
||||
bool symmetric = m->get_alt();
|
||||
|
||||
Vector2 drag_vector =
|
||||
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) -
|
||||
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dfrom);
|
||||
|
||||
switch (drag) {
|
||||
case DRAG_ALL:
|
||||
case DRAG_NODE_2D:
|
||||
@ -1626,61 +1709,55 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DRAG_ANCHOR_TOP_LEFT:
|
||||
case DRAG_ANCHOR_TOP_RIGHT:
|
||||
case DRAG_ANCHOR_BOTTOM_RIGHT:
|
||||
case DRAG_ANCHOR_BOTTOM_LEFT:
|
||||
case DRAG_ANCHOR_ALL:
|
||||
if (uniform) {
|
||||
if (ABS(dto.x - drag_from.x) > ABS(dto.y - drag_from.y)) {
|
||||
dto.y = drag_from.y;
|
||||
} else {
|
||||
dto.x = drag_from.x;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Control *control = Object::cast_to<Control>(canvas_item);
|
||||
if (control) {
|
||||
// Drag and snap the anchor
|
||||
Vector2 anchor = _position_to_anchor(control, canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto - drag_from + drag_point_from));
|
||||
Transform2D c_trans_rev = canvas_item->get_global_transform_with_canvas().affine_inverse();
|
||||
|
||||
Vector2 anchor = c_trans_rev.xform(dto - drag_from + drag_point_from);
|
||||
anchor = _position_to_anchor(control, anchor);
|
||||
|
||||
Vector2 anchor_snapped = c_trans_rev.xform(snap_point(dto - drag_from + drag_point_from, SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_NODE_SIDES, _get_single_item()));
|
||||
anchor_snapped = _position_to_anchor(control, anchor_snapped).snapped(Vector2(0.00001, 0.00001));
|
||||
|
||||
bool use_y = Math::abs(drag_vector.y) > Math::abs(drag_vector.x);
|
||||
|
||||
switch (drag) {
|
||||
case DRAG_ANCHOR_TOP_LEFT:
|
||||
control->set_anchor(MARGIN_LEFT, (uniform) ? anchor.x : _anchor_snap(anchor.x, NULL, control->get_anchor(MARGIN_RIGHT)), false, false);
|
||||
control->set_anchor(MARGIN_TOP, (uniform) ? anchor.y : _anchor_snap(anchor.y, NULL, control->get_anchor(MARGIN_BOTTOM)), false, false);
|
||||
if (!uniform || (uniform && !use_y)) control->set_anchor(MARGIN_LEFT, anchor_snapped.x);
|
||||
if (!uniform || (uniform && use_y)) control->set_anchor(MARGIN_TOP, anchor_snapped.y);
|
||||
continue;
|
||||
break;
|
||||
case DRAG_ANCHOR_TOP_RIGHT:
|
||||
control->set_anchor(MARGIN_RIGHT, (uniform) ? anchor.x : _anchor_snap(anchor.x, NULL, control->get_anchor(MARGIN_LEFT)), false, false);
|
||||
control->set_anchor(MARGIN_TOP, (uniform) ? anchor.y : _anchor_snap(anchor.y, NULL, control->get_anchor(MARGIN_BOTTOM)), false, false);
|
||||
if (!uniform || (uniform && !use_y)) control->set_anchor(MARGIN_RIGHT, anchor_snapped.x);
|
||||
if (!uniform || (uniform && use_y)) control->set_anchor(MARGIN_TOP, anchor_snapped.y);
|
||||
continue;
|
||||
break;
|
||||
case DRAG_ANCHOR_BOTTOM_RIGHT:
|
||||
control->set_anchor(MARGIN_RIGHT, (uniform) ? anchor.x : _anchor_snap(anchor.x, NULL, control->get_anchor(MARGIN_LEFT)), false, false);
|
||||
control->set_anchor(MARGIN_BOTTOM, (uniform) ? anchor.y : _anchor_snap(anchor.y, NULL, control->get_anchor(MARGIN_TOP)), false, false);
|
||||
continue;
|
||||
if (!uniform || (uniform && !use_y)) control->set_anchor(MARGIN_RIGHT, anchor_snapped.x);
|
||||
if (!uniform || (uniform && use_y)) control->set_anchor(MARGIN_BOTTOM, anchor_snapped.y);
|
||||
break;
|
||||
case DRAG_ANCHOR_BOTTOM_LEFT:
|
||||
control->set_anchor(MARGIN_LEFT, (uniform) ? anchor.x : _anchor_snap(anchor.x, NULL, control->get_anchor(MARGIN_RIGHT)), false, false);
|
||||
control->set_anchor(MARGIN_BOTTOM, (uniform) ? anchor.y : _anchor_snap(anchor.y, NULL, control->get_anchor(MARGIN_TOP)), false, false);
|
||||
if (!uniform || (uniform && !use_y)) control->set_anchor(MARGIN_LEFT, anchor_snapped.x);
|
||||
if (!uniform || (uniform && use_y)) control->set_anchor(MARGIN_BOTTOM, anchor_snapped.y);
|
||||
continue;
|
||||
break;
|
||||
case DRAG_ANCHOR_ALL:
|
||||
control->set_anchor(MARGIN_LEFT, (uniform) ? anchor.x : _anchor_snap(anchor.x));
|
||||
control->set_anchor(MARGIN_RIGHT, (uniform) ? anchor.x : _anchor_snap(anchor.x));
|
||||
control->set_anchor(MARGIN_TOP, (uniform) ? anchor.y : _anchor_snap(anchor.y));
|
||||
control->set_anchor(MARGIN_BOTTOM, (uniform) ? anchor.y : _anchor_snap(anchor.y));
|
||||
if (!uniform || (uniform && !use_y)) control->set_anchor(MARGIN_LEFT, anchor_snapped.x);
|
||||
if (!uniform || (uniform && !use_y)) control->set_anchor(MARGIN_RIGHT, anchor_snapped.x);
|
||||
if (!uniform || (uniform && use_y)) control->set_anchor(MARGIN_TOP, anchor_snapped.y);
|
||||
if (!uniform || (uniform && use_y)) control->set_anchor(MARGIN_BOTTOM, anchor_snapped.y);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dfrom = drag_point_from;
|
||||
dto = snap_point(dto, drag_point_from);
|
||||
dto = snap_point(dto, SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, _get_single_item());
|
||||
|
||||
Vector2 drag_vector =
|
||||
drag_vector =
|
||||
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) -
|
||||
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dfrom);
|
||||
|
||||
@ -2096,7 +2173,7 @@ void CanvasItemEditor::_draw_grid() {
|
||||
void CanvasItemEditor::_draw_selection() {
|
||||
bool pivot_found = false;
|
||||
Ref<Texture> pivot_icon = get_icon("EditorPivot", "EditorIcons");
|
||||
bool single = get_single_item() != NULL;
|
||||
bool single = _get_single_item() != NULL;
|
||||
RID ci = viewport->get_canvas_item();
|
||||
|
||||
Map<Node *, Object *> &selection = editor_selection->get_selection();
|
||||
@ -2222,7 +2299,7 @@ void CanvasItemEditor::_draw_selection() {
|
||||
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);
|
||||
_anchor_snap(anchors_values[i], &snapped);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -4021,7 +4098,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
|
||||
target_pos -= texture_size / 2;
|
||||
}
|
||||
// there's nothing to be used as source position so snapping will work as absolute if enabled
|
||||
target_pos = canvas->snap_point(target_pos, Vector2());
|
||||
target_pos = canvas->snap_point(target_pos);
|
||||
editor_data->get_undo_redo().add_do_method(child, "set_position", target_pos);
|
||||
}
|
||||
|
||||
@ -4055,22 +4132,13 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
|
||||
editor_data->get_undo_redo().add_do_method(sed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
|
||||
editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
|
||||
|
||||
Point2 pos;
|
||||
Node2D *parent_node2d = Object::cast_to<Node2D>(parent);
|
||||
if (parent_node2d) {
|
||||
pos = parent_node2d->get_global_position();
|
||||
} else {
|
||||
Control *parent_control = Object::cast_to<Control>(parent);
|
||||
if (parent_control) {
|
||||
pos = parent_control->get_global_position();
|
||||
}
|
||||
CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
|
||||
if (parent_ci) {
|
||||
Vector2 target_pos = canvas->get_canvas_transform().affine_inverse().xform(p_point);
|
||||
target_pos = canvas->snap_point(target_pos);
|
||||
target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
|
||||
editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos);
|
||||
}
|
||||
Transform2D trans = canvas->get_canvas_transform();
|
||||
Vector2 target_pos = (p_point - trans.get_origin()) / trans.get_scale().x - pos;
|
||||
// in relative snapping it may be useful for the user to take the original node position into account
|
||||
Vector2 start_pos = Object::cast_to<Node2D>(instanced_scene) ? Object::cast_to<Node2D>(instanced_scene)->get_position() : target_pos;
|
||||
target_pos = canvas->snap_point(target_pos, start_pos);
|
||||
editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -70,7 +70,6 @@ class CanvasItemEditor : public VBoxContainer {
|
||||
EditorNode *editor;
|
||||
|
||||
enum Tool {
|
||||
|
||||
TOOL_SELECT,
|
||||
TOOL_LIST_SELECT,
|
||||
TOOL_MOVE,
|
||||
@ -318,9 +317,8 @@ class CanvasItemEditor : public VBoxContainer {
|
||||
void _prepare_drag(const Point2 &p_click_pos);
|
||||
DragType _get_anchor_handle_drag_type(const Point2 &p_click, Vector2 &r_point);
|
||||
|
||||
float _anchor_snap(float p_anchor, bool *p_snapped = NULL, float p_opposite_anchor = -1);
|
||||
Vector2 _anchor_to_position(Control *p_control, Vector2 anchor);
|
||||
Vector2 _position_to_anchor(Control *p_control, Vector2 position);
|
||||
Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor);
|
||||
Vector2 _position_to_anchor(const Control *p_control, Vector2 position);
|
||||
|
||||
void _popup_callback(int p_op);
|
||||
bool updating_scroll;
|
||||
@ -345,7 +343,7 @@ class CanvasItemEditor : public VBoxContainer {
|
||||
|
||||
Object *_get_editor_data(Object *p_what);
|
||||
|
||||
CanvasItem *get_single_item();
|
||||
CanvasItem *_get_single_item();
|
||||
int get_item_count();
|
||||
void _keying_changed();
|
||||
|
||||
@ -370,6 +368,9 @@ class CanvasItemEditor : public VBoxContainer {
|
||||
|
||||
void _focus_selection(int p_op);
|
||||
|
||||
void _snap_if_closer(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation = 0.0, float p_radius = 10.0);
|
||||
void _snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap);
|
||||
|
||||
void _set_anchors_preset(Control::LayoutPreset p_preset);
|
||||
void _set_full_rect();
|
||||
|
||||
@ -420,7 +421,18 @@ protected:
|
||||
static CanvasItemEditor *singleton;
|
||||
|
||||
public:
|
||||
Vector2 snap_point(Vector2 p_target, Vector2 p_start = Vector2(0, 0)) const;
|
||||
enum SnapMode {
|
||||
SNAP_GRID = 1 << 0,
|
||||
SNAP_PIXEL = 1 << 1,
|
||||
SNAP_NODE_PARENT = 1 << 2,
|
||||
SNAP_NODE_ANCHORS = 1 << 3,
|
||||
SNAP_NODE_SIDES = 1 << 4,
|
||||
SNAP_OTHER_NODES = 1 << 5,
|
||||
|
||||
SNAP_DEFAULT = 0x03,
|
||||
};
|
||||
|
||||
Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, const CanvasItem *p_canvas_item = NULL);
|
||||
float snap_angle(float p_target, float p_start = 0) const;
|
||||
|
||||
Transform2D get_canvas_transform() const { return transform; }
|
||||
|
Loading…
Reference in New Issue
Block a user