1 /*************************************************************************/
2 /* path_2d_editor_plugin.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "path_2d_editor_plugin.h"
32
33 #include "canvas_item_editor_plugin.h"
34 #include "core/os/file_access.h"
35 #include "core/os/keyboard.h"
36 #include "editor/editor_scale.h"
37 #include "editor/editor_settings.h"
38
_notification(int p_what)39 void Path2DEditor::_notification(int p_what) {
40
41 switch (p_what) {
42
43 case NOTIFICATION_READY: {
44
45 //button_create->set_icon( get_icon("Edit","EditorIcons"));
46 //button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
47 //set_pressed_button(button_edit);
48 //button_edit->set_pressed(true);
49
50 } break;
51 case NOTIFICATION_PHYSICS_PROCESS: {
52
53 } break;
54 }
55 }
_node_removed(Node * p_node)56 void Path2DEditor::_node_removed(Node *p_node) {
57
58 if (p_node == node) {
59 node = NULL;
60 hide();
61 }
62 }
63
forward_gui_input(const Ref<InputEvent> & p_event)64 bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
65 if (!node)
66 return false;
67
68 if (!node->is_visible_in_tree())
69 return false;
70
71 if (!node->get_curve().is_valid())
72 return false;
73
74 real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
75
76 Ref<InputEventMouseButton> mb = p_event;
77 if (mb.is_valid()) {
78
79 Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
80
81 Vector2 gpoint = mb->get_position();
82 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())));
83
84 if (mb->is_pressed() && action == ACTION_NONE) {
85
86 Ref<Curve2D> curve = node->get_curve();
87
88 for (int i = 0; i < curve->get_point_count(); i++) {
89
90 real_t dist_to_p = gpoint.distance_to(xform.xform(curve->get_point_position(i)));
91 real_t dist_to_p_out = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_out(i)));
92 real_t dist_to_p_in = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_in(i)));
93
94 // Check for point movement start (for point + in/out controls).
95 if (mb->get_button_index() == BUTTON_LEFT) {
96 if (mode == MODE_EDIT && !mb->get_shift() && dist_to_p < grab_threshold) {
97 // Points can only be moved in edit mode.
98
99 action = ACTION_MOVING_POINT;
100 action_point = i;
101 moving_from = curve->get_point_position(i);
102 moving_screen_from = gpoint;
103 return true;
104 } else if (mode == MODE_EDIT || mode == MODE_EDIT_CURVE) {
105 // In/out controls can be moved in multiple modes.
106 if (dist_to_p_out < grab_threshold && i < (curve->get_point_count() - 1)) {
107
108 action = ACTION_MOVING_OUT;
109 action_point = i;
110 moving_from = curve->get_point_out(i);
111 moving_screen_from = gpoint;
112 orig_in_length = curve->get_point_in(action_point).length();
113 return true;
114 } else if (dist_to_p_in < grab_threshold && i > 0) {
115
116 action = ACTION_MOVING_IN;
117 action_point = i;
118 moving_from = curve->get_point_in(i);
119 moving_screen_from = gpoint;
120 orig_out_length = curve->get_point_out(action_point).length();
121 return true;
122 }
123 }
124 }
125
126 // Check for point deletion.
127 if ((mb->get_button_index() == BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == BUTTON_LEFT && mode == MODE_DELETE)) {
128 if (dist_to_p < grab_threshold) {
129
130 undo_redo->create_action(TTR("Remove Point from Curve"));
131 undo_redo->add_do_method(curve.ptr(), "remove_point", i);
132 undo_redo->add_undo_method(curve.ptr(), "add_point", curve->get_point_position(i), curve->get_point_in(i), curve->get_point_out(i), i);
133 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
134 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
135 undo_redo->commit_action();
136 return true;
137 } else if (dist_to_p_out < grab_threshold) {
138
139 undo_redo->create_action(TTR("Remove Out-Control from Curve"));
140 undo_redo->add_do_method(curve.ptr(), "set_point_out", i, Vector2());
141 undo_redo->add_undo_method(curve.ptr(), "set_point_out", i, curve->get_point_out(i));
142 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
143 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
144 undo_redo->commit_action();
145 return true;
146 } else if (dist_to_p_in < grab_threshold) {
147
148 undo_redo->create_action(TTR("Remove In-Control from Curve"));
149 undo_redo->add_do_method(curve.ptr(), "set_point_in", i, Vector2());
150 undo_redo->add_undo_method(curve.ptr(), "set_point_in", i, curve->get_point_in(i));
151 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
152 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
153 undo_redo->commit_action();
154 return true;
155 }
156 }
157 }
158 }
159
160 // Check for point creation.
161 if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
162
163 Ref<Curve2D> curve = node->get_curve();
164
165 undo_redo->create_action(TTR("Add Point to Curve"));
166 undo_redo->add_do_method(curve.ptr(), "add_point", cpoint);
167 undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count());
168 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
169 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
170 undo_redo->commit_action();
171
172 action = ACTION_MOVING_POINT;
173 action_point = curve->get_point_count() - 1;
174 moving_from = curve->get_point_position(action_point);
175 moving_screen_from = gpoint;
176
177 canvas_item_editor->update_viewport();
178
179 return true;
180 }
181
182 // Check for segment split.
183 if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mode == MODE_EDIT && on_edge) {
184 Vector2 gpoint2 = mb->get_position();
185 Ref<Curve2D> curve = node->get_curve();
186
187 int insertion_point = -1;
188 float mbLength = curve->get_closest_offset(xform.affine_inverse().xform(gpoint2));
189 int len = curve->get_point_count();
190 for (int i = 0; i < len - 1; i++) {
191 float compareLength = curve->get_closest_offset(curve->get_point_position(i + 1));
192 if (mbLength >= curve->get_closest_offset(curve->get_point_position(i)) && mbLength <= compareLength)
193 insertion_point = i;
194 }
195 if (insertion_point == -1)
196 insertion_point = curve->get_point_count() - 2;
197
198 undo_redo->create_action(TTR("Split Curve"));
199 undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
200 undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1);
201 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
202 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
203 undo_redo->commit_action();
204
205 action = ACTION_MOVING_POINT;
206 action_point = insertion_point + 1;
207 moving_from = curve->get_point_position(action_point);
208 moving_screen_from = gpoint2;
209
210 canvas_item_editor->update_viewport();
211
212 on_edge = false;
213
214 return true;
215 }
216
217 // Check for point movement completion.
218 if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && action != ACTION_NONE) {
219
220 Ref<Curve2D> curve = node->get_curve();
221
222 Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
223 switch (action) {
224
225 case ACTION_NONE:
226 // N/A, handled in above condition.
227 break;
228
229 case ACTION_MOVING_POINT: {
230
231 undo_redo->create_action(TTR("Move Point in Curve"));
232 undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint);
233 undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from);
234 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
235 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
236 undo_redo->commit_action();
237
238 } break;
239
240 case ACTION_MOVING_IN: {
241
242 undo_redo->create_action(TTR("Move In-Control in Curve"));
243 undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, new_pos);
244 undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, moving_from);
245
246 if (mirror_handle_angle) {
247 undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length));
248 undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_out_length));
249 }
250 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
251 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
252 undo_redo->commit_action();
253
254 } break;
255
256 case ACTION_MOVING_OUT: {
257
258 undo_redo->create_action(TTR("Move Out-Control in Curve"));
259 undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, new_pos);
260 undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, moving_from);
261
262 if (mirror_handle_angle) {
263 undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length));
264 undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_in_length));
265 }
266 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
267 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
268 undo_redo->commit_action();
269
270 } break;
271 }
272
273 action = ACTION_NONE;
274
275 return true;
276 }
277 }
278
279 Ref<InputEventMouseMotion> mm = p_event;
280
281 if (mm.is_valid()) {
282
283 if (action == ACTION_NONE && mode == MODE_EDIT) {
284 // Handle Edge Follow
285 bool old_edge = on_edge;
286
287 Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
288 Vector2 gpoint = mm->get_position();
289
290 Ref<Curve2D> curve = node->get_curve();
291 if (curve == NULL) return true;
292 if (curve->get_point_count() < 2) return true;
293
294 // Find edge
295 edge_point = xform.xform(curve->get_closest_point(xform.affine_inverse().xform(mm->get_position())));
296 on_edge = false;
297 if (edge_point.distance_to(gpoint) <= grab_threshold) {
298 on_edge = true;
299 }
300 // However, if near a control point or its in-out handles then not on edge
301 int len = curve->get_point_count();
302 for (int i = 0; i < len; i++) {
303 Vector2 pp = curve->get_point_position(i);
304 Vector2 p = xform.xform(pp);
305 if (p.distance_to(gpoint) <= grab_threshold) {
306 on_edge = false;
307 break;
308 }
309 p = xform.xform(pp + curve->get_point_in(i));
310 if (p.distance_to(gpoint) <= grab_threshold) {
311 on_edge = false;
312 break;
313 }
314 p = xform.xform(pp + curve->get_point_out(i));
315 if (p.distance_to(gpoint) <= grab_threshold) {
316 on_edge = false;
317 break;
318 }
319 }
320 if (on_edge || old_edge != on_edge) {
321 canvas_item_editor->update_viewport();
322 return true;
323 }
324 }
325
326 if (action != ACTION_NONE) {
327 // Handle point/control movement.
328 Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
329 Vector2 gpoint = mm->get_position();
330 Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position())));
331
332 Ref<Curve2D> curve = node->get_curve();
333
334 Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
335
336 switch (action) {
337
338 case ACTION_NONE:
339 // N/A, handled in above condition.
340 break;
341
342 case ACTION_MOVING_POINT: {
343 curve->set_point_position(action_point, cpoint);
344 } break;
345
346 case ACTION_MOVING_IN: {
347 curve->set_point_in(action_point, new_pos);
348
349 if (mirror_handle_angle)
350 curve->set_point_out(action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length));
351 } break;
352
353 case ACTION_MOVING_OUT: {
354 curve->set_point_out(action_point, new_pos);
355
356 if (mirror_handle_angle)
357 curve->set_point_in(action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length));
358 } break;
359 }
360
361 canvas_item_editor->update_viewport();
362 return true;
363 }
364 }
365
366 return false;
367 }
368
forward_canvas_draw_over_viewport(Control * p_overlay)369 void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
370
371 if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid())
372 return;
373
374 Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
375
376 const Ref<Texture> path_sharp_handle = get_icon("EditorPathSharpHandle", "EditorIcons");
377 const Ref<Texture> path_smooth_handle = get_icon("EditorPathSmoothHandle", "EditorIcons");
378 // Both handle icons must be of the same size
379 const Size2 handle_size = path_sharp_handle->get_size();
380
381 const Ref<Texture> curve_handle = get_icon("EditorCurveHandle", "EditorIcons");
382 const Size2 curve_handle_size = curve_handle->get_size();
383
384 Ref<Curve2D> curve = node->get_curve();
385
386 int len = curve->get_point_count();
387 Control *vpc = canvas_item_editor->get_viewport_control();
388
389 for (int i = 0; i < len; i++) {
390 Vector2 point = xform.xform(curve->get_point_position(i));
391 // Determines the point icon to be used
392 bool smooth = false;
393
394 if (i < len - 1) {
395 Vector2 pointout = xform.xform(curve->get_point_position(i) + curve->get_point_out(i));
396 if (point != pointout) {
397 smooth = true;
398 // Draw the line with a dark and light color to be visible on all backgrounds
399 vpc->draw_line(point, pointout, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true);
400 vpc->draw_line(point, pointout, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true);
401 vpc->draw_texture_rect(curve_handle, Rect2(pointout - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75));
402 }
403 }
404
405 if (i > 0) {
406 Vector2 pointin = xform.xform(curve->get_point_position(i) + curve->get_point_in(i));
407 if (point != pointin) {
408 smooth = true;
409 // Draw the line with a dark and light color to be visible on all backgrounds
410 vpc->draw_line(point, pointin, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true);
411 vpc->draw_line(point, pointin, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true);
412 vpc->draw_texture_rect(curve_handle, Rect2(pointin - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75));
413 }
414 }
415
416 vpc->draw_texture_rect(
417 smooth ? path_smooth_handle : path_sharp_handle,
418 Rect2(point - handle_size * 0.5, handle_size),
419 false);
420 }
421
422 if (on_edge) {
423 Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons");
424 p_overlay->draw_texture(add_handle, edge_point - add_handle->get_size() * 0.5);
425 }
426 }
427
_node_visibility_changed()428 void Path2DEditor::_node_visibility_changed() {
429 if (!node)
430 return;
431
432 canvas_item_editor->update_viewport();
433 }
434
edit(Node * p_path2d)435 void Path2DEditor::edit(Node *p_path2d) {
436
437 if (!canvas_item_editor) {
438 canvas_item_editor = CanvasItemEditor::get_singleton();
439 }
440
441 if (p_path2d) {
442
443 node = Object::cast_to<Path2D>(p_path2d);
444 if (!node->is_connected("visibility_changed", this, "_node_visibility_changed"))
445 node->connect("visibility_changed", this, "_node_visibility_changed");
446
447 } else {
448
449 // node may have been deleted at this point
450 if (node && node->is_connected("visibility_changed", this, "_node_visibility_changed"))
451 node->disconnect("visibility_changed", this, "_node_visibility_changed");
452 node = NULL;
453 }
454 }
455
_bind_methods()456 void Path2DEditor::_bind_methods() {
457
458 //ClassDB::bind_method(D_METHOD("_menu_option"),&Path2DEditor::_menu_option);
459 ClassDB::bind_method(D_METHOD("_node_visibility_changed"), &Path2DEditor::_node_visibility_changed);
460 ClassDB::bind_method(D_METHOD("_mode_selected"), &Path2DEditor::_mode_selected);
461 ClassDB::bind_method(D_METHOD("_handle_option_pressed"), &Path2DEditor::_handle_option_pressed);
462 }
463
_mode_selected(int p_mode)464 void Path2DEditor::_mode_selected(int p_mode) {
465
466 if (p_mode == MODE_CREATE) {
467
468 curve_create->set_pressed(true);
469 curve_edit->set_pressed(false);
470 curve_edit_curve->set_pressed(false);
471 curve_del->set_pressed(false);
472 } else if (p_mode == MODE_EDIT) {
473
474 curve_create->set_pressed(false);
475 curve_edit->set_pressed(true);
476 curve_edit_curve->set_pressed(false);
477 curve_del->set_pressed(false);
478 } else if (p_mode == MODE_EDIT_CURVE) {
479
480 curve_create->set_pressed(false);
481 curve_edit->set_pressed(false);
482 curve_edit_curve->set_pressed(true);
483 curve_del->set_pressed(false);
484 } else if (p_mode == MODE_DELETE) {
485
486 curve_create->set_pressed(false);
487 curve_edit->set_pressed(false);
488 curve_edit_curve->set_pressed(false);
489 curve_del->set_pressed(true);
490 } else if (p_mode == ACTION_CLOSE) {
491
492 //?
493
494 if (!node->get_curve().is_valid())
495 return;
496 if (node->get_curve()->get_point_count() < 3)
497 return;
498
499 Vector2 begin = node->get_curve()->get_point_position(0);
500 Vector2 end = node->get_curve()->get_point_position(node->get_curve()->get_point_count() - 1);
501 if (begin.distance_to(end) < CMP_EPSILON)
502 return;
503
504 undo_redo->create_action(TTR("Remove Point from Curve"));
505 undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin);
506 undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count());
507 undo_redo->add_do_method(canvas_item_editor, "update_viewport");
508 undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
509 undo_redo->commit_action();
510 return;
511 }
512
513 mode = Mode(p_mode);
514 }
515
_handle_option_pressed(int p_option)516 void Path2DEditor::_handle_option_pressed(int p_option) {
517
518 PopupMenu *pm;
519 pm = handle_menu->get_popup();
520
521 switch (p_option) {
522 case HANDLE_OPTION_ANGLE: {
523 bool is_checked = pm->is_item_checked(HANDLE_OPTION_ANGLE);
524 mirror_handle_angle = !is_checked;
525 pm->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
526 pm->set_item_disabled(HANDLE_OPTION_LENGTH, !mirror_handle_angle);
527 } break;
528 case HANDLE_OPTION_LENGTH: {
529 bool is_checked = pm->is_item_checked(HANDLE_OPTION_LENGTH);
530 mirror_handle_length = !is_checked;
531 pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
532 } break;
533 }
534 }
535
Path2DEditor(EditorNode * p_editor)536 Path2DEditor::Path2DEditor(EditorNode *p_editor) {
537
538 canvas_item_editor = NULL;
539 editor = p_editor;
540 undo_redo = editor->get_undo_redo();
541 mirror_handle_angle = true;
542 mirror_handle_length = true;
543 on_edge = false;
544
545 mode = MODE_EDIT;
546 action = ACTION_NONE;
547
548 base_hb = memnew(HBoxContainer);
549 CanvasItemEditor::get_singleton()->add_control_to_menu_panel(base_hb);
550
551 sep = memnew(VSeparator);
552 base_hb->add_child(sep);
553 curve_edit = memnew(ToolButton);
554 curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
555 curve_edit->set_toggle_mode(true);
556 curve_edit->set_focus_mode(Control::FOCUS_NONE);
557 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"));
558 curve_edit->connect("pressed", this, "_mode_selected", varray(MODE_EDIT));
559 base_hb->add_child(curve_edit);
560 curve_edit_curve = memnew(ToolButton);
561 curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCurve", "EditorIcons"));
562 curve_edit_curve->set_toggle_mode(true);
563 curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
564 curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)"));
565 curve_edit_curve->connect("pressed", this, "_mode_selected", varray(MODE_EDIT_CURVE));
566 base_hb->add_child(curve_edit_curve);
567 curve_create = memnew(ToolButton);
568 curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
569 curve_create->set_toggle_mode(true);
570 curve_create->set_focus_mode(Control::FOCUS_NONE);
571 curve_create->set_tooltip(TTR("Add Point (in empty space)"));
572 curve_create->connect("pressed", this, "_mode_selected", varray(MODE_CREATE));
573 base_hb->add_child(curve_create);
574 curve_del = memnew(ToolButton);
575 curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons"));
576 curve_del->set_toggle_mode(true);
577 curve_del->set_focus_mode(Control::FOCUS_NONE);
578 curve_del->set_tooltip(TTR("Delete Point"));
579 curve_del->connect("pressed", this, "_mode_selected", varray(MODE_DELETE));
580 base_hb->add_child(curve_del);
581 curve_close = memnew(ToolButton);
582 curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveClose", "EditorIcons"));
583 curve_close->set_focus_mode(Control::FOCUS_NONE);
584 curve_close->set_tooltip(TTR("Close Curve"));
585 curve_close->connect("pressed", this, "_mode_selected", varray(ACTION_CLOSE));
586 base_hb->add_child(curve_close);
587
588 PopupMenu *menu;
589
590 handle_menu = memnew(MenuButton);
591 handle_menu->set_text(TTR("Options"));
592 base_hb->add_child(handle_menu);
593
594 menu = handle_menu->get_popup();
595 menu->add_check_item(TTR("Mirror Handle Angles"));
596 menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
597 menu->add_check_item(TTR("Mirror Handle Lengths"));
598 menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
599 menu->connect("id_pressed", this, "_handle_option_pressed");
600
601 base_hb->hide();
602
603 curve_edit->set_pressed(true);
604 }
605
edit(Object * p_object)606 void Path2DEditorPlugin::edit(Object *p_object) {
607
608 path2d_editor->edit(Object::cast_to<Node>(p_object));
609 }
610
handles(Object * p_object) const611 bool Path2DEditorPlugin::handles(Object *p_object) const {
612
613 return p_object->is_class("Path2D");
614 }
615
make_visible(bool p_visible)616 void Path2DEditorPlugin::make_visible(bool p_visible) {
617
618 if (p_visible) {
619 path2d_editor->show();
620 path2d_editor->base_hb->show();
621
622 } else {
623
624 path2d_editor->hide();
625 path2d_editor->base_hb->hide();
626 path2d_editor->edit(NULL);
627 }
628 }
629
Path2DEditorPlugin(EditorNode * p_node)630 Path2DEditorPlugin::Path2DEditorPlugin(EditorNode *p_node) {
631
632 editor = p_node;
633 path2d_editor = memnew(Path2DEditor(p_node));
634 CanvasItemEditor::get_singleton()->add_control_to_menu_panel(path2d_editor);
635 path2d_editor->hide();
636 }
637
~Path2DEditorPlugin()638 Path2DEditorPlugin::~Path2DEditorPlugin() {
639 }
640