1 /*************************************************************************/
2 /* canvas_item_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 "canvas_item_editor_plugin.h"
32
33 #include "core/os/input.h"
34 #include "core/os/keyboard.h"
35 #include "core/print_string.h"
36 #include "core/project_settings.h"
37 #include "editor/editor_node.h"
38 #include "editor/editor_scale.h"
39 #include "editor/editor_settings.h"
40 #include "editor/plugins/animation_player_editor_plugin.h"
41 #include "editor/plugins/script_editor_plugin.h"
42 #include "editor/script_editor_debugger.h"
43 #include "scene/2d/light_2d.h"
44 #include "scene/2d/particles_2d.h"
45 #include "scene/2d/polygon_2d.h"
46 #include "scene/2d/skeleton_2d.h"
47 #include "scene/2d/sprite.h"
48 #include "scene/2d/touch_screen_button.h"
49 #include "scene/gui/grid_container.h"
50 #include "scene/gui/nine_patch_rect.h"
51 #include "scene/gui/viewport_container.h"
52 #include "scene/main/canvas_layer.h"
53 #include "scene/main/viewport.h"
54 #include "scene/resources/packed_scene.h"
55
56 // Min and Max are power of two in order to play nicely with successive increment.
57 // That way, we can naturally reach a 100% zoom from boundaries.
58 #define MIN_ZOOM 1. / 128
59 #define MAX_ZOOM 128
60
61 #define RULER_WIDTH (15 * EDSCALE)
62 #define SCALE_HANDLE_DISTANCE 25
63
64 class SnapDialog : public ConfirmationDialog {
65
66 GDCLASS(SnapDialog, ConfirmationDialog);
67
68 friend class CanvasItemEditor;
69
70 SpinBox *grid_offset_x;
71 SpinBox *grid_offset_y;
72 SpinBox *grid_step_x;
73 SpinBox *grid_step_y;
74 SpinBox *primary_grid_steps;
75 SpinBox *rotation_offset;
76 SpinBox *rotation_step;
77 SpinBox *scale_step;
78
79 public:
SnapDialog()80 SnapDialog() {
81 const int SPIN_BOX_GRID_RANGE = 16384;
82 const int SPIN_BOX_ROTATION_RANGE = 360;
83 const float SPIN_BOX_SCALE_MIN = 0.01f;
84 const float SPIN_BOX_SCALE_MAX = 100;
85
86 Label *label;
87 VBoxContainer *container;
88 GridContainer *child_container;
89
90 set_title(TTR("Configure Snap"));
91
92 container = memnew(VBoxContainer);
93 add_child(container);
94
95 child_container = memnew(GridContainer);
96 child_container->set_columns(3);
97 container->add_child(child_container);
98
99 label = memnew(Label);
100 label->set_text(TTR("Grid Offset:"));
101 child_container->add_child(label);
102 label->set_h_size_flags(SIZE_EXPAND_FILL);
103
104 grid_offset_x = memnew(SpinBox);
105 grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE);
106 grid_offset_x->set_max(SPIN_BOX_GRID_RANGE);
107 grid_offset_x->set_allow_lesser(true);
108 grid_offset_x->set_allow_greater(true);
109 grid_offset_x->set_suffix("px");
110 grid_offset_x->set_h_size_flags(SIZE_EXPAND_FILL);
111 child_container->add_child(grid_offset_x);
112
113 grid_offset_y = memnew(SpinBox);
114 grid_offset_y->set_min(-SPIN_BOX_GRID_RANGE);
115 grid_offset_y->set_max(SPIN_BOX_GRID_RANGE);
116 grid_offset_y->set_allow_lesser(true);
117 grid_offset_y->set_allow_greater(true);
118 grid_offset_y->set_suffix("px");
119 grid_offset_y->set_h_size_flags(SIZE_EXPAND_FILL);
120 child_container->add_child(grid_offset_y);
121
122 label = memnew(Label);
123 label->set_text(TTR("Grid Step:"));
124 child_container->add_child(label);
125 label->set_h_size_flags(SIZE_EXPAND_FILL);
126
127 grid_step_x = memnew(SpinBox);
128 grid_step_x->set_min(0.01);
129 grid_step_x->set_max(SPIN_BOX_GRID_RANGE);
130 grid_step_x->set_allow_greater(true);
131 grid_step_x->set_suffix("px");
132 grid_step_x->set_h_size_flags(SIZE_EXPAND_FILL);
133 child_container->add_child(grid_step_x);
134
135 grid_step_y = memnew(SpinBox);
136 grid_step_y->set_min(0.01);
137 grid_step_y->set_max(SPIN_BOX_GRID_RANGE);
138 grid_step_y->set_allow_greater(true);
139 grid_step_y->set_suffix("px");
140 grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL);
141 child_container->add_child(grid_step_y);
142
143 child_container = memnew(GridContainer);
144 child_container->set_columns(2);
145 container->add_child(child_container);
146
147 label = memnew(Label);
148 label->set_text(TTR("Primary Line Every:"));
149 label->set_h_size_flags(SIZE_EXPAND_FILL);
150 child_container->add_child(label);
151
152 primary_grid_steps = memnew(SpinBox);
153 primary_grid_steps->set_min(0);
154 primary_grid_steps->set_step(1);
155 primary_grid_steps->set_max(100);
156 primary_grid_steps->set_allow_greater(true);
157 primary_grid_steps->set_suffix(TTR("steps"));
158 primary_grid_steps->set_h_size_flags(SIZE_EXPAND_FILL);
159 child_container->add_child(primary_grid_steps);
160
161 container->add_child(memnew(HSeparator));
162
163 // We need to create another GridContainer with the same column count,
164 // so we can put an HSeparator above
165 child_container = memnew(GridContainer);
166 child_container->set_columns(2);
167 container->add_child(child_container);
168
169 label = memnew(Label);
170 label->set_text(TTR("Rotation Offset:"));
171 child_container->add_child(label);
172 label->set_h_size_flags(SIZE_EXPAND_FILL);
173
174 rotation_offset = memnew(SpinBox);
175 rotation_offset->set_min(-SPIN_BOX_ROTATION_RANGE);
176 rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE);
177 rotation_offset->set_suffix("deg");
178 rotation_offset->set_h_size_flags(SIZE_EXPAND_FILL);
179 child_container->add_child(rotation_offset);
180
181 label = memnew(Label);
182 label->set_text(TTR("Rotation Step:"));
183 child_container->add_child(label);
184 label->set_h_size_flags(SIZE_EXPAND_FILL);
185
186 rotation_step = memnew(SpinBox);
187 rotation_step->set_min(-SPIN_BOX_ROTATION_RANGE);
188 rotation_step->set_max(SPIN_BOX_ROTATION_RANGE);
189 rotation_step->set_suffix("deg");
190 rotation_step->set_h_size_flags(SIZE_EXPAND_FILL);
191 child_container->add_child(rotation_step);
192
193 container->add_child(memnew(HSeparator));
194
195 child_container = memnew(GridContainer);
196 child_container->set_columns(2);
197 container->add_child(child_container);
198 label = memnew(Label);
199 label->set_text(TTR("Scale Step:"));
200 child_container->add_child(label);
201 label->set_h_size_flags(SIZE_EXPAND_FILL);
202
203 scale_step = memnew(SpinBox);
204 scale_step->set_min(SPIN_BOX_SCALE_MIN);
205 scale_step->set_max(SPIN_BOX_SCALE_MAX);
206 scale_step->set_allow_greater(true);
207 scale_step->set_h_size_flags(SIZE_EXPAND_FILL);
208 scale_step->set_step(0.01f);
209 child_container->add_child(scale_step);
210 }
211
set_fields(const Point2 p_grid_offset,const Point2 p_grid_step,const int p_primary_grid_steps,const float p_rotation_offset,const float p_rotation_step,const float p_scale_step)212 void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const float p_rotation_offset, const float p_rotation_step, const float p_scale_step) {
213 grid_offset_x->set_value(p_grid_offset.x);
214 grid_offset_y->set_value(p_grid_offset.y);
215 grid_step_x->set_value(p_grid_step.x);
216 grid_step_y->set_value(p_grid_step.y);
217 primary_grid_steps->set_value(p_primary_grid_steps);
218 rotation_offset->set_value(p_rotation_offset * (180 / Math_PI));
219 rotation_step->set_value(p_rotation_step * (180 / Math_PI));
220 scale_step->set_value(p_scale_step);
221 }
222
get_fields(Point2 & p_grid_offset,Point2 & p_grid_step,int & p_primary_grid_steps,float & p_rotation_offset,float & p_rotation_step,float & p_scale_step)223 void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, float &p_rotation_offset, float &p_rotation_step, float &p_scale_step) {
224 p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value());
225 p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value());
226 p_primary_grid_steps = int(primary_grid_steps->get_value());
227 p_rotation_offset = rotation_offset->get_value() / (180 / Math_PI);
228 p_rotation_step = rotation_step->get_value() / (180 / Math_PI);
229 p_scale_step = scale_step->get_value();
230 }
231 };
232
_is_node_locked(const Node * p_node)233 bool CanvasItemEditor::_is_node_locked(const Node *p_node) {
234 return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
235 }
236
_is_node_movable(const Node * p_node,bool p_popup_warning)237 bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning) {
238 if (_is_node_locked(p_node)) {
239 return false;
240 }
241 if (Object::cast_to<Control>(p_node) && Object::cast_to<Container>(p_node->get_parent())) {
242 if (p_popup_warning) {
243 _popup_warning_temporarily(warning_child_of_container, 3.0);
244 }
245 return false;
246 }
247 return true;
248 }
249
_snap_if_closer_float(float p_value,float & r_current_snap,SnapTarget & r_current_snap_target,float p_target_value,SnapTarget p_snap_target,float p_radius)250 void CanvasItemEditor::_snap_if_closer_float(
251 float p_value,
252 float &r_current_snap, SnapTarget &r_current_snap_target,
253 float p_target_value, SnapTarget p_snap_target,
254 float p_radius) {
255
256 float radius = p_radius / zoom;
257 float dist = Math::abs(p_value - p_target_value);
258 if ((p_radius < 0 || dist < radius) && (r_current_snap_target == SNAP_TARGET_NONE || dist < Math::abs(r_current_snap - p_value))) {
259 r_current_snap = p_target_value;
260 r_current_snap_target = p_snap_target;
261 }
262 }
263
_snap_if_closer_point(Point2 p_value,Point2 & r_current_snap,SnapTarget (& r_current_snap_target)[2],Point2 p_target_value,SnapTarget p_snap_target,real_t rotation,float p_radius)264 void CanvasItemEditor::_snap_if_closer_point(
265 Point2 p_value,
266 Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],
267 Point2 p_target_value, SnapTarget p_snap_target,
268 real_t rotation,
269 float p_radius) {
270
271 Transform2D rot_trans = Transform2D(rotation, Point2());
272 p_value = rot_trans.inverse().xform(p_value);
273 p_target_value = rot_trans.inverse().xform(p_target_value);
274 r_current_snap = rot_trans.inverse().xform(r_current_snap);
275
276 _snap_if_closer_float(
277 p_value.x,
278 r_current_snap.x,
279 r_current_snap_target[0],
280 p_target_value.x,
281 p_snap_target,
282 p_radius);
283
284 _snap_if_closer_float(
285 p_value.y,
286 r_current_snap.y,
287 r_current_snap_target[1],
288 p_target_value.y,
289 p_snap_target,
290 p_radius);
291
292 r_current_snap = rot_trans.xform(r_current_snap);
293 }
294
_snap_other_nodes(const Point2 p_value,const Transform2D p_transform_to_snap,Point2 & r_current_snap,SnapTarget (& r_current_snap_target)[2],const SnapTarget p_snap_target,List<const CanvasItem * > p_exceptions,const Node * p_current)295 void CanvasItemEditor::_snap_other_nodes(
296 const Point2 p_value,
297 const Transform2D p_transform_to_snap,
298 Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],
299 const SnapTarget p_snap_target, List<const CanvasItem *> p_exceptions,
300 const Node *p_current) {
301 const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_current);
302
303 // Check if the element is in the exception
304 bool exception = false;
305 for (List<const CanvasItem *>::Element *E = p_exceptions.front(); E; E = E->next()) {
306 if (E->get() == p_current) {
307 exception = true;
308 break;
309 }
310 };
311
312 if (canvas_item && !exception) {
313 Transform2D ci_transform = canvas_item->get_global_transform_with_canvas();
314 if (fmod(ci_transform.get_rotation() - p_transform_to_snap.get_rotation(), (real_t)360.0) == 0.0) {
315 if (canvas_item->_edit_use_rect()) {
316 Point2 begin = ci_transform.xform(canvas_item->_edit_get_rect().get_position());
317 Point2 end = ci_transform.xform(canvas_item->_edit_get_rect().get_position() + canvas_item->_edit_get_rect().get_size());
318
319 _snap_if_closer_point(p_value, r_current_snap, r_current_snap_target, begin, p_snap_target, ci_transform.get_rotation());
320 _snap_if_closer_point(p_value, r_current_snap, r_current_snap_target, end, p_snap_target, ci_transform.get_rotation());
321 } else {
322 Point2 position = ci_transform.xform(Point2());
323 _snap_if_closer_point(p_value, r_current_snap, r_current_snap_target, position, p_snap_target, ci_transform.get_rotation());
324 }
325 }
326 }
327 for (int i = 0; i < p_current->get_child_count(); i++) {
328 _snap_other_nodes(p_value, p_transform_to_snap, r_current_snap, r_current_snap_target, p_snap_target, p_exceptions, p_current->get_child(i));
329 }
330 }
331
snap_point(Point2 p_target,unsigned int p_modes,unsigned int p_forced_modes,const CanvasItem * p_self_canvas_item,List<CanvasItem * > p_other_nodes_exceptions)332 Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsigned int p_forced_modes, const CanvasItem *p_self_canvas_item, List<CanvasItem *> p_other_nodes_exceptions) {
333
334 snap_target[0] = SNAP_TARGET_NONE;
335 snap_target[1] = SNAP_TARGET_NONE;
336
337 bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
338
339 // Smart snap using the canvas position
340 Vector2 output = p_target;
341 real_t rotation = 0.0;
342
343 if (p_self_canvas_item) {
344 rotation = p_self_canvas_item->get_global_transform_with_canvas().get_rotation();
345
346 // Parent sides and center
347 if ((is_snap_active && snap_node_parent && (p_modes & SNAP_NODE_PARENT)) || (p_forced_modes & SNAP_NODE_PARENT)) {
348 if (const Control *c = Object::cast_to<Control>(p_self_canvas_item)) {
349 Point2 begin = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(0, 0)));
350 Point2 end = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(1, 1)));
351 _snap_if_closer_point(p_target, output, snap_target, begin, SNAP_TARGET_PARENT, rotation);
352 _snap_if_closer_point(p_target, output, snap_target, (begin + end) / 2.0, SNAP_TARGET_PARENT, rotation);
353 _snap_if_closer_point(p_target, output, snap_target, end, SNAP_TARGET_PARENT, rotation);
354 } else if (const CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_self_canvas_item->get_parent())) {
355 if (parent_ci->_edit_use_rect()) {
356 Point2 begin = p_self_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position());
357 Point2 end = p_self_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position() + parent_ci->_edit_get_rect().get_size());
358 _snap_if_closer_point(p_target, output, snap_target, begin, SNAP_TARGET_PARENT, rotation);
359 _snap_if_closer_point(p_target, output, snap_target, (begin + end) / 2.0, SNAP_TARGET_PARENT, rotation);
360 _snap_if_closer_point(p_target, output, snap_target, end, SNAP_TARGET_PARENT, rotation);
361 } else {
362 Point2 position = p_self_canvas_item->get_transform().affine_inverse().xform(Point2());
363 _snap_if_closer_point(p_target, output, snap_target, position, SNAP_TARGET_PARENT, rotation);
364 }
365 }
366 }
367
368 // Self anchors
369 if ((is_snap_active && snap_node_anchors && (p_modes & SNAP_NODE_ANCHORS)) || (p_forced_modes & SNAP_NODE_ANCHORS)) {
370 if (const Control *c = Object::cast_to<Control>(p_self_canvas_item)) {
371 Point2 begin = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_LEFT), c->get_anchor(MARGIN_TOP))));
372 Point2 end = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_RIGHT), c->get_anchor(MARGIN_BOTTOM))));
373 _snap_if_closer_point(p_target, output, snap_target, begin, SNAP_TARGET_SELF_ANCHORS, rotation);
374 _snap_if_closer_point(p_target, output, snap_target, end, SNAP_TARGET_SELF_ANCHORS, rotation);
375 }
376 }
377
378 // Self sides
379 if ((is_snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) {
380 if (p_self_canvas_item->_edit_use_rect()) {
381 Point2 begin = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_position());
382 Point2 end = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_position() + p_self_canvas_item->_edit_get_rect().get_size());
383 _snap_if_closer_point(p_target, output, snap_target, begin, SNAP_TARGET_SELF, rotation);
384 _snap_if_closer_point(p_target, output, snap_target, end, SNAP_TARGET_SELF, rotation);
385 }
386 }
387
388 // Self center
389 if ((is_snap_active && snap_node_center && (p_modes & SNAP_NODE_CENTER)) || (p_forced_modes & SNAP_NODE_CENTER)) {
390 if (p_self_canvas_item->_edit_use_rect()) {
391 Point2 center = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_position() + p_self_canvas_item->_edit_get_rect().get_size() / 2.0);
392 _snap_if_closer_point(p_target, output, snap_target, center, SNAP_TARGET_SELF, rotation);
393 } else {
394 Point2 position = p_self_canvas_item->get_global_transform_with_canvas().xform(Point2());
395 _snap_if_closer_point(p_target, output, snap_target, position, SNAP_TARGET_SELF, rotation);
396 }
397 }
398 }
399
400 // Other nodes sides
401 if ((is_snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) {
402 Transform2D to_snap_transform = Transform2D();
403 List<const CanvasItem *> exceptions = List<const CanvasItem *>();
404 for (List<CanvasItem *>::Element *E = p_other_nodes_exceptions.front(); E; E = E->next()) {
405 exceptions.push_back(E->get());
406 }
407 if (p_self_canvas_item) {
408 exceptions.push_back(p_self_canvas_item);
409 to_snap_transform = p_self_canvas_item->get_global_transform_with_canvas();
410 }
411
412 _snap_other_nodes(
413 p_target, to_snap_transform,
414 output, snap_target,
415 SNAP_TARGET_OTHER_NODE,
416 exceptions,
417 get_tree()->get_edited_scene_root());
418 }
419
420 if (((is_snap_active && snap_guides && (p_modes & SNAP_GUIDES)) || (p_forced_modes & SNAP_GUIDES)) && fmod(rotation, (real_t)360.0) == 0.0) {
421 // Guides
422 if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
423 Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
424 for (int i = 0; i < vguides.size(); i++) {
425 _snap_if_closer_float(p_target.x, output.x, snap_target[0], vguides[i], SNAP_TARGET_GUIDE);
426 }
427 }
428
429 if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
430 Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
431 for (int i = 0; i < hguides.size(); i++) {
432 _snap_if_closer_float(p_target.y, output.y, snap_target[1], hguides[i], SNAP_TARGET_GUIDE);
433 }
434 }
435 }
436
437 if (((grid_snap_active && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && fmod(rotation, (real_t)360.0) == 0.0) {
438 // Grid
439 Point2 offset = grid_offset;
440 if (snap_relative) {
441 List<CanvasItem *> selection = _get_edited_canvas_items();
442 if (selection.size() == 1 && Object::cast_to<Node2D>(selection[0])) {
443 offset = Object::cast_to<Node2D>(selection[0])->get_global_position();
444 } else if (selection.size() > 0) {
445 offset = _get_encompassing_rect_from_list(selection).position;
446 }
447 }
448 Point2 grid_output;
449 grid_output.x = Math::stepify(p_target.x - offset.x, grid_step.x * Math::pow(2.0, grid_step_multiplier)) + offset.x;
450 grid_output.y = Math::stepify(p_target.y - offset.y, grid_step.y * Math::pow(2.0, grid_step_multiplier)) + offset.y;
451 _snap_if_closer_point(p_target, output, snap_target, grid_output, SNAP_TARGET_GRID, 0.0, -1.0);
452 }
453
454 if (((snap_pixel && (p_modes & SNAP_PIXEL)) || (p_forced_modes & SNAP_PIXEL)) && rotation == 0.0) {
455 // Pixel
456 output = output.snapped(Size2(1, 1));
457 }
458
459 snap_transform = Transform2D(rotation, output);
460
461 return output;
462 }
463
snap_angle(float p_target,float p_start) const464 float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
465 return (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) && snap_rotation_step != 0) ? Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset : p_target;
466 }
467
_unhandled_key_input(const Ref<InputEvent> & p_ev)468 void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
469
470 Ref<InputEventKey> k = p_ev;
471
472 if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
473 return;
474
475 if (k->get_scancode() == KEY_CONTROL || k->get_scancode() == KEY_ALT || k->get_scancode() == KEY_SHIFT) {
476 viewport->update();
477 }
478
479 if (k->is_pressed() && !k->get_control() && !k->is_echo()) {
480 if ((grid_snap_active || show_grid) && multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->is_shortcut(p_ev)) {
481 // Multiply the grid size
482 grid_step_multiplier = MIN(grid_step_multiplier + 1, 12);
483 viewport->update();
484 } else if ((grid_snap_active || show_grid) && divide_grid_step_shortcut.is_valid() && divide_grid_step_shortcut->is_shortcut(p_ev)) {
485 // Divide the grid size
486 Point2 new_grid_step = grid_step * Math::pow(2.0, grid_step_multiplier - 1);
487 if (new_grid_step.x >= 1.0 && new_grid_step.y >= 1.0)
488 grid_step_multiplier--;
489 viewport->update();
490 }
491 }
492 }
493
_get_editor_data(Object * p_what)494 Object *CanvasItemEditor::_get_editor_data(Object *p_what) {
495
496 CanvasItem *ci = Object::cast_to<CanvasItem>(p_what);
497 if (!ci)
498 return NULL;
499
500 return memnew(CanvasItemEditorSelectedItem);
501 }
502
_keying_changed()503 void CanvasItemEditor::_keying_changed() {
504
505 if (AnimationPlayerEditor::singleton->get_track_editor()->is_visible_in_tree())
506 animation_hb->show();
507 else
508 animation_hb->hide();
509 }
510
_get_encompassing_rect_from_list(List<CanvasItem * > p_list)511 Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_list) {
512 ERR_FAIL_COND_V(p_list.empty(), Rect2());
513
514 // Handles the first element
515 CanvasItem *canvas_item = p_list.front()->get();
516 Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
517
518 // Expand with the other ones
519 for (List<CanvasItem *>::Element *E = p_list.front(); E; E = E->next()) {
520 CanvasItem *canvas_item2 = E->get();
521 Transform2D xform = canvas_item2->get_global_transform_with_canvas();
522
523 Rect2 current_rect = canvas_item2->_edit_get_rect();
524 rect.expand_to(xform.xform(current_rect.position));
525 rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0)));
526 rect.expand_to(xform.xform(current_rect.position + current_rect.size));
527 rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y)));
528 }
529
530 return rect;
531 }
532
_expand_encompassing_rect_using_children(Rect2 & r_rect,const Node * p_node,bool & r_first,const Transform2D & p_parent_xform,const Transform2D & p_canvas_xform,bool include_locked_nodes)533 void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, bool include_locked_nodes) {
534 if (!p_node)
535 return;
536 if (Object::cast_to<Viewport>(p_node))
537 return;
538
539 const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
540
541 for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
542 if (canvas_item && !canvas_item->is_set_as_toplevel()) {
543 _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
544 } else {
545 const CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
546 _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
547 }
548 }
549
550 if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !_is_node_locked(canvas_item))) {
551 Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
552 Rect2 rect = canvas_item->_edit_get_rect();
553 if (r_first) {
554 r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
555 r_first = false;
556 }
557 r_rect.expand_to(xform.xform(rect.position));
558 r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0)));
559 r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y)));
560 r_rect.expand_to(xform.xform(rect.position + rect.size));
561 }
562 }
563
_get_encompassing_rect(const Node * p_node)564 Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) {
565 Rect2 rect;
566 bool first = true;
567 _expand_encompassing_rect_using_children(rect, p_node, first);
568
569 return rect;
570 }
571
_find_canvas_items_at_pos(const Point2 & p_pos,Node * p_node,Vector<_SelectResult> & r_items,const Transform2D & p_parent_xform,const Transform2D & p_canvas_xform)572 void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
573 if (!p_node)
574 return;
575 if (Object::cast_to<Viewport>(p_node))
576 return;
577
578 const real_t grab_distance = EDITOR_GET("editors/poly_editor/point_grab_radius");
579 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
580
581 for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
582 if (canvas_item) {
583 if (!canvas_item->is_set_as_toplevel()) {
584 _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
585 } else {
586 _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, canvas_item->get_transform(), p_canvas_xform);
587 }
588 } else {
589 CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
590 _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
591 }
592 }
593
594 if (canvas_item && canvas_item->is_visible_in_tree()) {
595 Transform2D xform = (p_parent_xform * p_canvas_xform * canvas_item->get_transform()).affine_inverse();
596 const real_t local_grab_distance = xform.basis_xform(Vector2(grab_distance, 0)).length() / zoom;
597 if (canvas_item->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) {
598 Node2D *node = Object::cast_to<Node2D>(canvas_item);
599
600 _SelectResult res;
601 res.item = canvas_item;
602 res.z_index = node ? node->get_z_index() : 0;
603 res.has_z = node;
604 r_items.push_back(res);
605 }
606 }
607 }
608
_get_canvas_items_at_pos(const Point2 & p_pos,Vector<_SelectResult> & r_items)609 void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) {
610
611 Node *scene = editor->get_edited_scene();
612
613 _find_canvas_items_at_pos(p_pos, scene, r_items);
614
615 //Remove invalid results
616 for (int i = 0; i < r_items.size(); i++) {
617 Node *node = r_items[i].item;
618
619 // Make sure the selected node is in the current scene, or editable
620 while (node && node != get_tree()->get_edited_scene_root() && node->get_owner() != scene && !scene->is_editable_instance(node->get_owner())) {
621 node = node->get_parent();
622 };
623
624 // Replace the node by the group if grouped
625 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node);
626 while (node && node != scene->get_parent()) {
627 CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
628 if (canvas_item_tmp && node->has_meta("_edit_group_")) {
629 canvas_item = canvas_item_tmp;
630 }
631 node = node->get_parent();
632 }
633
634 // Check if the canvas item is already in the list (for groups or scenes)
635 bool duplicate = false;
636 for (int j = 0; j < i; j++) {
637 if (r_items[j].item == canvas_item) {
638 duplicate = true;
639 break;
640 }
641 }
642
643 //Remove the item if invalid
644 if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || _is_node_locked(canvas_item)) {
645 r_items.remove(i);
646 i--;
647 } else {
648 r_items.write[i].item = canvas_item;
649 }
650 }
651 }
652
_get_bones_at_pos(const Point2 & p_pos,Vector<_SelectResult> & r_items)653 void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) {
654 Point2 screen_pos = transform.xform(p_pos);
655
656 for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
657 Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
658
659 Vector<Vector2> bone_shape;
660 if (!_get_bone_shape(&bone_shape, NULL, E))
661 continue;
662
663 // Check if the point is inside the Polygon2D
664 if (Geometry::is_point_in_polygon(screen_pos, bone_shape)) {
665 // Check if the item is already in the list
666 bool duplicate = false;
667 for (int i = 0; i < r_items.size(); i++) {
668 if (r_items[i].item == from_node) {
669 duplicate = true;
670 break;
671 }
672 }
673 if (duplicate)
674 continue;
675
676 // Else, add it
677 _SelectResult res;
678 res.item = from_node;
679 res.z_index = from_node ? from_node->get_z_index() : 0;
680 res.has_z = from_node;
681 r_items.push_back(res);
682 }
683 }
684 }
685
_get_bone_shape(Vector<Vector2> * shape,Vector<Vector2> * outline_shape,Map<BoneKey,BoneList>::Element * bone)686 bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone) {
687 int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
688 int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
689
690 Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().from));
691 Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().to));
692
693 if (!from_node)
694 return false;
695 if (!from_node->is_inside_tree())
696 return false; //may have been removed
697
698 if (!to_node && bone->get().length == 0)
699 return false;
700
701 Vector2 from = transform.xform(from_node->get_global_position());
702 Vector2 to;
703
704 if (to_node)
705 to = transform.xform(to_node->get_global_position());
706 else
707 to = transform.xform(from_node->get_global_transform().xform(Vector2(bone->get().length, 0)));
708
709 Vector2 rel = to - from;
710 Vector2 relt = rel.tangent().normalized() * bone_width;
711 Vector2 reln = rel.normalized();
712 Vector2 reltn = relt.normalized();
713
714 if (shape) {
715 shape->clear();
716 shape->push_back(from);
717 shape->push_back(from + rel * 0.2 + relt);
718 shape->push_back(to);
719 shape->push_back(from + rel * 0.2 - relt);
720 }
721
722 if (outline_shape) {
723 outline_shape->clear();
724 outline_shape->push_back(from + (-reln - reltn) * bone_outline_width);
725 outline_shape->push_back(from + (-reln + reltn) * bone_outline_width);
726 outline_shape->push_back(from + rel * 0.2 + relt + reltn * bone_outline_width);
727 outline_shape->push_back(to + (reln + reltn) * bone_outline_width);
728 outline_shape->push_back(to + (reln - reltn) * bone_outline_width);
729 outline_shape->push_back(from + rel * 0.2 - relt - reltn * bone_outline_width);
730 }
731 return true;
732 }
733
_find_canvas_items_in_rect(const Rect2 & p_rect,Node * p_node,List<CanvasItem * > * r_items,const Transform2D & p_parent_xform,const Transform2D & p_canvas_xform)734 void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
735 if (!p_node)
736 return;
737 if (Object::cast_to<Viewport>(p_node))
738 return;
739
740 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
741 Node *scene = editor->get_edited_scene();
742
743 bool editable = p_node == scene || p_node->get_owner() == scene || scene->is_editable_instance(p_node->get_owner());
744 bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
745 bool locked = _is_node_locked(p_node);
746
747 if (!lock_children || !editable) {
748 for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
749 if (canvas_item) {
750 if (!canvas_item->is_set_as_toplevel()) {
751 _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
752 } else {
753 _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, canvas_item->get_transform(), p_canvas_xform);
754 }
755 } else {
756 CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
757 _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
758 }
759 }
760 }
761
762 if (canvas_item && canvas_item->is_visible_in_tree() && !locked && editable) {
763 Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
764
765 if (canvas_item->_edit_use_rect()) {
766 Rect2 rect = canvas_item->_edit_get_rect();
767 if (p_rect.has_point(xform.xform(rect.position)) &&
768 p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, 0))) &&
769 p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, rect.size.y))) &&
770 p_rect.has_point(xform.xform(rect.position + Vector2(0, rect.size.y)))) {
771
772 r_items->push_back(canvas_item);
773 }
774 } else {
775 if (p_rect.has_point(xform.xform(Point2()))) {
776 r_items->push_back(canvas_item);
777 }
778 }
779 }
780 }
781
_select_click_on_item(CanvasItem * item,Point2 p_click_pos,bool p_append)782 bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append) {
783 bool still_selected = true;
784 if (p_append) {
785 if (editor_selection->is_selected(item)) {
786 // Already in the selection, remove it from the selected nodes
787 editor_selection->remove_node(item);
788 still_selected = false;
789 } else {
790 // Add the item to the selection
791 editor_selection->add_node(item);
792 }
793 } else {
794 if (!editor_selection->is_selected(item)) {
795 // Select a new one and clear previous selection
796 editor_selection->clear();
797 editor_selection->add_node(item);
798 // Reselect
799 if (Engine::get_singleton()->is_editor_hint()) {
800 selected_from_canvas = true;
801 editor->call("edit_node", item);
802 }
803 }
804 }
805 viewport->update();
806 return still_selected;
807 }
808
_get_edited_canvas_items(bool retreive_locked,bool remove_canvas_item_if_parent_in_selection)809 List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retreive_locked, bool remove_canvas_item_if_parent_in_selection) {
810 List<CanvasItem *> selection;
811 for (Map<Node *, Object *>::Element *E = editor_selection->get_selection().front(); E; E = E->next()) {
812 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key());
813 if (canvas_item && canvas_item->is_visible_in_tree() && canvas_item->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retreive_locked || !_is_node_locked(canvas_item))) {
814 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
815 if (se) {
816 selection.push_back(canvas_item);
817 }
818 }
819 }
820
821 if (remove_canvas_item_if_parent_in_selection) {
822 List<CanvasItem *> filtered_selection;
823 for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
824 if (!selection.find(E->get()->get_parent())) {
825 filtered_selection.push_back(E->get());
826 }
827 }
828 return filtered_selection;
829 } else {
830 return selection;
831 }
832 }
833
_anchor_to_position(const Control * p_control,Vector2 anchor)834 Vector2 CanvasItemEditor::_anchor_to_position(const Control *p_control, Vector2 anchor) {
835 ERR_FAIL_COND_V(!p_control, Vector2());
836
837 Transform2D parent_transform = p_control->get_transform().affine_inverse();
838 Rect2 parent_rect = p_control->get_parent_anchorable_rect();
839
840 return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
841 }
842
_position_to_anchor(const Control * p_control,Vector2 position)843 Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 position) {
844 ERR_FAIL_COND_V(!p_control, Vector2());
845
846 Rect2 parent_rect = p_control->get_parent_anchorable_rect();
847 ERR_FAIL_COND_V(parent_rect.size.x == 0, Vector2());
848 ERR_FAIL_COND_V(parent_rect.size.y == 0, Vector2());
849
850 return (p_control->get_transform().xform(position) - parent_rect.position) / parent_rect.size;
851 }
852
_save_canvas_item_ik_chain(const CanvasItem * p_canvas_item,List<float> * p_bones_length,List<Dictionary> * p_bones_state)853 void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state) {
854 if (p_bones_length)
855 *p_bones_length = List<float>();
856 if (p_bones_state)
857 *p_bones_state = List<Dictionary>();
858
859 const Node2D *bone = Object::cast_to<Node2D>(p_canvas_item);
860 if (bone && bone->has_meta("_edit_bone_")) {
861 // Check if we have an IK chain
862 List<const Node2D *> bone_ik_list;
863 bool ik_found = false;
864 bone = Object::cast_to<Node2D>(bone->get_parent());
865 while (bone) {
866 bone_ik_list.push_back(bone);
867 if (bone->has_meta("_edit_ik_")) {
868 ik_found = true;
869 break;
870 } else if (!bone->has_meta("_edit_bone_")) {
871 break;
872 }
873 bone = Object::cast_to<Node2D>(bone->get_parent());
874 }
875
876 //Save the bone state and length if we have an IK chain
877 if (ik_found) {
878 bone = Object::cast_to<Node2D>(p_canvas_item);
879 Transform2D bone_xform = bone->get_global_transform();
880 for (List<const Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) {
881 bone_xform = bone_xform * bone->get_transform().affine_inverse();
882 const Node2D *parent_bone = bone_E->get();
883 if (p_bones_length)
884 p_bones_length->push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position()));
885 if (p_bones_state)
886 p_bones_state->push_back(parent_bone->_edit_get_state());
887 bone = parent_bone;
888 }
889 }
890 }
891 }
892
_save_canvas_item_state(List<CanvasItem * > p_canvas_items,bool save_bones)893 void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
894 for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) {
895 CanvasItem *canvas_item = E->get();
896 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
897 if (se) {
898 se->undo_state = canvas_item->_edit_get_state();
899 se->pre_drag_xform = canvas_item->get_global_transform_with_canvas();
900 if (canvas_item->_edit_use_rect()) {
901 se->pre_drag_rect = canvas_item->_edit_get_rect();
902 } else {
903 se->pre_drag_rect = Rect2();
904 }
905
906 // If we have a bone, save the state of all nodes in the IK chain
907 _save_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_length), &(se->pre_drag_bones_undo_state));
908 }
909 }
910 }
911
_restore_canvas_item_ik_chain(CanvasItem * p_canvas_item,const List<Dictionary> * p_bones_state)912 void CanvasItemEditor::_restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state) {
913 CanvasItem *canvas_item = p_canvas_item;
914 for (const List<Dictionary>::Element *E = p_bones_state->front(); E; E = E->next()) {
915 canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
916 canvas_item->_edit_set_state(E->get());
917 }
918 }
919
_restore_canvas_item_state(List<CanvasItem * > p_canvas_items,bool restore_bones)920 void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) {
921 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
922 CanvasItem *canvas_item = E->get();
923 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
924 canvas_item->_edit_set_state(se->undo_state);
925 if (restore_bones) {
926 _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state));
927 }
928 }
929 }
930
_commit_canvas_item_state(List<CanvasItem * > p_canvas_items,String action_name,bool commit_bones)931 void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones) {
932 undo_redo->create_action(action_name);
933 for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) {
934 CanvasItem *canvas_item = E->get();
935 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
936 undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
937 undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state);
938 if (commit_bones) {
939 for (List<Dictionary>::Element *F = se->pre_drag_bones_undo_state.front(); F; F = F->next()) {
940 canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
941 undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
942 undo_redo->add_undo_method(canvas_item, "_edit_set_state", F->get());
943 }
944 }
945 }
946 undo_redo->add_do_method(viewport, "update");
947 undo_redo->add_undo_method(viewport, "update");
948 undo_redo->commit_action();
949 }
950
_snap_changed()951 void CanvasItemEditor::_snap_changed() {
952 ((SnapDialog *)snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
953 grid_step_multiplier = 0;
954 viewport->update();
955 }
956
_selection_result_pressed(int p_result)957 void CanvasItemEditor::_selection_result_pressed(int p_result) {
958
959 if (selection_results.size() <= p_result)
960 return;
961
962 CanvasItem *item = selection_results[p_result].item;
963
964 if (item)
965 _select_click_on_item(item, Point2(), selection_menu_additive_selection);
966 }
967
_selection_menu_hide()968 void CanvasItemEditor::_selection_menu_hide() {
969
970 selection_results.clear();
971 selection_menu->clear();
972 selection_menu->set_size(Vector2(0, 0));
973 }
974
_gui_input_rulers_and_guides(const Ref<InputEvent> & p_event)975 bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
976 Ref<InputEventMouseButton> b = p_event;
977 Ref<InputEventMouseMotion> m = p_event;
978
979 if (drag_type == DRAG_NONE) {
980 if (show_guides && show_rulers && EditorNode::get_singleton()->get_edited_scene()) {
981 Transform2D xform = viewport_scrollable->get_transform() * transform;
982 // Retrieve the guide lists
983 Array vguides;
984 if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
985 vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
986 }
987 Array hguides;
988 if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
989 hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
990 }
991
992 // Hover over guides
993 float minimum = 1e20;
994 is_hovering_h_guide = false;
995 is_hovering_v_guide = false;
996
997 if (m.is_valid() && m->get_position().x < RULER_WIDTH) {
998 // Check if we are hovering an existing horizontal guide
999 for (int i = 0; i < hguides.size(); i++) {
1000 if (ABS(xform.xform(Point2(0, hguides[i])).y - m->get_position().y) < MIN(minimum, 8)) {
1001 is_hovering_h_guide = true;
1002 is_hovering_v_guide = false;
1003 break;
1004 }
1005 }
1006
1007 } else if (m.is_valid() && m->get_position().y < RULER_WIDTH) {
1008 // Check if we are hovering an existing vertical guide
1009 for (int i = 0; i < vguides.size(); i++) {
1010 if (ABS(xform.xform(Point2(vguides[i], 0)).x - m->get_position().x) < MIN(minimum, 8)) {
1011 is_hovering_v_guide = true;
1012 is_hovering_h_guide = false;
1013 break;
1014 }
1015 }
1016 }
1017
1018 // Start dragging a guide
1019 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
1020
1021 // Press button
1022 if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) {
1023 // Drag a new double guide
1024 drag_type = DRAG_DOUBLE_GUIDE;
1025 dragged_guide_index = -1;
1026 return true;
1027 } else if (b->get_position().x < RULER_WIDTH) {
1028 // Check if we drag an existing horizontal guide
1029 dragged_guide_index = -1;
1030 for (int i = 0; i < hguides.size(); i++) {
1031 if (ABS(xform.xform(Point2(0, hguides[i])).y - b->get_position().y) < MIN(minimum, 8)) {
1032 dragged_guide_index = i;
1033 }
1034 }
1035
1036 if (dragged_guide_index >= 0) {
1037 // Drag an existing horizontal guide
1038 drag_type = DRAG_H_GUIDE;
1039 } else {
1040 // Drag a new vertical guide
1041 drag_type = DRAG_V_GUIDE;
1042 }
1043 return true;
1044 } else if (b->get_position().y < RULER_WIDTH) {
1045 // Check if we drag an existing vertical guide
1046 dragged_guide_index = -1;
1047 for (int i = 0; i < vguides.size(); i++) {
1048 if (ABS(xform.xform(Point2(vguides[i], 0)).x - b->get_position().x) < MIN(minimum, 8)) {
1049 dragged_guide_index = i;
1050 }
1051 }
1052
1053 if (dragged_guide_index >= 0) {
1054 // Drag an existing vertical guide
1055 drag_type = DRAG_V_GUIDE;
1056 } else {
1057 // Drag a new vertical guide
1058 drag_type = DRAG_H_GUIDE;
1059 }
1060 drag_from = xform.affine_inverse().xform(b->get_position());
1061 return true;
1062 }
1063 }
1064 }
1065 }
1066
1067 if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_V_GUIDE || drag_type == DRAG_H_GUIDE) {
1068 // Move the guide
1069 if (m.is_valid()) {
1070 Transform2D xform = viewport_scrollable->get_transform() * transform;
1071 drag_to = xform.affine_inverse().xform(m->get_position());
1072
1073 dragged_guide_pos = xform.xform(snap_point(drag_to, SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES));
1074 viewport->update();
1075 return true;
1076 }
1077
1078 // Release confirms the guide move
1079 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
1080 if (show_guides && EditorNode::get_singleton()->get_edited_scene()) {
1081 Transform2D xform = viewport_scrollable->get_transform() * transform;
1082
1083 // Retrieve the guide lists
1084 Array vguides;
1085 if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
1086 vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
1087 }
1088 Array hguides;
1089 if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
1090 hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
1091 }
1092
1093 Point2 edited = snap_point(xform.affine_inverse().xform(b->get_position()), SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES);
1094 if (drag_type == DRAG_V_GUIDE) {
1095 Array prev_vguides = vguides.duplicate();
1096 if (b->get_position().x > RULER_WIDTH) {
1097 // Adds a new vertical guide
1098 if (dragged_guide_index >= 0) {
1099 vguides[dragged_guide_index] = edited.x;
1100 undo_redo->create_action(TTR("Move Vertical Guide"));
1101 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
1102 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
1103 undo_redo->add_undo_method(viewport, "update");
1104 undo_redo->commit_action();
1105 } else {
1106 vguides.push_back(edited.x);
1107 undo_redo->create_action(TTR("Create Vertical Guide"));
1108 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
1109 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
1110 undo_redo->add_undo_method(viewport, "update");
1111 undo_redo->commit_action();
1112 }
1113 } else {
1114 if (dragged_guide_index >= 0) {
1115 vguides.remove(dragged_guide_index);
1116 undo_redo->create_action(TTR("Remove Vertical Guide"));
1117 if (vguides.empty()) {
1118 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_vertical_guides_");
1119 } else {
1120 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
1121 }
1122 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
1123 undo_redo->add_undo_method(viewport, "update");
1124 undo_redo->commit_action();
1125 }
1126 }
1127 } else if (drag_type == DRAG_H_GUIDE) {
1128 Array prev_hguides = hguides.duplicate();
1129 if (b->get_position().y > RULER_WIDTH) {
1130 // Adds a new horizontal guide
1131 if (dragged_guide_index >= 0) {
1132 hguides[dragged_guide_index] = edited.y;
1133 undo_redo->create_action(TTR("Move Horizontal Guide"));
1134 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
1135 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
1136 undo_redo->add_undo_method(viewport, "update");
1137 undo_redo->commit_action();
1138 } else {
1139 hguides.push_back(edited.y);
1140 undo_redo->create_action(TTR("Create Horizontal Guide"));
1141 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
1142 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
1143 undo_redo->add_undo_method(viewport, "update");
1144 undo_redo->commit_action();
1145 }
1146 } else {
1147 if (dragged_guide_index >= 0) {
1148 hguides.remove(dragged_guide_index);
1149 undo_redo->create_action(TTR("Remove Horizontal Guide"));
1150 if (hguides.empty()) {
1151 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_horizontal_guides_");
1152 } else {
1153 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
1154 }
1155 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
1156 undo_redo->add_undo_method(viewport, "update");
1157 undo_redo->commit_action();
1158 }
1159 }
1160 } else if (drag_type == DRAG_DOUBLE_GUIDE) {
1161 Array prev_hguides = hguides.duplicate();
1162 Array prev_vguides = vguides.duplicate();
1163 if (b->get_position().x > RULER_WIDTH && b->get_position().y > RULER_WIDTH) {
1164 // Adds a new horizontal guide a new vertical guide
1165 vguides.push_back(edited.x);
1166 hguides.push_back(edited.y);
1167 undo_redo->create_action(TTR("Create Horizontal and Vertical Guides"));
1168 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
1169 undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
1170 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
1171 undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
1172 undo_redo->add_undo_method(viewport, "update");
1173 undo_redo->commit_action();
1174 }
1175 }
1176 }
1177 drag_type = DRAG_NONE;
1178 viewport->update();
1179 return true;
1180 }
1181 }
1182 return false;
1183 }
1184
_gui_input_zoom_or_pan(const Ref<InputEvent> & p_event,bool p_already_accepted)1185 bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bool p_already_accepted) {
1186 Ref<InputEventMouseButton> b = p_event;
1187 if (b.is_valid() && !p_already_accepted) {
1188 const bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control();
1189
1190 if (pan_on_scroll) {
1191 // Perform horizontal scrolling first so we can check for Shift being held.
1192 if (b->is_pressed() &&
1193 (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_UP))) {
1194 // Pan left
1195 view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
1196 update_viewport();
1197 return true;
1198 }
1199
1200 if (b->is_pressed() &&
1201 (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_DOWN))) {
1202 // Pan right
1203 view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
1204 update_viewport();
1205 return true;
1206 }
1207 }
1208
1209 if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) {
1210 // Scroll or pan down
1211 if (pan_on_scroll) {
1212 view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
1213 update_viewport();
1214 } else {
1215 float new_zoom = _get_next_zoom_value(-1);
1216 if (b->get_factor() != 1.f) {
1217 new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f);
1218 }
1219 _zoom_on_position(new_zoom, b->get_position());
1220 }
1221 return true;
1222 }
1223
1224 if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_UP) {
1225 // Scroll or pan up
1226 if (pan_on_scroll) {
1227 view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
1228 update_viewport();
1229 } else {
1230 float new_zoom = _get_next_zoom_value(1);
1231 if (b->get_factor() != 1.f) {
1232 new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f);
1233 }
1234 _zoom_on_position(new_zoom, b->get_position());
1235 }
1236 return true;
1237 }
1238
1239 if (!panning) {
1240 if (b->is_pressed() &&
1241 (b->get_button_index() == BUTTON_MIDDLE ||
1242 b->get_button_index() == BUTTON_RIGHT ||
1243 (b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) ||
1244 (b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) {
1245 // Pan the viewport
1246 panning = true;
1247 }
1248 }
1249
1250 if (panning) {
1251 if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != BUTTON_WHEEL_DOWN && b->get_button_index() != BUTTON_WHEEL_UP))) {
1252 // Stop panning the viewport (for any mouse button press except zooming)
1253 panning = false;
1254 }
1255 }
1256 }
1257
1258 Ref<InputEventKey> k = p_event;
1259 if (k.is_valid()) {
1260 bool is_pan_key = pan_view_shortcut.is_valid() && pan_view_shortcut->is_shortcut(p_event);
1261
1262 if (is_pan_key && (EditorSettings::get_singleton()->get("editors/2d/simple_panning") || drag_type != DRAG_NONE)) {
1263 if (!panning) {
1264 if (k->is_pressed() && !k->is_echo()) {
1265 //Pan the viewport
1266 panning = true;
1267 }
1268 } else {
1269 if (!k->is_pressed()) {
1270 // Stop panning the viewport (for any mouse button press)
1271 panning = false;
1272 }
1273 }
1274 }
1275
1276 if (is_pan_key)
1277 pan_pressed = k->is_pressed();
1278 }
1279
1280 Ref<InputEventMouseMotion> m = p_event;
1281 if (m.is_valid()) {
1282 if (panning) {
1283 // Pan the viewport
1284 Point2i relative;
1285 if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
1286 relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect());
1287 } else {
1288 relative = m->get_relative();
1289 }
1290 view_offset.x -= relative.x / zoom;
1291 view_offset.y -= relative.y / zoom;
1292 update_viewport();
1293 return true;
1294 }
1295 }
1296
1297 Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
1298 if (magnify_gesture.is_valid() && !p_already_accepted) {
1299 // Zoom gesture
1300 _zoom_on_position(zoom * magnify_gesture->get_factor(), magnify_gesture->get_position());
1301 return true;
1302 }
1303
1304 Ref<InputEventPanGesture> pan_gesture = p_event;
1305 if (pan_gesture.is_valid() && !p_already_accepted) {
1306 // If control key pressed, then zoom instead of pan
1307 if (pan_gesture->get_control()) {
1308 const float factor = pan_gesture->get_delta().y;
1309 float new_zoom = _get_next_zoom_value(-1);
1310
1311 if (factor != 1.f) {
1312 new_zoom = zoom * ((new_zoom / zoom - 1.f) * factor + 1.f);
1313 }
1314 _zoom_on_position(new_zoom, pan_gesture->get_position());
1315 return true;
1316 }
1317
1318 // Pan gesture
1319 const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
1320 view_offset.x += delta.x;
1321 view_offset.y += delta.y;
1322 update_viewport();
1323 return true;
1324 }
1325
1326 return false;
1327 }
1328
_gui_input_pivot(const Ref<InputEvent> & p_event)1329 bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
1330 Ref<InputEventMouseMotion> m = p_event;
1331 Ref<InputEventMouseButton> b = p_event;
1332 Ref<InputEventKey> k = p_event;
1333
1334 // Drag the pivot (in pivot mode / with V key)
1335 if (drag_type == DRAG_NONE) {
1336 if ((b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
1337 (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_scancode() == KEY_V)) {
1338 List<CanvasItem *> selection = _get_edited_canvas_items();
1339
1340 // Filters the selection with nodes that allow setting the pivot
1341 drag_selection = List<CanvasItem *>();
1342 for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
1343 CanvasItem *canvas_item = E->get();
1344 if (canvas_item->_edit_use_pivot()) {
1345 drag_selection.push_back(canvas_item);
1346 }
1347 }
1348
1349 // Start dragging if we still have nodes
1350 if (drag_selection.size() > 0) {
1351 _save_canvas_item_state(drag_selection);
1352 drag_from = transform.affine_inverse().xform((b.is_valid()) ? b->get_position() : viewport->get_local_mouse_position());
1353 Vector2 new_pos;
1354 if (drag_selection.size() == 1) {
1355 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]);
1356 } else {
1357 new_pos = snap_point(drag_from, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, NULL, drag_selection);
1358 }
1359 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
1360 CanvasItem *canvas_item = E->get();
1361 canvas_item->_edit_set_pivot(canvas_item->get_global_transform_with_canvas().affine_inverse().xform(new_pos));
1362 }
1363
1364 drag_type = DRAG_PIVOT;
1365 }
1366 return true;
1367 }
1368 }
1369
1370 if (drag_type == DRAG_PIVOT) {
1371 // Move the pivot
1372 if (m.is_valid()) {
1373 drag_to = transform.affine_inverse().xform(m->get_position());
1374 _restore_canvas_item_state(drag_selection);
1375 Vector2 new_pos;
1376 if (drag_selection.size() == 1)
1377 new_pos = snap_point(drag_to, SNAP_NODE_SIDES | SNAP_NODE_CENTER | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, drag_selection[0]);
1378 else
1379 new_pos = snap_point(drag_to, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL);
1380 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
1381 CanvasItem *canvas_item = E->get();
1382 canvas_item->_edit_set_pivot(canvas_item->get_global_transform_with_canvas().affine_inverse().xform(new_pos));
1383 }
1384 return true;
1385 }
1386
1387 // Confirm the pivot move
1388 if ((b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
1389 (k.is_valid() && !k->is_pressed() && k->get_scancode() == KEY_V)) {
1390 _commit_canvas_item_state(drag_selection, TTR("Move pivot"));
1391 drag_type = DRAG_NONE;
1392 return true;
1393 }
1394
1395 // Cancel a drag
1396 if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
1397 _restore_canvas_item_state(drag_selection);
1398 drag_type = DRAG_NONE;
1399 viewport->update();
1400 return true;
1401 }
1402 }
1403 return false;
1404 }
1405
_solve_IK(Node2D * leaf_node,Point2 target_position)1406 void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
1407 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(leaf_node);
1408 if (se) {
1409 int nb_bones = se->pre_drag_bones_undo_state.size();
1410 if (nb_bones > 0) {
1411
1412 // Build the node list
1413 Point2 leaf_pos = target_position;
1414
1415 List<Node2D *> joints_list;
1416 List<Point2> joints_pos;
1417 Node2D *joint = leaf_node;
1418 Transform2D joint_transform = leaf_node->get_global_transform_with_canvas();
1419 for (int i = 0; i < nb_bones + 1; i++) {
1420 joints_list.push_back(joint);
1421 joints_pos.push_back(joint_transform.get_origin());
1422 joint_transform = joint_transform * joint->get_transform().affine_inverse();
1423 joint = Object::cast_to<Node2D>(joint->get_parent());
1424 }
1425 Point2 root_pos = joints_list.back()->get()->get_global_transform_with_canvas().get_origin();
1426
1427 // Restraints the node to a maximum distance is necessary
1428 float total_len = 0;
1429 for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
1430 total_len += E->get();
1431 }
1432 if ((root_pos.distance_to(leaf_pos)) > total_len) {
1433 Vector2 rel = leaf_pos - root_pos;
1434 rel = rel.normalized() * total_len;
1435 leaf_pos = root_pos + rel;
1436 }
1437 joints_pos[0] = leaf_pos;
1438
1439 // Run the solver
1440 int solver_iterations = 64;
1441 float solver_k = 0.3;
1442
1443 // Build the position list
1444 for (int i = 0; i < solver_iterations; i++) {
1445 // Handle the leaf joint
1446 int node_id = 0;
1447 for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
1448 Vector2 direction = (joints_pos[node_id + 1] - joints_pos[node_id]).normalized();
1449 int len = E->get();
1450 if (E == se->pre_drag_bones_length.front()) {
1451 joints_pos[1] = joints_pos[1].linear_interpolate(joints_pos[0] + len * direction, solver_k);
1452 } else if (E == se->pre_drag_bones_length.back()) {
1453 joints_pos[node_id] = joints_pos[node_id].linear_interpolate(joints_pos[node_id + 1] - len * direction, solver_k);
1454 } else {
1455 Vector2 center = (joints_pos[node_id + 1] + joints_pos[node_id]) / 2.0;
1456 joints_pos[node_id] = joints_pos[node_id].linear_interpolate(center - (direction * len) / 2.0, solver_k);
1457 joints_pos[node_id + 1] = joints_pos[node_id + 1].linear_interpolate(center + (direction * len) / 2.0, solver_k);
1458 }
1459 node_id++;
1460 }
1461 }
1462
1463 // Set the position
1464 for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) {
1465 Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized();
1466 Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized();
1467 float rot = current.angle_to(target);
1468 if (joints_list[node_id]->get_global_transform().basis_determinant() < 0) {
1469 rot = -rot;
1470 }
1471 joints_list[node_id]->rotate(rot);
1472 }
1473 }
1474 }
1475 }
1476
_gui_input_rotate(const Ref<InputEvent> & p_event)1477 bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
1478 Ref<InputEventMouseButton> b = p_event;
1479 Ref<InputEventMouseMotion> m = p_event;
1480
1481 // Start rotation
1482 if (drag_type == DRAG_NONE) {
1483 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
1484 if ((b->get_control() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
1485 List<CanvasItem *> selection = _get_edited_canvas_items();
1486
1487 // Remove not movable nodes
1488 for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
1489 if (!_is_node_movable(E->get(), true))
1490 selection.erase(E);
1491 }
1492
1493 drag_selection = selection;
1494 if (drag_selection.size() > 0) {
1495 drag_type = DRAG_ROTATE;
1496 drag_from = transform.affine_inverse().xform(b->get_position());
1497 CanvasItem *canvas_item = drag_selection[0];
1498 if (canvas_item->_edit_use_pivot()) {
1499 drag_rotation_center = canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_pivot());
1500 } else {
1501 drag_rotation_center = canvas_item->get_global_transform_with_canvas().get_origin();
1502 }
1503 _save_canvas_item_state(drag_selection);
1504 return true;
1505 }
1506 }
1507 }
1508 }
1509
1510 if (drag_type == DRAG_ROTATE) {
1511 // Rotate the node
1512 if (m.is_valid()) {
1513 _restore_canvas_item_state(drag_selection);
1514 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
1515 CanvasItem *canvas_item = E->get();
1516 drag_to = transform.affine_inverse().xform(m->get_position());
1517 //Rotate the opposite way if the canvas item's compounded scale has an uneven number of negative elements
1518 bool opposite = (canvas_item->get_global_transform().get_scale().sign().dot(canvas_item->get_transform().get_scale().sign()) == 0);
1519 canvas_item->_edit_set_rotation(snap_angle(canvas_item->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), canvas_item->_edit_get_rotation()));
1520 viewport->update();
1521 }
1522 return true;
1523 }
1524
1525 // Confirms the node rotation
1526 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
1527 _commit_canvas_item_state(drag_selection, TTR("Rotate CanvasItem"));
1528 if (key_auto_insert_button->is_pressed()) {
1529 _insert_animation_keys(false, true, false, true);
1530 }
1531
1532 drag_type = DRAG_NONE;
1533 return true;
1534 }
1535
1536 // Cancel a drag
1537 if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
1538 _restore_canvas_item_state(drag_selection);
1539 drag_type = DRAG_NONE;
1540 viewport->update();
1541 return true;
1542 }
1543 }
1544 return false;
1545 }
1546
_gui_input_open_scene_on_double_click(const Ref<InputEvent> & p_event)1547 bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEvent> &p_event) {
1548 Ref<InputEventMouseButton> b = p_event;
1549
1550 // Open a sub-scene on double-click
1551 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
1552 List<CanvasItem *> selection = _get_edited_canvas_items();
1553 if (selection.size() == 1) {
1554 CanvasItem *canvas_item = selection[0];
1555 if (canvas_item->get_filename() != "" && canvas_item != editor->get_edited_scene()) {
1556 editor->open_request(canvas_item->get_filename());
1557 return true;
1558 }
1559 }
1560 }
1561 return false;
1562 }
1563
_gui_input_anchors(const Ref<InputEvent> & p_event)1564 bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
1565 Ref<InputEventMouseButton> b = p_event;
1566 Ref<InputEventMouseMotion> m = p_event;
1567
1568 // Starts anchor dragging if needed
1569 if (drag_type == DRAG_NONE) {
1570 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
1571 List<CanvasItem *> selection = _get_edited_canvas_items();
1572 if (selection.size() == 1) {
1573 Control *control = Object::cast_to<Control>(selection[0]);
1574 if (control && _is_node_movable(control)) {
1575 Vector2 anchor_pos[4];
1576 anchor_pos[0] = Vector2(control->get_anchor(MARGIN_LEFT), control->get_anchor(MARGIN_TOP));
1577 anchor_pos[1] = Vector2(control->get_anchor(MARGIN_RIGHT), control->get_anchor(MARGIN_TOP));
1578 anchor_pos[2] = Vector2(control->get_anchor(MARGIN_RIGHT), control->get_anchor(MARGIN_BOTTOM));
1579 anchor_pos[3] = Vector2(control->get_anchor(MARGIN_LEFT), control->get_anchor(MARGIN_BOTTOM));
1580
1581 Rect2 anchor_rects[4];
1582 for (int i = 0; i < 4; i++) {
1583 anchor_pos[i] = (transform * control->get_global_transform_with_canvas()).xform(_anchor_to_position(control, anchor_pos[i]));
1584 anchor_rects[i] = Rect2(anchor_pos[i], anchor_handle->get_size());
1585 anchor_rects[i].position -= anchor_handle->get_size() * Vector2(float(i == 0 || i == 3), float(i <= 1));
1586 }
1587
1588 DragType dragger[] = {
1589 DRAG_ANCHOR_TOP_LEFT,
1590 DRAG_ANCHOR_TOP_RIGHT,
1591 DRAG_ANCHOR_BOTTOM_RIGHT,
1592 DRAG_ANCHOR_BOTTOM_LEFT,
1593 };
1594
1595 for (int i = 0; i < 4; i++) {
1596 if (anchor_rects[i].has_point(b->get_position())) {
1597 if ((anchor_pos[0] == anchor_pos[2]) && (anchor_pos[0].distance_to(b->get_position()) < anchor_handle->get_size().length() / 3.0)) {
1598 drag_type = DRAG_ANCHOR_ALL;
1599 } else {
1600 drag_type = dragger[i];
1601 }
1602 drag_from = transform.affine_inverse().xform(b->get_position());
1603 drag_selection = List<CanvasItem *>();
1604 drag_selection.push_back(control);
1605 _save_canvas_item_state(drag_selection);
1606 return true;
1607 }
1608 }
1609 }
1610 }
1611 }
1612 }
1613
1614 if (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_TOP_RIGHT || drag_type == DRAG_ANCHOR_BOTTOM_RIGHT || drag_type == DRAG_ANCHOR_BOTTOM_LEFT || drag_type == DRAG_ANCHOR_ALL) {
1615 // Drag the anchor
1616 if (m.is_valid()) {
1617 _restore_canvas_item_state(drag_selection);
1618 Control *control = Object::cast_to<Control>(drag_selection[0]);
1619
1620 drag_to = transform.affine_inverse().xform(m->get_position());
1621
1622 Transform2D xform = control->get_global_transform_with_canvas().affine_inverse();
1623
1624 Point2 previous_anchor;
1625 previous_anchor.x = (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_BOTTOM_LEFT) ? control->get_anchor(MARGIN_LEFT) : control->get_anchor(MARGIN_RIGHT);
1626 previous_anchor.y = (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_TOP_RIGHT) ? control->get_anchor(MARGIN_TOP) : control->get_anchor(MARGIN_BOTTOM);
1627 previous_anchor = xform.affine_inverse().xform(_anchor_to_position(control, previous_anchor));
1628
1629 Vector2 new_anchor = xform.xform(snap_point(previous_anchor + (drag_to - drag_from), SNAP_GRID | SNAP_OTHER_NODES, SNAP_NODE_PARENT | SNAP_NODE_SIDES | SNAP_NODE_CENTER, control));
1630 new_anchor = _position_to_anchor(control, new_anchor).snapped(Vector2(0.001, 0.001));
1631
1632 bool use_single_axis = m->get_shift();
1633 Vector2 drag_vector = xform.xform(drag_to) - xform.xform(drag_from);
1634 bool use_y = Math::abs(drag_vector.y) > Math::abs(drag_vector.x);
1635
1636 switch (drag_type) {
1637 case DRAG_ANCHOR_TOP_LEFT:
1638 if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false);
1639 if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false);
1640 break;
1641 case DRAG_ANCHOR_TOP_RIGHT:
1642 if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false);
1643 if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false);
1644 break;
1645 case DRAG_ANCHOR_BOTTOM_RIGHT:
1646 if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false);
1647 if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false);
1648 break;
1649 case DRAG_ANCHOR_BOTTOM_LEFT:
1650 if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false);
1651 if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false);
1652 break;
1653 case DRAG_ANCHOR_ALL:
1654 if (!use_single_axis || !use_y) {
1655 control->set_anchor(MARGIN_LEFT, new_anchor.x, false, true);
1656 control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, true);
1657 }
1658 if (!use_single_axis || use_y) {
1659 control->set_anchor(MARGIN_TOP, new_anchor.y, false, true);
1660 control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, true);
1661 }
1662 break;
1663 default:
1664 break;
1665 }
1666 return true;
1667 }
1668
1669 // Confirms new anchor position
1670 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
1671 _commit_canvas_item_state(drag_selection, TTR("Move anchor"));
1672 drag_type = DRAG_NONE;
1673 return true;
1674 }
1675
1676 // Cancel a drag
1677 if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
1678 _restore_canvas_item_state(drag_selection);
1679 drag_type = DRAG_NONE;
1680 viewport->update();
1681 return true;
1682 }
1683 }
1684 return false;
1685 }
1686
_gui_input_resize(const Ref<InputEvent> & p_event)1687 bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
1688 Ref<InputEventMouseButton> b = p_event;
1689 Ref<InputEventMouseMotion> m = p_event;
1690
1691 // Drag resize handles
1692 if (drag_type == DRAG_NONE) {
1693 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
1694 List<CanvasItem *> selection = _get_edited_canvas_items();
1695 if (selection.size() == 1) {
1696 CanvasItem *canvas_item = selection[0];
1697 if (canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
1698 Rect2 rect = canvas_item->_edit_get_rect();
1699 Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
1700
1701 Vector2 endpoints[4] = {
1702 xform.xform(rect.position),
1703 xform.xform(rect.position + Vector2(rect.size.x, 0)),
1704 xform.xform(rect.position + rect.size),
1705 xform.xform(rect.position + Vector2(0, rect.size.y))
1706 };
1707
1708 DragType dragger[] = {
1709 DRAG_TOP_LEFT,
1710 DRAG_TOP,
1711 DRAG_TOP_RIGHT,
1712 DRAG_RIGHT,
1713 DRAG_BOTTOM_RIGHT,
1714 DRAG_BOTTOM,
1715 DRAG_BOTTOM_LEFT,
1716 DRAG_LEFT
1717 };
1718
1719 DragType resize_drag = DRAG_NONE;
1720 float radius = (select_handle->get_size().width / 2) * 1.5;
1721
1722 for (int i = 0; i < 4; i++) {
1723 int prev = (i + 3) % 4;
1724 int next = (i + 1) % 4;
1725
1726 Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
1727 ofs *= (select_handle->get_size().width / 2);
1728 ofs += endpoints[i];
1729 if (ofs.distance_to(b->get_position()) < radius)
1730 resize_drag = dragger[i * 2];
1731
1732 ofs = (endpoints[i] + endpoints[next]) / 2;
1733 ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2);
1734 if (ofs.distance_to(b->get_position()) < radius)
1735 resize_drag = dragger[i * 2 + 1];
1736 }
1737
1738 if (resize_drag != DRAG_NONE) {
1739 drag_type = resize_drag;
1740 drag_from = transform.affine_inverse().xform(b->get_position());
1741 drag_selection = List<CanvasItem *>();
1742 drag_selection.push_back(canvas_item);
1743 _save_canvas_item_state(drag_selection);
1744 return true;
1745 }
1746 }
1747 }
1748 }
1749 }
1750
1751 if (drag_type == DRAG_LEFT || drag_type == DRAG_RIGHT || drag_type == DRAG_TOP || drag_type == DRAG_BOTTOM ||
1752 drag_type == DRAG_TOP_LEFT || drag_type == DRAG_TOP_RIGHT || drag_type == DRAG_BOTTOM_LEFT || drag_type == DRAG_BOTTOM_RIGHT) {
1753 // Resize the node
1754 if (m.is_valid()) {
1755 CanvasItem *canvas_item = drag_selection[0];
1756 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
1757 //Reset state
1758 canvas_item->_edit_set_state(se->undo_state);
1759
1760 bool uniform = m->get_shift();
1761 bool symmetric = m->get_alt();
1762
1763 Rect2 local_rect = canvas_item->_edit_get_rect();
1764 float aspect = local_rect.get_size().y / local_rect.get_size().x;
1765 Point2 current_begin = local_rect.get_position();
1766 Point2 current_end = local_rect.get_position() + local_rect.get_size();
1767 Point2 max_begin = (symmetric) ? (current_begin + current_end - canvas_item->_edit_get_minimum_size()) / 2.0 : current_end - canvas_item->_edit_get_minimum_size();
1768 Point2 min_end = (symmetric) ? (current_begin + current_end + canvas_item->_edit_get_minimum_size()) / 2.0 : current_begin + canvas_item->_edit_get_minimum_size();
1769 Point2 center = (current_begin + current_end) / 2.0;
1770
1771 drag_to = transform.affine_inverse().xform(m->get_position());
1772
1773 Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse();
1774
1775 Point2 drag_to_snapped_begin;
1776 Point2 drag_to_snapped_end;
1777
1778 // last call decides which snapping lines are drawn
1779 if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP || drag_type == DRAG_TOP_LEFT) {
1780 drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
1781 drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
1782 } else {
1783 drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
1784 drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
1785 }
1786
1787 Point2 drag_begin = xform.xform(drag_to_snapped_begin);
1788 Point2 drag_end = xform.xform(drag_to_snapped_end);
1789
1790 // Horizontal resize
1791 if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP_LEFT || drag_type == DRAG_BOTTOM_LEFT) {
1792 current_begin.x = MIN(drag_begin.x, max_begin.x);
1793 } else if (drag_type == DRAG_RIGHT || drag_type == DRAG_TOP_RIGHT || drag_type == DRAG_BOTTOM_RIGHT) {
1794 current_end.x = MAX(drag_end.x, min_end.x);
1795 }
1796
1797 // Vertical resize
1798 if (drag_type == DRAG_TOP || drag_type == DRAG_TOP_LEFT || drag_type == DRAG_TOP_RIGHT) {
1799 current_begin.y = MIN(drag_begin.y, max_begin.y);
1800 } else if (drag_type == DRAG_BOTTOM || drag_type == DRAG_BOTTOM_LEFT || drag_type == DRAG_BOTTOM_RIGHT) {
1801 current_end.y = MAX(drag_end.y, min_end.y);
1802 }
1803
1804 // Uniform resize
1805 if (uniform) {
1806 if (drag_type == DRAG_LEFT || drag_type == DRAG_RIGHT) {
1807 current_end.y = current_begin.y + aspect * (current_end.x - current_begin.x);
1808 } else if (drag_type == DRAG_TOP || drag_type == DRAG_BOTTOM) {
1809 current_end.x = current_begin.x + (current_end.y - current_begin.y) / aspect;
1810 } else {
1811 if (aspect >= 1.0) {
1812 if (drag_type == DRAG_TOP_LEFT || drag_type == DRAG_TOP_RIGHT) {
1813 current_begin.y = current_end.y - aspect * (current_end.x - current_begin.x);
1814 } else {
1815 current_end.y = current_begin.y + aspect * (current_end.x - current_begin.x);
1816 }
1817 } else {
1818 if (drag_type == DRAG_TOP_LEFT || drag_type == DRAG_BOTTOM_LEFT) {
1819 current_begin.x = current_end.x - (current_end.y - current_begin.y) / aspect;
1820 } else {
1821 current_end.x = current_begin.x + (current_end.y - current_begin.y) / aspect;
1822 }
1823 }
1824 }
1825 }
1826
1827 // Symmetric resize
1828 if (symmetric) {
1829 if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP_LEFT || drag_type == DRAG_BOTTOM_LEFT) {
1830 current_end.x = 2.0 * center.x - current_begin.x;
1831 } else if (drag_type == DRAG_RIGHT || drag_type == DRAG_TOP_RIGHT || drag_type == DRAG_BOTTOM_RIGHT) {
1832 current_begin.x = 2.0 * center.x - current_end.x;
1833 }
1834 if (drag_type == DRAG_TOP || drag_type == DRAG_TOP_LEFT || drag_type == DRAG_TOP_RIGHT) {
1835 current_end.y = 2.0 * center.y - current_begin.y;
1836 } else if (drag_type == DRAG_BOTTOM || drag_type == DRAG_BOTTOM_LEFT || drag_type == DRAG_BOTTOM_RIGHT) {
1837 current_begin.y = 2.0 * center.y - current_end.y;
1838 }
1839 }
1840 canvas_item->_edit_set_rect(Rect2(current_begin, current_end - current_begin));
1841 return true;
1842 }
1843
1844 // Confirm resize
1845 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
1846 _commit_canvas_item_state(drag_selection, TTR("Resize CanvasItem"));
1847 if (key_auto_insert_button->is_pressed()) {
1848 _insert_animation_keys(false, false, true, true);
1849 }
1850
1851 snap_target[0] = SNAP_TARGET_NONE;
1852 snap_target[1] = SNAP_TARGET_NONE;
1853 drag_type = DRAG_NONE;
1854 viewport->update();
1855 return true;
1856 }
1857
1858 // Cancel a drag
1859 if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
1860 _restore_canvas_item_state(drag_selection);
1861 snap_target[0] = SNAP_TARGET_NONE;
1862 snap_target[1] = SNAP_TARGET_NONE;
1863 drag_type = DRAG_NONE;
1864 viewport->update();
1865 return true;
1866 }
1867 }
1868 return false;
1869 }
1870
_gui_input_scale(const Ref<InputEvent> & p_event)1871 bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
1872
1873 Ref<InputEventMouseButton> b = p_event;
1874 Ref<InputEventMouseMotion> m = p_event;
1875
1876 // Drag resize handles
1877 if (drag_type == DRAG_NONE) {
1878 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) {
1879 List<CanvasItem *> selection = _get_edited_canvas_items();
1880 if (selection.size() == 1) {
1881 CanvasItem *canvas_item = selection[0];
1882
1883 if (_is_node_movable(canvas_item)) {
1884
1885 Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
1886 Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
1887 Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
1888
1889 drag_type = DRAG_SCALE_BOTH;
1890
1891 Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
1892 Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
1893 if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
1894 drag_type = DRAG_SCALE_X;
1895 }
1896 Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
1897 if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
1898 drag_type = DRAG_SCALE_Y;
1899 }
1900
1901 drag_from = transform.affine_inverse().xform(b->get_position());
1902 drag_selection = List<CanvasItem *>();
1903 drag_selection.push_back(canvas_item);
1904 _save_canvas_item_state(drag_selection);
1905 return true;
1906 }
1907 }
1908 }
1909 }
1910
1911 if (drag_type == DRAG_SCALE_BOTH || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
1912 // Resize the node
1913 if (m.is_valid()) {
1914 _restore_canvas_item_state(drag_selection);
1915 CanvasItem *canvas_item = drag_selection[0];
1916
1917 drag_to = transform.affine_inverse().xform(m->get_position());
1918
1919 Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse();
1920 Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized();
1921 Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
1922
1923 bool uniform = m->get_shift();
1924 bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
1925
1926 Point2 drag_from_local = simple_xform.xform(drag_from);
1927 Point2 drag_to_local = simple_xform.xform(drag_to);
1928 Point2 offset = drag_to_local - drag_from_local;
1929
1930 Size2 scale = canvas_item->call("get_scale");
1931 float ratio = scale.y / scale.x;
1932 if (drag_type == DRAG_SCALE_BOTH) {
1933 Size2 scale_factor = drag_to_local / drag_from_local;
1934 if (uniform) {
1935 scale *= (scale_factor.x + scale_factor.y) / 2.0;
1936 } else {
1937 scale *= scale_factor;
1938 }
1939 } else {
1940 Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE;
1941 Size2 parent_scale = parent_xform.get_scale();
1942 scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y);
1943 if (drag_type == DRAG_SCALE_X) {
1944 scale.x += scale_factor.x;
1945 if (uniform) {
1946 scale.y = scale.x * ratio;
1947 }
1948 } else if (drag_type == DRAG_SCALE_Y) {
1949 scale.y += scale_factor.y;
1950 if (uniform) {
1951 scale.x = scale.y / ratio;
1952 }
1953 }
1954 }
1955
1956 if (snap_scale && !is_ctrl) {
1957 scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step;
1958 scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step;
1959 }
1960
1961 canvas_item->call("set_scale", scale);
1962 return true;
1963 }
1964
1965 // Confirm resize
1966 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
1967 _commit_canvas_item_state(drag_selection, TTR("Scale CanvasItem"));
1968 if (key_auto_insert_button->is_pressed()) {
1969 _insert_animation_keys(false, false, true, true);
1970 }
1971
1972 drag_type = DRAG_NONE;
1973 viewport->update();
1974 return true;
1975 }
1976
1977 // Cancel a drag
1978 if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
1979 _restore_canvas_item_state(drag_selection);
1980 drag_type = DRAG_NONE;
1981 viewport->update();
1982 return true;
1983 }
1984 }
1985 return false;
1986 }
1987
_gui_input_move(const Ref<InputEvent> & p_event)1988 bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
1989 Ref<InputEventMouseButton> b = p_event;
1990 Ref<InputEventMouseMotion> m = p_event;
1991 Ref<InputEventKey> k = p_event;
1992
1993 if (drag_type == DRAG_NONE) {
1994 //Start moving the nodes
1995 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
1996 if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
1997 List<CanvasItem *> selection = _get_edited_canvas_items();
1998
1999 drag_selection.clear();
2000 for (int i = 0; i < selection.size(); i++) {
2001 if (_is_node_movable(selection[i], true)) {
2002 drag_selection.push_back(selection[i]);
2003 }
2004 }
2005
2006 if (selection.size() > 0) {
2007 drag_type = DRAG_MOVE;
2008 drag_from = transform.affine_inverse().xform(b->get_position());
2009 _save_canvas_item_state(drag_selection);
2010 }
2011 return true;
2012 }
2013 }
2014 }
2015
2016 if (drag_type == DRAG_MOVE) {
2017 // Move the nodes
2018 if (m.is_valid()) {
2019
2020 // Save the ik chain for reapplying before IK solve
2021 Vector<List<Dictionary> > all_bones_ik_states;
2022 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
2023 List<Dictionary> bones_ik_states;
2024 _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
2025 all_bones_ik_states.push_back(bones_ik_states);
2026 }
2027
2028 _restore_canvas_item_state(drag_selection, true);
2029
2030 drag_to = transform.affine_inverse().xform(m->get_position());
2031 Point2 previous_pos;
2032 if (drag_selection.size() == 1) {
2033 Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
2034 previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
2035 } else {
2036 previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
2037 }
2038 Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, NULL, drag_selection);
2039 bool single_axis = m->get_shift();
2040 if (single_axis) {
2041 if (ABS(new_pos.x - previous_pos.x) > ABS(new_pos.y - previous_pos.y)) {
2042 new_pos.y = previous_pos.y;
2043 } else {
2044 new_pos.x = previous_pos.x;
2045 }
2046 }
2047
2048 bool force_no_IK = m->get_alt();
2049 int index = 0;
2050 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
2051 CanvasItem *canvas_item = E->get();
2052 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
2053 Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
2054
2055 Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
2056 if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
2057 real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
2058 _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
2059 real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
2060 node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
2061 _solve_IK(node2d, new_pos);
2062 } else {
2063 canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
2064 }
2065 index++;
2066 }
2067 return true;
2068 }
2069
2070 // Confirm the move (only if it was moved)
2071 if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
2072 if (transform.affine_inverse().xform(b->get_position()) != drag_from) {
2073 _commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true);
2074 }
2075
2076 if (key_auto_insert_button->is_pressed()) {
2077 _insert_animation_keys(true, false, false, true);
2078 }
2079
2080 //Make sure smart snapping lines disappear.
2081 snap_target[0] = SNAP_TARGET_NONE;
2082 snap_target[1] = SNAP_TARGET_NONE;
2083
2084 drag_type = DRAG_NONE;
2085 viewport->update();
2086 return true;
2087 }
2088
2089 // Cancel a drag
2090 if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
2091 _restore_canvas_item_state(drag_selection, true);
2092 snap_target[0] = SNAP_TARGET_NONE;
2093 snap_target[1] = SNAP_TARGET_NONE;
2094 drag_type = DRAG_NONE;
2095 viewport->update();
2096 return true;
2097 }
2098 }
2099
2100 // Move the canvas items with the arrow keys
2101 if (k.is_valid() && k->is_pressed() && (tool == TOOL_SELECT || tool == TOOL_MOVE) &&
2102 (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_LEFT || k->get_scancode() == KEY_RIGHT)) {
2103 if (!k->is_echo()) {
2104 // Start moving the canvas items with the keyboard
2105 drag_selection = _get_edited_canvas_items();
2106 drag_type = DRAG_KEY_MOVE;
2107 drag_from = Vector2();
2108 drag_to = Vector2();
2109 _save_canvas_item_state(drag_selection, true);
2110 }
2111
2112 if (drag_selection.size() > 0) {
2113
2114 // Save the ik chain for reapplying before IK solve
2115 Vector<List<Dictionary> > all_bones_ik_states;
2116 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
2117 List<Dictionary> bones_ik_states;
2118 _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
2119 all_bones_ik_states.push_back(bones_ik_states);
2120 }
2121
2122 _restore_canvas_item_state(drag_selection, true);
2123
2124 bool move_local_base = k->get_alt();
2125 bool move_local_base_rotated = k->get_control() || k->get_metakey();
2126
2127 Vector2 dir;
2128 if (k->get_scancode() == KEY_UP)
2129 dir += Vector2(0, -1);
2130 else if (k->get_scancode() == KEY_DOWN)
2131 dir += Vector2(0, 1);
2132 else if (k->get_scancode() == KEY_LEFT)
2133 dir += Vector2(-1, 0);
2134 else if (k->get_scancode() == KEY_RIGHT)
2135 dir += Vector2(1, 0);
2136 if (k->get_shift())
2137 dir *= grid_step * Math::pow(2.0, grid_step_multiplier);
2138
2139 drag_to += dir;
2140 if (k->get_shift())
2141 drag_to = drag_to.snapped(grid_step * Math::pow(2.0, grid_step_multiplier));
2142
2143 Point2 previous_pos;
2144 if (drag_selection.size() == 1) {
2145 Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
2146 previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
2147 } else {
2148 previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
2149 }
2150
2151 Point2 new_pos;
2152 if (drag_selection.size() == 1) {
2153 Node2D *node_2d = Object::cast_to<Node2D>(drag_selection[0]);
2154 if (node_2d && move_local_base_rotated) {
2155 Transform2D m2;
2156 m2.rotate(node_2d->get_rotation());
2157 new_pos += m2.xform(drag_to);
2158 } else if (move_local_base) {
2159 new_pos += drag_to;
2160 } else {
2161 new_pos = previous_pos + (drag_to - drag_from);
2162 }
2163 } else {
2164 new_pos = previous_pos + (drag_to - drag_from);
2165 }
2166
2167 int index = 0;
2168 for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
2169 CanvasItem *canvas_item = E->get();
2170 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
2171 Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
2172
2173 Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
2174 if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
2175 real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
2176 _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
2177 real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
2178 node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
2179 _solve_IK(node2d, new_pos);
2180 } else {
2181 canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
2182 }
2183 index++;
2184 }
2185 }
2186 return true;
2187 }
2188
2189 if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && (tool == TOOL_SELECT || tool == TOOL_MOVE) &&
2190 (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_LEFT || k->get_scancode() == KEY_RIGHT)) {
2191 // Confirm canvas items move by arrow keys
2192 if ((!Input::get_singleton()->is_key_pressed(KEY_UP)) &&
2193 (!Input::get_singleton()->is_key_pressed(KEY_DOWN)) &&
2194 (!Input::get_singleton()->is_key_pressed(KEY_LEFT)) &&
2195 (!Input::get_singleton()->is_key_pressed(KEY_RIGHT))) {
2196 _commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true);
2197 drag_type = DRAG_NONE;
2198 }
2199 viewport->update();
2200 return true;
2201 }
2202
2203 return (k.is_valid() && (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_LEFT || k->get_scancode() == KEY_RIGHT)); // Accept the key event in any case
2204 }
2205
_gui_input_select(const Ref<InputEvent> & p_event)2206 bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
2207 Ref<InputEventMouseButton> b = p_event;
2208 Ref<InputEventMouseMotion> m = p_event;
2209 Ref<InputEventKey> k = p_event;
2210
2211 if (drag_type == DRAG_NONE) {
2212 if (b.is_valid() &&
2213 ((b->get_button_index() == BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) ||
2214 (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
2215 // Popup the selection menu list
2216 Point2 click = transform.affine_inverse().xform(b->get_position());
2217
2218 _get_canvas_items_at_pos(click, selection_results);
2219
2220 if (selection_results.size() == 1) {
2221 CanvasItem *item = selection_results[0].item;
2222 selection_results.clear();
2223
2224 _select_click_on_item(item, click, b->get_shift());
2225
2226 return true;
2227 } else if (!selection_results.empty()) {
2228 // Sorts items according the their z-index
2229 selection_results.sort();
2230
2231 NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
2232 StringName root_name = root_path.get_name(root_path.get_name_count() - 1);
2233
2234 for (int i = 0; i < selection_results.size(); i++) {
2235 CanvasItem *item = selection_results[i].item;
2236
2237 Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(item, "Node");
2238 String node_path = "/" + root_name + "/" + root_path.rel_path_to(item->get_path());
2239
2240 selection_menu->add_item(item->get_name());
2241 selection_menu->set_item_icon(i, icon);
2242 selection_menu->set_item_metadata(i, node_path);
2243 selection_menu->set_item_tooltip(i, String(item->get_name()) + "\nType: " + item->get_class() + "\nPath: " + node_path);
2244 }
2245
2246 selection_menu_additive_selection = b->get_shift();
2247 selection_menu->set_global_position(b->get_global_position());
2248 selection_menu->popup();
2249 return true;
2250 }
2251 }
2252
2253 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
2254 // Single item selection
2255 Point2 click = transform.affine_inverse().xform(b->get_position());
2256
2257 Node *scene = editor->get_edited_scene();
2258 if (!scene)
2259 return true;
2260
2261 // Find the item to select
2262 CanvasItem *canvas_item = NULL;
2263
2264 // Retrieve the bones
2265 Vector<_SelectResult> selection = Vector<_SelectResult>();
2266 _get_bones_at_pos(click, selection);
2267 if (!selection.empty()) {
2268 canvas_item = selection[0].item;
2269 } else {
2270 // Retrieve the canvas items
2271 selection = Vector<_SelectResult>();
2272 _get_canvas_items_at_pos(click, selection);
2273 if (!selection.empty()) {
2274 canvas_item = selection[0].item;
2275 }
2276 }
2277
2278 if (!canvas_item) {
2279 // Start a box selection
2280 if (!b->get_shift()) {
2281 // Clear the selection if not additive
2282 editor_selection->clear();
2283 viewport->update();
2284 selected_from_canvas = true;
2285 };
2286
2287 drag_from = click;
2288 drag_type = DRAG_BOX_SELECTION;
2289 box_selecting_to = drag_from;
2290 return true;
2291 } else {
2292 bool still_selected = _select_click_on_item(canvas_item, click, b->get_shift());
2293 // Start dragging
2294 if (still_selected) {
2295 // Drag the node(s) if requested
2296 List<CanvasItem *> selection2 = _get_edited_canvas_items();
2297
2298 drag_selection.clear();
2299 for (int i = 0; i < selection2.size(); i++) {
2300 if (_is_node_movable(selection2[i], true)) {
2301 drag_selection.push_back(selection2[i]);
2302 }
2303 }
2304
2305 if (selection2.size() > 0) {
2306 drag_type = DRAG_MOVE;
2307 drag_from = click;
2308 _save_canvas_item_state(drag_selection);
2309 }
2310 }
2311 // Select the item
2312 return true;
2313 }
2314 }
2315 }
2316
2317 if (drag_type == DRAG_BOX_SELECTION) {
2318 if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
2319 // Confirms box selection
2320 Node *scene = editor->get_edited_scene();
2321 if (scene) {
2322 List<CanvasItem *> selitems;
2323
2324 Point2 bsfrom = drag_from;
2325 Point2 bsto = box_selecting_to;
2326 if (bsfrom.x > bsto.x)
2327 SWAP(bsfrom.x, bsto.x);
2328 if (bsfrom.y > bsto.y)
2329 SWAP(bsfrom.y, bsto.y);
2330
2331 _find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
2332 for (List<CanvasItem *>::Element *E = selitems.front(); E; E = E->next()) {
2333 editor_selection->add_node(E->get());
2334 }
2335 }
2336
2337 drag_type = DRAG_NONE;
2338 viewport->update();
2339 return true;
2340 }
2341
2342 if (b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_RIGHT) {
2343 // Cancel box selection
2344 drag_type = DRAG_NONE;
2345 viewport->update();
2346 return true;
2347 }
2348
2349 if (m.is_valid()) {
2350 // Update box selection
2351 box_selecting_to = transform.affine_inverse().xform(m->get_position());
2352 viewport->update();
2353 return true;
2354 }
2355 }
2356
2357 if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) {
2358 // Unselect everything
2359 editor_selection->clear();
2360 viewport->update();
2361 }
2362 return false;
2363 }
2364
_gui_input_ruler_tool(const Ref<InputEvent> & p_event)2365 bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
2366
2367 if (tool != TOOL_RULER)
2368 return false;
2369
2370 Ref<InputEventMouseButton> b = p_event;
2371 Ref<InputEventMouseMotion> m = p_event;
2372
2373 Point2 previous_origin = ruler_tool_origin;
2374 if (!ruler_tool_active)
2375 ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset);
2376
2377 if (b.is_valid() && b->get_button_index() == BUTTON_LEFT) {
2378 if (b->is_pressed()) {
2379 ruler_tool_active = true;
2380 } else {
2381 ruler_tool_active = false;
2382 }
2383
2384 viewport->update();
2385 return true;
2386 }
2387
2388 if (m.is_valid() && (ruler_tool_active || (grid_snap_active && previous_origin != ruler_tool_origin))) {
2389
2390 viewport->update();
2391 return true;
2392 }
2393
2394 return false;
2395 }
2396
_gui_input_hover(const Ref<InputEvent> & p_event)2397 bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
2398
2399 Ref<InputEventMouseMotion> m = p_event;
2400 if (m.is_valid()) {
2401 Point2 click = transform.affine_inverse().xform(m->get_position());
2402
2403 // Checks if the hovered items changed, update the viewport if so
2404 Vector<_SelectResult> hovering_results_items;
2405 _get_canvas_items_at_pos(click, hovering_results_items);
2406 hovering_results_items.sort();
2407
2408 // Compute the nodes names and icon position
2409 Vector<_HoverResult> hovering_results_tmp;
2410 for (int i = 0; i < hovering_results_items.size(); i++) {
2411 CanvasItem *canvas_item = hovering_results_items[i].item;
2412
2413 if (canvas_item->_edit_use_rect())
2414 continue;
2415
2416 _HoverResult hover_result;
2417 hover_result.position = canvas_item->get_global_transform_with_canvas().get_origin();
2418 hover_result.icon = EditorNode::get_singleton()->get_object_icon(canvas_item);
2419 hover_result.name = canvas_item->get_name();
2420
2421 hovering_results_tmp.push_back(hover_result);
2422 }
2423
2424 // Check if changed, if so, update.
2425 bool changed = false;
2426 if (hovering_results_tmp.size() == hovering_results.size()) {
2427 for (int i = 0; i < hovering_results_tmp.size(); i++) {
2428 _HoverResult a = hovering_results_tmp[i];
2429 _HoverResult b = hovering_results[i];
2430 if (a.icon != b.icon || a.name != b.name || a.position != b.position) {
2431 changed = true;
2432 break;
2433 }
2434 }
2435 } else {
2436 changed = true;
2437 }
2438
2439 if (changed) {
2440 hovering_results = hovering_results_tmp;
2441 viewport->update();
2442 }
2443
2444 return true;
2445 }
2446
2447 return false;
2448 }
2449
_gui_input_viewport(const Ref<InputEvent> & p_event)2450 void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
2451 bool accepted = false;
2452
2453 if (EditorSettings::get_singleton()->get("editors/2d/simple_panning") || !pan_pressed) {
2454 if ((accepted = _gui_input_rulers_and_guides(p_event))) {
2455 //printf("Rulers and guides\n");
2456 } else if ((accepted = editor->get_editor_plugins_over()->forward_gui_input(p_event))) {
2457 //printf("Plugin\n");
2458 } else if ((accepted = _gui_input_open_scene_on_double_click(p_event))) {
2459 //printf("Open scene on double click\n");
2460 } else if ((accepted = _gui_input_scale(p_event))) {
2461 //printf("Set scale\n");
2462 } else if ((accepted = _gui_input_pivot(p_event))) {
2463 //printf("Set pivot\n");
2464 } else if ((accepted = _gui_input_resize(p_event))) {
2465 //printf("Resize\n");
2466 } else if ((accepted = _gui_input_rotate(p_event))) {
2467 //printf("Rotate\n");
2468 } else if ((accepted = _gui_input_move(p_event))) {
2469 //printf("Move\n");
2470 } else if ((accepted = _gui_input_anchors(p_event))) {
2471 //printf("Anchors\n");
2472 } else if ((accepted = _gui_input_select(p_event))) {
2473 //printf("Selection\n");
2474 } else if ((accepted = _gui_input_ruler_tool(p_event))) {
2475 //printf("Measure\n");
2476 } else {
2477 //printf("Not accepted\n");
2478 }
2479 }
2480
2481 accepted = (_gui_input_zoom_or_pan(p_event, accepted) || accepted);
2482
2483 if (accepted)
2484 accept_event();
2485
2486 // Handles the mouse hovering
2487 _gui_input_hover(p_event);
2488
2489 // Change the cursor
2490 CursorShape c = CURSOR_ARROW;
2491 switch (drag_type) {
2492 case DRAG_NONE:
2493 switch (tool) {
2494 case TOOL_MOVE:
2495 c = CURSOR_MOVE;
2496 break;
2497 case TOOL_EDIT_PIVOT:
2498 c = CURSOR_CROSS;
2499 break;
2500 case TOOL_PAN:
2501 c = CURSOR_DRAG;
2502 break;
2503 case TOOL_RULER:
2504 c = CURSOR_CROSS;
2505 break;
2506 default:
2507 break;
2508 }
2509 break;
2510 case DRAG_LEFT:
2511 case DRAG_RIGHT:
2512 case DRAG_V_GUIDE:
2513 c = CURSOR_HSIZE;
2514 break;
2515 case DRAG_TOP:
2516 case DRAG_BOTTOM:
2517 case DRAG_H_GUIDE:
2518 c = CURSOR_VSIZE;
2519 break;
2520 case DRAG_TOP_LEFT:
2521 case DRAG_BOTTOM_RIGHT:
2522 case DRAG_DOUBLE_GUIDE:
2523 c = CURSOR_FDIAGSIZE;
2524 break;
2525 case DRAG_TOP_RIGHT:
2526 case DRAG_BOTTOM_LEFT:
2527 c = CURSOR_BDIAGSIZE;
2528 break;
2529 case DRAG_MOVE:
2530 c = CURSOR_MOVE;
2531 break;
2532 default:
2533 break;
2534 }
2535
2536 if (is_hovering_h_guide)
2537 c = CURSOR_VSIZE;
2538 else if (is_hovering_v_guide)
2539 c = CURSOR_HSIZE;
2540
2541 viewport->set_default_cursor_shape(c);
2542
2543 // Grab focus
2544 if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) {
2545 viewport->call_deferred("grab_focus");
2546 }
2547 }
2548
_draw_text_at_position(Point2 p_position,String p_string,Margin p_side)2549 void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Margin p_side) {
2550 Color color = get_color("font_color", "Editor");
2551 color.a = 0.8;
2552 Ref<Font> font = get_font("font", "Label");
2553 Size2 text_size = font->get_string_size(p_string);
2554 switch (p_side) {
2555 case MARGIN_LEFT:
2556 p_position += Vector2(-text_size.x - 5, text_size.y / 2);
2557 break;
2558 case MARGIN_TOP:
2559 p_position += Vector2(-text_size.x / 2, -5);
2560 break;
2561 case MARGIN_RIGHT:
2562 p_position += Vector2(5, text_size.y / 2);
2563 break;
2564 case MARGIN_BOTTOM:
2565 p_position += Vector2(-text_size.x / 2, text_size.y + 5);
2566 break;
2567 }
2568 viewport->draw_string(font, p_position, p_string, color);
2569 }
2570
_draw_margin_at_position(int p_value,Point2 p_position,Margin p_side)2571 void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position, Margin p_side) {
2572 String str = vformat("%d px", p_value);
2573 if (p_value != 0) {
2574 _draw_text_at_position(p_position, str, p_side);
2575 }
2576 }
2577
_draw_percentage_at_position(float p_value,Point2 p_position,Margin p_side)2578 void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_position, Margin p_side) {
2579 String str = vformat("%.1f %%", p_value * 100.0);
2580 if (p_value != 0) {
2581 _draw_text_at_position(p_position, str, p_side);
2582 }
2583 }
2584
_draw_focus()2585 void CanvasItemEditor::_draw_focus() {
2586 // Draw the focus around the base viewport
2587 if (viewport->has_focus()) {
2588 get_stylebox("Focus", "EditorStyles")->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size()));
2589 }
2590 }
2591
_draw_guides()2592 void CanvasItemEditor::_draw_guides() {
2593
2594 Color guide_color = EditorSettings::get_singleton()->get("editors/2d/guides_color");
2595 Transform2D xform = viewport_scrollable->get_transform() * transform;
2596
2597 // Guides already there
2598 if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
2599 Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
2600 for (int i = 0; i < vguides.size(); i++) {
2601 if (drag_type == DRAG_V_GUIDE && i == dragged_guide_index)
2602 continue;
2603 float x = xform.xform(Point2(vguides[i], 0)).x;
2604 viewport->draw_line(Point2(x, 0), Point2(x, viewport->get_size().y), guide_color, Math::round(EDSCALE));
2605 }
2606 }
2607
2608 if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
2609 Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
2610 for (int i = 0; i < hguides.size(); i++) {
2611 if (drag_type == DRAG_H_GUIDE && i == dragged_guide_index)
2612 continue;
2613 float y = xform.xform(Point2(0, hguides[i])).y;
2614 viewport->draw_line(Point2(0, y), Point2(viewport->get_size().x, y), guide_color, Math::round(EDSCALE));
2615 }
2616 }
2617
2618 // Dragged guide
2619 Color text_color = get_color("font_color", "Editor");
2620 text_color.a = 0.5;
2621 if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_V_GUIDE) {
2622 String str = vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x));
2623 Ref<Font> font = get_font("font", "Label");
2624 Size2 text_size = font->get_string_size(str);
2625 viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, text_color);
2626 viewport->draw_line(Point2(dragged_guide_pos.x, 0), Point2(dragged_guide_pos.x, viewport->get_size().y), guide_color, Math::round(EDSCALE));
2627 }
2628 if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_H_GUIDE) {
2629 String str = vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y));
2630 Ref<Font> font = get_font("font", "Label");
2631 Size2 text_size = font->get_string_size(str);
2632 viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, text_color);
2633 viewport->draw_line(Point2(0, dragged_guide_pos.y), Point2(viewport->get_size().x, dragged_guide_pos.y), guide_color, Math::round(EDSCALE));
2634 }
2635 }
2636
_draw_smart_snapping()2637 void CanvasItemEditor::_draw_smart_snapping() {
2638 Color line_color = EditorSettings::get_singleton()->get("editors/2d/smart_snapping_line_color");
2639 if (snap_target[0] != SNAP_TARGET_NONE && snap_target[0] != SNAP_TARGET_GRID) {
2640 viewport->draw_set_transform_matrix(viewport->get_transform() * transform * snap_transform);
2641 viewport->draw_line(Point2(0, -1.0e+10F), Point2(0, 1.0e+10F), line_color);
2642 viewport->draw_set_transform_matrix(viewport->get_transform());
2643 }
2644 if (snap_target[1] != SNAP_TARGET_NONE && snap_target[1] != SNAP_TARGET_GRID) {
2645 viewport->draw_set_transform_matrix(viewport->get_transform() * transform * snap_transform);
2646 viewport->draw_line(Point2(-1.0e+10F, 0), Point2(1.0e+10F, 0), line_color);
2647 viewport->draw_set_transform_matrix(viewport->get_transform());
2648 }
2649 }
2650
_draw_rulers()2651 void CanvasItemEditor::_draw_rulers() {
2652 Color bg_color = get_color("dark_color_2", "Editor");
2653 Color graduation_color = get_color("font_color", "Editor").linear_interpolate(bg_color, 0.5);
2654 Color font_color = get_color("font_color", "Editor");
2655 font_color.a = 0.8;
2656 Ref<Font> font = get_font("rulers", "EditorFonts");
2657
2658 // The rule transform
2659 Transform2D ruler_transform = Transform2D();
2660 if (show_grid || grid_snap_active) {
2661 List<CanvasItem *> selection = _get_edited_canvas_items();
2662 if (snap_relative && selection.size() > 0) {
2663 ruler_transform.translate(_get_encompassing_rect_from_list(selection).position);
2664 ruler_transform.scale_basis(grid_step * Math::pow(2.0, grid_step_multiplier));
2665 } else {
2666 ruler_transform.translate(grid_offset);
2667 ruler_transform.scale_basis(grid_step * Math::pow(2.0, grid_step_multiplier));
2668 }
2669 while ((transform * ruler_transform).get_scale().x < 50 || (transform * ruler_transform).get_scale().y < 50) {
2670 ruler_transform.scale_basis(Point2(2, 2));
2671 }
2672 } else {
2673 float basic_rule = 100;
2674 for (int i = 0; basic_rule * zoom > 100; i++) {
2675 basic_rule /= (i % 2) ? 5.0 : 2.0;
2676 }
2677 for (int i = 0; basic_rule * zoom < 100; i++) {
2678 basic_rule *= (i % 2) ? 2.0 : 5.0;
2679 }
2680 ruler_transform.scale(Size2(basic_rule, basic_rule));
2681 }
2682
2683 // Subdivisions
2684 int major_subdivision = 2;
2685 Transform2D major_subdivide = Transform2D();
2686 major_subdivide.scale(Size2(1.0 / major_subdivision, 1.0 / major_subdivision));
2687
2688 int minor_subdivision = 5;
2689 Transform2D minor_subdivide = Transform2D();
2690 minor_subdivide.scale(Size2(1.0 / minor_subdivision, 1.0 / minor_subdivision));
2691
2692 // First and last graduations to draw (in the ruler space)
2693 Point2 first = (transform * ruler_transform * major_subdivide * minor_subdivide).affine_inverse().xform(Point2(RULER_WIDTH, RULER_WIDTH));
2694 Point2 last = (transform * ruler_transform * major_subdivide * minor_subdivide).affine_inverse().xform(viewport->get_size());
2695
2696 // Draw top ruler
2697 viewport->draw_rect(Rect2(Point2(RULER_WIDTH, 0), Size2(viewport->get_size().x, RULER_WIDTH)), bg_color);
2698 for (int i = Math::ceil(first.x); i < last.x; i++) {
2699 Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0));
2700 if (i % (major_subdivision * minor_subdivision) == 0) {
2701 viewport->draw_line(Point2(position.x, 0), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE));
2702 float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x;
2703 viewport->draw_string(font, Point2(position.x + 2, font->get_height()), vformat(((int)val == val) ? "%d" : "%.1f", val), font_color);
2704 } else {
2705 if (i % minor_subdivision == 0) {
2706 viewport->draw_line(Point2(position.x, RULER_WIDTH * 0.33), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE));
2707 } else {
2708 viewport->draw_line(Point2(position.x, RULER_WIDTH * 0.75), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE));
2709 }
2710 }
2711 }
2712
2713 // Draw left ruler
2714 viewport->draw_rect(Rect2(Point2(0, RULER_WIDTH), Size2(RULER_WIDTH, viewport->get_size().y)), bg_color);
2715 for (int i = Math::ceil(first.y); i < last.y; i++) {
2716 Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i));
2717 if (i % (major_subdivision * minor_subdivision) == 0) {
2718 viewport->draw_line(Point2(0, position.y), Point2(RULER_WIDTH, position.y), graduation_color, Math::round(EDSCALE));
2719 float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y;
2720
2721 Transform2D text_xform = Transform2D(-Math_PI / 2.0, Point2(font->get_height(), position.y - 2));
2722 viewport->draw_set_transform_matrix(viewport->get_transform() * text_xform);
2723 viewport->draw_string(font, Point2(), vformat(((int)val == val) ? "%d" : "%.1f", val), font_color);
2724 viewport->draw_set_transform_matrix(viewport->get_transform());
2725
2726 } else {
2727 if (i % minor_subdivision == 0) {
2728 viewport->draw_line(Point2(RULER_WIDTH * 0.33, position.y), Point2(RULER_WIDTH, position.y), graduation_color, Math::round(EDSCALE));
2729 } else {
2730 viewport->draw_line(Point2(RULER_WIDTH * 0.75, position.y), Point2(RULER_WIDTH, position.y), graduation_color, Math::round(EDSCALE));
2731 }
2732 }
2733 }
2734
2735 // Draw the top left corner
2736 viewport->draw_rect(Rect2(Point2(), Size2(RULER_WIDTH, RULER_WIDTH)), graduation_color);
2737 }
2738
_draw_grid()2739 void CanvasItemEditor::_draw_grid() {
2740
2741 if (show_grid || grid_snap_active) {
2742 // Draw the grid
2743 Vector2 real_grid_offset;
2744 const List<CanvasItem *> selection = _get_edited_canvas_items();
2745
2746 if (snap_relative && selection.size() > 0) {
2747 const Vector2 topleft = _get_encompassing_rect_from_list(selection).position;
2748 real_grid_offset.x = fmod(topleft.x, grid_step.x * (real_t)Math::pow(2.0, grid_step_multiplier));
2749 real_grid_offset.y = fmod(topleft.y, grid_step.y * (real_t)Math::pow(2.0, grid_step_multiplier));
2750 } else {
2751 real_grid_offset = grid_offset;
2752 }
2753
2754 // Draw a "primary" line every several lines to make measurements easier.
2755 // The step is configurable in the Configure Snap dialog.
2756 const Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/2d/grid_color");
2757 const Color primary_grid_color =
2758 Color(secondary_grid_color.r, secondary_grid_color.g, secondary_grid_color.b, secondary_grid_color.a * 2.5);
2759
2760 const Size2 viewport_size = viewport->get_size();
2761 const Transform2D xform = transform.affine_inverse();
2762 int last_cell = 0;
2763
2764 if (grid_step.x != 0) {
2765 for (int i = 0; i < viewport_size.width; i++) {
2766 const int cell =
2767 Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - real_grid_offset.x) / (grid_step.x * Math::pow(2.0, grid_step_multiplier))));
2768
2769 if (i == 0) {
2770 last_cell = cell;
2771 }
2772
2773 if (last_cell != cell) {
2774 Color grid_color;
2775 if (primary_grid_steps == 0) {
2776 grid_color = secondary_grid_color;
2777 } else {
2778 grid_color = cell % primary_grid_steps == 0 ? primary_grid_color : secondary_grid_color;
2779 }
2780
2781 viewport->draw_line(Point2(i, 0), Point2(i, viewport_size.height), grid_color, Math::round(EDSCALE));
2782 }
2783 last_cell = cell;
2784 }
2785 }
2786
2787 if (grid_step.y != 0) {
2788 for (int i = 0; i < viewport_size.height; i++) {
2789 const int cell =
2790 Math::fast_ftoi(Math::floor((xform.xform(Vector2(0, i)).y - real_grid_offset.y) / (grid_step.y * Math::pow(2.0, grid_step_multiplier))));
2791
2792 if (i == 0) {
2793 last_cell = cell;
2794 }
2795
2796 if (last_cell != cell) {
2797 Color grid_color;
2798 if (primary_grid_steps == 0) {
2799 grid_color = secondary_grid_color;
2800 } else {
2801 grid_color = cell % primary_grid_steps == 0 ? primary_grid_color : secondary_grid_color;
2802 }
2803
2804 viewport->draw_line(Point2(0, i), Point2(viewport_size.width, i), grid_color, Math::round(EDSCALE));
2805 }
2806 last_cell = cell;
2807 }
2808 }
2809 }
2810 }
2811
_draw_ruler_tool()2812 void CanvasItemEditor::_draw_ruler_tool() {
2813
2814 if (tool != TOOL_RULER)
2815 return;
2816
2817 if (ruler_tool_active) {
2818 Color ruler_primary_color = get_color("accent_color", "Editor");
2819 Color ruler_secondary_color = ruler_primary_color;
2820 ruler_secondary_color.a = 0.5;
2821
2822 Point2 begin = (ruler_tool_origin - view_offset) * zoom;
2823 Point2 end = snap_point(viewport->get_local_mouse_position() / zoom + view_offset) * zoom - view_offset * zoom;
2824 Point2 corner = Point2(begin.x, end.y);
2825 Vector2 length_vector = (begin - end).abs() / zoom;
2826
2827 bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x));
2828
2829 viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3), true);
2830 if (draw_secondary_lines) {
2831 viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE));
2832 viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE));
2833 }
2834
2835 Ref<Font> font = get_font("bold", "EditorFonts");
2836 Color font_color = get_color("font_color", "Editor");
2837 Color font_secondary_color = font_color;
2838 font_secondary_color.a = 0.5;
2839 float text_height = font->get_height();
2840 const float text_width = 76;
2841 const float angle_text_width = 54;
2842
2843 Point2 text_pos = (begin + end) / 2 - Vector2(text_width / 2, text_height / 2);
2844 text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5);
2845 text_pos.y = CLAMP(text_pos.y, text_height * 1.5, viewport->get_rect().size.y - text_height * 1.5);
2846 viewport->draw_string(font, text_pos, vformat("%.2f px", length_vector.length()), font_color);
2847
2848 if (draw_secondary_lines) {
2849 const float horizontal_angle_rad = atan2(length_vector.y, length_vector.x);
2850 const float vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
2851 const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI);
2852 const int vertical_angle = round(180 * vertical_angle_rad / Math_PI);
2853
2854 Point2 text_pos2 = text_pos;
2855 text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
2856 viewport->draw_string(font, text_pos2, vformat("%.2f px", length_vector.y), font_secondary_color);
2857
2858 Point2 v_angle_text_pos = Point2();
2859 v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
2860 v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5);
2861 viewport->draw_string(font, v_angle_text_pos, vformat("%d deg", vertical_angle), font_secondary_color);
2862
2863 text_pos2 = text_pos;
2864 text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2);
2865 viewport->draw_string(font, text_pos2, vformat("%.2f px", length_vector.x), font_secondary_color);
2866
2867 Point2 h_angle_text_pos = Point2();
2868 h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
2869 if (begin.y < end.y) {
2870 h_angle_text_pos.y = end.y + text_height * 1.5;
2871 if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) {
2872 int height_multiplier = 1.5 + (int)grid_snap_active;
2873 h_angle_text_pos.y = MAX(text_pos.y + height_multiplier * text_height, MAX(end.y + text_height * 1.5, text_pos2.y + height_multiplier * text_height));
2874 }
2875 } else {
2876 h_angle_text_pos.y = end.y - text_height * 0.5;
2877 if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) {
2878 int height_multiplier = 1 + (int)grid_snap_active;
2879 h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height));
2880 }
2881 }
2882 viewport->draw_string(font, h_angle_text_pos, vformat("%d deg", horizontal_angle), font_secondary_color);
2883
2884 // Angle arcs
2885 int arc_point_count = 8;
2886 float arc_radius_max_length_percent = 0.1;
2887 float ruler_length = length_vector.length() * zoom;
2888 float arc_max_radius = 50.0;
2889 float arc_line_width = 2.0;
2890
2891 const Vector2 end_to_begin = (end - begin);
2892
2893 float arc_1_start_angle =
2894 end_to_begin.x < 0 ?
2895 (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) :
2896 (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
2897 float arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
2898 // Constrain arc to triangle height & max size
2899 float arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
2900
2901 float arc_2_start_angle =
2902 end_to_begin.x < 0 ?
2903 (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) :
2904 (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
2905 float arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
2906 // Constrain arc to triangle width & max size
2907 float arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
2908
2909 viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
2910 viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
2911 }
2912
2913 if (grid_snap_active) {
2914
2915 text_pos = (begin + end) / 2 + Vector2(-text_width / 2, text_height / 2);
2916 text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5);
2917 text_pos.y = CLAMP(text_pos.y, text_height * 2.5, viewport->get_rect().size.y - text_height / 2);
2918
2919 if (draw_secondary_lines) {
2920 viewport->draw_string(font, text_pos, vformat("%.2f units", (length_vector / grid_step).length()), font_color);
2921
2922 Point2 text_pos2 = text_pos;
2923 text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
2924 viewport->draw_string(font, text_pos2, vformat("%d units", roundf(length_vector.y / grid_step.y)), font_secondary_color);
2925
2926 text_pos2 = text_pos;
2927 text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y + text_height / 2) : MAX(text_pos.y + text_height * 2, end.y + text_height / 2);
2928 viewport->draw_string(font, text_pos2, vformat("%d units", roundf(length_vector.x / grid_step.x)), font_secondary_color);
2929 } else {
2930 viewport->draw_string(font, text_pos, vformat("%d units", roundf((length_vector / grid_step).length())), font_color);
2931 }
2932 }
2933 } else {
2934
2935 if (grid_snap_active) {
2936 Ref<Texture> position_icon = get_icon("EditorPosition", "EditorIcons");
2937 viewport->draw_texture(get_icon("EditorPosition", "EditorIcons"), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
2938 }
2939 }
2940 }
2941
_draw_control_anchors(Control * control)2942 void CanvasItemEditor::_draw_control_anchors(Control *control) {
2943 Transform2D xform = transform * control->get_global_transform_with_canvas();
2944 RID ci = viewport->get_canvas_item();
2945 if (tool == TOOL_SELECT && !Object::cast_to<Container>(control->get_parent())) {
2946
2947 // Compute the anchors
2948 float anchors_values[4];
2949 anchors_values[0] = control->get_anchor(MARGIN_LEFT);
2950 anchors_values[1] = control->get_anchor(MARGIN_TOP);
2951 anchors_values[2] = control->get_anchor(MARGIN_RIGHT);
2952 anchors_values[3] = control->get_anchor(MARGIN_BOTTOM);
2953
2954 Vector2 anchors_pos[4];
2955 for (int i = 0; i < 4; i++) {
2956 Vector2 value = Vector2((i % 2 == 0) ? anchors_values[i] : anchors_values[(i + 1) % 4], (i % 2 == 1) ? anchors_values[i] : anchors_values[(i + 1) % 4]);
2957 anchors_pos[i] = xform.xform(_anchor_to_position(control, value));
2958 }
2959
2960 // Draw the anchors handles
2961 Rect2 anchor_rects[4];
2962 anchor_rects[0] = Rect2(anchors_pos[0] - anchor_handle->get_size(), anchor_handle->get_size());
2963 anchor_rects[1] = Rect2(anchors_pos[1] - Vector2(0.0, anchor_handle->get_size().y), Point2(-anchor_handle->get_size().x, anchor_handle->get_size().y));
2964 anchor_rects[2] = Rect2(anchors_pos[2], -anchor_handle->get_size());
2965 anchor_rects[3] = Rect2(anchors_pos[3] - Vector2(anchor_handle->get_size().x, 0.0), Point2(anchor_handle->get_size().x, -anchor_handle->get_size().y));
2966
2967 for (int i = 0; i < 4; i++) {
2968 anchor_handle->draw_rect(ci, anchor_rects[i]);
2969 }
2970 }
2971 }
2972
_draw_control_helpers(Control * control)2973 void CanvasItemEditor::_draw_control_helpers(Control *control) {
2974 Transform2D xform = transform * control->get_global_transform_with_canvas();
2975 if (tool == TOOL_SELECT && show_helpers && !Object::cast_to<Container>(control->get_parent())) {
2976 // Draw the helpers
2977 Color color_base = Color(0.8, 0.8, 0.8, 0.5);
2978
2979 // Compute the anchors
2980 float anchors_values[4];
2981 anchors_values[0] = control->get_anchor(MARGIN_LEFT);
2982 anchors_values[1] = control->get_anchor(MARGIN_TOP);
2983 anchors_values[2] = control->get_anchor(MARGIN_RIGHT);
2984 anchors_values[3] = control->get_anchor(MARGIN_BOTTOM);
2985
2986 Vector2 anchors[4];
2987 Vector2 anchors_pos[4];
2988 for (int i = 0; i < 4; i++) {
2989 anchors[i] = Vector2((i % 2 == 0) ? anchors_values[i] : anchors_values[(i + 1) % 4], (i % 2 == 1) ? anchors_values[i] : anchors_values[(i + 1) % 4]);
2990 anchors_pos[i] = xform.xform(_anchor_to_position(control, anchors[i]));
2991 }
2992
2993 // Get which anchor is dragged
2994 int dragged_anchor = -1;
2995 switch (drag_type) {
2996 case DRAG_ANCHOR_ALL:
2997 case DRAG_ANCHOR_TOP_LEFT:
2998 dragged_anchor = 0;
2999 break;
3000 case DRAG_ANCHOR_TOP_RIGHT:
3001 dragged_anchor = 1;
3002 break;
3003 case DRAG_ANCHOR_BOTTOM_RIGHT:
3004 dragged_anchor = 2;
3005 break;
3006 case DRAG_ANCHOR_BOTTOM_LEFT:
3007 dragged_anchor = 3;
3008 break;
3009 default:
3010 break;
3011 }
3012
3013 if (dragged_anchor >= 0) {
3014 // Draw the 4 lines when dragged
3015 bool anchor_snapped;
3016 Color color_snapped = Color(0.64, 0.93, 0.67, 0.5);
3017
3018 Vector2 corners_pos[4];
3019 for (int i = 0; i < 4; i++) {
3020 corners_pos[i] = xform.xform(_anchor_to_position(control, Vector2((i == 0 || i == 3) ? ANCHOR_BEGIN : ANCHOR_END, (i <= 1) ? ANCHOR_BEGIN : ANCHOR_END)));
3021 }
3022
3023 Vector2 line_starts[4];
3024 Vector2 line_ends[4];
3025 for (int i = 0; i < 4; i++) {
3026 float anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i];
3027 line_starts[i] = Vector2::linear_interpolate(corners_pos[i], corners_pos[(i + 1) % 4], anchor_val);
3028 line_ends[i] = Vector2::linear_interpolate(corners_pos[(i + 3) % 4], corners_pos[(i + 2) % 4], anchor_val);
3029 anchor_snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0;
3030 viewport->draw_line(line_starts[i], line_ends[i], anchor_snapped ? color_snapped : color_base, (i == dragged_anchor || (i + 3) % 4 == dragged_anchor) ? 2 : 1);
3031 }
3032
3033 // Display the percentages next to the lines
3034 float percent_val;
3035 percent_val = anchors_values[(dragged_anchor + 2) % 4] - anchors_values[dragged_anchor];
3036 percent_val = (dragged_anchor >= 2) ? -percent_val : percent_val;
3037 _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Margin)((dragged_anchor + 1) % 4));
3038
3039 percent_val = anchors_values[(dragged_anchor + 3) % 4] - anchors_values[(dragged_anchor + 1) % 4];
3040 percent_val = ((dragged_anchor + 1) % 4 >= 2) ? -percent_val : percent_val;
3041 _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 3) % 4]) / 2, (Margin)(dragged_anchor));
3042
3043 percent_val = anchors_values[(dragged_anchor + 1) % 4];
3044 percent_val = ((dragged_anchor + 1) % 4 >= 2) ? ANCHOR_END - percent_val : percent_val;
3045 _draw_percentage_at_position(percent_val, (line_starts[dragged_anchor] + anchors_pos[dragged_anchor]) / 2, (Margin)(dragged_anchor));
3046
3047 percent_val = anchors_values[dragged_anchor];
3048 percent_val = (dragged_anchor >= 2) ? ANCHOR_END - percent_val : percent_val;
3049 _draw_percentage_at_position(percent_val, (line_ends[(dragged_anchor + 1) % 4] + anchors_pos[dragged_anchor]) / 2, (Margin)((dragged_anchor + 1) % 4));
3050 }
3051
3052 // Draw the margin values and the node width/height when dragging control side
3053 float ratio = 0.33;
3054 Transform2D parent_transform = xform * control->get_transform().affine_inverse();
3055 float node_pos_in_parent[4];
3056
3057 Rect2 parent_rect = control->get_parent_anchorable_rect();
3058
3059 node_pos_in_parent[0] = control->get_anchor(MARGIN_LEFT) * parent_rect.size.width + control->get_margin(MARGIN_LEFT) + parent_rect.position.x;
3060 node_pos_in_parent[1] = control->get_anchor(MARGIN_TOP) * parent_rect.size.height + control->get_margin(MARGIN_TOP) + parent_rect.position.y;
3061 node_pos_in_parent[2] = control->get_anchor(MARGIN_RIGHT) * parent_rect.size.width + control->get_margin(MARGIN_RIGHT) + parent_rect.position.x;
3062 node_pos_in_parent[3] = control->get_anchor(MARGIN_BOTTOM) * parent_rect.size.height + control->get_margin(MARGIN_BOTTOM) + parent_rect.position.y;
3063
3064 Point2 start, end;
3065 switch (drag_type) {
3066 case DRAG_LEFT:
3067 case DRAG_TOP_LEFT:
3068 case DRAG_BOTTOM_LEFT:
3069 _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM);
3070 FALLTHROUGH;
3071 case DRAG_MOVE:
3072 start = Vector2(node_pos_in_parent[0], Math::lerp(node_pos_in_parent[1], node_pos_in_parent[3], ratio));
3073 end = start - Vector2(control->get_margin(MARGIN_LEFT), 0);
3074 _draw_margin_at_position(control->get_margin(MARGIN_LEFT), parent_transform.xform((start + end) / 2), MARGIN_TOP);
3075 viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE));
3076 break;
3077 default:
3078 break;
3079 }
3080 switch (drag_type) {
3081 case DRAG_RIGHT:
3082 case DRAG_TOP_RIGHT:
3083 case DRAG_BOTTOM_RIGHT:
3084 _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM);
3085 FALLTHROUGH;
3086 case DRAG_MOVE:
3087 start = Vector2(node_pos_in_parent[2], Math::lerp(node_pos_in_parent[3], node_pos_in_parent[1], ratio));
3088 end = start - Vector2(control->get_margin(MARGIN_RIGHT), 0);
3089 _draw_margin_at_position(control->get_margin(MARGIN_RIGHT), parent_transform.xform((start + end) / 2), MARGIN_BOTTOM);
3090 viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE));
3091 break;
3092 default:
3093 break;
3094 }
3095 switch (drag_type) {
3096 case DRAG_TOP:
3097 case DRAG_TOP_LEFT:
3098 case DRAG_TOP_RIGHT:
3099 _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), MARGIN_RIGHT);
3100 FALLTHROUGH;
3101 case DRAG_MOVE:
3102 start = Vector2(Math::lerp(node_pos_in_parent[0], node_pos_in_parent[2], ratio), node_pos_in_parent[1]);
3103 end = start - Vector2(0, control->get_margin(MARGIN_TOP));
3104 _draw_margin_at_position(control->get_margin(MARGIN_TOP), parent_transform.xform((start + end) / 2), MARGIN_LEFT);
3105 viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE));
3106 break;
3107 default:
3108 break;
3109 }
3110 switch (drag_type) {
3111 case DRAG_BOTTOM:
3112 case DRAG_BOTTOM_LEFT:
3113 case DRAG_BOTTOM_RIGHT:
3114 _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), MARGIN_RIGHT);
3115 FALLTHROUGH;
3116 case DRAG_MOVE:
3117 start = Vector2(Math::lerp(node_pos_in_parent[2], node_pos_in_parent[0], ratio), node_pos_in_parent[3]);
3118 end = start - Vector2(0, control->get_margin(MARGIN_BOTTOM));
3119 _draw_margin_at_position(control->get_margin(MARGIN_BOTTOM), parent_transform.xform((start + end) / 2), MARGIN_RIGHT);
3120 viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE));
3121 break;
3122 default:
3123 break;
3124 }
3125
3126 switch (drag_type) {
3127 //Draw the ghost rect if the node if rotated/scaled
3128 case DRAG_LEFT:
3129 case DRAG_TOP_LEFT:
3130 case DRAG_TOP:
3131 case DRAG_TOP_RIGHT:
3132 case DRAG_RIGHT:
3133 case DRAG_BOTTOM_RIGHT:
3134 case DRAG_BOTTOM:
3135 case DRAG_BOTTOM_LEFT:
3136 case DRAG_MOVE:
3137 if (control->get_rotation() != 0.0 || control->get_scale() != Vector2(1, 1)) {
3138 Rect2 rect = Rect2(Vector2(node_pos_in_parent[0], node_pos_in_parent[1]), control->get_size());
3139 viewport->draw_rect(parent_transform.xform(rect), color_base, false, Math::round(EDSCALE));
3140 }
3141 break;
3142 default:
3143 break;
3144 }
3145 }
3146 }
3147
_draw_selection()3148 void CanvasItemEditor::_draw_selection() {
3149 Ref<Texture> pivot_icon = get_icon("EditorPivot", "EditorIcons");
3150 Ref<Texture> position_icon = get_icon("EditorPosition", "EditorIcons");
3151 Ref<Texture> previous_position_icon = get_icon("EditorPositionPrevious", "EditorIcons");
3152
3153 RID ci = viewport->get_canvas_item();
3154
3155 List<CanvasItem *> selection = _get_edited_canvas_items(true, false);
3156
3157 bool single = selection.size() == 1;
3158 for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
3159 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
3160 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
3161
3162 bool item_locked = canvas_item->has_meta("_edit_lock_");
3163
3164 // Draw the previous position if we are dragging the node
3165 if (show_helpers &&
3166 (drag_type == DRAG_MOVE || drag_type == DRAG_ROTATE ||
3167 drag_type == DRAG_LEFT || drag_type == DRAG_RIGHT || drag_type == DRAG_TOP || drag_type == DRAG_BOTTOM ||
3168 drag_type == DRAG_TOP_LEFT || drag_type == DRAG_TOP_RIGHT || drag_type == DRAG_BOTTOM_LEFT || drag_type == DRAG_BOTTOM_RIGHT)) {
3169 const Transform2D pre_drag_xform = transform * se->pre_drag_xform;
3170 const Color pre_drag_color = Color(0.4, 0.6, 1, 0.7);
3171
3172 if (canvas_item->_edit_use_rect()) {
3173 Vector2 pre_drag_endpoints[4] = {
3174
3175 pre_drag_xform.xform(se->pre_drag_rect.position),
3176 pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(se->pre_drag_rect.size.x, 0)),
3177 pre_drag_xform.xform(se->pre_drag_rect.position + se->pre_drag_rect.size),
3178 pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(0, se->pre_drag_rect.size.y))
3179 };
3180
3181 for (int i = 0; i < 4; i++) {
3182 viewport->draw_line(pre_drag_endpoints[i], pre_drag_endpoints[(i + 1) % 4], pre_drag_color, Math::round(2 * EDSCALE), true);
3183 }
3184 } else {
3185 viewport->draw_texture(previous_position_icon, (pre_drag_xform.xform(Point2()) - (previous_position_icon->get_size() / 2)).floor());
3186 }
3187 }
3188
3189 Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
3190
3191 // Draw the selected items position / surrounding boxes
3192 if (canvas_item->_edit_use_rect()) {
3193 Rect2 rect = canvas_item->_edit_get_rect();
3194 Vector2 endpoints[4] = {
3195 xform.xform(rect.position),
3196 xform.xform(rect.position + Vector2(rect.size.x, 0)),
3197 xform.xform(rect.position + rect.size),
3198 xform.xform(rect.position + Vector2(0, rect.size.y))
3199 };
3200
3201 Color c = Color(1, 0.6, 0.4, 0.7);
3202
3203 if (item_locked) {
3204 c = Color(0.7, 0.7, 0.7, 0.7);
3205 }
3206
3207 for (int i = 0; i < 4; i++) {
3208 viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, Math::round(2 * EDSCALE), true);
3209 }
3210 } else {
3211
3212 Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
3213 Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
3214 viewport->draw_set_transform_matrix(simple_xform);
3215 viewport->draw_texture(position_icon, -(position_icon->get_size() / 2));
3216 viewport->draw_set_transform_matrix(viewport->get_transform());
3217 }
3218
3219 if (single && !item_locked && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks
3220 // Draw the pivot
3221 if (canvas_item->_edit_use_pivot()) {
3222
3223 // Draw the node's pivot
3224 Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
3225 Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
3226
3227 viewport->draw_set_transform_matrix(simple_xform);
3228 viewport->draw_texture(pivot_icon, -(pivot_icon->get_size() / 2).floor());
3229 viewport->draw_set_transform_matrix(viewport->get_transform());
3230 }
3231
3232 // Draw control-related helpers
3233 Control *control = Object::cast_to<Control>(canvas_item);
3234 if (control && _is_node_movable(control)) {
3235 _draw_control_anchors(control);
3236 _draw_control_helpers(control);
3237 }
3238
3239 // Draw the resize handles
3240 if (tool == TOOL_SELECT && canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
3241 Rect2 rect = canvas_item->_edit_get_rect();
3242 Vector2 endpoints[4] = {
3243 xform.xform(rect.position),
3244 xform.xform(rect.position + Vector2(rect.size.x, 0)),
3245 xform.xform(rect.position + rect.size),
3246 xform.xform(rect.position + Vector2(0, rect.size.y))
3247 };
3248 for (int i = 0; i < 4; i++) {
3249 int prev = (i + 3) % 4;
3250 int next = (i + 1) % 4;
3251
3252 Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
3253 ofs *= Math_SQRT2 * (select_handle->get_size().width / 2);
3254
3255 select_handle->draw(ci, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor());
3256
3257 ofs = (endpoints[i] + endpoints[next]) / 2;
3258 ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2);
3259
3260 select_handle->draw(ci, (ofs - (select_handle->get_size() / 2)).floor());
3261 }
3262 }
3263
3264 // Draw the rescale handles
3265 bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
3266 bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
3267 if ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
3268 if (_is_node_movable(canvas_item)) {
3269 Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
3270 Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
3271
3272 Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
3273 bool uniform = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
3274 Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
3275
3276 if (drag_type == DRAG_SCALE_X) {
3277 scale_factor.x += offset.x;
3278 if (uniform) {
3279 scale_factor.y += offset.x;
3280 }
3281 } else if (drag_type == DRAG_SCALE_Y) {
3282 scale_factor.y -= offset.y;
3283 if (uniform) {
3284 scale_factor.x -= offset.y;
3285 }
3286 }
3287
3288 viewport->draw_set_transform_matrix(simple_xform);
3289 Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
3290 viewport->draw_rect(x_handle_rect, get_color("axis_x_color", "Editor"));
3291 viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_color("axis_x_color", "Editor"), Math::round(EDSCALE), true);
3292
3293 Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
3294 viewport->draw_rect(y_handle_rect, get_color("axis_y_color", "Editor"));
3295 viewport->draw_line(Point2(), Point2(0, -scale_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE), true);
3296
3297 viewport->draw_set_transform_matrix(viewport->get_transform());
3298 }
3299 }
3300 }
3301 }
3302
3303 if (drag_type == DRAG_BOX_SELECTION) {
3304 // Draw the dragging box
3305 Point2 bsfrom = transform.xform(drag_from);
3306 Point2 bsto = transform.xform(box_selecting_to);
3307
3308 viewport->draw_rect(
3309 Rect2(bsfrom, bsto - bsfrom),
3310 get_color("box_selection_fill_color", "Editor"));
3311
3312 viewport->draw_rect(
3313 Rect2(bsfrom, bsto - bsfrom),
3314 get_color("box_selection_stroke_color", "Editor"),
3315 false,
3316 Math::round(EDSCALE));
3317 }
3318
3319 if (drag_type == DRAG_ROTATE) {
3320 // Draw the line when rotating a node
3321 viewport->draw_line(
3322 transform.xform(drag_rotation_center),
3323 transform.xform(drag_to),
3324 get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
3325 Math::round(2 * EDSCALE),
3326 true);
3327 }
3328 }
3329
_draw_straight_line(Point2 p_from,Point2 p_to,Color p_color)3330 void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_color) {
3331 // Draw a line going through the whole screen from a vector
3332 RID ci = viewport->get_canvas_item();
3333 Vector<Point2> points;
3334 Point2 from = transform.xform(p_from);
3335 Point2 to = transform.xform(p_to);
3336 Size2 viewport_size = viewport->get_size();
3337
3338 if (to.x == from.x) {
3339 // Vertical line
3340 points.push_back(Point2(to.x, 0));
3341 points.push_back(Point2(to.x, viewport_size.y));
3342 } else if (to.y == from.y) {
3343 // Horizontal line
3344 points.push_back(Point2(0, to.y));
3345 points.push_back(Point2(viewport_size.x, to.y));
3346 } else {
3347 float y_for_zero_x = (to.y * from.x - from.y * to.x) / (from.x - to.x);
3348 float x_for_zero_y = (to.x * from.y - from.x * to.y) / (from.y - to.y);
3349 float y_for_viewport_x = ((to.y - from.y) * (viewport_size.x - from.x)) / (to.x - from.x) + from.y;
3350 float x_for_viewport_y = ((to.x - from.x) * (viewport_size.y - from.y)) / (to.y - from.y) + from.x; // faux
3351
3352 //bool start_set = false;
3353 if (y_for_zero_x >= 0 && y_for_zero_x <= viewport_size.y) {
3354 points.push_back(Point2(0, y_for_zero_x));
3355 }
3356 if (x_for_zero_y >= 0 && x_for_zero_y <= viewport_size.x) {
3357 points.push_back(Point2(x_for_zero_y, 0));
3358 }
3359 if (y_for_viewport_x >= 0 && y_for_viewport_x <= viewport_size.y) {
3360 points.push_back(Point2(viewport_size.x, y_for_viewport_x));
3361 }
3362 if (x_for_viewport_y >= 0 && x_for_viewport_y <= viewport_size.x) {
3363 points.push_back(Point2(x_for_viewport_y, viewport_size.y));
3364 }
3365 }
3366 if (points.size() >= 2) {
3367 VisualServer::get_singleton()->canvas_item_add_line(ci, points[0], points[1], p_color);
3368 }
3369 }
3370
_draw_axis()3371 void CanvasItemEditor::_draw_axis() {
3372
3373 if (show_origin) {
3374
3375 _draw_straight_line(Point2(), Point2(1, 0), get_color("axis_x_color", "Editor") * Color(1, 1, 1, 0.75));
3376 _draw_straight_line(Point2(), Point2(0, 1), get_color("axis_y_color", "Editor") * Color(1, 1, 1, 0.75));
3377 }
3378
3379 if (show_viewport) {
3380
3381 RID ci = viewport->get_canvas_item();
3382
3383 Color area_axis_color = EditorSettings::get_singleton()->get("editors/2d/viewport_border_color");
3384
3385 Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
3386
3387 Vector2 screen_endpoints[4] = {
3388 transform.xform(Vector2(0, 0)),
3389 transform.xform(Vector2(screen_size.width, 0)),
3390 transform.xform(Vector2(screen_size.width, screen_size.height)),
3391 transform.xform(Vector2(0, screen_size.height))
3392 };
3393
3394 for (int i = 0; i < 4; i++) {
3395 VisualServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color);
3396 }
3397 }
3398 }
3399
_draw_bones()3400 void CanvasItemEditor::_draw_bones() {
3401 RID ci = viewport->get_canvas_item();
3402
3403 if (skeleton_show_bones) {
3404 Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
3405 Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
3406 Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
3407 Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
3408 Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
3409
3410 for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
3411
3412 Vector<Vector2> bone_shape;
3413 Vector<Vector2> bone_shape_outline;
3414 if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E))
3415 continue;
3416
3417 Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
3418 if (!from_node->is_visible_in_tree())
3419 continue;
3420
3421 Vector<Color> colors;
3422 if (from_node->has_meta("_edit_ik_")) {
3423 colors.push_back(bone_ik_color);
3424 colors.push_back(bone_ik_color);
3425 colors.push_back(bone_ik_color);
3426 colors.push_back(bone_ik_color);
3427 } else {
3428 colors.push_back(bone_color1);
3429 colors.push_back(bone_color2);
3430 colors.push_back(bone_color1);
3431 colors.push_back(bone_color2);
3432 }
3433
3434 Vector<Color> outline_colors;
3435
3436 if (editor_selection->is_selected(from_node)) {
3437 outline_colors.push_back(bone_selected_color);
3438 outline_colors.push_back(bone_selected_color);
3439 outline_colors.push_back(bone_selected_color);
3440 outline_colors.push_back(bone_selected_color);
3441 outline_colors.push_back(bone_selected_color);
3442 outline_colors.push_back(bone_selected_color);
3443 } else {
3444 outline_colors.push_back(bone_outline_color);
3445 outline_colors.push_back(bone_outline_color);
3446 outline_colors.push_back(bone_outline_color);
3447 outline_colors.push_back(bone_outline_color);
3448 outline_colors.push_back(bone_outline_color);
3449 outline_colors.push_back(bone_outline_color);
3450 }
3451
3452 VisualServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors);
3453 VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID());
3454 }
3455 }
3456 }
3457
_draw_invisible_nodes_positions(Node * p_node,const Transform2D & p_parent_xform,const Transform2D & p_canvas_xform)3458 void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
3459 ERR_FAIL_COND(!p_node);
3460
3461 Node *scene = editor->get_edited_scene();
3462 if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner()))
3463 return;
3464 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
3465 if (canvas_item && !canvas_item->is_visible())
3466 return;
3467
3468 Transform2D parent_xform = p_parent_xform;
3469 Transform2D canvas_xform = p_canvas_xform;
3470
3471 if (canvas_item && !canvas_item->is_set_as_toplevel()) {
3472 parent_xform = parent_xform * canvas_item->get_transform();
3473 } else {
3474 CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
3475 parent_xform = Transform2D();
3476 canvas_xform = cl ? cl->get_transform() : p_canvas_xform;
3477 }
3478
3479 for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
3480 _draw_invisible_nodes_positions(p_node->get_child(i), parent_xform, canvas_xform);
3481 }
3482
3483 if (canvas_item && !canvas_item->_edit_use_rect() && (!editor_selection->is_selected(canvas_item) || _is_node_locked(canvas_item))) {
3484 Transform2D xform = transform * canvas_xform * parent_xform;
3485
3486 // Draw the node's position
3487 Ref<Texture> position_icon = get_icon("EditorPositionUnselected", "EditorIcons");
3488 Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
3489 Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
3490 viewport->draw_set_transform_matrix(simple_xform);
3491 viewport->draw_texture(position_icon, -position_icon->get_size() / 2, Color(1.0, 1.0, 1.0, 0.5));
3492 viewport->draw_set_transform_matrix(viewport->get_transform());
3493 }
3494 }
3495
_draw_hover()3496 void CanvasItemEditor::_draw_hover() {
3497 List<Rect2> previous_rects;
3498
3499 for (int i = 0; i < hovering_results.size(); i++) {
3500
3501 Ref<Texture> node_icon = hovering_results[i].icon;
3502 String node_name = hovering_results[i].name;
3503
3504 Ref<Font> font = get_font("font", "Label");
3505 Size2 node_name_size = font->get_string_size(node_name);
3506 Size2 item_size = Size2(node_icon->get_size().x + 4 + node_name_size.x, MAX(node_icon->get_size().y, node_name_size.y - 3));
3507
3508 Point2 pos = transform.xform(hovering_results[i].position) - Point2(0, item_size.y) + (Point2(node_icon->get_size().x, -node_icon->get_size().y) / 4);
3509 // Rectify the position to avoid overlapping items
3510 for (List<Rect2>::Element *E = previous_rects.front(); E; E = E->next()) {
3511 if (E->get().intersects(Rect2(pos, item_size))) {
3512 pos.y = E->get().get_position().y - item_size.y;
3513 }
3514 }
3515
3516 previous_rects.push_back(Rect2(pos, item_size));
3517
3518 // Draw icon
3519 viewport->draw_texture(node_icon, pos, Color(1.0, 1.0, 1.0, 0.5));
3520
3521 // Draw name
3522 viewport->draw_string(font, pos + Point2(node_icon->get_size().x + 4, item_size.y - 3), node_name, Color(1.0, 1.0, 1.0, 0.5));
3523 }
3524 }
3525
_draw_locks_and_groups(Node * p_node,const Transform2D & p_parent_xform,const Transform2D & p_canvas_xform)3526 void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
3527 ERR_FAIL_COND(!p_node);
3528
3529 Node *scene = editor->get_edited_scene();
3530 if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner()))
3531 return;
3532 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
3533 if (canvas_item && !canvas_item->is_visible())
3534 return;
3535
3536 Transform2D parent_xform = p_parent_xform;
3537 Transform2D canvas_xform = p_canvas_xform;
3538
3539 if (canvas_item && !canvas_item->is_set_as_toplevel()) {
3540 parent_xform = parent_xform * canvas_item->get_transform();
3541 } else {
3542 CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
3543 parent_xform = Transform2D();
3544 canvas_xform = cl ? cl->get_transform() : p_canvas_xform;
3545 }
3546
3547 for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
3548 _draw_locks_and_groups(p_node->get_child(i), parent_xform, canvas_xform);
3549 }
3550
3551 RID viewport_canvas_item = viewport->get_canvas_item();
3552 if (canvas_item) {
3553 float offset = 0;
3554
3555 Ref<Texture> lock = get_icon("LockViewport", "EditorIcons");
3556 if (p_node->has_meta("_edit_lock_") && show_edit_locks) {
3557 lock->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
3558 offset += lock->get_size().x;
3559 }
3560
3561 Ref<Texture> group = get_icon("GroupViewport", "EditorIcons");
3562 if (canvas_item->has_meta("_edit_group_") && show_edit_locks) {
3563 group->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
3564 //offset += group->get_size().x;
3565 }
3566 }
3567 }
3568
_build_bones_list(Node * p_node)3569 bool CanvasItemEditor::_build_bones_list(Node *p_node) {
3570 ERR_FAIL_COND_V(!p_node, false);
3571
3572 bool has_child_bones = false;
3573
3574 for (int i = 0; i < p_node->get_child_count(); i++) {
3575 if (_build_bones_list(p_node->get_child(i))) {
3576 has_child_bones = true;
3577 }
3578 }
3579
3580 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
3581 Node *scene = editor->get_edited_scene();
3582 if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner()))) {
3583 return false;
3584 }
3585
3586 Node *parent = canvas_item->get_parent();
3587
3588 if (Object::cast_to<Bone2D>(canvas_item)) {
3589 if (Object::cast_to<Bone2D>(parent)) {
3590 // Add as bone->parent relationship
3591 BoneKey bk;
3592 bk.from = parent->get_instance_id();
3593 bk.to = canvas_item->get_instance_id();
3594 if (!bone_list.has(bk)) {
3595 BoneList b;
3596 b.length = 0;
3597 bone_list[bk] = b;
3598 }
3599
3600 bone_list[bk].last_pass = bone_last_frame;
3601 }
3602
3603 if (!has_child_bones) {
3604 // Add a last bone if the Bone2D has no Bone2D child
3605 BoneKey bk;
3606 bk.from = canvas_item->get_instance_id();
3607 bk.to = 0;
3608 if (!bone_list.has(bk)) {
3609 BoneList b;
3610 b.length = 0;
3611 bone_list[bk] = b;
3612 }
3613 bone_list[bk].last_pass = bone_last_frame;
3614 }
3615
3616 return true;
3617 }
3618
3619 if (canvas_item->has_meta("_edit_bone_")) {
3620 // Add a "custom bone"
3621 BoneKey bk;
3622 bk.from = parent->get_instance_id();
3623 bk.to = canvas_item->get_instance_id();
3624 if (!bone_list.has(bk)) {
3625 BoneList b;
3626 b.length = 0;
3627 bone_list[bk] = b;
3628 }
3629 bone_list[bk].last_pass = bone_last_frame;
3630 }
3631
3632 return false;
3633 }
3634
_draw_viewport()3635 void CanvasItemEditor::_draw_viewport() {
3636
3637 // Update the transform
3638 transform = Transform2D();
3639 transform.scale_basis(Size2(zoom, zoom));
3640 transform.elements[2] = -view_offset * zoom;
3641 editor->get_scene_root()->set_global_canvas_transform(transform);
3642
3643 // hide/show buttons depending on the selection
3644 bool all_locked = true;
3645 bool all_group = true;
3646 List<Node *> selection = editor_selection->get_selected_node_list();
3647 if (selection.empty()) {
3648 all_locked = false;
3649 all_group = false;
3650 } else {
3651 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
3652 if (Object::cast_to<CanvasItem>(E->get()) && !Object::cast_to<CanvasItem>(E->get())->has_meta("_edit_lock_")) {
3653 all_locked = false;
3654 break;
3655 }
3656 }
3657 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
3658 if (Object::cast_to<CanvasItem>(E->get()) && !Object::cast_to<CanvasItem>(E->get())->has_meta("_edit_group_")) {
3659 all_group = false;
3660 break;
3661 }
3662 }
3663 }
3664
3665 lock_button->set_visible(!all_locked);
3666 lock_button->set_disabled(selection.empty());
3667 unlock_button->set_visible(all_locked);
3668 group_button->set_visible(!all_group);
3669 group_button->set_disabled(selection.empty());
3670 ungroup_button->set_visible(all_group);
3671
3672 info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
3673
3674 _draw_grid();
3675 _draw_ruler_tool();
3676 _draw_selection();
3677 _draw_axis();
3678 if (editor->get_edited_scene()) {
3679 _draw_locks_and_groups(editor->get_edited_scene());
3680 _draw_invisible_nodes_positions(editor->get_edited_scene());
3681 }
3682
3683 RID ci = viewport->get_canvas_item();
3684 VisualServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D());
3685
3686 EditorPluginList *over_plugin_list = editor->get_editor_plugins_over();
3687 if (!over_plugin_list->empty()) {
3688 over_plugin_list->forward_canvas_draw_over_viewport(viewport);
3689 }
3690 EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
3691 if (!force_over_plugin_list->empty()) {
3692 force_over_plugin_list->forward_canvas_force_draw_over_viewport(viewport);
3693 }
3694
3695 _draw_bones();
3696 if (show_rulers)
3697 _draw_rulers();
3698 if (show_guides)
3699 _draw_guides();
3700 _draw_smart_snapping();
3701 _draw_focus();
3702 _draw_hover();
3703 }
3704
update_viewport()3705 void CanvasItemEditor::update_viewport() {
3706 _update_scrollbars();
3707 viewport->update();
3708 }
3709
set_current_tool(Tool p_tool)3710 void CanvasItemEditor::set_current_tool(Tool p_tool) {
3711 _button_tool_select(p_tool);
3712 }
3713
_notification(int p_what)3714 void CanvasItemEditor::_notification(int p_what) {
3715
3716 if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
3717 EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels"));
3718
3719 bool has_container_parents = false;
3720 int nb_control = 0;
3721 int nb_having_pivot = 0;
3722
3723 // Update the viewport if the canvas_item changes
3724 List<CanvasItem *> selection = _get_edited_canvas_items(true);
3725 for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
3726 CanvasItem *canvas_item = E->get();
3727 CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
3728
3729 Rect2 rect;
3730 if (canvas_item->_edit_use_rect()) {
3731 rect = canvas_item->_edit_get_rect();
3732 } else {
3733 rect = Rect2();
3734 }
3735 Transform2D xform = canvas_item->get_transform();
3736
3737 if (rect != se->prev_rect || xform != se->prev_xform) {
3738 viewport->update();
3739 se->prev_rect = rect;
3740 se->prev_xform = xform;
3741 }
3742
3743 Control *control = Object::cast_to<Control>(canvas_item);
3744 if (control) {
3745 float anchors[4];
3746 Vector2 pivot;
3747
3748 pivot = control->get_pivot_offset();
3749 anchors[MARGIN_LEFT] = control->get_anchor(MARGIN_LEFT);
3750 anchors[MARGIN_RIGHT] = control->get_anchor(MARGIN_RIGHT);
3751 anchors[MARGIN_TOP] = control->get_anchor(MARGIN_TOP);
3752 anchors[MARGIN_BOTTOM] = control->get_anchor(MARGIN_BOTTOM);
3753
3754 if (pivot != se->prev_pivot || anchors[MARGIN_LEFT] != se->prev_anchors[MARGIN_LEFT] || anchors[MARGIN_RIGHT] != se->prev_anchors[MARGIN_RIGHT] || anchors[MARGIN_TOP] != se->prev_anchors[MARGIN_TOP] || anchors[MARGIN_BOTTOM] != se->prev_anchors[MARGIN_BOTTOM]) {
3755 se->prev_pivot = pivot;
3756 se->prev_anchors[MARGIN_LEFT] = anchors[MARGIN_LEFT];
3757 se->prev_anchors[MARGIN_RIGHT] = anchors[MARGIN_RIGHT];
3758 se->prev_anchors[MARGIN_TOP] = anchors[MARGIN_TOP];
3759 se->prev_anchors[MARGIN_BOTTOM] = anchors[MARGIN_BOTTOM];
3760 viewport->update();
3761 }
3762 nb_control++;
3763
3764 if (Object::cast_to<Container>(control->get_parent())) {
3765 has_container_parents = true;
3766 }
3767 }
3768
3769 if (canvas_item->_edit_use_pivot()) {
3770 nb_having_pivot++;
3771 }
3772 }
3773
3774 // Activate / Deactivate the pivot tool
3775 pivot_button->set_disabled(nb_having_pivot == 0);
3776
3777 // Show / Hide the layout and anchors mode buttons
3778 if (nb_control > 0 && nb_control == selection.size()) {
3779 presets_menu->set_visible(true);
3780 anchor_mode_button->set_visible(true);
3781
3782 // Disable if the selected node is child of a container
3783 if (has_container_parents) {
3784 presets_menu->set_disabled(true);
3785 presets_menu->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent."));
3786 anchor_mode_button->set_disabled(true);
3787 anchor_mode_button->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent."));
3788 } else {
3789 presets_menu->set_disabled(false);
3790 presets_menu->set_tooltip(TTR("Presets for the anchors and margins values of a Control node."));
3791 anchor_mode_button->set_disabled(false);
3792 anchor_mode_button->set_tooltip(TTR("When active, moving Control nodes changes their anchors instead of their margins."));
3793 }
3794 } else {
3795 presets_menu->set_visible(false);
3796 anchor_mode_button->set_visible(false);
3797 }
3798
3799 // Update the viewport if bones changes
3800 for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
3801
3802 Object *b = ObjectDB::get_instance(E->key().from);
3803 if (!b) {
3804
3805 viewport->update();
3806 break;
3807 }
3808
3809 Node2D *b2 = Object::cast_to<Node2D>(b);
3810 if (!b2 || !b2->is_inside_tree()) {
3811 continue;
3812 }
3813
3814 Transform2D global_xform = b2->get_global_transform();
3815
3816 if (global_xform != E->get().xform) {
3817
3818 E->get().xform = global_xform;
3819 viewport->update();
3820 }
3821
3822 Bone2D *bone = Object::cast_to<Bone2D>(b);
3823 if (bone && bone->get_default_length() != E->get().length) {
3824
3825 E->get().length = bone->get_default_length();
3826 viewport->update();
3827 }
3828 }
3829 }
3830
3831 if (p_what == NOTIFICATION_ENTER_TREE) {
3832
3833 select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons"));
3834 for (int i = 0; i < 4; i++) {
3835 select_sb->set_margin_size(Margin(i), 4);
3836 select_sb->set_default_margin(Margin(i), 4);
3837 }
3838
3839 AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", this, "_keying_changed");
3840 _keying_changed();
3841 get_tree()->connect("node_added", this, "_tree_changed", varray());
3842 get_tree()->connect("node_removed", this, "_tree_changed", varray());
3843
3844 } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
3845
3846 select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons"));
3847 }
3848
3849 if (p_what == NOTIFICATION_EXIT_TREE) {
3850 get_tree()->disconnect("node_added", this, "_tree_changed");
3851 get_tree()->disconnect("node_removed", this, "_tree_changed");
3852 }
3853
3854 if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
3855 select_button->set_icon(get_icon("ToolSelect", "EditorIcons"));
3856 list_select_button->set_icon(get_icon("ListSelect", "EditorIcons"));
3857 move_button->set_icon(get_icon("ToolMove", "EditorIcons"));
3858 scale_button->set_icon(get_icon("ToolScale", "EditorIcons"));
3859 rotate_button->set_icon(get_icon("ToolRotate", "EditorIcons"));
3860 smart_snap_button->set_icon(get_icon("Snap", "EditorIcons"));
3861 grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons"));
3862 snap_config_menu->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
3863 skeleton_menu->set_icon(get_icon("Bone", "EditorIcons"));
3864 override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons"));
3865 pan_button->set_icon(get_icon("ToolPan", "EditorIcons"));
3866 ruler_button->set_icon(get_icon("Ruler", "EditorIcons"));
3867 pivot_button->set_icon(get_icon("EditPivot", "EditorIcons"));
3868 select_handle = get_icon("EditorHandle", "EditorIcons");
3869 anchor_handle = get_icon("EditorControlAnchor", "EditorIcons");
3870 lock_button->set_icon(get_icon("Lock", "EditorIcons"));
3871 unlock_button->set_icon(get_icon("Unlock", "EditorIcons"));
3872 group_button->set_icon(get_icon("Group", "EditorIcons"));
3873 ungroup_button->set_icon(get_icon("Ungroup", "EditorIcons"));
3874 key_loc_button->set_icon(get_icon("KeyPosition", "EditorIcons"));
3875 key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons"));
3876 key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons"));
3877 key_insert_button->set_icon(get_icon("Key", "EditorIcons"));
3878 key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons"));
3879 animation_menu->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
3880
3881 zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons"));
3882 zoom_plus->set_icon(get_icon("ZoomMore", "EditorIcons"));
3883
3884 presets_menu->set_icon(get_icon("ControlLayout", "EditorIcons"));
3885 PopupMenu *p = presets_menu->get_popup();
3886
3887 p->clear();
3888 p->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_MARGINS_PRESET_TOP_LEFT);
3889 p->add_icon_item(get_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT);
3890 p->add_icon_item(get_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT);
3891 p->add_icon_item(get_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT);
3892 p->add_separator();
3893 p->add_icon_item(get_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT);
3894 p->add_icon_item(get_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_MARGINS_PRESET_CENTER_TOP);
3895 p->add_icon_item(get_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT);
3896 p->add_icon_item(get_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM);
3897 p->add_icon_item(get_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_MARGINS_PRESET_CENTER);
3898 p->add_separator();
3899 p->add_icon_item(get_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE);
3900 p->add_icon_item(get_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_MARGINS_PRESET_TOP_WIDE);
3901 p->add_icon_item(get_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE);
3902 p->add_icon_item(get_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE);
3903 p->add_icon_item(get_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE);
3904 p->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE);
3905 p->add_separator();
3906 p->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_MARGINS_PRESET_WIDE);
3907 p->add_icon_item(get_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO);
3908 p->add_separator();
3909 p->add_submenu_item(TTR("Anchors only"), "Anchors");
3910 p->set_item_icon(21, get_icon("Anchor", "EditorIcons"));
3911
3912 anchors_popup->clear();
3913 anchors_popup->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT);
3914 anchors_popup->add_icon_item(get_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT);
3915 anchors_popup->add_icon_item(get_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT);
3916 anchors_popup->add_icon_item(get_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT);
3917 anchors_popup->add_separator();
3918 anchors_popup->add_icon_item(get_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT);
3919 anchors_popup->add_icon_item(get_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP);
3920 anchors_popup->add_icon_item(get_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT);
3921 anchors_popup->add_icon_item(get_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM);
3922 anchors_popup->add_icon_item(get_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_PRESET_CENTER);
3923 anchors_popup->add_separator();
3924 anchors_popup->add_icon_item(get_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE);
3925 anchors_popup->add_icon_item(get_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE);
3926 anchors_popup->add_icon_item(get_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE);
3927 anchors_popup->add_icon_item(get_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE);
3928 anchors_popup->add_icon_item(get_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE);
3929 anchors_popup->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE);
3930 anchors_popup->add_separator();
3931 anchors_popup->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_PRESET_WIDE);
3932
3933 anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons"));
3934 }
3935
3936 if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
3937 if (!is_visible() && override_camera_button->is_pressed()) {
3938 ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
3939
3940 debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
3941 override_camera_button->set_pressed(false);
3942 }
3943 }
3944 }
3945
_selection_changed()3946 void CanvasItemEditor::_selection_changed() {
3947 // Update the anchors_mode
3948 int nbValidControls = 0;
3949 int nbAnchorsMode = 0;
3950 List<Node *> selection = editor_selection->get_selected_node_list();
3951 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
3952 Control *control = Object::cast_to<Control>(E->get());
3953 if (!control)
3954 continue;
3955 if (Object::cast_to<Container>(control->get_parent()))
3956 continue;
3957
3958 nbValidControls++;
3959 if (control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_")) {
3960 nbAnchorsMode++;
3961 }
3962 }
3963 anchors_mode = (nbValidControls == nbAnchorsMode);
3964 anchor_mode_button->set_pressed(anchors_mode);
3965
3966 if (!selected_from_canvas) {
3967 drag_type = DRAG_NONE;
3968 }
3969 selected_from_canvas = false;
3970 }
3971
edit(CanvasItem * p_canvas_item)3972 void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
3973
3974 Array selection = editor_selection->get_selected_nodes();
3975 if (selection.size() != 1 || (Node *)selection[0] != p_canvas_item) {
3976 drag_type = DRAG_NONE;
3977
3978 // Clear the selection
3979 editor_selection->clear(); //_clear_canvas_items();
3980 editor_selection->add_node(p_canvas_item);
3981 }
3982 }
3983
_queue_update_bone_list()3984 void CanvasItemEditor::_queue_update_bone_list() {
3985
3986 if (bone_list_dirty)
3987 return;
3988
3989 call_deferred("_update_bone_list");
3990 bone_list_dirty = true;
3991 }
3992
_update_bone_list()3993 void CanvasItemEditor::_update_bone_list() {
3994
3995 bone_last_frame++;
3996
3997 if (editor->get_edited_scene()) {
3998 _build_bones_list(editor->get_edited_scene());
3999 }
4000
4001 List<Map<BoneKey, BoneList>::Element *> bone_to_erase;
4002 for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
4003 if (E->get().last_pass != bone_last_frame) {
4004 bone_to_erase.push_back(E);
4005 continue;
4006 }
4007
4008 Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E->key().from));
4009 if (!node || !node->is_inside_tree() || (node != get_tree()->get_edited_scene_root() && !get_tree()->get_edited_scene_root()->is_a_parent_of(node))) {
4010 bone_to_erase.push_back(E);
4011 continue;
4012 }
4013 }
4014 while (bone_to_erase.size()) {
4015 bone_list.erase(bone_to_erase.front()->get());
4016 bone_to_erase.pop_front();
4017 }
4018 bone_list_dirty = false;
4019 }
4020
_tree_changed(Node *)4021 void CanvasItemEditor::_tree_changed(Node *) {
4022 _queue_update_bone_list();
4023 }
4024
_update_scrollbars()4025 void CanvasItemEditor::_update_scrollbars() {
4026
4027 updating_scroll = true;
4028
4029 // Move the zoom buttons.
4030 Point2 controls_vb_begin = Point2(5, 5);
4031 controls_vb_begin += (show_rulers) ? Point2(RULER_WIDTH, RULER_WIDTH) : Point2();
4032 controls_vb->set_begin(controls_vb_begin);
4033
4034 Size2 hmin = h_scroll->get_minimum_size();
4035 Size2 vmin = v_scroll->get_minimum_size();
4036
4037 // Get the visible frame.
4038 Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
4039 Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
4040
4041 _queue_update_bone_list();
4042
4043 // Calculate scrollable area.
4044 Rect2 canvas_item_rect = Rect2(Point2(), screen_rect);
4045 if (editor->get_edited_scene()) {
4046 Rect2 content_rect = _get_encompassing_rect(editor->get_edited_scene());
4047 canvas_item_rect.expand_to(content_rect.position);
4048 canvas_item_rect.expand_to(content_rect.position + content_rect.size);
4049 }
4050 canvas_item_rect.size += screen_rect * 2;
4051 canvas_item_rect.position -= screen_rect;
4052
4053 // Constraints the view offset and updates the scrollbars.
4054 Size2 size = viewport->get_size();
4055 Point2 begin = canvas_item_rect.position;
4056 Point2 end = canvas_item_rect.position + canvas_item_rect.size - local_rect.size / zoom;
4057 bool constrain_editor_view = bool(EditorSettings::get_singleton()->get("editors/2d/constrain_editor_view"));
4058
4059 if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) {
4060 float centered = -(size.y / 2) / zoom + screen_rect.y / 2;
4061 if (constrain_editor_view && ABS(centered - previous_update_view_offset.y) < ABS(centered - view_offset.y)) {
4062 view_offset.y = previous_update_view_offset.y;
4063 }
4064
4065 v_scroll->hide();
4066 } else {
4067 if (constrain_editor_view && view_offset.y > end.y && view_offset.y > previous_update_view_offset.y) {
4068 view_offset.y = MAX(end.y, previous_update_view_offset.y);
4069 }
4070 if (constrain_editor_view && view_offset.y < begin.y && view_offset.y < previous_update_view_offset.y) {
4071 view_offset.y = MIN(begin.y, previous_update_view_offset.y);
4072 }
4073
4074 v_scroll->show();
4075 v_scroll->set_min(MIN(view_offset.y, begin.y));
4076 v_scroll->set_max(MAX(view_offset.y, end.y) + screen_rect.y);
4077 v_scroll->set_page(screen_rect.y);
4078 }
4079
4080 if (canvas_item_rect.size.width <= (local_rect.size.x / zoom)) {
4081 float centered = -(size.x / 2) / zoom + screen_rect.x / 2;
4082 if (constrain_editor_view && ABS(centered - previous_update_view_offset.x) < ABS(centered - view_offset.x)) {
4083 view_offset.x = previous_update_view_offset.x;
4084 }
4085
4086 h_scroll->hide();
4087 } else {
4088 if (constrain_editor_view && view_offset.x > end.x && view_offset.x > previous_update_view_offset.x) {
4089 view_offset.x = MAX(end.x, previous_update_view_offset.x);
4090 }
4091 if (constrain_editor_view && view_offset.x < begin.x && view_offset.x < previous_update_view_offset.x) {
4092 view_offset.x = MIN(begin.x, previous_update_view_offset.x);
4093 }
4094
4095 h_scroll->show();
4096 h_scroll->set_min(MIN(view_offset.x, begin.x));
4097 h_scroll->set_max(MAX(view_offset.x, end.x) + screen_rect.x);
4098 h_scroll->set_page(screen_rect.x);
4099 }
4100
4101 // Move and resize the scrollbars, avoiding overlap.
4102 v_scroll->set_begin(Point2(size.width - vmin.width, (show_rulers) ? RULER_WIDTH : 0));
4103 v_scroll->set_end(Point2(size.width, size.height - (h_scroll->is_visible() ? hmin.height : 0)));
4104 h_scroll->set_begin(Point2((show_rulers) ? RULER_WIDTH : 0, size.height - hmin.height));
4105 h_scroll->set_end(Point2(size.width - (v_scroll->is_visible() ? vmin.width : 0), size.height));
4106
4107 // Calculate scrollable area.
4108 v_scroll->set_value(view_offset.y);
4109 h_scroll->set_value(view_offset.x);
4110
4111 previous_update_view_offset = view_offset;
4112 updating_scroll = false;
4113 }
4114
_popup_warning_depop(Control * p_control)4115 void CanvasItemEditor::_popup_warning_depop(Control *p_control) {
4116 ERR_FAIL_COND(!popup_temporarily_timers.has(p_control));
4117
4118 Timer *timer = popup_temporarily_timers[p_control];
4119 timer->queue_delete();
4120 p_control->hide();
4121 popup_temporarily_timers.erase(p_control);
4122 info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
4123 }
4124
_popup_warning_temporarily(Control * p_control,const float p_duration)4125 void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const float p_duration) {
4126 Timer *timer;
4127 if (!popup_temporarily_timers.has(p_control)) {
4128 timer = memnew(Timer);
4129 timer->connect("timeout", this, "_popup_warning_depop", varray(p_control));
4130 timer->set_one_shot(true);
4131 add_child(timer);
4132
4133 popup_temporarily_timers[p_control] = timer;
4134 } else {
4135 timer = popup_temporarily_timers[p_control];
4136 }
4137
4138 timer->start(p_duration);
4139 p_control->show();
4140 info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
4141 }
4142
_update_scroll(float)4143 void CanvasItemEditor::_update_scroll(float) {
4144
4145 if (updating_scroll)
4146 return;
4147
4148 view_offset.x = h_scroll->get_value();
4149 view_offset.y = v_scroll->get_value();
4150 viewport->update();
4151 }
4152
_set_anchors_and_margins_preset(Control::LayoutPreset p_preset)4153 void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_preset) {
4154 List<Node *> selection = editor_selection->get_selected_node_list();
4155
4156 undo_redo->create_action(TTR("Change Anchors and Margins"));
4157
4158 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4159
4160 Control *control = Object::cast_to<Control>(E->get());
4161 if (control) {
4162 undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
4163 switch (p_preset) {
4164 case PRESET_TOP_LEFT:
4165 case PRESET_TOP_RIGHT:
4166 case PRESET_BOTTOM_LEFT:
4167 case PRESET_BOTTOM_RIGHT:
4168 case PRESET_CENTER_LEFT:
4169 case PRESET_CENTER_TOP:
4170 case PRESET_CENTER_RIGHT:
4171 case PRESET_CENTER_BOTTOM:
4172 case PRESET_CENTER:
4173 undo_redo->add_do_method(control, "set_margins_preset", p_preset, Control::PRESET_MODE_KEEP_SIZE);
4174 break;
4175 case PRESET_LEFT_WIDE:
4176 case PRESET_TOP_WIDE:
4177 case PRESET_RIGHT_WIDE:
4178 case PRESET_BOTTOM_WIDE:
4179 case PRESET_VCENTER_WIDE:
4180 case PRESET_HCENTER_WIDE:
4181 case PRESET_WIDE:
4182 undo_redo->add_do_method(control, "set_margins_preset", p_preset, Control::PRESET_MODE_MINSIZE);
4183 break;
4184 }
4185 undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
4186 }
4187 }
4188
4189 undo_redo->commit_action();
4190
4191 anchors_mode = false;
4192 anchor_mode_button->set_pressed(anchors_mode);
4193 }
4194
_set_anchors_and_margins_to_keep_ratio()4195 void CanvasItemEditor::_set_anchors_and_margins_to_keep_ratio() {
4196 List<Node *> selection = editor_selection->get_selected_node_list();
4197
4198 undo_redo->create_action(TTR("Change Anchors and Margins"));
4199
4200 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4201
4202 Control *control = Object::cast_to<Control>(E->get());
4203 if (control) {
4204 Point2 top_left_anchor = _position_to_anchor(control, Point2());
4205 Point2 bottom_right_anchor = _position_to_anchor(control, control->get_size());
4206 undo_redo->add_do_method(control, "set_anchor", MARGIN_LEFT, top_left_anchor.x, false, true);
4207 undo_redo->add_do_method(control, "set_anchor", MARGIN_RIGHT, bottom_right_anchor.x, false, true);
4208 undo_redo->add_do_method(control, "set_anchor", MARGIN_TOP, top_left_anchor.y, false, true);
4209 undo_redo->add_do_method(control, "set_anchor", MARGIN_BOTTOM, bottom_right_anchor.y, false, true);
4210 undo_redo->add_do_method(control, "set_meta", "_edit_use_anchors_", true);
4211
4212 bool use_anchors = control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_");
4213 undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
4214 undo_redo->add_undo_method(control, "set_meta", "_edit_use_anchors_", use_anchors);
4215
4216 anchors_mode = true;
4217 anchor_mode_button->set_pressed(anchors_mode);
4218 }
4219 }
4220
4221 undo_redo->commit_action();
4222 }
4223
_set_anchors_preset(Control::LayoutPreset p_preset)4224 void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) {
4225 List<Node *> selection = editor_selection->get_selected_node_list();
4226
4227 undo_redo->create_action(TTR("Change Anchors"));
4228 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4229
4230 Control *control = Object::cast_to<Control>(E->get());
4231 if (control) {
4232 undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
4233 undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
4234 }
4235 }
4236
4237 undo_redo->commit_action();
4238 }
4239
_get_next_zoom_value(int p_increment_count) const4240 float CanvasItemEditor::_get_next_zoom_value(int p_increment_count) const {
4241 // Base increment factor defined as the twelveth root of two.
4242 // This allow a smooth geometric evolution of the zoom, with the advantage of
4243 // visiting all integer power of two scale factors.
4244 // note: this is analogous to the 'semitones' interval in the music world
4245 // In order to avoid numerical imprecisions, we compute and edit a zoom index
4246 // with the following relation: zoom = 2 ^ (index / 12)
4247
4248 if (zoom < CMP_EPSILON || p_increment_count == 0) {
4249 return 1.f;
4250 }
4251
4252 // Remove Editor scale from the index computation
4253 float zoom_noscale = zoom / MAX(1, EDSCALE);
4254
4255 // zoom = 2**(index/12) => log2(zoom) = index/12
4256 float closest_zoom_index = Math::round(Math::log(zoom_noscale) * 12.f / Math::log(2.f));
4257
4258 float new_zoom_index = closest_zoom_index + p_increment_count;
4259 float new_zoom = Math::pow(2.f, new_zoom_index / 12.f);
4260
4261 // Restore Editor scale transformation
4262 new_zoom *= MAX(1, EDSCALE);
4263
4264 return new_zoom;
4265 }
4266
_zoom_on_position(float p_zoom,Point2 p_position)4267 void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
4268 p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
4269
4270 if (p_zoom == zoom)
4271 return;
4272
4273 float prev_zoom = zoom;
4274 zoom = p_zoom;
4275
4276 view_offset += p_position / prev_zoom - p_position / zoom;
4277
4278 // We want to align in-scene pixels to screen pixels, this prevents blurry rendering
4279 // in small details (texts, lines).
4280 // This correction adds a jitter movement when zooming, so we correct only when the
4281 // zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway)
4282 float closest_zoom_factor = Math::round(zoom);
4283 if (Math::is_zero_approx(zoom - closest_zoom_factor)) {
4284 // make sure scene pixel at view_offset is aligned on a screen pixel
4285 Vector2 view_offset_int = view_offset.floor();
4286 Vector2 view_offset_frac = view_offset - view_offset_int;
4287 view_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor;
4288 }
4289
4290 _update_zoom_label();
4291 update_viewport();
4292 }
4293
_update_zoom_label()4294 void CanvasItemEditor::_update_zoom_label() {
4295 String zoom_text;
4296 // The zoom level displayed is relative to the editor scale
4297 // (like in most image editors). Its lower bound is clamped to 1 as some people
4298 // lower the editor scale to increase the available real estate,
4299 // even if their display doesn't have a particularly low DPI.
4300 if (zoom >= 10) {
4301 // Don't show a decimal when the zoom level is higher than 1000 %.
4302 zoom_text = rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100)) + " %";
4303 } else {
4304 zoom_text = rtos(Math::stepify((zoom / MAX(1, EDSCALE)) * 100, 0.1)) + " %";
4305 }
4306
4307 zoom_reset->set_text(zoom_text);
4308 }
4309
_button_zoom_minus()4310 void CanvasItemEditor::_button_zoom_minus() {
4311 _zoom_on_position(_get_next_zoom_value(-6), viewport_scrollable->get_size() / 2.0);
4312 }
4313
_button_zoom_reset()4314 void CanvasItemEditor::_button_zoom_reset() {
4315 _zoom_on_position(1.0 * MAX(1, EDSCALE), viewport_scrollable->get_size() / 2.0);
4316 }
4317
_button_zoom_plus()4318 void CanvasItemEditor::_button_zoom_plus() {
4319 _zoom_on_position(_get_next_zoom_value(6), viewport_scrollable->get_size() / 2.0);
4320 }
4321
_button_toggle_smart_snap(bool p_status)4322 void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) {
4323 smart_snap_active = p_status;
4324 viewport->update();
4325 }
4326
_button_toggle_grid_snap(bool p_status)4327 void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
4328 grid_snap_active = p_status;
4329 viewport->update();
4330 }
_button_override_camera(bool p_pressed)4331 void CanvasItemEditor::_button_override_camera(bool p_pressed) {
4332 ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
4333
4334 if (p_pressed) {
4335 debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_2D);
4336 } else {
4337 debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
4338 }
4339 }
4340
_button_tool_select(int p_index)4341 void CanvasItemEditor::_button_tool_select(int p_index) {
4342
4343 ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button };
4344 for (int i = 0; i < TOOL_MAX; i++) {
4345 tb[i]->set_pressed(i == p_index);
4346 }
4347
4348 tool = (Tool)p_index;
4349 viewport->update();
4350 }
4351
_insert_animation_keys(bool p_location,bool p_rotation,bool p_scale,bool p_on_existing)4352 void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) {
4353
4354 Map<Node *, Object *> &selection = editor_selection->get_selection();
4355
4356 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4357
4358 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key());
4359 if (!canvas_item || !canvas_item->is_visible_in_tree())
4360 continue;
4361
4362 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4363 continue;
4364
4365 if (Object::cast_to<Node2D>(canvas_item)) {
4366 Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
4367
4368 if (key_pos && p_location)
4369 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing);
4370 if (key_rot && p_rotation)
4371 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), p_on_existing);
4372 if (key_scale && p_scale)
4373 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing);
4374
4375 if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) {
4376 //look for an IK chain
4377 List<Node2D *> ik_chain;
4378
4379 Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item());
4380 bool has_chain = false;
4381
4382 while (n) {
4383
4384 ik_chain.push_back(n);
4385 if (n->has_meta("_edit_ik_")) {
4386 has_chain = true;
4387 break;
4388 }
4389
4390 if (!n->get_parent_item())
4391 break;
4392 n = Object::cast_to<Node2D>(n->get_parent_item());
4393 }
4394
4395 if (has_chain && ik_chain.size()) {
4396
4397 for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) {
4398
4399 if (key_pos)
4400 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), p_on_existing);
4401 if (key_rot)
4402 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), p_on_existing);
4403 if (key_scale)
4404 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), p_on_existing);
4405 }
4406 }
4407 }
4408
4409 } else if (Object::cast_to<Control>(canvas_item)) {
4410
4411 Control *ctrl = Object::cast_to<Control>(canvas_item);
4412
4413 if (key_pos)
4414 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing);
4415 if (key_rot)
4416 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), p_on_existing);
4417 if (key_scale)
4418 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing);
4419 }
4420 }
4421 }
4422
_button_toggle_anchor_mode(bool p_status)4423 void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) {
4424 List<CanvasItem *> selection = _get_edited_canvas_items(false, false);
4425 for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
4426 Control *control = Object::cast_to<Control>(E->get());
4427 if (!control || Object::cast_to<Container>(control->get_parent()))
4428 continue;
4429
4430 control->set_meta("_edit_use_anchors_", p_status);
4431 }
4432
4433 anchors_mode = p_status;
4434 viewport->update();
4435 }
4436
_update_override_camera_button(bool p_game_running)4437 void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
4438 if (p_game_running) {
4439 override_camera_button->set_disabled(false);
4440 override_camera_button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
4441 } else {
4442 override_camera_button->set_disabled(true);
4443 override_camera_button->set_pressed(false);
4444 override_camera_button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
4445 }
4446 }
4447
_popup_callback(int p_op)4448 void CanvasItemEditor::_popup_callback(int p_op) {
4449
4450 last_option = MenuOption(p_op);
4451 switch (p_op) {
4452
4453 case SHOW_GRID: {
4454 show_grid = !show_grid;
4455 int idx = view_menu->get_popup()->get_item_index(SHOW_GRID);
4456 view_menu->get_popup()->set_item_checked(idx, show_grid);
4457 viewport->update();
4458 } break;
4459 case SHOW_ORIGIN: {
4460 show_origin = !show_origin;
4461 int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
4462 view_menu->get_popup()->set_item_checked(idx, show_origin);
4463 viewport->update();
4464 } break;
4465 case SHOW_VIEWPORT: {
4466 show_viewport = !show_viewport;
4467 int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT);
4468 view_menu->get_popup()->set_item_checked(idx, show_viewport);
4469 viewport->update();
4470 } break;
4471 case SHOW_EDIT_LOCKS: {
4472 show_edit_locks = !show_edit_locks;
4473 int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS);
4474 view_menu->get_popup()->set_item_checked(idx, show_edit_locks);
4475 viewport->update();
4476 } break;
4477 case SNAP_USE_NODE_PARENT: {
4478 snap_node_parent = !snap_node_parent;
4479 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_PARENT);
4480 smartsnap_config_popup->set_item_checked(idx, snap_node_parent);
4481 } break;
4482 case SNAP_USE_NODE_ANCHORS: {
4483 snap_node_anchors = !snap_node_anchors;
4484 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_ANCHORS);
4485 smartsnap_config_popup->set_item_checked(idx, snap_node_anchors);
4486 } break;
4487 case SNAP_USE_NODE_SIDES: {
4488 snap_node_sides = !snap_node_sides;
4489 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_SIDES);
4490 smartsnap_config_popup->set_item_checked(idx, snap_node_sides);
4491 } break;
4492 case SNAP_USE_NODE_CENTER: {
4493 snap_node_center = !snap_node_center;
4494 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_CENTER);
4495 smartsnap_config_popup->set_item_checked(idx, snap_node_center);
4496 } break;
4497 case SNAP_USE_OTHER_NODES: {
4498 snap_other_nodes = !snap_other_nodes;
4499 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_OTHER_NODES);
4500 smartsnap_config_popup->set_item_checked(idx, snap_other_nodes);
4501 } break;
4502 case SNAP_USE_GUIDES: {
4503 snap_guides = !snap_guides;
4504 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_GUIDES);
4505 smartsnap_config_popup->set_item_checked(idx, snap_guides);
4506 } break;
4507 case SNAP_USE_ROTATION: {
4508 snap_rotation = !snap_rotation;
4509 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION);
4510 snap_config_menu->get_popup()->set_item_checked(idx, snap_rotation);
4511 } break;
4512 case SNAP_USE_SCALE: {
4513 snap_scale = !snap_scale;
4514 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_SCALE);
4515 snap_config_menu->get_popup()->set_item_checked(idx, snap_scale);
4516 } break;
4517 case SNAP_RELATIVE: {
4518 snap_relative = !snap_relative;
4519 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE);
4520 snap_config_menu->get_popup()->set_item_checked(idx, snap_relative);
4521 viewport->update();
4522 } break;
4523 case SNAP_USE_PIXEL: {
4524 snap_pixel = !snap_pixel;
4525 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_PIXEL);
4526 snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel);
4527 } break;
4528 case SNAP_CONFIGURE: {
4529 ((SnapDialog *)snap_dialog)->set_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
4530 snap_dialog->popup_centered(Size2(220, 160) * EDSCALE);
4531 } break;
4532 case SKELETON_SHOW_BONES: {
4533 skeleton_show_bones = !skeleton_show_bones;
4534 int idx = skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES);
4535 skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones);
4536 viewport->update();
4537 } break;
4538 case SHOW_HELPERS: {
4539 show_helpers = !show_helpers;
4540 int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS);
4541 view_menu->get_popup()->set_item_checked(idx, show_helpers);
4542 viewport->update();
4543 } break;
4544 case SHOW_RULERS: {
4545 show_rulers = !show_rulers;
4546 int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
4547 view_menu->get_popup()->set_item_checked(idx, show_rulers);
4548 _update_scrollbars();
4549 viewport->update();
4550 } break;
4551 case SHOW_GUIDES: {
4552 show_guides = !show_guides;
4553 int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES);
4554 view_menu->get_popup()->set_item_checked(idx, show_guides);
4555 viewport->update();
4556 } break;
4557 case LOCK_SELECTED: {
4558 undo_redo->create_action(TTR("Lock Selected"));
4559
4560 List<Node *> selection = editor_selection->get_selected_node_list();
4561 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4562 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
4563 if (!canvas_item || !canvas_item->is_inside_tree())
4564 continue;
4565 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4566 continue;
4567
4568 undo_redo->add_do_method(canvas_item, "set_meta", "_edit_lock_", true);
4569 undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_lock_");
4570 undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
4571 undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
4572 }
4573 undo_redo->add_do_method(viewport, "update", Variant());
4574 undo_redo->add_undo_method(viewport, "update", Variant());
4575 undo_redo->commit_action();
4576 } break;
4577 case UNLOCK_SELECTED: {
4578 undo_redo->create_action(TTR("Unlock Selected"));
4579
4580 List<Node *> selection = editor_selection->get_selected_node_list();
4581 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4582 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
4583 if (!canvas_item || !canvas_item->is_inside_tree())
4584 continue;
4585 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4586 continue;
4587
4588 undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_lock_");
4589 undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_lock_", true);
4590 undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
4591 undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
4592 }
4593 undo_redo->add_do_method(viewport, "update", Variant());
4594 undo_redo->add_undo_method(viewport, "update", Variant());
4595 undo_redo->commit_action();
4596 } break;
4597 case GROUP_SELECTED: {
4598 undo_redo->create_action(TTR("Group Selected"));
4599
4600 List<Node *> selection = editor_selection->get_selected_node_list();
4601 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4602 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
4603 if (!canvas_item || !canvas_item->is_inside_tree())
4604 continue;
4605 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4606 continue;
4607
4608 undo_redo->add_do_method(canvas_item, "set_meta", "_edit_group_", true);
4609 undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_group_");
4610 undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
4611 undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
4612 }
4613 undo_redo->add_do_method(viewport, "update", Variant());
4614 undo_redo->add_undo_method(viewport, "update", Variant());
4615 undo_redo->commit_action();
4616 } break;
4617 case UNGROUP_SELECTED: {
4618 undo_redo->create_action(TTR("Ungroup Selected"));
4619
4620 List<Node *> selection = editor_selection->get_selected_node_list();
4621 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4622 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
4623 if (!canvas_item || !canvas_item->is_inside_tree())
4624 continue;
4625 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4626 continue;
4627
4628 undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_group_");
4629 undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_group_", true);
4630 undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
4631 undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
4632 }
4633 undo_redo->add_do_method(viewport, "update", Variant());
4634 undo_redo->add_undo_method(viewport, "update", Variant());
4635 undo_redo->commit_action();
4636 } break;
4637 case ANCHORS_AND_MARGINS_PRESET_TOP_LEFT: {
4638 _set_anchors_and_margins_preset(PRESET_TOP_LEFT);
4639 } break;
4640 case ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT: {
4641 _set_anchors_and_margins_preset(PRESET_TOP_RIGHT);
4642 } break;
4643 case ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT: {
4644 _set_anchors_and_margins_preset(PRESET_BOTTOM_LEFT);
4645 } break;
4646 case ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT: {
4647 _set_anchors_and_margins_preset(PRESET_BOTTOM_RIGHT);
4648 } break;
4649 case ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT: {
4650 _set_anchors_and_margins_preset(PRESET_CENTER_LEFT);
4651 } break;
4652 case ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT: {
4653 _set_anchors_and_margins_preset(PRESET_CENTER_RIGHT);
4654 } break;
4655 case ANCHORS_AND_MARGINS_PRESET_CENTER_TOP: {
4656 _set_anchors_and_margins_preset(PRESET_CENTER_TOP);
4657 } break;
4658 case ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM: {
4659 _set_anchors_and_margins_preset(PRESET_CENTER_BOTTOM);
4660 } break;
4661 case ANCHORS_AND_MARGINS_PRESET_CENTER: {
4662 _set_anchors_and_margins_preset(PRESET_CENTER);
4663 } break;
4664 case ANCHORS_AND_MARGINS_PRESET_TOP_WIDE: {
4665 _set_anchors_and_margins_preset(PRESET_TOP_WIDE);
4666 } break;
4667 case ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE: {
4668 _set_anchors_and_margins_preset(PRESET_LEFT_WIDE);
4669 } break;
4670 case ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE: {
4671 _set_anchors_and_margins_preset(PRESET_RIGHT_WIDE);
4672 } break;
4673 case ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE: {
4674 _set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE);
4675 } break;
4676 case ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE: {
4677 _set_anchors_and_margins_preset(PRESET_VCENTER_WIDE);
4678 } break;
4679 case ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE: {
4680 _set_anchors_and_margins_preset(PRESET_HCENTER_WIDE);
4681 } break;
4682 case ANCHORS_AND_MARGINS_PRESET_WIDE: {
4683 _set_anchors_and_margins_preset(Control::PRESET_WIDE);
4684 } break;
4685 case ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO: {
4686 _set_anchors_and_margins_to_keep_ratio();
4687 } break;
4688
4689 case ANCHORS_PRESET_TOP_LEFT: {
4690 _set_anchors_preset(PRESET_TOP_LEFT);
4691 } break;
4692 case ANCHORS_PRESET_TOP_RIGHT: {
4693 _set_anchors_preset(PRESET_TOP_RIGHT);
4694 } break;
4695 case ANCHORS_PRESET_BOTTOM_LEFT: {
4696 _set_anchors_preset(PRESET_BOTTOM_LEFT);
4697 } break;
4698 case ANCHORS_PRESET_BOTTOM_RIGHT: {
4699 _set_anchors_preset(PRESET_BOTTOM_RIGHT);
4700 } break;
4701 case ANCHORS_PRESET_CENTER_LEFT: {
4702 _set_anchors_preset(PRESET_CENTER_LEFT);
4703 } break;
4704 case ANCHORS_PRESET_CENTER_RIGHT: {
4705 _set_anchors_preset(PRESET_CENTER_RIGHT);
4706 } break;
4707 case ANCHORS_PRESET_CENTER_TOP: {
4708 _set_anchors_preset(PRESET_CENTER_TOP);
4709 } break;
4710 case ANCHORS_PRESET_CENTER_BOTTOM: {
4711 _set_anchors_preset(PRESET_CENTER_BOTTOM);
4712 } break;
4713 case ANCHORS_PRESET_CENTER: {
4714 _set_anchors_preset(PRESET_CENTER);
4715 } break;
4716 case ANCHORS_PRESET_TOP_WIDE: {
4717 _set_anchors_preset(PRESET_TOP_WIDE);
4718 } break;
4719 case ANCHORS_PRESET_LEFT_WIDE: {
4720 _set_anchors_preset(PRESET_LEFT_WIDE);
4721 } break;
4722 case ANCHORS_PRESET_RIGHT_WIDE: {
4723 _set_anchors_preset(PRESET_RIGHT_WIDE);
4724 } break;
4725 case ANCHORS_PRESET_BOTTOM_WIDE: {
4726 _set_anchors_preset(PRESET_BOTTOM_WIDE);
4727 } break;
4728 case ANCHORS_PRESET_VCENTER_WIDE: {
4729 _set_anchors_preset(PRESET_VCENTER_WIDE);
4730 } break;
4731 case ANCHORS_PRESET_HCENTER_WIDE: {
4732 _set_anchors_preset(PRESET_HCENTER_WIDE);
4733 } break;
4734 case ANCHORS_PRESET_WIDE: {
4735 _set_anchors_preset(Control::PRESET_WIDE);
4736 } break;
4737
4738 case ANIM_INSERT_KEY:
4739 case ANIM_INSERT_KEY_EXISTING: {
4740
4741 bool existing = p_op == ANIM_INSERT_KEY_EXISTING;
4742
4743 _insert_animation_keys(true, true, true, existing);
4744
4745 } break;
4746 case ANIM_INSERT_POS: {
4747
4748 key_pos = key_loc_button->is_pressed();
4749 } break;
4750 case ANIM_INSERT_ROT: {
4751
4752 key_rot = key_rot_button->is_pressed();
4753 } break;
4754 case ANIM_INSERT_SCALE: {
4755
4756 key_scale = key_scale_button->is_pressed();
4757 } break;
4758 case ANIM_COPY_POSE: {
4759
4760 pose_clipboard.clear();
4761
4762 Map<Node *, Object *> &selection = editor_selection->get_selection();
4763
4764 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4765
4766 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key());
4767 if (!canvas_item || !canvas_item->is_visible_in_tree())
4768 continue;
4769
4770 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4771 continue;
4772
4773 if (Object::cast_to<Node2D>(canvas_item)) {
4774
4775 Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
4776 PoseClipboard pc;
4777 pc.pos = n2d->get_position();
4778 pc.rot = n2d->get_rotation();
4779 pc.scale = n2d->get_scale();
4780 pc.id = n2d->get_instance_id();
4781 pose_clipboard.push_back(pc);
4782 }
4783 }
4784
4785 } break;
4786 case ANIM_PASTE_POSE: {
4787
4788 if (!pose_clipboard.size())
4789 break;
4790
4791 undo_redo->create_action(TTR("Paste Pose"));
4792 for (List<PoseClipboard>::Element *E = pose_clipboard.front(); E; E = E->next()) {
4793
4794 Node2D *n2d = Object::cast_to<Node2D>(ObjectDB::get_instance(E->get().id));
4795 if (!n2d)
4796 continue;
4797 undo_redo->add_do_method(n2d, "set_position", E->get().pos);
4798 undo_redo->add_do_method(n2d, "set_rotation", E->get().rot);
4799 undo_redo->add_do_method(n2d, "set_scale", E->get().scale);
4800 undo_redo->add_undo_method(n2d, "set_position", n2d->get_position());
4801 undo_redo->add_undo_method(n2d, "set_rotation", n2d->get_rotation());
4802 undo_redo->add_undo_method(n2d, "set_scale", n2d->get_scale());
4803 }
4804 undo_redo->commit_action();
4805
4806 } break;
4807 case ANIM_CLEAR_POSE: {
4808
4809 Map<Node *, Object *> &selection = editor_selection->get_selection();
4810
4811 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4812
4813 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key());
4814 if (!canvas_item || !canvas_item->is_visible_in_tree())
4815 continue;
4816
4817 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4818 continue;
4819
4820 if (Object::cast_to<Node2D>(canvas_item)) {
4821 Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
4822
4823 if (key_pos)
4824 n2d->set_position(Vector2());
4825 if (key_rot)
4826 n2d->set_rotation(0);
4827 if (key_scale)
4828 n2d->set_scale(Vector2(1, 1));
4829 } else if (Object::cast_to<Control>(canvas_item)) {
4830
4831 Control *ctrl = Object::cast_to<Control>(canvas_item);
4832
4833 if (key_pos)
4834 ctrl->set_position(Point2());
4835 /*
4836 if (key_scale)
4837 AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size());
4838 */
4839 }
4840 }
4841
4842 } break;
4843 case CLEAR_GUIDES: {
4844
4845 Node *const root = EditorNode::get_singleton()->get_edited_scene();
4846
4847 if (root && (root->has_meta("_edit_horizontal_guides_") || root->has_meta("_edit_vertical_guides_"))) {
4848 undo_redo->create_action(TTR("Clear Guides"));
4849 if (root->has_meta("_edit_horizontal_guides_")) {
4850 Array hguides = root->get_meta("_edit_horizontal_guides_");
4851
4852 undo_redo->add_do_method(root, "remove_meta", "_edit_horizontal_guides_");
4853 undo_redo->add_undo_method(root, "set_meta", "_edit_horizontal_guides_", hguides);
4854 }
4855 if (root->has_meta("_edit_vertical_guides_")) {
4856 Array vguides = root->get_meta("_edit_vertical_guides_");
4857
4858 undo_redo->add_do_method(root, "remove_meta", "_edit_vertical_guides_");
4859 undo_redo->add_undo_method(root, "set_meta", "_edit_vertical_guides_", vguides);
4860 }
4861 undo_redo->add_undo_method(viewport, "update");
4862 undo_redo->commit_action();
4863 }
4864
4865 } break;
4866 case VIEW_CENTER_TO_SELECTION:
4867 case VIEW_FRAME_TO_SELECTION: {
4868
4869 _focus_selection(p_op);
4870
4871 } break;
4872 case PREVIEW_CANVAS_SCALE: {
4873
4874 bool preview = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE));
4875 preview = !preview;
4876 VS::get_singleton()->canvas_set_disable_scale(!preview);
4877 view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE), preview);
4878
4879 } break;
4880 case SKELETON_MAKE_BONES: {
4881
4882 Map<Node *, Object *> &selection = editor_selection->get_selection();
4883
4884 undo_redo->create_action(TTR("Create Custom Bone(s) from Node(s)"));
4885 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4886
4887 Node2D *n2d = Object::cast_to<Node2D>(E->key());
4888 if (!n2d)
4889 continue;
4890 if (!n2d->is_visible_in_tree())
4891 continue;
4892 if (!n2d->get_parent_item())
4893 continue;
4894 if (n2d->has_meta("_edit_bone_") && n2d->get_meta("_edit_bone_"))
4895 continue;
4896
4897 undo_redo->add_do_method(n2d, "set_meta", "_edit_bone_", true);
4898 undo_redo->add_undo_method(n2d, "remove_meta", "_edit_bone_");
4899 }
4900 undo_redo->add_do_method(this, "_queue_update_bone_list");
4901 undo_redo->add_undo_method(this, "_queue_update_bone_list");
4902 undo_redo->add_do_method(viewport, "update");
4903 undo_redo->add_undo_method(viewport, "update");
4904 undo_redo->commit_action();
4905
4906 } break;
4907 case SKELETON_CLEAR_BONES: {
4908
4909 Map<Node *, Object *> &selection = editor_selection->get_selection();
4910
4911 undo_redo->create_action(TTR("Clear Bones"));
4912 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4913
4914 Node2D *n2d = Object::cast_to<Node2D>(E->key());
4915 if (!n2d)
4916 continue;
4917 if (!n2d->is_visible_in_tree())
4918 continue;
4919 if (!n2d->has_meta("_edit_bone_"))
4920 continue;
4921
4922 undo_redo->add_do_method(n2d, "remove_meta", "_edit_bone_");
4923 undo_redo->add_undo_method(n2d, "set_meta", "_edit_bone_", n2d->get_meta("_edit_bone_"));
4924 }
4925 undo_redo->add_do_method(this, "_queue_update_bone_list");
4926 undo_redo->add_undo_method(this, "_queue_update_bone_list");
4927 undo_redo->add_do_method(viewport, "update");
4928 undo_redo->add_undo_method(viewport, "update");
4929 undo_redo->commit_action();
4930
4931 } break;
4932 case SKELETON_SET_IK_CHAIN: {
4933
4934 List<Node *> selection = editor_selection->get_selected_node_list();
4935
4936 undo_redo->create_action(TTR("Make IK Chain"));
4937 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4938
4939 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
4940 if (!canvas_item || !canvas_item->is_visible_in_tree())
4941 continue;
4942 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4943 continue;
4944 if (canvas_item->has_meta("_edit_ik_") && canvas_item->get_meta("_edit_ik_"))
4945 continue;
4946
4947 undo_redo->add_do_method(canvas_item, "set_meta", "_edit_ik_", true);
4948 undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_ik_");
4949 }
4950 undo_redo->add_do_method(viewport, "update");
4951 undo_redo->add_undo_method(viewport, "update");
4952 undo_redo->commit_action();
4953
4954 } break;
4955 case SKELETON_CLEAR_IK_CHAIN: {
4956
4957 Map<Node *, Object *> &selection = editor_selection->get_selection();
4958
4959 undo_redo->create_action(TTR("Clear IK Chain"));
4960 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4961
4962 CanvasItem *n2d = Object::cast_to<CanvasItem>(E->key());
4963 if (!n2d)
4964 continue;
4965 if (!n2d->is_visible_in_tree())
4966 continue;
4967 if (!n2d->has_meta("_edit_ik_"))
4968 continue;
4969
4970 undo_redo->add_do_method(n2d, "remove_meta", "_edit_ik_");
4971 undo_redo->add_undo_method(n2d, "set_meta", "_edit_ik_", n2d->get_meta("_edit_ik_"));
4972 }
4973 undo_redo->add_do_method(viewport, "update");
4974 undo_redo->add_undo_method(viewport, "update");
4975 undo_redo->commit_action();
4976
4977 } break;
4978 }
4979 }
4980
_focus_selection(int p_op)4981 void CanvasItemEditor::_focus_selection(int p_op) {
4982 Vector2 center(0.f, 0.f);
4983 Rect2 rect;
4984 int count = 0;
4985
4986 Map<Node *, Object *> &selection = editor_selection->get_selection();
4987 for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
4988 CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key());
4989 if (!canvas_item) continue;
4990 if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4991 continue;
4992
4993 // counting invisible items, for now
4994 //if (!canvas_item->is_visible_in_tree()) continue;
4995 ++count;
4996
4997 Rect2 item_rect;
4998 if (canvas_item->_edit_use_rect()) {
4999 item_rect = canvas_item->_edit_get_rect();
5000 } else {
5001 item_rect = Rect2();
5002 }
5003
5004 Vector2 pos = canvas_item->get_global_transform().get_origin();
5005 Vector2 scale = canvas_item->get_global_transform().get_scale();
5006 real_t angle = canvas_item->get_global_transform().get_rotation();
5007
5008 Transform2D t(angle, Vector2(0.f, 0.f));
5009 item_rect = t.xform(item_rect);
5010 Rect2 canvas_item_rect(pos + scale * item_rect.position, scale * item_rect.size);
5011 if (count == 1) {
5012 rect = canvas_item_rect;
5013 } else {
5014 rect = rect.merge(canvas_item_rect);
5015 }
5016 };
5017 if (count == 0) return;
5018
5019 if (p_op == VIEW_CENTER_TO_SELECTION) {
5020
5021 center = rect.position + rect.size / 2;
5022 Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
5023 view_offset.x -= Math::round(offset.x / zoom);
5024 view_offset.y -= Math::round(offset.y / zoom);
5025 update_viewport();
5026
5027 } else { // VIEW_FRAME_TO_SELECTION
5028
5029 if (rect.size.x > CMP_EPSILON && rect.size.y > CMP_EPSILON) {
5030 float scale_x = viewport->get_size().x / rect.size.x;
5031 float scale_y = viewport->get_size().y / rect.size.y;
5032 zoom = scale_x < scale_y ? scale_x : scale_y;
5033 zoom *= 0.90;
5034 viewport->update();
5035 _update_zoom_label();
5036 call_deferred("_popup_callback", VIEW_CENTER_TO_SELECTION);
5037 }
5038 }
5039 }
5040
_bind_methods()5041 void CanvasItemEditor::_bind_methods() {
5042
5043 ClassDB::bind_method("_button_zoom_minus", &CanvasItemEditor::_button_zoom_minus);
5044 ClassDB::bind_method("_button_zoom_reset", &CanvasItemEditor::_button_zoom_reset);
5045 ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus);
5046 ClassDB::bind_method("_button_toggle_smart_snap", &CanvasItemEditor::_button_toggle_smart_snap);
5047 ClassDB::bind_method("_button_toggle_grid_snap", &CanvasItemEditor::_button_toggle_grid_snap);
5048 ClassDB::bind_method(D_METHOD("_button_override_camera", "pressed"), &CanvasItemEditor::_button_override_camera);
5049 ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button);
5050 ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode);
5051 ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll);
5052 ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars);
5053 ClassDB::bind_method("_popup_callback", &CanvasItemEditor::_popup_callback);
5054 ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data);
5055 ClassDB::bind_method("_button_tool_select", &CanvasItemEditor::_button_tool_select);
5056 ClassDB::bind_method("_keying_changed", &CanvasItemEditor::_keying_changed);
5057 ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input);
5058 ClassDB::bind_method("_draw_viewport", &CanvasItemEditor::_draw_viewport);
5059 ClassDB::bind_method("_gui_input_viewport", &CanvasItemEditor::_gui_input_viewport);
5060 ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed);
5061 ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list);
5062 ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list);
5063 ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed);
5064 ClassDB::bind_method("_selection_changed", &CanvasItemEditor::_selection_changed);
5065 ClassDB::bind_method("_popup_warning_depop", &CanvasItemEditor::_popup_warning_depop);
5066 ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed);
5067 ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide);
5068 ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
5069 ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
5070
5071 ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
5072 ADD_SIGNAL(MethodInfo("item_group_status_changed"));
5073 }
5074
get_state() const5075 Dictionary CanvasItemEditor::get_state() const {
5076
5077 Dictionary state;
5078 // Take the editor scale into account.
5079 state["zoom"] = zoom / MAX(1, EDSCALE);
5080 state["ofs"] = view_offset;
5081 state["grid_offset"] = grid_offset;
5082 state["grid_step"] = grid_step;
5083 state["primary_grid_steps"] = primary_grid_steps;
5084 state["snap_rotation_offset"] = snap_rotation_offset;
5085 state["snap_rotation_step"] = snap_rotation_step;
5086 state["snap_scale_step"] = snap_scale_step;
5087 state["smart_snap_active"] = smart_snap_active;
5088 state["grid_snap_active"] = grid_snap_active;
5089 state["snap_node_parent"] = snap_node_parent;
5090 state["snap_node_anchors"] = snap_node_anchors;
5091 state["snap_node_sides"] = snap_node_sides;
5092 state["snap_node_center"] = snap_node_center;
5093 state["snap_other_nodes"] = snap_other_nodes;
5094 state["snap_guides"] = snap_guides;
5095 state["show_grid"] = show_grid;
5096 state["show_origin"] = show_origin;
5097 state["show_viewport"] = show_viewport;
5098 state["show_rulers"] = show_rulers;
5099 state["show_guides"] = show_guides;
5100 state["show_helpers"] = show_helpers;
5101 state["show_zoom_control"] = zoom_hb->is_visible();
5102 state["show_edit_locks"] = show_edit_locks;
5103 state["snap_rotation"] = snap_rotation;
5104 state["snap_scale"] = snap_scale;
5105 state["snap_relative"] = snap_relative;
5106 state["snap_pixel"] = snap_pixel;
5107 state["skeleton_show_bones"] = skeleton_show_bones;
5108 return state;
5109 }
5110
set_state(const Dictionary & p_state)5111 void CanvasItemEditor::set_state(const Dictionary &p_state) {
5112
5113 bool update_scrollbars = false;
5114 Dictionary state = p_state;
5115 if (state.has("zoom")) {
5116 // Compensate the editor scale, so that the editor scale can be changed
5117 // and the zoom level will still be the same (relative to the editor scale).
5118 zoom = float(p_state["zoom"]) * MAX(1, EDSCALE);
5119 _update_zoom_label();
5120 }
5121
5122 if (state.has("ofs")) {
5123 view_offset = p_state["ofs"];
5124 previous_update_view_offset = view_offset;
5125 update_scrollbars = true;
5126 }
5127
5128 if (state.has("grid_offset")) {
5129 grid_offset = state["grid_offset"];
5130 }
5131
5132 if (state.has("grid_step")) {
5133 grid_step = state["grid_step"];
5134 }
5135
5136 if (state.has("primary_grid_steps")) {
5137 primary_grid_steps = state["primary_grid_steps"];
5138 }
5139
5140 if (state.has("snap_rotation_step")) {
5141 snap_rotation_step = state["snap_rotation_step"];
5142 }
5143
5144 if (state.has("snap_rotation_offset")) {
5145 snap_rotation_offset = state["snap_rotation_offset"];
5146 }
5147
5148 if (state.has("snap_scale_step")) {
5149 snap_scale_step = state["snap_scale_step"];
5150 }
5151
5152 if (state.has("smart_snap_active")) {
5153 smart_snap_active = state["smart_snap_active"];
5154 smart_snap_button->set_pressed(smart_snap_active);
5155 }
5156
5157 if (state.has("grid_snap_active")) {
5158 grid_snap_active = state["grid_snap_active"];
5159 grid_snap_button->set_pressed(grid_snap_active);
5160 }
5161
5162 if (state.has("snap_node_parent")) {
5163 snap_node_parent = state["snap_node_parent"];
5164 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_PARENT);
5165 smartsnap_config_popup->set_item_checked(idx, snap_node_parent);
5166 }
5167
5168 if (state.has("snap_node_anchors")) {
5169 snap_node_anchors = state["snap_node_anchors"];
5170 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_ANCHORS);
5171 smartsnap_config_popup->set_item_checked(idx, snap_node_anchors);
5172 }
5173
5174 if (state.has("snap_node_sides")) {
5175 snap_node_sides = state["snap_node_sides"];
5176 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_SIDES);
5177 smartsnap_config_popup->set_item_checked(idx, snap_node_sides);
5178 }
5179
5180 if (state.has("snap_node_center")) {
5181 snap_node_center = state["snap_node_center"];
5182 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_CENTER);
5183 smartsnap_config_popup->set_item_checked(idx, snap_node_center);
5184 }
5185
5186 if (state.has("snap_other_nodes")) {
5187 snap_other_nodes = state["snap_other_nodes"];
5188 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_OTHER_NODES);
5189 smartsnap_config_popup->set_item_checked(idx, snap_other_nodes);
5190 }
5191
5192 if (state.has("snap_guides")) {
5193 snap_guides = state["snap_guides"];
5194 int idx = smartsnap_config_popup->get_item_index(SNAP_USE_GUIDES);
5195 smartsnap_config_popup->set_item_checked(idx, snap_guides);
5196 }
5197
5198 if (state.has("show_grid")) {
5199 show_grid = state["show_grid"];
5200 int idx = view_menu->get_popup()->get_item_index(SHOW_GRID);
5201 view_menu->get_popup()->set_item_checked(idx, show_grid);
5202 }
5203
5204 if (state.has("show_origin")) {
5205 show_origin = state["show_origin"];
5206 int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
5207 view_menu->get_popup()->set_item_checked(idx, show_origin);
5208 }
5209
5210 if (state.has("show_viewport")) {
5211 show_viewport = state["show_viewport"];
5212 int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT);
5213 view_menu->get_popup()->set_item_checked(idx, show_viewport);
5214 }
5215
5216 if (state.has("show_rulers")) {
5217 show_rulers = state["show_rulers"];
5218 int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
5219 view_menu->get_popup()->set_item_checked(idx, show_rulers);
5220 update_scrollbars = true;
5221 }
5222
5223 if (state.has("show_guides")) {
5224 show_guides = state["show_guides"];
5225 int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES);
5226 view_menu->get_popup()->set_item_checked(idx, show_guides);
5227 }
5228
5229 if (state.has("show_helpers")) {
5230 show_helpers = state["show_helpers"];
5231 int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS);
5232 view_menu->get_popup()->set_item_checked(idx, show_helpers);
5233 }
5234
5235 if (state.has("show_edit_locks")) {
5236 show_edit_locks = state["show_edit_locks"];
5237 int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS);
5238 view_menu->get_popup()->set_item_checked(idx, show_edit_locks);
5239 }
5240
5241 if (state.has("show_zoom_control")) {
5242 // This one is not user-controllable, but instrumentable
5243 zoom_hb->set_visible(state["show_zoom_control"]);
5244 }
5245
5246 if (state.has("snap_rotation")) {
5247 snap_rotation = state["snap_rotation"];
5248 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION);
5249 snap_config_menu->get_popup()->set_item_checked(idx, snap_rotation);
5250 }
5251
5252 if (state.has("snap_scale")) {
5253 snap_scale = state["snap_scale"];
5254 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_SCALE);
5255 snap_config_menu->get_popup()->set_item_checked(idx, snap_scale);
5256 }
5257
5258 if (state.has("snap_relative")) {
5259 snap_relative = state["snap_relative"];
5260 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE);
5261 snap_config_menu->get_popup()->set_item_checked(idx, snap_relative);
5262 }
5263
5264 if (state.has("snap_pixel")) {
5265 snap_pixel = state["snap_pixel"];
5266 int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_PIXEL);
5267 snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel);
5268 }
5269
5270 if (state.has("skeleton_show_bones")) {
5271 skeleton_show_bones = state["skeleton_show_bones"];
5272 int idx = skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES);
5273 skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones);
5274 }
5275
5276 if (update_scrollbars) {
5277 _update_scrollbars();
5278 }
5279 viewport->update();
5280 }
5281
add_control_to_info_overlay(Control * p_control)5282 void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) {
5283 ERR_FAIL_COND(!p_control);
5284
5285 p_control->set_h_size_flags(p_control->get_h_size_flags() & ~Control::SIZE_EXPAND_FILL);
5286 info_overlay->add_child(p_control);
5287 info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
5288 }
5289
remove_control_from_info_overlay(Control * p_control)5290 void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {
5291
5292 info_overlay->remove_child(p_control);
5293 info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
5294 }
5295
add_control_to_menu_panel(Control * p_control)5296 void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
5297 ERR_FAIL_COND(!p_control);
5298
5299 hb->add_child(p_control);
5300 }
5301
remove_control_from_menu_panel(Control * p_control)5302 void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
5303
5304 hb->remove_child(p_control);
5305 }
5306
get_palette_split()5307 HSplitContainer *CanvasItemEditor::get_palette_split() {
5308
5309 return palette_split;
5310 }
5311
get_bottom_split()5312 VSplitContainer *CanvasItemEditor::get_bottom_split() {
5313
5314 return bottom_split;
5315 }
5316
focus_selection()5317 void CanvasItemEditor::focus_selection() {
5318 _focus_selection(VIEW_CENTER_TO_SELECTION);
5319 }
5320
CanvasItemEditor(EditorNode * p_editor)5321 CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
5322
5323 key_pos = true;
5324 key_rot = true;
5325 key_scale = false;
5326
5327 show_grid = false;
5328 show_origin = true;
5329 show_viewport = true;
5330 show_helpers = false;
5331 show_rulers = true;
5332 show_guides = true;
5333 show_edit_locks = true;
5334 zoom = 1.0 / MAX(1, EDSCALE);
5335 view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
5336 previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen
5337 grid_offset = Point2();
5338 grid_step = Point2(8, 8); // A power-of-two value works better as a default
5339 primary_grid_steps = 8; // A power-of-two value works better as a default
5340 grid_step_multiplier = 0;
5341 snap_rotation_offset = 0;
5342 snap_rotation_step = 15 / (180 / Math_PI);
5343 snap_scale_step = 0.1f;
5344 smart_snap_active = false;
5345 grid_snap_active = false;
5346 snap_node_parent = true;
5347 snap_node_anchors = true;
5348 snap_node_sides = true;
5349 snap_node_center = true;
5350 snap_other_nodes = true;
5351 snap_guides = true;
5352 snap_rotation = false;
5353 snap_scale = false;
5354 snap_relative = false;
5355 snap_pixel = false;
5356 snap_target[0] = SNAP_TARGET_NONE;
5357 snap_target[1] = SNAP_TARGET_NONE;
5358
5359 selected_from_canvas = false;
5360 anchors_mode = false;
5361
5362 skeleton_show_bones = true;
5363
5364 drag_type = DRAG_NONE;
5365 drag_from = Vector2();
5366 drag_to = Vector2();
5367 dragged_guide_pos = Point2();
5368 dragged_guide_index = -1;
5369 is_hovering_h_guide = false;
5370 is_hovering_v_guide = false;
5371 panning = false;
5372 pan_pressed = false;
5373
5374 ruler_tool_active = false;
5375 ruler_tool_origin = Point2();
5376
5377 bone_last_frame = 0;
5378
5379 bone_list_dirty = false;
5380 tool = TOOL_SELECT;
5381 undo_redo = p_editor->get_undo_redo();
5382 editor = p_editor;
5383 editor_selection = p_editor->get_editor_selection();
5384 editor_selection->add_editor_plugin(this);
5385 editor_selection->connect("selection_changed", this, "update");
5386 editor_selection->connect("selection_changed", this, "_selection_changed");
5387
5388 editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true));
5389 editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false));
5390
5391 hb = memnew(HBoxContainer);
5392 add_child(hb);
5393 hb->set_anchors_and_margins_preset(Control::PRESET_WIDE);
5394
5395 bottom_split = memnew(VSplitContainer);
5396 add_child(bottom_split);
5397 bottom_split->set_v_size_flags(SIZE_EXPAND_FILL);
5398
5399 palette_split = memnew(HSplitContainer);
5400 bottom_split->add_child(palette_split);
5401 palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
5402
5403 viewport_scrollable = memnew(Control);
5404 palette_split->add_child(viewport_scrollable);
5405 viewport_scrollable->set_mouse_filter(MOUSE_FILTER_PASS);
5406 viewport_scrollable->set_clip_contents(true);
5407 viewport_scrollable->set_v_size_flags(SIZE_EXPAND_FILL);
5408 viewport_scrollable->set_h_size_flags(SIZE_EXPAND_FILL);
5409 viewport_scrollable->connect("draw", this, "_update_scrollbars");
5410
5411 ViewportContainer *scene_tree = memnew(ViewportContainer);
5412 viewport_scrollable->add_child(scene_tree);
5413 scene_tree->set_stretch(true);
5414 scene_tree->set_anchors_and_margins_preset(Control::PRESET_WIDE);
5415 scene_tree->add_child(p_editor->get_scene_root());
5416
5417 controls_vb = memnew(VBoxContainer);
5418 controls_vb->set_begin(Point2(5, 5));
5419
5420 zoom_hb = memnew(HBoxContainer);
5421 // Bring the zoom percentage closer to the zoom buttons
5422 zoom_hb->add_constant_override("separation", Math::round(-8 * EDSCALE));
5423 controls_vb->add_child(zoom_hb);
5424
5425 viewport = memnew(CanvasItemEditorViewport(p_editor, this));
5426 viewport_scrollable->add_child(viewport);
5427 viewport->set_mouse_filter(MOUSE_FILTER_PASS);
5428 viewport->set_anchors_and_margins_preset(Control::PRESET_WIDE);
5429 viewport->set_clip_contents(true);
5430 viewport->set_focus_mode(FOCUS_ALL);
5431 viewport->connect("draw", this, "_draw_viewport");
5432 viewport->connect("gui_input", this, "_gui_input_viewport");
5433
5434 info_overlay = memnew(VBoxContainer);
5435 info_overlay->set_anchors_and_margins_preset(Control::PRESET_BOTTOM_LEFT);
5436 info_overlay->set_margin(MARGIN_LEFT, 10);
5437 info_overlay->set_margin(MARGIN_BOTTOM, -15);
5438 info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN);
5439 info_overlay->add_constant_override("separation", 10);
5440 viewport_scrollable->add_child(info_overlay);
5441
5442 Theme *info_overlay_theme = memnew(Theme);
5443 info_overlay_theme->copy_default_theme();
5444 info_overlay->set_theme(info_overlay_theme);
5445
5446 StyleBoxFlat *info_overlay_label_stylebox = memnew(StyleBoxFlat);
5447 info_overlay_label_stylebox->set_bg_color(Color(0.0, 0.0, 0.0, 0.2));
5448 info_overlay_label_stylebox->set_expand_margin_size_all(4);
5449 info_overlay_theme->set_stylebox("normal", "Label", info_overlay_label_stylebox);
5450
5451 warning_child_of_container = memnew(Label);
5452 warning_child_of_container->hide();
5453 warning_child_of_container->set_text(TTR("Warning: Children of a container get their position and size determined only by their parent."));
5454 warning_child_of_container->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor"));
5455 warning_child_of_container->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts"));
5456 add_control_to_info_overlay(warning_child_of_container);
5457
5458 h_scroll = memnew(HScrollBar);
5459 viewport->add_child(h_scroll);
5460 h_scroll->connect("value_changed", this, "_update_scroll");
5461 h_scroll->hide();
5462
5463 v_scroll = memnew(VScrollBar);
5464 viewport->add_child(v_scroll);
5465 v_scroll->connect("value_changed", this, "_update_scroll");
5466 v_scroll->hide();
5467
5468 viewport->add_child(controls_vb);
5469
5470 zoom_minus = memnew(ToolButton);
5471 zoom_hb->add_child(zoom_minus);
5472 zoom_minus->connect("pressed", this, "_button_zoom_minus");
5473 zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS));
5474 zoom_minus->set_focus_mode(FOCUS_NONE);
5475
5476 zoom_reset = memnew(ToolButton);
5477 zoom_hb->add_child(zoom_reset);
5478 zoom_reset->connect("pressed", this, "_button_zoom_reset");
5479 zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KEY_MASK_CMD | KEY_0));
5480 zoom_reset->set_focus_mode(FOCUS_NONE);
5481 zoom_reset->set_text_align(Button::TextAlign::ALIGN_CENTER);
5482 // Prevent the button's size from changing when the text size changes
5483 zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0));
5484
5485 zoom_plus = memnew(ToolButton);
5486 zoom_hb->add_child(zoom_plus);
5487 zoom_plus->connect("pressed", this, "_button_zoom_plus");
5488 zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)); // Usually direct access key for PLUS
5489 zoom_plus->set_focus_mode(FOCUS_NONE);
5490
5491 updating_scroll = false;
5492
5493 select_button = memnew(ToolButton);
5494 hb->add_child(select_button);
5495 select_button->set_toggle_mode(true);
5496 select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SELECT));
5497 select_button->set_pressed(true);
5498 select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), KEY_Q));
5499 select_button->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate") + "\n" + TTR("Alt+Drag: Move") + "\n" + TTR("Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).") + "\n" + TTR("Alt+RMB: Depth list selection"));
5500
5501 hb->add_child(memnew(VSeparator));
5502
5503 move_button = memnew(ToolButton);
5504 hb->add_child(move_button);
5505 move_button->set_toggle_mode(true);
5506 move_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_MOVE));
5507 move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W));
5508 move_button->set_tooltip(TTR("Move Mode"));
5509
5510 rotate_button = memnew(ToolButton);
5511 hb->add_child(rotate_button);
5512 rotate_button->set_toggle_mode(true);
5513 rotate_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_ROTATE));
5514 rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), KEY_E));
5515 rotate_button->set_tooltip(TTR("Rotate Mode"));
5516
5517 scale_button = memnew(ToolButton);
5518 hb->add_child(scale_button);
5519 scale_button->set_toggle_mode(true);
5520 scale_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SCALE));
5521 scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S));
5522 scale_button->set_tooltip(TTR("Scale Mode"));
5523
5524 hb->add_child(memnew(VSeparator));
5525
5526 list_select_button = memnew(ToolButton);
5527 hb->add_child(list_select_button);
5528 list_select_button->set_toggle_mode(true);
5529 list_select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_LIST_SELECT));
5530 list_select_button->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
5531
5532 pivot_button = memnew(ToolButton);
5533 hb->add_child(pivot_button);
5534 pivot_button->set_toggle_mode(true);
5535 pivot_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_EDIT_PIVOT));
5536 pivot_button->set_tooltip(TTR("Click to change object's rotation pivot."));
5537
5538 pan_button = memnew(ToolButton);
5539 hb->add_child(pan_button);
5540 pan_button->set_toggle_mode(true);
5541 pan_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PAN));
5542 pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), KEY_G));
5543 pan_button->set_tooltip(TTR("Pan Mode"));
5544
5545 ruler_button = memnew(ToolButton);
5546 hb->add_child(ruler_button);
5547 ruler_button->set_toggle_mode(true);
5548 ruler_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_RULER));
5549 ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), KEY_R));
5550 ruler_button->set_tooltip(TTR("Ruler Mode"));
5551
5552 hb->add_child(memnew(VSeparator));
5553
5554 smart_snap_button = memnew(ToolButton);
5555 hb->add_child(smart_snap_button);
5556 smart_snap_button->set_toggle_mode(true);
5557 smart_snap_button->connect("toggled", this, "_button_toggle_smart_snap");
5558 smart_snap_button->set_tooltip(TTR("Toggle smart snapping."));
5559 smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KEY_MASK_SHIFT | KEY_S));
5560
5561 grid_snap_button = memnew(ToolButton);
5562 hb->add_child(grid_snap_button);
5563 grid_snap_button->set_toggle_mode(true);
5564 grid_snap_button->connect("toggled", this, "_button_toggle_grid_snap");
5565 grid_snap_button->set_tooltip(TTR("Toggle grid snapping."));
5566 grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KEY_MASK_SHIFT | KEY_G));
5567
5568 snap_config_menu = memnew(MenuButton);
5569 hb->add_child(snap_config_menu);
5570 snap_config_menu->set_h_size_flags(SIZE_SHRINK_END);
5571 snap_config_menu->set_tooltip(TTR("Snapping Options"));
5572 snap_config_menu->set_switch_on_hover(true);
5573
5574 PopupMenu *p = snap_config_menu->get_popup();
5575 p->connect("id_pressed", this, "_popup_callback");
5576 p->set_hide_on_checkable_item_selection(false);
5577 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION);
5578 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_scale_snap", TTR("Use Scale Snap")), SNAP_USE_SCALE);
5579 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE);
5580 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL);
5581 p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping");
5582
5583 p->add_separator();
5584 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE);
5585
5586 smartsnap_config_popup = memnew(PopupMenu);
5587 p->add_child(smartsnap_config_popup);
5588 smartsnap_config_popup->set_name("SmartSnapping");
5589 smartsnap_config_popup->connect("id_pressed", this, "_popup_callback");
5590 smartsnap_config_popup->set_hide_on_checkable_item_selection(false);
5591 smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to Parent")), SNAP_USE_NODE_PARENT);
5592 smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to Node Anchor")), SNAP_USE_NODE_ANCHORS);
5593 smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to Node Sides")), SNAP_USE_NODE_SIDES);
5594 smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_center", TTR("Snap to Node Center")), SNAP_USE_NODE_CENTER);
5595 smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to Other Nodes")), SNAP_USE_OTHER_NODES);
5596 smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to Guides")), SNAP_USE_GUIDES);
5597
5598 hb->add_child(memnew(VSeparator));
5599
5600 lock_button = memnew(ToolButton);
5601 hb->add_child(lock_button);
5602
5603 lock_button->connect("pressed", this, "_popup_callback", varray(LOCK_SELECTED));
5604 lock_button->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
5605
5606 unlock_button = memnew(ToolButton);
5607 hb->add_child(unlock_button);
5608 unlock_button->connect("pressed", this, "_popup_callback", varray(UNLOCK_SELECTED));
5609 unlock_button->set_tooltip(TTR("Unlock the selected object (can be moved)."));
5610
5611 group_button = memnew(ToolButton);
5612 hb->add_child(group_button);
5613 group_button->connect("pressed", this, "_popup_callback", varray(GROUP_SELECTED));
5614 group_button->set_tooltip(TTR("Makes sure the object's children are not selectable."));
5615
5616 ungroup_button = memnew(ToolButton);
5617 hb->add_child(ungroup_button);
5618 ungroup_button->connect("pressed", this, "_popup_callback", varray(UNGROUP_SELECTED));
5619 ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected."));
5620
5621 hb->add_child(memnew(VSeparator));
5622
5623 skeleton_menu = memnew(MenuButton);
5624 hb->add_child(skeleton_menu);
5625 skeleton_menu->set_tooltip(TTR("Skeleton Options"));
5626 skeleton_menu->set_switch_on_hover(true);
5627
5628 p = skeleton_menu->get_popup();
5629 p->set_hide_on_checkable_item_selection(false);
5630 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES);
5631 p->add_separator();
5632 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN);
5633 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN);
5634 p->add_separator();
5635 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Custom Bone(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES);
5636 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES);
5637 p->connect("id_pressed", this, "_popup_callback");
5638
5639 hb->add_child(memnew(VSeparator));
5640
5641 override_camera_button = memnew(ToolButton);
5642 hb->add_child(override_camera_button);
5643 override_camera_button->connect("toggled", this, "_button_override_camera");
5644 override_camera_button->set_toggle_mode(true);
5645 override_camera_button->set_disabled(true);
5646 _update_override_camera_button(false);
5647
5648 hb->add_child(memnew(VSeparator));
5649
5650 view_menu = memnew(MenuButton);
5651 view_menu->set_text(TTR("View"));
5652 hb->add_child(view_menu);
5653 view_menu->get_popup()->connect("id_pressed", this, "_popup_callback");
5654 view_menu->set_switch_on_hover(true);
5655
5656 p = view_menu->get_popup();
5657 p->set_hide_on_checkable_item_selection(false);
5658 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Always Show Grid"), KEY_G), SHOW_GRID);
5659 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS);
5660 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers")), SHOW_RULERS);
5661 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), KEY_Y), SHOW_GUIDES);
5662 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_origin", TTR("Show Origin")), SHOW_ORIGIN);
5663 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_viewport", TTR("Show Viewport")), SHOW_VIEWPORT);
5664 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_edit_locks", TTR("Show Group And Lock Icons")), SHOW_EDIT_LOCKS);
5665
5666 p->add_separator();
5667 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION);
5668 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION);
5669 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/clear_guides", TTR("Clear Guides")), CLEAR_GUIDES);
5670 p->add_separator();
5671 p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE);
5672
5673 presets_menu = memnew(MenuButton);
5674 presets_menu->set_text(TTR("Layout"));
5675 hb->add_child(presets_menu);
5676 presets_menu->hide();
5677 presets_menu->set_switch_on_hover(true);
5678
5679 p = presets_menu->get_popup();
5680 p->connect("id_pressed", this, "_popup_callback");
5681
5682 anchors_popup = memnew(PopupMenu);
5683 p->add_child(anchors_popup);
5684 anchors_popup->set_name("Anchors");
5685 anchors_popup->connect("id_pressed", this, "_popup_callback");
5686
5687 anchor_mode_button = memnew(ToolButton);
5688 hb->add_child(anchor_mode_button);
5689 anchor_mode_button->set_toggle_mode(true);
5690 anchor_mode_button->hide();
5691 anchor_mode_button->connect("toggled", this, "_button_toggle_anchor_mode");
5692
5693 animation_hb = memnew(HBoxContainer);
5694 hb->add_child(animation_hb);
5695 animation_hb->add_child(memnew(VSeparator));
5696 animation_hb->hide();
5697
5698 key_loc_button = memnew(Button);
5699 key_loc_button->set_toggle_mode(true);
5700 key_loc_button->set_flat(true);
5701 key_loc_button->set_pressed(true);
5702 key_loc_button->set_focus_mode(FOCUS_NONE);
5703 key_loc_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_POS));
5704 key_loc_button->set_tooltip(TTR("Translation mask for inserting keys."));
5705 animation_hb->add_child(key_loc_button);
5706 key_rot_button = memnew(Button);
5707 key_rot_button->set_toggle_mode(true);
5708 key_rot_button->set_flat(true);
5709 key_rot_button->set_pressed(true);
5710 key_rot_button->set_focus_mode(FOCUS_NONE);
5711 key_rot_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_ROT));
5712 key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys."));
5713 animation_hb->add_child(key_rot_button);
5714 key_scale_button = memnew(Button);
5715 key_scale_button->set_toggle_mode(true);
5716 key_scale_button->set_flat(true);
5717 key_scale_button->set_focus_mode(FOCUS_NONE);
5718 key_scale_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_SCALE));
5719 key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
5720 animation_hb->add_child(key_scale_button);
5721 key_insert_button = memnew(Button);
5722 key_insert_button->set_flat(true);
5723 key_insert_button->set_focus_mode(FOCUS_NONE);
5724 key_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY));
5725 key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
5726 key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT));
5727 animation_hb->add_child(key_insert_button);
5728 key_auto_insert_button = memnew(Button);
5729 key_auto_insert_button->set_flat(true);
5730 key_auto_insert_button->set_toggle_mode(true);
5731 key_auto_insert_button->set_focus_mode(FOCUS_NONE);
5732 //key_auto_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY));
5733 key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
5734 key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key")));
5735 animation_hb->add_child(key_auto_insert_button);
5736
5737 animation_menu = memnew(MenuButton);
5738 animation_menu->set_tooltip(TTR("Animation Key and Pose Options"));
5739 animation_hb->add_child(animation_menu);
5740 animation_menu->get_popup()->connect("id_pressed", this, "_popup_callback");
5741 animation_menu->set_switch_on_hover(true);
5742
5743 p = animation_menu->get_popup();
5744
5745 p->add_shortcut(ED_GET_SHORTCUT("canvas_item_editor/anim_insert_key"), ANIM_INSERT_KEY);
5746 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key_existing_tracks", TTR("Insert Key (Existing Tracks)"), KEY_MASK_CMD + KEY_INSERT), ANIM_INSERT_KEY_EXISTING);
5747 p->add_separator();
5748 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_copy_pose", TTR("Copy Pose")), ANIM_COPY_POSE);
5749 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_paste_pose", TTR("Paste Pose")), ANIM_PASTE_POSE);
5750 p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_clear_pose", TTR("Clear Pose"), KEY_MASK_SHIFT | KEY_K), ANIM_CLEAR_POSE);
5751
5752 snap_dialog = memnew(SnapDialog);
5753 snap_dialog->connect("confirmed", this, "_snap_changed");
5754 add_child(snap_dialog);
5755
5756 select_sb = Ref<StyleBoxTexture>(memnew(StyleBoxTexture));
5757
5758 selection_menu = memnew(PopupMenu);
5759 add_child(selection_menu);
5760 selection_menu->set_custom_minimum_size(Vector2(100, 0));
5761 selection_menu->connect("id_pressed", this, "_selection_result_pressed");
5762 selection_menu->connect("popup_hide", this, "_selection_menu_hide");
5763
5764 multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), KEY_KP_MULTIPLY);
5765 divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), KEY_KP_DIVIDE);
5766 pan_view_shortcut = ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), KEY_SPACE);
5767
5768 skeleton_menu->get_popup()->set_item_checked(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES), true);
5769 singleton = this;
5770
5771 set_process_unhandled_key_input(true);
5772
5773 // Update the menus' checkboxes
5774 call_deferred("set_state", get_state());
5775 }
5776
5777 CanvasItemEditor *CanvasItemEditor::singleton = NULL;
5778
edit(Object * p_object)5779 void CanvasItemEditorPlugin::edit(Object *p_object) {
5780
5781 canvas_item_editor->set_undo_redo(&get_undo_redo());
5782 canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object));
5783 }
5784
handles(Object * p_object) const5785 bool CanvasItemEditorPlugin::handles(Object *p_object) const {
5786
5787 return p_object->is_class("CanvasItem");
5788 }
5789
make_visible(bool p_visible)5790 void CanvasItemEditorPlugin::make_visible(bool p_visible) {
5791
5792 if (p_visible) {
5793 canvas_item_editor->show();
5794 canvas_item_editor->set_physics_process(true);
5795 VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false);
5796
5797 } else {
5798
5799 canvas_item_editor->hide();
5800 canvas_item_editor->set_physics_process(false);
5801 VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), true);
5802 }
5803 }
5804
get_state() const5805 Dictionary CanvasItemEditorPlugin::get_state() const {
5806
5807 return canvas_item_editor->get_state();
5808 }
set_state(const Dictionary & p_state)5809 void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) {
5810
5811 canvas_item_editor->set_state(p_state);
5812 }
5813
CanvasItemEditorPlugin(EditorNode * p_node)5814 CanvasItemEditorPlugin::CanvasItemEditorPlugin(EditorNode *p_node) {
5815
5816 editor = p_node;
5817 canvas_item_editor = memnew(CanvasItemEditor(editor));
5818 canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
5819 editor->get_viewport()->add_child(canvas_item_editor);
5820 canvas_item_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE);
5821 canvas_item_editor->hide();
5822 }
5823
~CanvasItemEditorPlugin()5824 CanvasItemEditorPlugin::~CanvasItemEditorPlugin() {
5825 }
5826
_on_mouse_exit()5827 void CanvasItemEditorViewport::_on_mouse_exit() {
5828 if (!selector->is_visible()) {
5829 _remove_preview();
5830 }
5831 }
5832
_on_select_type(Object * selected)5833 void CanvasItemEditorViewport::_on_select_type(Object *selected) {
5834 CheckBox *check = Object::cast_to<CheckBox>(selected);
5835 String type = check->get_text();
5836 selector->set_title(vformat(TTR("Add %s"), type));
5837 label->set_text(vformat(TTR("Adding %s..."), type));
5838 }
5839
_on_change_type_confirmed()5840 void CanvasItemEditorViewport::_on_change_type_confirmed() {
5841 if (!button_group->get_pressed_button())
5842 return;
5843
5844 CheckBox *check = Object::cast_to<CheckBox>(button_group->get_pressed_button());
5845 default_type = check->get_text();
5846 _perform_drop_data();
5847 selector->hide();
5848 }
5849
_on_change_type_closed()5850 void CanvasItemEditorViewport::_on_change_type_closed() {
5851
5852 _remove_preview();
5853 }
5854
_create_preview(const Vector<String> & files) const5855 void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) const {
5856 bool add_preview = false;
5857 for (int i = 0; i < files.size(); i++) {
5858 String path = files[i];
5859 RES res = ResourceLoader::load(path);
5860 ERR_FAIL_COND(res.is_null());
5861 Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(*res));
5862 Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
5863 if (texture != NULL || scene != NULL) {
5864 if (texture != NULL) {
5865 Sprite *sprite = memnew(Sprite);
5866 sprite->set_texture(texture);
5867 sprite->set_modulate(Color(1, 1, 1, 0.7f));
5868 preview_node->add_child(sprite);
5869 label->show();
5870 label_desc->show();
5871 } else {
5872 if (scene.is_valid()) {
5873 Node *instance = scene->instance();
5874 if (instance) {
5875 preview_node->add_child(instance);
5876 }
5877 }
5878 }
5879 add_preview = true;
5880 }
5881 }
5882
5883 if (add_preview)
5884 editor->get_scene_root()->add_child(preview_node);
5885 }
5886
_remove_preview()5887 void CanvasItemEditorViewport::_remove_preview() {
5888 if (preview_node->get_parent()) {
5889 for (int i = preview_node->get_child_count() - 1; i >= 0; i--) {
5890 Node *node = preview_node->get_child(i);
5891 node->queue_delete();
5892 preview_node->remove_child(node);
5893 }
5894 editor->get_scene_root()->remove_child(preview_node);
5895
5896 label->hide();
5897 label_desc->hide();
5898 }
5899 }
5900
_cyclical_dependency_exists(const String & p_target_scene_path,Node * p_desired_node)5901 bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) {
5902 if (p_desired_node->get_filename() == p_target_scene_path) {
5903 return true;
5904 }
5905
5906 int childCount = p_desired_node->get_child_count();
5907 for (int i = 0; i < childCount; i++) {
5908 Node *child = p_desired_node->get_child(i);
5909 if (_cyclical_dependency_exists(p_target_scene_path, child)) {
5910 return true;
5911 }
5912 }
5913 return false;
5914 }
5915
_create_nodes(Node * parent,Node * child,String & path,const Point2 & p_point)5916 void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) {
5917 child->set_name(path.get_file().get_basename());
5918 Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(ResourceCache::get(path)));
5919 Size2 texture_size = texture->get_size();
5920
5921 if (parent) {
5922 editor_data->get_undo_redo().add_do_method(parent, "add_child", child);
5923 editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
5924 editor_data->get_undo_redo().add_do_reference(child);
5925 editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child);
5926 } else { // if we haven't parent, lets try to make a child as a parent.
5927 editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
5928 editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
5929 editor_data->get_undo_redo().add_do_reference(child);
5930 editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
5931 }
5932
5933 if (parent) {
5934 String new_name = parent->validate_child_name(child);
5935 ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
5936 editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
5937 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));
5938 }
5939
5940 // handle with different property for texture
5941 String property = "texture";
5942 List<PropertyInfo> props;
5943 child->get_property_list(&props);
5944 for (const List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
5945 if (E->get().name == "config/texture") { // Particles2D
5946 property = "config/texture";
5947 break;
5948 } else if (E->get().name == "texture/texture") { // Polygon2D
5949 property = "texture/texture";
5950 break;
5951 } else if (E->get().name == "normal") { // TouchScreenButton
5952 property = "normal";
5953 break;
5954 }
5955 }
5956 editor_data->get_undo_redo().add_do_property(child, property, texture);
5957
5958 // make visible for certain node type
5959 if (default_type == "NinePatchRect") {
5960 editor_data->get_undo_redo().add_do_property(child, "rect/size", texture_size);
5961 } else if (default_type == "Polygon2D") {
5962 PoolVector<Vector2> list;
5963 list.push_back(Vector2(0, 0));
5964 list.push_back(Vector2(texture_size.width, 0));
5965 list.push_back(Vector2(texture_size.width, texture_size.height));
5966 list.push_back(Vector2(0, texture_size.height));
5967 editor_data->get_undo_redo().add_do_property(child, "polygon", list);
5968 }
5969
5970 // Compute the global position
5971 Transform2D xform = canvas_item_editor->get_canvas_transform();
5972 Point2 target_position = xform.affine_inverse().xform(p_point);
5973
5974 // there's nothing to be used as source position so snapping will work as absolute if enabled
5975 target_position = canvas_item_editor->snap_point(target_position);
5976 editor_data->get_undo_redo().add_do_method(child, "set_global_position", target_position);
5977 }
5978
_create_instance(Node * parent,String & path,const Point2 & p_point)5979 bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
5980 Ref<PackedScene> sdata = ResourceLoader::load(path);
5981 if (!sdata.is_valid()) { // invalid scene
5982 return false;
5983 }
5984
5985 Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
5986 if (!instanced_scene) { // error on instancing
5987 return false;
5988 }
5989
5990 if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing
5991 if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) {
5992 memdelete(instanced_scene);
5993 return false;
5994 }
5995 }
5996
5997 instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
5998
5999 editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
6000 editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
6001 editor_data->get_undo_redo().add_do_reference(instanced_scene);
6002 editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene);
6003
6004 String new_name = parent->validate_child_name(instanced_scene);
6005 ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
6006 editor_data->get_undo_redo().add_do_method(sed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
6007 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));
6008
6009 CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
6010 if (parent_ci) {
6011 Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point);
6012 target_pos = canvas_item_editor->snap_point(target_pos);
6013 target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
6014 // Preserve instance position of the original scene.
6015 CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instanced_scene);
6016 if (instance_ci) {
6017 target_pos += instance_ci->_edit_get_position();
6018 }
6019 editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos);
6020 }
6021
6022 return true;
6023 }
6024
_perform_drop_data()6025 void CanvasItemEditorViewport::_perform_drop_data() {
6026 _remove_preview();
6027
6028 // Without root dropping multiple files is not allowed
6029 if (!target_node && selected_files.size() > 1) {
6030 accept->set_text(TTR("Cannot instantiate multiple nodes without root."));
6031 accept->popup_centered_minsize();
6032 return;
6033 }
6034
6035 Vector<String> error_files;
6036
6037 editor_data->get_undo_redo().create_action(TTR("Create Node"));
6038
6039 for (int i = 0; i < selected_files.size(); i++) {
6040 String path = selected_files[i];
6041 RES res = ResourceLoader::load(path);
6042 if (res.is_null()) {
6043 continue;
6044 }
6045 Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
6046 if (scene != NULL && scene.is_valid()) {
6047 if (!target_node) {
6048 // Without root node act the same as "Load Inherited Scene"
6049 Error err = EditorNode::get_singleton()->load_scene(path, false, true);
6050 if (err != OK) {
6051 error_files.push_back(path);
6052 }
6053 } else {
6054 bool success = _create_instance(target_node, path, drop_pos);
6055 if (!success) {
6056 error_files.push_back(path);
6057 }
6058 }
6059 } else {
6060 Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(*res));
6061 if (texture != NULL && texture.is_valid()) {
6062 Node *child;
6063 if (default_type == "Light2D")
6064 child = memnew(Light2D);
6065 else if (default_type == "Particles2D")
6066 child = memnew(Particles2D);
6067 else if (default_type == "Polygon2D")
6068 child = memnew(Polygon2D);
6069 else if (default_type == "TouchScreenButton")
6070 child = memnew(TouchScreenButton);
6071 else if (default_type == "TextureRect")
6072 child = memnew(TextureRect);
6073 else if (default_type == "NinePatchRect")
6074 child = memnew(NinePatchRect);
6075 else
6076 child = memnew(Sprite); // default
6077
6078 _create_nodes(target_node, child, path, drop_pos);
6079 }
6080 }
6081 }
6082
6083 editor_data->get_undo_redo().commit_action();
6084
6085 if (error_files.size() > 0) {
6086 String files_str;
6087 for (int i = 0; i < error_files.size(); i++) {
6088 files_str += error_files[i].get_file().get_basename() + ",";
6089 }
6090 files_str = files_str.substr(0, files_str.length() - 1);
6091 accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
6092 accept->popup_centered_minsize();
6093 }
6094 }
6095
can_drop_data(const Point2 & p_point,const Variant & p_data) const6096 bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
6097 Dictionary d = p_data;
6098 if (d.has("type")) {
6099 if (String(d["type"]) == "files") {
6100 Vector<String> files = d["files"];
6101 bool can_instance = false;
6102 for (int i = 0; i < files.size(); i++) { // check if dragged files contain resource or scene can be created at least once
6103 RES res = ResourceLoader::load(files[i]);
6104 if (res.is_null()) {
6105 continue;
6106 }
6107 String type = res->get_class();
6108 if (type == "PackedScene") {
6109 Ref<PackedScene> sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
6110 Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
6111 if (!instanced_scene) {
6112 continue;
6113 }
6114 memdelete(instanced_scene);
6115 } else if (type == "Texture" ||
6116 type == "ImageTexture" ||
6117 type == "ViewportTexture" ||
6118 type == "CurveTexture" ||
6119 type == "GradientTexture" ||
6120 type == "StreamTexture" ||
6121 type == "AtlasTexture" ||
6122 type == "LargeTexture") {
6123 Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(*res));
6124 if (!texture.is_valid()) {
6125 continue;
6126 }
6127 } else {
6128 continue;
6129 }
6130 can_instance = true;
6131 break;
6132 }
6133 if (can_instance) {
6134 if (!preview_node->get_parent()) { // create preview only once
6135 _create_preview(files);
6136 }
6137 Transform2D trans = canvas_item_editor->get_canvas_transform();
6138 preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x);
6139 label->set_text(vformat(TTR("Adding %s..."), default_type));
6140 }
6141 return can_instance;
6142 }
6143 }
6144 label->hide();
6145 return false;
6146 }
6147
_show_resource_type_selector()6148 void CanvasItemEditorViewport::_show_resource_type_selector() {
6149 _remove_preview();
6150 List<BaseButton *> btn_list;
6151 button_group->get_buttons(&btn_list);
6152
6153 for (int i = 0; i < btn_list.size(); i++) {
6154 CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
6155 check->set_pressed(check->get_text() == default_type);
6156 }
6157 selector->set_title(vformat(TTR("Add %s"), default_type));
6158 selector->popup_centered_minsize();
6159 }
6160
_only_packed_scenes_selected() const6161 bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
6162
6163 for (int i = 0; i < selected_files.size(); ++i) {
6164 if (ResourceLoader::load(selected_files[i])->get_class() != "PackedScene") {
6165 return false;
6166 }
6167 }
6168
6169 return true;
6170 }
6171
drop_data(const Point2 & p_point,const Variant & p_data)6172 void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
6173 bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
6174 bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
6175
6176 selected_files.clear();
6177 Dictionary d = p_data;
6178 if (d.has("type") && String(d["type"]) == "files") {
6179 selected_files = d["files"];
6180 }
6181 if (selected_files.size() == 0)
6182 return;
6183
6184 List<Node *> list = editor->get_editor_selection()->get_selected_node_list();
6185 if (list.size() == 0) {
6186 Node *root_node = editor->get_edited_scene();
6187 if (root_node) {
6188 list.push_back(root_node);
6189 } else {
6190 drop_pos = p_point;
6191 target_node = NULL;
6192 }
6193 }
6194
6195 if (list.size() > 0) {
6196 target_node = list[0];
6197 if (is_shift && target_node != editor->get_edited_scene()) {
6198 target_node = target_node->get_parent();
6199 }
6200 }
6201
6202 drop_pos = p_point;
6203
6204 if (is_alt && !_only_packed_scenes_selected()) {
6205 _show_resource_type_selector();
6206 } else {
6207 _perform_drop_data();
6208 }
6209 }
6210
_notification(int p_what)6211 void CanvasItemEditorViewport::_notification(int p_what) {
6212 switch (p_what) {
6213 case NOTIFICATION_ENTER_TREE: {
6214 connect("mouse_exited", this, "_on_mouse_exit");
6215 label->add_color_override("font_color", get_color("warning_color", "Editor"));
6216 } break;
6217 case NOTIFICATION_EXIT_TREE: {
6218 disconnect("mouse_exited", this, "_on_mouse_exit");
6219 } break;
6220
6221 default: break;
6222 }
6223 }
6224
_bind_methods()6225 void CanvasItemEditorViewport::_bind_methods() {
6226 ClassDB::bind_method(D_METHOD("_on_select_type"), &CanvasItemEditorViewport::_on_select_type);
6227 ClassDB::bind_method(D_METHOD("_on_change_type_confirmed"), &CanvasItemEditorViewport::_on_change_type_confirmed);
6228 ClassDB::bind_method(D_METHOD("_on_change_type_closed"), &CanvasItemEditorViewport::_on_change_type_closed);
6229 ClassDB::bind_method(D_METHOD("_on_mouse_exit"), &CanvasItemEditorViewport::_on_mouse_exit);
6230 }
6231
CanvasItemEditorViewport(EditorNode * p_node,CanvasItemEditor * p_canvas_item_editor)6232 CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasItemEditor *p_canvas_item_editor) {
6233 default_type = "Sprite";
6234 // Node2D
6235 types.push_back("Sprite");
6236 types.push_back("Light2D");
6237 types.push_back("Particles2D");
6238 types.push_back("Polygon2D");
6239 types.push_back("TouchScreenButton");
6240 // Control
6241 types.push_back("TextureRect");
6242 types.push_back("NinePatchRect");
6243
6244 target_node = NULL;
6245 editor = p_node;
6246 editor_data = editor->get_scene_tree_dock()->get_editor_data();
6247 canvas_item_editor = p_canvas_item_editor;
6248 preview_node = memnew(Node2D);
6249
6250 accept = memnew(AcceptDialog);
6251 editor->get_gui_base()->add_child(accept);
6252
6253 selector = memnew(AcceptDialog);
6254 editor->get_gui_base()->add_child(selector);
6255 selector->set_title(TTR("Change Default Type"));
6256 selector->connect("confirmed", this, "_on_change_type_confirmed");
6257 selector->connect("popup_hide", this, "_on_change_type_closed");
6258
6259 VBoxContainer *vbc = memnew(VBoxContainer);
6260 selector->add_child(vbc);
6261 vbc->set_h_size_flags(SIZE_EXPAND_FILL);
6262 vbc->set_v_size_flags(SIZE_EXPAND_FILL);
6263 vbc->set_custom_minimum_size(Size2(240, 260) * EDSCALE);
6264
6265 btn_group = memnew(VBoxContainer);
6266 vbc->add_child(btn_group);
6267 btn_group->set_h_size_flags(0);
6268
6269 button_group.instance();
6270 for (int i = 0; i < types.size(); i++) {
6271 CheckBox *check = memnew(CheckBox);
6272 btn_group->add_child(check);
6273 check->set_text(types[i]);
6274 check->connect("button_down", this, "_on_select_type", varray(check));
6275 check->set_button_group(button_group);
6276 }
6277
6278 label = memnew(Label);
6279 label->add_color_override("font_color_shadow", Color(0, 0, 0, 1));
6280 label->add_constant_override("shadow_as_outline", 1 * EDSCALE);
6281 label->hide();
6282 canvas_item_editor->get_controls_container()->add_child(label);
6283
6284 label_desc = memnew(Label);
6285 label_desc->set_text(TTR("Drag & drop + Shift : Add node as sibling\nDrag & drop + Alt : Change node type"));
6286 label_desc->add_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1));
6287 label_desc->add_color_override("font_color_shadow", Color(0.2f, 0.2f, 0.2f, 1));
6288 label_desc->add_constant_override("shadow_as_outline", 1 * EDSCALE);
6289 label_desc->add_constant_override("line_spacing", 0);
6290 label_desc->hide();
6291 canvas_item_editor->get_controls_container()->add_child(label_desc);
6292
6293 VS::get_singleton()->canvas_set_disable_scale(true);
6294 }
6295
~CanvasItemEditorViewport()6296 CanvasItemEditorViewport::~CanvasItemEditorViewport() {
6297 memdelete(preview_node);
6298 }
6299