summaryrefslogtreecommitdiffstats
path: root/editor/plugins/canvas_item_editor_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/canvas_item_editor_plugin.cpp')
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp444
1 files changed, 295 insertions, 149 deletions
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 70afc9a716..93aeca6632 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -44,6 +44,7 @@
#include "scene/2d/particles_2d.h"
#include "scene/2d/polygon_2d.h"
#include "scene/2d/screen_button.h"
+#include "scene/2d/skeleton_2d.h"
#include "scene/2d/sprite.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/nine_patch_rect.h"
@@ -457,7 +458,7 @@ Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) {
return rect;
}
-void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int limit, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
+void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
if (!p_node)
return;
if (Object::cast_to<Viewport>(p_node))
@@ -466,23 +467,20 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
const real_t grab_distance = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- Node *scene = editor->get_edited_scene();
- if (!(p_node != scene && p_node->get_owner() != scene && (!scene->is_editable_instance(p_node) || p_node->has_meta("_edit_lock_")))) {
- for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
- if (canvas_item && !canvas_item->is_set_as_toplevel()) {
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, limit, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
- } else {
- CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, limit, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
- }
- if (limit != 0 && r_items.size() >= limit)
- return;
+ for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
+ if (canvas_item && !canvas_item->is_set_as_toplevel()) {
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+ } else {
+ CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
}
+ if (p_limit != 0 && r_items.size() >= p_limit)
+ return;
}
- if (canvas_item && canvas_item->is_visible_in_tree() && (canvas_item->get_owner() != editor->get_edited_scene() || !canvas_item->has_meta("_edit_lock_"))) {
+ if (canvas_item && canvas_item->is_visible_in_tree()) {
Transform2D xform = (p_parent_xform * p_canvas_xform * canvas_item->get_transform()).affine_inverse();
- const real_t local_grab_distance = xform.basis_xform(Vector2(grab_distance, 0)).length() / zoom;
+ const real_t local_grab_distance = xform.basis_xform(Vector2(grab_distance, 0)).length();
if (canvas_item->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) {
Node2D *node = Object::cast_to<Node2D>(canvas_item);
@@ -497,6 +495,41 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
return;
}
+void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit) {
+
+ Node *scene = editor->get_edited_scene();
+
+ _find_canvas_items_at_pos(p_pos, scene, r_items, p_limit);
+
+ //Remove invalid results
+ for (int i = 0; i < r_items.size(); i++) {
+ Node *node = r_items[i].item;
+
+ // Make sure the selected node is in the current scene, or editable
+ while (node && node != get_tree()->get_edited_scene_root() && node->get_owner() != scene && !scene->is_editable_instance(node->get_owner())) {
+ node = node->get_parent();
+ };
+
+ // Replace the node by the group if grouped
+ CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node);
+ while (node && node != scene->get_parent()) {
+ CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
+ if (canvas_item_tmp && node->has_meta("_edit_group_")) {
+ canvas_item = canvas_item_tmp;
+ }
+ node = node->get_parent();
+ }
+
+ //Remove the item if invalid
+ if (!canvas_item || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || (canvas_item->has_meta("_edit_lock_") && canvas_item->get_meta("_edit_lock_"))) {
+ r_items.remove(i);
+ i--;
+ } else {
+ r_items[i].item = canvas_item;
+ }
+ }
+}
+
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) {
if (!p_node)
return;
@@ -504,13 +537,13 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
return;
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
+ Node *scene = editor->get_edited_scene();
- bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != "";
- bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
+ bool editable = p_node == scene || p_node->get_owner() == scene || scene->is_editable_instance(p_node->get_owner());
bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
bool locked = p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
- if (!lock_children && !locked && editable) {
+ if (!lock_children || !editable) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
if (canvas_item && !canvas_item->is_set_as_toplevel()) {
_find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
@@ -521,7 +554,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
}
}
- if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) {
+ if (canvas_item && canvas_item->is_visible_in_tree() && !locked && editable) {
Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
if (canvas_item->_edit_use_rect()) {
@@ -628,7 +661,7 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
if (bone && bone->has_meta("_edit_bone_")) {
// Check if we have an IK chain
List<Node2D *> bone_ik_list;
- bool ik_found;
+ bool ik_found = false;
bone = Object::cast_to<Node2D>(bone->get_parent());
while (bone) {
bone_ik_list.push_back(bone);
@@ -896,7 +929,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
- if (b->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) {
// Scroll or pan down
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -908,7 +941,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
return true;
}
- if (b->get_button_index() == BUTTON_WHEEL_UP) {
+ if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_UP) {
// Scroll or pan up
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -920,7 +953,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
return true;
}
- if (b->get_button_index() == BUTTON_WHEEL_LEFT) {
+ if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_LEFT) {
// Pan left
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -930,7 +963,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
}
}
- if (b->get_button_index() == BUTTON_WHEEL_RIGHT) {
+ if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_RIGHT) {
// Pan right
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -939,28 +972,57 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
return true;
}
}
- }
- Ref<InputEventMouseMotion> m = p_event;
- if (m.is_valid()) {
if (drag_type == DRAG_NONE) {
- if (((m->get_button_mask() & BUTTON_MASK_LEFT) && tool == TOOL_PAN) ||
- (m->get_button_mask() & BUTTON_MASK_MIDDLE) ||
- ((m->get_button_mask() & BUTTON_MASK_LEFT) && Input::get_singleton()->is_key_pressed(KEY_SPACE)) ||
- (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") && Input::get_singleton()->is_key_pressed(KEY_SPACE))) {
+ if (b->is_pressed() &&
+ (b->get_button_index() == BUTTON_MIDDLE ||
+ (b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) ||
+ (b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
// Pan the viewport
- Point2i relative;
- if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
- relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect());
- } else {
- relative = m->get_relative();
+ drag_type = DRAG_PAN;
+ }
+ }
+
+ if (drag_type == DRAG_PAN) {
+ if (!b->is_pressed()) {
+ // Stop panning the viewport (for any mouse button press)
+ drag_type = DRAG_NONE;
+ }
+ }
+ }
+
+ Ref<InputEventKey> k = p_event;
+ if (k.is_valid()) {
+ if (k->get_scancode() == KEY_SPACE && EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning")) {
+ if (drag_type == DRAG_NONE) {
+ if (k->is_pressed() && !k->is_echo()) {
+ //Pan the viewport
+ drag_type = DRAG_PAN;
}
- view_offset.x -= relative.x / zoom;
- view_offset.y -= relative.y / zoom;
- _update_scrollbars();
- viewport->update();
- return true;
+ } else if (drag_type == DRAG_PAN) {
+ if (!k->is_pressed()) {
+ // Stop panning the viewport (for any mouse button press)
+ drag_type = DRAG_NONE;
+ }
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> m = p_event;
+ if (m.is_valid()) {
+ if (drag_type == DRAG_PAN) {
+ // Pan the viewport
+ Point2i relative;
+ if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
+ relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect());
+ } else {
+ relative = m->get_relative();
}
+ view_offset.x -= relative.x / zoom;
+ view_offset.y -= relative.y / zoom;
+ _update_scrollbars();
+ viewport->update();
+ return true;
}
}
@@ -1675,17 +1737,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
// Popup the selection menu list
Point2 click = transform.affine_inverse().xform(b->get_position());
- Node *scene = editor->get_edited_scene();
-
- _find_canvas_items_at_pos(click, scene, selection_results);
- for (int i = 0; i < selection_results.size(); i++) {
- CanvasItem *item = selection_results[i].item;
- if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
- //invalid result
- selection_results.remove(i);
- i--;
- }
- }
+ _get_canvas_items_at_pos(click, selection_results);
if (selection_results.size() == 1) {
CanvasItem *item = selection_results[0].item;
@@ -1735,7 +1787,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
// Find the item to select
CanvasItem *canvas_item = NULL;
Vector<_SelectResult> selection;
- _find_canvas_items_at_pos(click, scene, selection, editor_selection->get_selection().empty() ? 1 : 0);
+ _get_canvas_items_at_pos(click, selection, editor_selection->get_selection().empty() ? 1 : 0);
for (int i = 0; i < selection.size(); i++) {
if (editor_selection->is_selected(selection[i].item)) {
@@ -1754,23 +1806,6 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (!selection.empty())
canvas_item = selection[0].item;
- // Check if the canvas item is in a group, and select the group instead if it is the case
- Node *node = canvas_item;
- while (node && node != scene) {
- CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
- if (canvas_item_tmp && node->has_meta("_edit_group_")) {
- canvas_item = canvas_item_tmp;
- }
- node = node->get_parent();
- }
-
- // Make sure the selected node is in the current scene
- node = canvas_item;
- while (node && ((node != scene && node->get_owner() != scene) || !node->is_class("CanvasItem"))) {
- node = node->get_parent();
- };
- canvas_item = Object::cast_to<CanvasItem>(node);
-
if (!canvas_item) {
// Start a box selection
if (!b->get_shift()) {
@@ -1855,11 +1890,10 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
if (m.is_valid()) {
if (drag_type == DRAG_NONE && tool == TOOL_SELECT) {
Point2 click = transform.affine_inverse().xform(m->get_position());
- Node *scene = editor->get_edited_scene();
//Checks if the hovered items changed, update the viewport if so
Vector<_SelectResult> hovering_results_tmp;
- _find_canvas_items_at_pos(click, scene, hovering_results_tmp);
+ _get_canvas_items_at_pos(click, hovering_results_tmp);
hovering_results_tmp.sort();
bool changed = false;
if (hovering_results.size() == hovering_results_tmp.size()) {
@@ -1903,10 +1937,10 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
//printf("Rotate\n");
} else if ((accepted = _gui_input_move(p_event))) {
//printf("Move\n");
- } else if ((accepted = _gui_input_select(p_event))) {
- //printf("Selection\n");
} else if ((accepted = _gui_input_zoom_or_pan(p_event))) {
//printf("Zoom or pan\n");
+ } else if ((accepted = _gui_input_select(p_event))) {
+ //printf("Selection\n");
}
if (accepted)
@@ -1919,22 +1953,18 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
CursorShape c = CURSOR_ARROW;
switch (drag_type) {
case DRAG_NONE:
- if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
- c = CURSOR_DRAG;
- } else {
- switch (tool) {
- case TOOL_MOVE:
- c = CURSOR_MOVE;
- break;
- case TOOL_EDIT_PIVOT:
- c = CURSOR_CROSS;
- break;
- case TOOL_PAN:
- c = CURSOR_DRAG;
- break;
- default:
- break;
- }
+ switch (tool) {
+ case TOOL_MOVE:
+ c = CURSOR_MOVE;
+ break;
+ case TOOL_EDIT_PIVOT:
+ c = CURSOR_CROSS;
+ break;
+ case TOOL_PAN:
+ c = CURSOR_DRAG;
+ break;
+ default:
+ break;
}
break;
case DRAG_LEFT:
@@ -1956,6 +1986,8 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
case DRAG_ALL:
c = CURSOR_MOVE;
break;
+ case DRAG_PAN:
+ c = CURSOR_DRAG;
default:
break;
}
@@ -2551,43 +2583,52 @@ void CanvasItemEditor::_draw_bones() {
Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
+ int bone_outline_size = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
- for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
+ for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
- E->get().from = Vector2();
- E->get().to = Vector2();
+ Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
+ Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().to));
- Node2D *n2d = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key()));
- if (!n2d)
+ if (!from_node->is_inside_tree())
+ continue; //may have been removed
+ if (!from_node)
continue;
- if (!n2d->get_parent())
+ if (!to_node && E->get().length == 0)
continue;
- CanvasItem *pi = n2d->get_parent_item();
+ Vector2 from = transform.xform(from_node->get_global_position());
+ Vector2 to;
- Node2D *pn2d = Object::cast_to<Node2D>(n2d->get_parent());
-
- if (!pn2d)
- continue;
-
- Vector2 from = transform.xform(pn2d->get_global_position());
- Vector2 to = transform.xform(n2d->get_global_position());
-
- E->get().from = from;
- E->get().to = to;
+ if (to_node)
+ to = transform.xform(to_node->get_global_position());
+ else
+ to = transform.xform(from_node->get_global_transform().xform(Vector2(E->get().length, 0)));
Vector2 rel = to - from;
Vector2 relt = rel.tangent().normalized() * bone_width;
+ Vector2 reln = rel.normalized();
+ Vector2 reltn = relt.normalized();
Vector<Vector2> bone_shape;
bone_shape.push_back(from);
bone_shape.push_back(from + rel * 0.2 + relt);
bone_shape.push_back(to);
bone_shape.push_back(from + rel * 0.2 - relt);
+
+ Vector<Vector2> bone_shape_outline;
+ bone_shape_outline.push_back(from + (-reln - reltn) * bone_outline_size);
+ bone_shape_outline.push_back(from + (-reln + reltn) * bone_outline_size);
+ bone_shape_outline.push_back(from + rel * 0.2 + relt + reltn * bone_outline_size);
+ bone_shape_outline.push_back(to + (reln + reltn) * bone_outline_size);
+ bone_shape_outline.push_back(to + (reln - reltn) * bone_outline_size);
+ bone_shape_outline.push_back(from + rel * 0.2 - relt - reltn * bone_outline_size);
+
Vector<Color> colors;
- if (pi->has_meta("_edit_ik_")) {
+ if (from_node->has_meta("_edit_ik_")) {
colors.push_back(bone_ik_color);
colors.push_back(bone_ik_color);
@@ -2600,14 +2641,26 @@ void CanvasItemEditor::_draw_bones() {
colors.push_back(bone_color2);
}
- VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID());
-
- if (editor_selection->is_selected(pi)) {
- for (int i = 0; i < bone_shape.size(); i++) {
+ Vector<Color> outline_colors;
- VisualServer::get_singleton()->canvas_item_add_line(ci, bone_shape[i], bone_shape[(i + 1) % bone_shape.size()], bone_selected_color, 2);
- }
+ if (editor_selection->is_selected(from_node)) {
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ } else {
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
}
+
+ VisualServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors);
+ VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID());
}
}
}
@@ -2616,7 +2669,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
ERR_FAIL_COND(!p_node);
Node *scene = editor->get_edited_scene();
- if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node))
+ if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner()))
return;
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
if (canvas_item && !canvas_item->is_visible())
@@ -2731,26 +2784,70 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
}
}
-void CanvasItemEditor::_build_bones_list(Node *p_node) {
- ERR_FAIL_COND(!p_node);
+bool CanvasItemEditor::_build_bones_list(Node *p_node) {
+ ERR_FAIL_COND_V(!p_node, false);
+
+ bool has_child_bones = false;
for (int i = 0; i < p_node->get_child_count(); i++) {
- _build_bones_list(p_node->get_child(i));
+ if (_build_bones_list(p_node->get_child(i))) {
+ has_child_bones = true;
+ }
+ }
+
+ CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
+ Node *scene = editor->get_edited_scene();
+ if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner()))) {
+ return false;
}
- CanvasItem *c = Object::cast_to<CanvasItem>(p_node);
- if (c && c->is_visible_in_tree()) {
- if (c->has_meta("_edit_bone_")) {
+ Node *parent = canvas_item->get_parent();
- ObjectID id = c->get_instance_id();
- if (!bone_list.has(id)) {
- BoneList bone;
- bone_list[id] = bone;
+ if (Object::cast_to<Bone2D>(canvas_item)) {
+ if (Object::cast_to<Bone2D>(parent)) {
+ // Add as bone->parent relationship
+ BoneKey bk;
+ bk.from = parent->get_instance_id();
+ bk.to = canvas_item->get_instance_id();
+ if (!bone_list.has(bk)) {
+ BoneList b;
+ b.length = 0;
+ bone_list[bk] = b;
}
- bone_list[id].last_pass = bone_last_frame;
+ bone_list[bk].last_pass = bone_last_frame;
}
+
+ if (!has_child_bones) {
+ // Add a last bone if the Bone2D has no Bone2D child
+ BoneKey bk;
+ bk.from = canvas_item->get_instance_id();
+ bk.to = 0;
+ if (!bone_list.has(bk)) {
+ BoneList b;
+ b.length = 0;
+ bone_list[bk] = b;
+ }
+ bone_list[bk].last_pass = bone_last_frame;
+ }
+
+ return true;
}
+
+ if (canvas_item->has_meta("_edit_bone_")) {
+ // Add a "custom bone"
+ BoneKey bk;
+ bk.from = parent->get_instance_id();
+ bk.to = canvas_item->get_instance_id();
+ if (!bone_list.has(bk)) {
+ BoneList b;
+ b.length = 0;
+ bone_list[bk] = b;
+ }
+ bone_list[bk].last_pass = bone_last_frame;
+ }
+
+ return false;
}
void CanvasItemEditor::_draw_viewport() {
@@ -2826,6 +2923,7 @@ void CanvasItemEditor::_notification(int p_what) {
int nb_control = 0;
int nb_having_pivot = 0;
+ // Update the viewport if the canvas_item changes
List<CanvasItem *> selection = _get_edited_canvas_items();
for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
@@ -2871,15 +2969,17 @@ void CanvasItemEditor::_notification(int p_what) {
nb_having_pivot++;
}
}
+
// Activate / Deactivate the pivot tool
pivot_button->set_disabled(nb_having_pivot == 0);
// Show / Hide the layout button
presets_menu->set_visible(nb_control > 0 && nb_control == selection.size());
- for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
+ // Update the viewport if bones changes
+ for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
- Object *b = ObjectDB::get_instance(E->key());
+ Object *b = ObjectDB::get_instance(E->key().from);
if (!b) {
viewport->update();
@@ -2887,13 +2987,22 @@ void CanvasItemEditor::_notification(int p_what) {
}
Node2D *b2 = Object::cast_to<Node2D>(b);
- if (!b2) {
+ if (!b2 || !b2->is_inside_tree()) {
continue;
}
- if (b2->get_global_transform() != E->get().xform) {
+ Transform2D global_xform = b2->get_global_transform();
+
+ if (global_xform != E->get().xform) {
+
+ E->get().xform = global_xform;
+ viewport->update();
+ }
+
+ Bone2D *bone = Object::cast_to<Bone2D>(b);
+ if (bone && bone->get_default_length() != E->get().length) {
- E->get().xform = b2->get_global_transform();
+ E->get().length = bone->get_default_length();
viewport->update();
}
}
@@ -2909,12 +3018,19 @@ void CanvasItemEditor::_notification(int p_what) {
AnimationPlayerEditor::singleton->get_key_editor()->connect("visibility_changed", this, "_keying_changed");
_keying_changed();
+ get_tree()->connect("node_added", this, "_tree_changed", varray());
+ get_tree()->connect("node_removed", this, "_tree_changed", varray());
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons"));
}
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ get_tree()->disconnect("node_added", this, "_tree_changed");
+ get_tree()->disconnect("node_removed", this, "_tree_changed");
+ }
+
if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
select_button->set_icon(get_icon("ToolSelect", "EditorIcons"));
list_select_button->set_icon(get_icon("ListSelect", "EditorIcons"));
@@ -2999,6 +3115,47 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
editor_selection->add_node(p_canvas_item);
}
+void CanvasItemEditor::_queue_update_bone_list() {
+
+ if (bone_list_dirty)
+ return;
+
+ call_deferred("_update_bone_list");
+ bone_list_dirty = true;
+}
+
+void CanvasItemEditor::_update_bone_list() {
+
+ bone_last_frame++;
+
+ if (editor->get_edited_scene()) {
+ _build_bones_list(editor->get_edited_scene());
+ }
+
+ List<Map<BoneKey, BoneList>::Element *> bone_to_erase;
+ for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
+ if (E->get().last_pass != bone_last_frame) {
+ bone_to_erase.push_back(E);
+ continue;
+ }
+
+ Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E->key().from));
+ if (!node || !node->is_inside_tree() || (node != get_tree()->get_edited_scene_root() && !get_tree()->get_edited_scene_root()->is_a_parent_of(node))) {
+ bone_to_erase.push_back(E);
+ continue;
+ }
+ }
+ while (bone_to_erase.size()) {
+ bone_list.erase(bone_to_erase.front()->get());
+ bone_to_erase.pop_front();
+ }
+ bone_list_dirty = false;
+}
+
+void CanvasItemEditor::_tree_changed(Node *) {
+ _queue_update_bone_list();
+}
+
void CanvasItemEditor::_update_scrollbars() {
updating_scroll = true;
@@ -3023,22 +3180,7 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
- bone_last_frame++;
-
- if (editor->get_edited_scene()) {
- _build_bones_list(editor->get_edited_scene());
- }
-
- List<Map<ObjectID, BoneList>::Element *> bone_to_erase;
- for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
- if (E->get().last_pass != bone_last_frame) {
- bone_to_erase.push_back(E);
- }
- }
- while (bone_to_erase.size()) {
- bone_list.erase(bone_to_erase.front()->get());
- bone_to_erase.pop_front();
- }
+ _queue_update_bone_list();
// Calculate scrollable area
Rect2 canvas_item_rect = Rect2(Point2(), screen_rect);
@@ -3802,6 +3944,9 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_draw_viewport", &CanvasItemEditor::_draw_viewport);
ClassDB::bind_method("_gui_input_viewport", &CanvasItemEditor::_gui_input_viewport);
ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed);
+ ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list);
+ ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed);
+
ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed);
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
@@ -4005,6 +4150,7 @@ void CanvasItemEditor::focus_selection() {
CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
+ bone_list_dirty = false;
tool = TOOL_SELECT;
undo_redo = p_editor->get_undo_redo();
editor = p_editor;
@@ -4189,13 +4335,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p = skeleton_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bones"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Bones")), SKELETON_CLEAR_BONES);
- p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN);
+ p->add_separator();
+ 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);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES);
p->connect("id_pressed", this, "_popup_callback");
hb->add_child(memnew(VSeparator));