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 a button to clear curve points in the Path2D editor #81325

Merged
merged 1 commit into from
Jan 5, 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
107 changes: 92 additions & 15 deletions editor/plugins/path_2d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/menu_button.h"

void Path2DEditor::_notification(int p_what) {
Expand All @@ -48,6 +49,7 @@ void Path2DEditor::_notification(int p_what) {
curve_create->set_icon(get_editor_theme_icon(SNAME("CurveCreate")));
curve_del->set_icon(get_editor_theme_icon(SNAME("CurveDelete")));
curve_close->set_icon(get_editor_theme_icon(SNAME("CurveClose")));
curve_clear_points->set_icon(get_editor_theme_icon(SNAME("Clear")));
} break;
}
}
Expand All @@ -68,7 +70,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}

if (!node->get_curve().is_valid()) {
if (node->get_curve().is_null()) {
return false;
}

Expand Down Expand Up @@ -121,7 +123,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {

// Check for point deletion.
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if ((mb->get_button_index() == MouseButton::RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) {
if ((mb->get_button_index() == MouseButton::RIGHT && (mode == MODE_EDIT || mode == MODE_CREATE)) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) {
if (dist_to_p < grab_threshold) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(curve.ptr(), "remove_point", i);
Expand Down Expand Up @@ -364,7 +366,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}

void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid()) {
if (!node || !node->is_visible_in_tree() || node->get_curve().is_null()) {
return;
}

Expand Down Expand Up @@ -437,12 +439,12 @@ void Path2DEditor::edit(Node *p_path2d) {

if (p_path2d) {
node = Object::cast_to<Path2D>(p_path2d);

if (!node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed))) {
node->connect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed));
}

} else {
// node may have been deleted at this point
// The node may have been deleted at this point.
if (node && node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed))) {
node->disconnect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed));
}
Expand All @@ -452,6 +454,8 @@ void Path2DEditor::edit(Node *p_path2d) {

void Path2DEditor::_bind_methods() {
//ClassDB::bind_method(D_METHOD("_menu_option"),&Path2DEditor::_menu_option);
ClassDB::bind_method(D_METHOD("_clear_curve_points"), &Path2DEditor::_clear_curve_points);
ClassDB::bind_method(D_METHOD("_restore_curve_points"), &Path2DEditor::_restore_curve_points);
}

void Path2DEditor::_mode_selected(int p_mode) {
Expand All @@ -475,32 +479,46 @@ void Path2DEditor::_mode_selected(int p_mode) {
curve_edit->set_pressed(false);
curve_edit_curve->set_pressed(false);
curve_del->set_pressed(true);
} else if (p_mode == ACTION_CLOSE) {
//?

if (!node->get_curve().is_valid()) {
} else if (p_mode == MODE_CLOSE) {
if (node->get_curve().is_null()) {
return;
}
if (node->get_curve()->get_point_count() < 3) {
return;
}

Vector2 begin = node->get_curve()->get_point_position(0);
Vector2 end = node->get_curve()->get_point_position(node->get_curve()->get_point_count() - 1);

if (begin.is_equal_approx(end)) {
return;
}

EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Point from Curve"));

undo_redo->create_action(TTR("Close the Curve"));
undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin);
undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return;
}
} else if (p_mode == MODE_CLEAR_POINTS) {
if (node->get_curve().is_null()) {
return;
}
if (node->get_curve()->get_point_count() == 0) {
return;
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
PackedVector2Array points = node->get_curve()->get_points().duplicate();

undo_redo->create_action(TTR("Clear Curve Points"), UndoRedo::MERGE_DISABLE, node);
undo_redo->add_do_method(this, "_clear_curve_points", node);
undo_redo->add_undo_method(this, "_restore_curve_points", node, points);
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return;
}
mode = Mode(p_mode);
}

Expand All @@ -523,6 +541,52 @@ void Path2DEditor::_handle_option_pressed(int p_option) {
}
}

void Path2DEditor::_confirm_clear_points() {
if (!node || node->get_curve().is_null()) {
return;
}
if (node->get_curve()->get_point_count() == 0) {
return;
}
clear_points_dialog->reset_size();
clear_points_dialog->popup_centered();
}

void Path2DEditor::_clear_curve_points(Path2D *p_path2d) {
if (!p_path2d || p_path2d->get_curve().is_null()) {
return;
}
Ref<Curve2D> curve = p_path2d->get_curve();

if (curve->get_point_count() == 0) {
return;
}
curve->clear_points();

if (node == p_path2d) {
_mode_selected(MODE_CREATE);
}
}

