|
@@ -70,8 +70,9 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
|
|
if (!node->get_curve().is_valid())
|
|
|
return false;
|
|
|
|
|
|
- Ref<InputEventMouseButton> mb = p_event;
|
|
|
+ real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
|
|
|
|
|
|
+ Ref<InputEventMouseButton> mb = p_event;
|
|
|
if (mb.is_valid()) {
|
|
|
|
|
|
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
|
|
@@ -79,8 +80,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
|
|
Vector2 gpoint = mb->get_position();
|
|
|
Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
|
|
|
|
|
|
- real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
|
|
|
-
|
|
|
if (mb->is_pressed() && action == ACTION_NONE) {
|
|
|
|
|
|
Ref<Curve2D> curve = node->get_curve();
|
|
@@ -179,6 +178,41 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ // Check for segment split.
|
|
|
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mode == MODE_EDIT && on_edge == true) {
|
|
|
+ Vector2 gpoint = mb->get_position();
|
|
|
+ Ref<Curve2D> curve = node->get_curve();
|
|
|
+
|
|
|
+ int insertion_point = -1;
|
|
|
+ float mbLength = curve->get_closest_offset(xform.affine_inverse().xform(gpoint));
|
|
|
+ int len = curve->get_point_count();
|
|
|
+ for (int i = 0; i < len - 1; i++) {
|
|
|
+ float compareLength = curve->get_closest_offset(curve->get_point_position(i + 1));
|
|
|
+ if (mbLength >= curve->get_closest_offset(curve->get_point_position(i)) && mbLength <= compareLength)
|
|
|
+ insertion_point = i;
|
|
|
+ }
|
|
|
+ if (insertion_point == -1)
|
|
|
+ insertion_point = curve->get_point_count() - 2;
|
|
|
+
|
|
|
+ undo_redo->create_action(TTR("Split Curve"));
|
|
|
+ undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint), Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
|
|
|
+ undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1);
|
|
|
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
|
|
|
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
|
|
|
+ undo_redo->commit_action();
|
|
|
+
|
|
|
+ action = ACTION_MOVING_POINT;
|
|
|
+ action_point = insertion_point + 1;
|
|
|
+ moving_from = curve->get_point_position(action_point);
|
|
|
+ moving_screen_from = gpoint;
|
|
|
+
|
|
|
+ canvas_item_editor->update_viewport();
|
|
|
+
|
|
|
+ on_edge = false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
// Check for point movement completion.
|
|
|
if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && action != ACTION_NONE) {
|
|
|
|
|
@@ -245,6 +279,49 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
|
|
|
|
|
if (mm.is_valid()) {
|
|
|
|
|
|
+ if (action == ACTION_NONE && mode == MODE_EDIT) {
|
|
|
+ // Handle Edge Follow
|
|
|
+ bool old_edge = on_edge;
|
|
|
+
|
|
|
+ Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
|
|
|
+ Vector2 gpoint = mm->get_position();
|
|
|
+
|
|
|
+ Ref<Curve2D> curve = node->get_curve();
|
|
|
+ if (curve == NULL) return true;
|
|
|
+ if (curve->get_point_count() < 2) return true;
|
|
|
+
|
|
|
+ // Find edge
|
|
|
+ edge_point = xform.xform(curve->get_closest_point(xform.affine_inverse().xform(mm->get_position())));
|
|
|
+ on_edge = false;
|
|
|
+ if (edge_point.distance_to(gpoint) <= grab_threshold) {
|
|
|
+ on_edge = true;
|
|
|
+ }
|
|
|
+ // However, if near a control point or its in-out handles then not on edge
|
|
|
+ int len = curve->get_point_count();
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ Vector2 pp = curve->get_point_position(i);
|
|
|
+ Vector2 p = xform.xform(pp);
|
|
|
+ if (p.distance_to(gpoint) <= grab_threshold) {
|
|
|
+ on_edge = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ p = xform.xform(pp + curve->get_point_in(i));
|
|
|
+ if (p.distance_to(gpoint) <= grab_threshold) {
|
|
|
+ on_edge = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ p = xform.xform(pp + curve->get_point_out(i));
|
|
|
+ if (p.distance_to(gpoint) <= grab_threshold) {
|
|
|
+ on_edge = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (on_edge || old_edge != on_edge) {
|
|
|
+ canvas_item_editor->update_viewport();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (action != ACTION_NONE) {
|
|
|
// Handle point/control movement.
|
|
|
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
|
|
@@ -309,7 +386,6 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
|
|
Control *vpc = canvas_item_editor->get_viewport_control();
|
|
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
-
|
|
|
Vector2 point = xform.xform(curve->get_point_position(i));
|
|
|
vpc->draw_texture_rect(handle, Rect2(point - handle_size * 0.5, handle_size), false, Color(1, 1, 1, 1));
|
|
|
|
|
@@ -325,6 +401,11 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
|
|
vpc->draw_texture_rect(handle, Rect2(pointin - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3));
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (on_edge) {
|
|
|
+ Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons");
|
|
|
+ p_overlay->draw_texture(add_handle, edge_point - add_handle->get_size() * 0.5);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void Path2DEditor::_node_visibility_changed() {
|
|
@@ -442,6 +523,7 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
|
|
|
undo_redo = editor->get_undo_redo();
|
|
|
mirror_handle_angle = true;
|
|
|
mirror_handle_length = true;
|
|
|
+ on_edge = false;
|
|
|
|
|
|
mode = MODE_EDIT;
|
|
|
action = ACTION_NONE;
|
|
@@ -455,7 +537,7 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
|
|
|
curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
|
|
|
curve_edit->set_toggle_mode(true);
|
|
|
curve_edit->set_focus_mode(Control::FOCUS_NONE);
|
|
|
- curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
|
|
|
+ curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
|
|
|
curve_edit->connect("pressed", this, "_mode_selected", varray(MODE_EDIT));
|
|
|
base_hb->add_child(curve_edit);
|
|
|
curve_edit_curve = memnew(ToolButton);
|
|
@@ -469,7 +551,7 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
|
|
|
curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
|
|
|
curve_create->set_toggle_mode(true);
|
|
|
curve_create->set_focus_mode(Control::FOCUS_NONE);
|
|
|
- curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
|
|
|
+ curve_create->set_tooltip(TTR("Add Point (in empty space)"));
|
|
|
curve_create->connect("pressed", this, "_mode_selected", varray(MODE_CREATE));
|
|
|
base_hb->add_child(curve_create);
|
|
|
curve_del = memnew(ToolButton);
|