diff options
Diffstat (limited to 'editor/plugins/canvas_item_editor_plugin.cpp')
-rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 444 |
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)); |