void Path2DEditor::_restore_curve_points(Path2D *p_path2d, const PackedVector2Array &p_points) {
if (!p_path2d || p_path2d->get_curve().is_null()) {
return;
}
Ref<Curve2D> curve = p_path2d->get_curve();

if (curve->get_point_count() > 0) {
curve->clear_points();
}

for (int i = 0; i < p_points.size(); i += 3) {
curve->add_point(p_points[i + 2], p_points[i], p_points[i + 1]); // The Curve2D::points pattern is [point_in, point_out, point_position].
}

if (node == p_path2d) {
_mode_selected(MODE_EDIT);
}
}

Path2DEditor::Path2DEditor() {
canvas_item_editor = nullptr;
mirror_handle_angle = true;
Expand Down Expand Up @@ -553,7 +617,7 @@ Path2DEditor::Path2DEditor() {
curve_create->set_theme_type_variation("FlatButton");
curve_create->set_toggle_mode(true);
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip_text(TTR("Add Point (in empty space)"));
curve_create->set_tooltip_text(TTR("Add Point (in empty space)") + "\n" + TTR("Right Click: Delete Point"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CREATE));
add_child(curve_create);

Expand All @@ -569,9 +633,22 @@ Path2DEditor::Path2DEditor() {
curve_close->set_theme_type_variation("FlatButton");
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip_text(TTR("Close Curve"));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(ACTION_CLOSE));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CLOSE));
add_child(curve_close);

curve_clear_points = memnew(Button);
curve_clear_points->set_theme_type_variation("FlatButton");
curve_clear_points->set_focus_mode(Control::FOCUS_NONE);
curve_clear_points->set_tooltip_text(TTR("Clear Points"));
curve_clear_points->connect("pressed", callable_mp(this, &Path2DEditor::_confirm_clear_points));
add_child(curve_clear_points);

clear_points_dialog = memnew(ConfirmationDialog);
clear_points_dialog->set_title(TTR("Please Confirm..."));
clear_points_dialog->set_text(TTR("Remove all curve points?"));
clear_points_dialog->connect("confirmed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CLEAR_POINTS));
add_child(clear_points_dialog);

PopupMenu *menu;

handle_menu = memnew(MenuButton);
Expand Down
22 changes: 15 additions & 7 deletions editor/plugins/path_2d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,40 +36,45 @@
#include "scene/gui/box_container.h"

class CanvasItemEditor;
class ConfirmationDialog;
class MenuButton;

class Path2DEditor : public HBoxContainer {
GDCLASS(Path2DEditor, HBoxContainer);

friend class Path2DEditorPlugin;
AttackButton marked this conversation as resolved.
Show resolved Hide resolved

CanvasItemEditor *canvas_item_editor = nullptr;
Panel *panel = nullptr;
Path2D *node = nullptr;

HBoxContainer *base_hb = nullptr;

enum Mode {
MODE_CREATE,
MODE_EDIT,
MODE_EDIT_CURVE,
MODE_DELETE,
ACTION_CLOSE
MODE_CLOSE,
MODE_CLEAR_POINTS,
};

Mode mode;
Button *curve_clear_points = nullptr;
Button *curve_close = nullptr;
Button *curve_create = nullptr;
Button *curve_del = nullptr;
Button *curve_edit = nullptr;
Button *curve_edit_curve = nullptr;
Button *curve_del = nullptr;
Button *curve_close = nullptr;
MenuButton *handle_menu = nullptr;

ConfirmationDialog *clear_points_dialog = nullptr;

bool mirror_handle_angle;
bool mirror_handle_length;
bool on_edge;

enum HandleOption {
HANDLE_OPTION_ANGLE,
HANDLE_OPTION_LENGTH
HANDLE_OPTION_LENGTH,
};

enum Action {
Expand All @@ -91,7 +96,10 @@ class Path2DEditor : public HBoxContainer {
void _handle_option_pressed(int p_option);

void _node_visibility_changed();
friend class Path2DEditorPlugin;

void _confirm_clear_points();
void _clear_curve_points(Path2D *p_path2d);
void _restore_curve_points(Path2D *p_path2d, const PackedVector2Array &p_points);

protected:
void _notification(int p_what);
Expand Down
4 changes: 4 additions & 0 deletions scene/resources/curve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,10 @@ real_t Curve2D::get_bake_interval() const {
return bake_interval;
}

PackedVector2Array Curve2D::get_points() const {
return _get_data()["points"];
}

Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
// Brute force method.

Expand Down
1 change: 1 addition & 0 deletions scene/resources/curve.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class Curve2D : public Resource {
real_t get_baked_length() const;
Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const;
Transform2D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false) const;
PackedVector2Array get_points() const;
PackedVector2Array get_baked_points() const; //useful for going through
Vector2 get_closest_point(const Vector2 &p_to_point) const;
real_t get_closest_offset(const Vector2 &p_to_point) const;
Expand Down
Loading