diff options
Diffstat (limited to 'editor/plugins')
47 files changed, 2005 insertions, 758 deletions
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 7612f18aff..23c5e36a92 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -85,7 +85,7 @@ void AnimationPlayerEditor::_notification(int p_what) { } frame->set_value(player->get_current_animation_position()); key_editor->set_anim_pos(player->get_current_animation_position()); - EditorNode::get_singleton()->get_property_editor()->refresh(); + EditorNode::get_singleton()->get_inspector()->refresh(); } else if (last_active) { //need the last frame after it stopped @@ -440,7 +440,7 @@ void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource) file->set_current_path(existing); } file->popup_centered_ratio(); - file->set_title(TTR("Save Resource As..")); + file->set_title(TTR("Save Resource As...")); current_option = RESOURCE_SAVE; } @@ -459,6 +459,12 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { Ref<Animation> anim = player->get_animation(current); undo_redo->create_action(TTR("Remove Animation")); + if (player->get_autoplay() == current) { + undo_redo->add_do_method(player, "set_autoplay", ""); + undo_redo->add_undo_method(player, "set_autoplay", current); + // Avoid having the autoplay icon linger around if there is only one animation in the player + undo_redo->add_do_method(this, "_animation_player_changed", player); + } undo_redo->add_do_method(player, "remove_animation", current); undo_redo->add_undo_method(player, "add_animation", current, anim); undo_redo->add_do_method(this, "_animation_player_changed", player); @@ -491,7 +497,7 @@ void AnimationPlayerEditor::_animation_name_edited() { String new_name = name->get_text(); if (new_name == "" || new_name.find(":") != -1 || new_name.find("/") != -1) { - error_dialog->set_text(TTR("ERROR: Invalid animation name!")); + error_dialog->set_text(TTR("Invalid animation name!")); error_dialog->popup_centered_minsize(); return; } @@ -502,7 +508,7 @@ void AnimationPlayerEditor::_animation_name_edited() { } if (player->has_animation(new_name)) { - error_dialog->set_text(TTR("ERROR: Animation name already exists!")); + error_dialog->set_text(TTR("Animation name already exists!")); error_dialog->popup_centered_minsize(); return; } @@ -811,6 +817,8 @@ void AnimationPlayerEditor::_update_player() { play_bw->set_disabled(animlist.size() == 0); play_bw_from->set_disabled(animlist.size() == 0); play_from->set_disabled(animlist.size() == 0); + frame->set_editable(animlist.size() != 0); + animation->set_disabled(animlist.size() == 0); autoplay->set_disabled(animlist.size() == 0); duplicate_anim->set_disabled(animlist.size() == 0); rename_anim->set_disabled(animlist.size() == 0); @@ -820,6 +828,7 @@ void AnimationPlayerEditor::_update_player() { save_anim->set_disabled(animlist.size() == 0); tool_anim->set_disabled(player == NULL); onion_skinning->set_disabled(player == NULL); + pin->set_disabled(player == NULL); int active_idx = -1; for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) { @@ -1064,7 +1073,7 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) updating = false; _seek_value_changed(p_pos, !p_drag); - EditorNode::get_singleton()->get_property_editor()->refresh(); + EditorNode::get_singleton()->get_inspector()->refresh(); //seekit } @@ -1088,7 +1097,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { case TOOL_COPY_ANIM: { if (!animation->get_item_count()) { - error_dialog->set_text(TTR("ERROR: No animation to copy!")); + error_dialog->set_text(TTR("No animation to copy!")); error_dialog->popup_centered_minsize(); return; } @@ -1103,7 +1112,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard(); if (!anim.is_valid()) { - error_dialog->set_text(TTR("ERROR: No animation resource on clipboard!")); + error_dialog->set_text(TTR("No animation resource on clipboard!")); error_dialog->popup_centered_minsize(); return; } @@ -1134,7 +1143,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { case TOOL_EDIT_RESOURCE: { if (!animation->get_item_count()) { - error_dialog->set_text(TTR("ERROR: No animation to edit!")); + error_dialog->set_text(TTR("No animation to edit!")); error_dialog->popup_centered_minsize(); return; } @@ -1611,7 +1620,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay hb->add_child(load_anim); save_anim = memnew(MenuButton); - save_anim->set_tooltip(TTR("Save the current animation")); + save_anim->set_tooltip(TTR("Save the current animation.")); save_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/save", TTR("Save")), ANIM_SAVE); save_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/save_as", TTR("Save As")), ANIM_SAVE_AS); save_anim->set_focus_mode(Control::FOCUS_NONE); @@ -1691,6 +1700,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay pin = memnew(ToolButton); pin->set_toggle_mode(true); + pin->set_tooltip(TTR("Pin AnimationPlayer")); hb->add_child(pin); resource_edit_anim = memnew(Button); @@ -1718,7 +1728,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay error_dialog = memnew(ConfirmationDialog); error_dialog->get_ok()->set_text(TTR("Close")); - error_dialog->set_text(TTR("Error!")); + error_dialog->set_title(TTR("Error!")); add_child(error_dialog); name_dialog->connect("confirmed", this, "_animation_name_edited"); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 37213c1866..25582ae0b9 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -578,7 +578,7 @@ void AnimationTreeEditor::_draw_node(const StringName &p_node) { if (anim_tree->animation_node_get_master_animation(p_node) != "") text = anim_tree->animation_node_get_master_animation(p_node); else if (anim.is_null()) - text = "load.."; + text = "load..."; else text = anim->get_name(); @@ -593,7 +593,7 @@ void AnimationTreeEditor::_draw_node(const StringName &p_node) { case AnimationTreePlayer::NODE_TIMESCALE: case AnimationTreePlayer::NODE_TRANSITION: { - font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, "edit..", font_color_title); + font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, "edit...", font_color_title); } break; default: editable = false; } @@ -1290,7 +1290,7 @@ AnimationTreeEditor::AnimationTreeEditor() { p->add_item(TTR("TimeSeek Node"), AnimationTreePlayer::NODE_TIMESEEK); p->add_item(TTR("Transition Node"), AnimationTreePlayer::NODE_TRANSITION); p->add_separator(); - p->add_item(TTR("Import Animations.."), MENU_IMPORT_ANIMATIONS); // wtf + p->add_item(TTR("Import Animations..."), MENU_IMPORT_ANIMATIONS); // wtf p->add_separator(); p->add_item(TTR("Clear"), MENU_GRAPH_CLEAR); @@ -1399,7 +1399,7 @@ AnimationTreeEditor::AnimationTreeEditor() { filter_button->set_margin(MARGIN_RIGHT, -10); edit_dialog->add_child(filter_button); filter_button->hide(); - filter_button->set_text(TTR("Filters..")); + filter_button->set_text(TTR("Filters...")); filter_button->connect("pressed", this, "_edit_filters"); set_clip_contents(true); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index c203b4b81e..d595d4dd98 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -65,7 +65,7 @@ void EditorAssetLibraryItem::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - icon->set_normal_texture(get_icon("GodotAssetDefault", "EditorIcons")); + icon->set_normal_texture(get_icon("DefaultProjectIcon", "EditorIcons")); category->add_color_override("font_color", Color(0.5, 0.5, 0.5)); author->add_color_override("font_color", Color(0.5, 0.5, 0.5)); } @@ -110,6 +110,7 @@ EditorAssetLibraryItem::EditorAssetLibraryItem() { add_child(hb); icon = memnew(TextureButton); + icon->set_custom_minimum_size(Size2(64, 64)); icon->set_default_cursor_shape(CURSOR_POINTING_HAND); icon->connect("pressed", this, "_asset_clicked"); @@ -170,7 +171,23 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const for (int i = 0; i < preview_images.size(); i++) { if (preview_images[i].id == p_index) { - preview_images[i].button->set_icon(p_image); + if (preview_images[i].is_video) { + Ref<Image> overlay = get_icon("PlayOverlay", "EditorIcons")->get_data(); + Ref<Image> thumbnail = p_image->get_data(); + Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2); + + thumbnail->lock(); + thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos); + thumbnail->unlock(); + + Ref<ImageTexture> tex; + tex.instance(); + tex->create_from_image(thumbnail); + + preview_images[i].button->set_icon(tex); + } else { + preview_images[i].button->set_icon(p_image); + } break; } } @@ -383,7 +400,7 @@ void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asse icon->set_texture(p_preview); asset_id = p_asset_id; if (!p_preview.is_valid()) - icon->set_texture(get_icon("GodotAssetDefault", "EditorIcons")); + icon->set_texture(get_icon("DefaultProjectIcon", "EditorIcons")); host = p_download_url; sha256 = p_sha256_hash; asset_installer->connect("confirmed", this, "_close"); @@ -407,13 +424,13 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { switch (cstatus) { case HTTPClient::STATUS_RESOLVING: { - status->set_text(TTR("Resolving..")); + status->set_text(TTR("Resolving...")); } break; case HTTPClient::STATUS_CONNECTING: { - status->set_text(TTR("Connecting..")); + status->set_text(TTR("Connecting...")); } break; case HTTPClient::STATUS_REQUESTING: { - status->set_text(TTR("Requesting..")); + status->set_text(TTR("Requesting...")); } break; default: {} } @@ -639,7 +656,7 @@ const char *EditorAssetLibrary::support_key[SUPPORT_MAX] = { void EditorAssetLibrary::_select_author(int p_id) { - //opemn author window + // Open author window } void EditorAssetLibrary::_select_category(int p_id) { @@ -659,16 +676,6 @@ void EditorAssetLibrary::_select_category(int p_id) { void EditorAssetLibrary::_select_asset(int p_id) { _api_request("asset/" + itos(p_id), REQUESTING_ASSET); - - /* - if (description) { - memdelete(description); - } - - - description = memnew( EditorAssetLibraryItemDescription ); - add_child(description); - description->popup_centered_minsize();*/ } void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByteArray &p_data, int p_queue_id) { @@ -698,13 +705,24 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt int len = image_data.size(); PoolByteArray::Read r = image_data.read(); - Ref<Image> image = Ref<Image>(memnew(Image(r.ptr(), len))); + Ref<Image> image = Ref<Image>(memnew(Image)); + + uint8_t png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + uint8_t jpg_signature[3] = { 255, 216, 255 }; + + if (r.ptr()) { + if (memcmp(&r[0], &png_signature[0], 8) == 0) { + image->copy_internals_from(Image::_png_mem_loader_func(r.ptr(), len)); + } else if (memcmp(&r[0], &jpg_signature[0], 3) == 0) { + image->copy_internals_from(Image::_jpg_mem_loader_func(r.ptr(), len)); + } + } if (!image->empty()) { switch (image_queue[p_queue_id].image_type) { case IMAGE_QUEUE_ICON: - image->resize(80 * EDSCALE, 80 * EDSCALE, Image::INTERPOLATE_CUBIC); + image->resize(64 * EDSCALE, 64 * EDSCALE, Image::INTERPOLATE_CUBIC); break; case IMAGE_QUEUE_THUMBNAIL: { @@ -734,7 +752,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt } if (!image_set && final) { - obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("ErrorSign", "EditorIcons")); + obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("DefaultProjectIcon", "EditorIcons")); } } } @@ -743,7 +761,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons ERR_FAIL_COND(!image_queue.has(p_queue_id)); - if (p_status == HTTPRequest::RESULT_SUCCESS) { + if (p_status == HTTPRequest::RESULT_SUCCESS && p_code < HTTPClient::RESPONSE_BAD_REQUEST) { if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { @@ -774,10 +792,10 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons _image_update(p_code == HTTPClient::RESPONSE_NOT_MODIFIED, true, p_data, p_queue_id); } else { - WARN_PRINTS("Error getting PNG file for asset id " + itos(image_queue[p_queue_id].asset_id)); + // WARN_PRINTS("Error getting image file from URL: " + image_queue[p_queue_id].image_url); Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target); if (obj) { - obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("ErrorSign", "EditorIcons")); + obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("DefaultProjectIcon", "EditorIcons")); } } @@ -929,41 +947,43 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int if (to > p_page_count) to = p_page_count; - Color gray = Color(0.65, 0.65, 0.65); - hbc->add_spacer(); - hbc->add_constant_override("separation", 10); + hbc->add_constant_override("separation", 5); + Button *first = memnew(Button); + first->set_text(TTR("First")); if (p_page != 0) { - LinkButton *first = memnew(LinkButton); - first->set_text(TTR("first")); - first->add_color_override("font_color", gray); - first->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); first->connect("pressed", this, "_search", varray(0)); - hbc->add_child(first); + } else { + first->set_disabled(true); + first->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(first); + Button *prev = memnew(Button); + prev->set_text(TTR("Previous")); if (p_page > 0) { - LinkButton *prev = memnew(LinkButton); - prev->set_text(TTR("prev")); - prev->add_color_override("font_color", gray); - prev->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); prev->connect("pressed", this, "_search", varray(p_page - 1)); - hbc->add_child(prev); + } else { + prev->set_disabled(true); + prev->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(prev); + hbc->add_child(memnew(VSeparator)); for (int i = from; i < to; i++) { if (i == p_page) { - Label *current = memnew(Label); + Button *current = memnew(Button); current->set_text(itos(i + 1)); + current->set_disabled(true); + current->set_focus_mode(Control::FOCUS_NONE); + hbc->add_child(current); } else { - LinkButton *current = memnew(LinkButton); - current->add_color_override("font_color", gray); - current->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); + Button *current = memnew(Button); current->set_text(itos(i + 1)); current->connect("pressed", this, "_search", varray(i)); @@ -971,28 +991,26 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int } } + Button *next = memnew(Button); + next->set_text(TTR("Next")); if (p_page < p_page_count - 1) { - LinkButton *next = memnew(LinkButton); - next->set_text(TTR("next")); - next->add_color_override("font_color", gray); - next->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); next->connect("pressed", this, "_search", varray(p_page + 1)); - - hbc->add_child(next); + } else { + next->set_disabled(true); + next->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(memnew(VSeparator)); + hbc->add_child(next); + Button *last = memnew(Button); + last->set_text(TTR("Last")); if (p_page != p_page_count - 1) { - LinkButton *last = memnew(LinkButton); - last->set_text(TTR("last")); - last->add_color_override("font_color", gray); - last->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - hbc->add_child(last); last->connect("pressed", this, "_search", varray(p_page_count - 1)); + } else { + last->set_disabled(true); + last->set_focus_mode(Control::FOCUS_NONE); } - - Label *totals = memnew(Label); - totals->set_text("( " + itos(from * p_page_len) + " - " + itos(from * p_page_len + p_current_items - 1) + " / " + itos(p_total_items) + " )"); - hbc->add_child(totals); + hbc->add_child(last); hbc->add_spacer(); @@ -1382,7 +1400,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { support = memnew(MenuButton); search_hb2->add_child(support); - support->set_text(TTR("Support..")); + support->set_text(TTR("Support...")); support->get_popup()->add_check_item(TTR("Official"), SUPPORT_OFFICIAL); support->get_popup()->add_check_item(TTR("Community"), SUPPORT_COMMUNITY); support->get_popup()->add_check_item(TTR("Testing"), SUPPORT_TESTING); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 89b79d7cfb..69a65dd3dc 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -241,7 +241,6 @@ class EditorAssetLibrary : public PanelContainer { bool active; int queue_id; - int asset_id; ImageType image_type; int image_index; String image_url; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index bb94aee462..ca5aa7039d 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,21 +467,18 @@ 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(); if (canvas_item->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) { @@ -497,6 +495,132 @@ 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(); + } + + // Check if the canvas item is already in the list (for groups or scenes) + bool duplicate = false; + for (int j = 0; j < i; j++) { + if (r_items[j].item == canvas_item) { + duplicate = true; + break; + } + } + + //Remove the item if invalid + if (!canvas_item || duplicate || (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::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) { + Point2 screen_pos = transform.xform(p_pos); + + for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { + 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)); + + Vector<Vector2> bone_shape; + if (!_get_bone_shape(&bone_shape, NULL, E)) + continue; + + // Check if the point is inside the Polygon2D + if (Geometry::is_point_in_polygon(screen_pos, bone_shape)) { + // Check if the item is already in the list + bool duplicate = false; + for (int i = 0; i < r_items.size(); i++) { + if (r_items[i].item == from_node) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + + // Else, add it + _SelectResult res; + res.item = from_node; + res.z_index = from_node ? from_node->get_z_index() : 0; + res.has_z = from_node; + r_items.push_back(res); + } + } +} + +bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone) { + int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width"); + int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size"); + + Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().from)); + Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().to)); + + if (!from_node->is_inside_tree()) + return false; //may have been removed + if (!from_node) + return false; + + if (!to_node && bone->get().length == 0) + return false; + + Vector2 from = transform.xform(from_node->get_global_position()); + Vector2 to; + + if (to_node) + to = transform.xform(to_node->get_global_position()); + else + to = transform.xform(from_node->get_global_transform().xform(Vector2(bone->get().length, 0))); + + Vector2 rel = to - from; + Vector2 relt = rel.tangent().normalized() * bone_width; + Vector2 reln = rel.normalized(); + Vector2 reltn = relt.normalized(); + + if (shape) { + shape->clear(); + shape->push_back(from); + shape->push_back(from + rel * 0.2 + relt); + shape->push_back(to); + shape->push_back(from + rel * 0.2 - relt); + } + + if (outline_shape) { + outline_shape->clear(); + outline_shape->push_back(from + (-reln - reltn) * bone_outline_width); + outline_shape->push_back(from + (-reln + reltn) * bone_outline_width); + outline_shape->push_back(from + rel * 0.2 + relt + reltn * bone_outline_width); + outline_shape->push_back(to + (reln + reltn) * bone_outline_width); + outline_shape->push_back(to + (reln - reltn) * bone_outline_width); + outline_shape->push_back(from + rel * 0.2 - relt - reltn * bone_outline_width); + } + return true; +} + 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 +628,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 +645,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 +752,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 +1020,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 +1032,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 +1044,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 +1054,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 +1063,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 +1828,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 +1878,12 @@ 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); + + // Retrieve the items + _get_canvas_items_at_pos(click, selection, editor_selection->get_selection().empty() ? 1 : 0); + + // Retrieve the bones + _get_bones_at_pos(click, selection); for (int i = 0; i < selection.size(); i++) { if (editor_selection->is_selected(selection[i].item)) { @@ -1754,23 +1902,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 +1986,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 +2033,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 +2049,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 +2082,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; } @@ -2547,48 +2675,25 @@ void CanvasItemEditor::_draw_bones() { RID ci = viewport->get_canvas_item(); if (skeleton_show_bones) { - int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width"); 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"); - for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - - E->get().from = Vector2(); - E->get().to = Vector2(); + for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Node2D *n2d = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key())); - if (!n2d) + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E)) continue; - if (!n2d->get_parent()) + Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); + if (!from_node->is_visible_in_tree()) continue; - CanvasItem *pi = n2d->get_parent_item(); - - 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; - - Vector2 rel = to - from; - Vector2 relt = rel.tangent().normalized() * bone_width; - - 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<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); colors.push_back(bone_ik_color); @@ -2600,14 +2705,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 +2733,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 +2848,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 *c = Object::cast_to<CanvasItem>(p_node); - if (c && c->is_visible_in_tree()) { - if (c->has_meta("_edit_bone_")) { + 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; + } + + 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 +2987,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 +3033,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 +3051,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 = b2->get_global_transform(); + 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().length = bone->get_default_length(); viewport->update(); } } @@ -2909,12 +3082,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 +3179,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 +3244,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); @@ -3183,7 +3389,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) { } void CanvasItemEditor::_button_zoom_minus() { - _zoom_on_position(zoom / 2.0, viewport_scrollable->get_size() / 2.0); + _zoom_on_position(zoom / 1.5, viewport_scrollable->get_size() / 2.0); } void CanvasItemEditor::_button_zoom_reset() { @@ -3191,7 +3397,7 @@ void CanvasItemEditor::_button_zoom_reset() { } void CanvasItemEditor::_button_zoom_plus() { - _zoom_on_position(zoom * 2.0, viewport_scrollable->get_size() / 2.0); + _zoom_on_position(zoom * 1.5, viewport_scrollable->get_size() / 2.0); } void CanvasItemEditor::_button_toggle_snap(bool p_status) { @@ -3802,6 +4008,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 +4214,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; @@ -4064,16 +4274,19 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { zoom_minus = memnew(ToolButton); zoom_hb->add_child(zoom_minus); zoom_minus->connect("pressed", this, "_button_zoom_minus"); + zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom out"), KEY_MASK_CMD | KEY_MINUS)); zoom_minus->set_focus_mode(FOCUS_NONE); zoom_reset = memnew(ToolButton); zoom_hb->add_child(zoom_reset); zoom_reset->connect("pressed", this, "_button_zoom_reset"); + zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom reset"), KEY_MASK_CMD | KEY_0)); zoom_reset->set_focus_mode(FOCUS_NONE); zoom_plus = memnew(ToolButton); zoom_hb->add_child(zoom_plus); zoom_plus->connect("pressed", this, "_button_zoom_plus"); + zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom in"), KEY_MASK_CMD | KEY_PLUS)); zoom_plus->set_focus_mode(FOCUS_NONE); updating_scroll = false; @@ -4186,13 +4399,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)); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 5ca8a37610..4d2af11303 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -194,7 +194,8 @@ class CanvasItemEditor : public VBoxContainer { DRAG_V_GUIDE, DRAG_H_GUIDE, DRAG_DOUBLE_GUIDE, - DRAG_KEY_MOVE + DRAG_KEY_MOVE, + DRAG_PAN }; EditorSelection *editor_selection; @@ -263,12 +264,24 @@ class CanvasItemEditor : public VBoxContainer { struct BoneList { Transform2D xform; - Vector2 from; - Vector2 to; + float length; uint64_t last_pass; }; + uint64_t bone_last_frame; - Map<ObjectID, BoneList> bone_list; + + struct BoneKey { + ObjectID from; + ObjectID to; + _FORCE_INLINE_ bool operator<(const BoneKey &p_key) const { + if (from == p_key.from) + return to < p_key.to; + else + return from < p_key.from; + } + }; + + Map<BoneKey, BoneList> bone_list; struct PoseClipboard { Vector2 pos; @@ -336,7 +349,10 @@ class CanvasItemEditor : public VBoxContainer { Ref<ShortCut> multiply_grid_step_shortcut; Ref<ShortCut> divide_grid_step_shortcut; - void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); + void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); + void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit = 0); + void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items); + void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append); @@ -363,7 +379,8 @@ class CanvasItemEditor : public VBoxContainer { void _selection_menu_hide(); UndoRedo *undo_redo; - void _build_bones_list(Node *p_node); + bool _build_bones_list(Node *p_node); + bool _get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone); List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); @@ -430,6 +447,11 @@ class CanvasItemEditor : public VBoxContainer { HSplitContainer *palette_split; VSplitContainer *bottom_split; + bool bone_list_dirty; + void _queue_update_bone_list(); + void _update_bone_list(); + void _tree_changed(Node *); + friend class CanvasItemEditorPlugin; protected: diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp index b624d69810..672337ba2f 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -42,6 +42,7 @@ void CollisionPolygon2DEditor::_set_node(Node *p_polygon) { CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; } CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_editor_plugin.cpp index 4410242d9c..e837359d0c 100644 --- a/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_editor_plugin.cpp @@ -33,10 +33,12 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_settings.h" #include "os/file_access.h" +#include "os/input.h" +#include "os/keyboard.h" #include "scene/3d/camera.h" #include "spatial_editor_plugin.h" -void CollisionPolygonEditor::_notification(int p_what) { +void Polygon3DEditor::_notification(int p_what) { switch (p_what) { @@ -53,15 +55,15 @@ void CollisionPolygonEditor::_notification(int p_what) { return; } - if (node->get_depth() != prev_depth) { + if (_get_depth() != prev_depth) { _polygon_draw(); - prev_depth = node->get_depth(); + prev_depth = _get_depth(); } } break; } } -void CollisionPolygonEditor::_node_removed(Node *p_node) { +void Polygon3DEditor::_node_removed(Node *p_node) { if (p_node == node) { node = NULL; @@ -72,7 +74,7 @@ void CollisionPolygonEditor::_node_removed(Node *p_node) { } } -void CollisionPolygonEditor::_menu_option(int p_option) { +void Polygon3DEditor::_menu_option(int p_option) { switch (p_option) { @@ -91,10 +93,10 @@ void CollisionPolygonEditor::_menu_option(int p_option) { } } -void CollisionPolygonEditor::_wip_close() { +void Polygon3DEditor::_wip_close() { undo_redo->create_action(TTR("Create Poly3D")); - undo_redo->add_undo_method(node, "set_polygon", node->get_polygon()); + undo_redo->add_undo_method(node, "set_polygon", node->call("get_polygon")); undo_redo->add_do_method(node, "set_polygon", wip); undo_redo->add_do_method(this, "_polygon_draw"); undo_redo->add_undo_method(this, "_polygon_draw"); @@ -107,14 +109,14 @@ void CollisionPolygonEditor::_wip_close() { undo_redo->commit_action(); } -bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { +bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { if (!node) return false; Transform gt = node->get_global_transform(); Transform gi = gt.affine_inverse(); - float depth = node->get_depth() * 0.5; + float depth = _get_depth() * 0.5; Vector3 n = gt.basis.get_axis(2).normalized(); Plane p(gt.origin + n * depth, n); @@ -135,9 +137,11 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R Vector2 cpoint(spoint.x, spoint.y); - cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint); + //DO NOT snap here, it's confusing in 3D for adding points. + //Let the snap happen when the point is being moved, instead. + //cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint); - Vector<Vector2> poly = node->get_polygon(); + Vector<Vector2> poly = node->call("get_polygon"); //first check if a point is to be added (segment split) real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); @@ -154,6 +158,7 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R wip.push_back(cpoint); wip_active = true; edited_point_pos = cpoint; + snap_ignore = false; _polygon_draw(); edited_point = 1; return true; @@ -168,6 +173,7 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R wip.push_back(cpoint); edited_point = wip.size(); + snap_ignore = false; _polygon_draw(); return true; } @@ -226,8 +232,10 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R poly.insert(closest_idx + 1, cpoint); edited_point = closest_idx + 1; edited_point_pos = cpoint; - node->set_polygon(poly); + node->call("set_polygon", poly); _polygon_draw(); + snap_ignore = true; + return true; } } else { @@ -255,11 +263,14 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R edited_point = closest_idx; edited_point_pos = poly[closest_idx]; _polygon_draw(); + snap_ignore = false; return true; } } } else { + snap_ignore = false; + if (edited_point != -1) { //apply @@ -315,7 +326,6 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - if (edited_point != -1 && (wip_active || mm->get_button_mask() & BUTTON_MASK_LEFT)) { Vector2 gpoint = mm->get_position(); @@ -332,7 +342,13 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R Vector2 cpoint(spoint.x, spoint.y); - cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint); + if (snap_ignore && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + snap_ignore = false; + } + + if (!snap_ignore) { + cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint); + } edited_point_pos = cpoint; _polygon_draw(); @@ -341,7 +357,16 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R return false; } -void CollisionPolygonEditor::_polygon_draw() { + +float Polygon3DEditor::_get_depth() { + + if (bool(node->call("_has_editable_3d_polygon_no_depth"))) + return 0; + + return float(node->call("get_depth")); +} + +void Polygon3DEditor::_polygon_draw() { if (!node) return; @@ -351,9 +376,9 @@ void CollisionPolygonEditor::_polygon_draw() { if (wip_active) poly = wip; else - poly = node->get_polygon(); + poly = node->call("get_polygon"); - float depth = node->get_depth() * 0.5; + float depth = _get_depth() * 0.5; imgeom->clear(); imgeom->set_material_override(line_material); @@ -464,13 +489,13 @@ void CollisionPolygonEditor::_polygon_draw() { m->surface_set_material(0, handle_material); } -void CollisionPolygonEditor::edit(Node *p_collision_polygon) { +void Polygon3DEditor::edit(Node *p_collision_polygon) { if (p_collision_polygon) { - node = Object::cast_to<CollisionPolygon>(p_collision_polygon); + node = Object::cast_to<Spatial>(p_collision_polygon); //Enable the pencil tool if the polygon is empty - if (node->get_polygon().size() == 0) { + if (Vector<Vector2>(node->call("get_polygon")).size() == 0) { _menu_option(MODE_CREATE); } wip.clear(); @@ -491,14 +516,14 @@ void CollisionPolygonEditor::edit(Node *p_collision_polygon) { } } -void CollisionPolygonEditor::_bind_methods() { +void Polygon3DEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_menu_option"), &CollisionPolygonEditor::_menu_option); - ClassDB::bind_method(D_METHOD("_polygon_draw"), &CollisionPolygonEditor::_polygon_draw); - ClassDB::bind_method(D_METHOD("_node_removed"), &CollisionPolygonEditor::_node_removed); + ClassDB::bind_method(D_METHOD("_menu_option"), &Polygon3DEditor::_menu_option); + ClassDB::bind_method(D_METHOD("_polygon_draw"), &Polygon3DEditor::_polygon_draw); + ClassDB::bind_method(D_METHOD("_node_removed"), &Polygon3DEditor::_node_removed); } -CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) { +Polygon3DEditor::Polygon3DEditor(EditorNode *p_editor) { node = NULL; editor = p_editor; @@ -543,24 +568,26 @@ CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) { m.instance(); pointsm->set_mesh(m); pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001))); + + snap_ignore = false; } -CollisionPolygonEditor::~CollisionPolygonEditor() { +Polygon3DEditor::~Polygon3DEditor() { memdelete(imgeom); } -void CollisionPolygonEditorPlugin::edit(Object *p_object) { +void Polygon3DEditorPlugin::edit(Object *p_object) { collision_polygon_editor->edit(Object::cast_to<Node>(p_object)); } -bool CollisionPolygonEditorPlugin::handles(Object *p_object) const { +bool Polygon3DEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("CollisionPolygon"); + return Object::cast_to<Spatial>(p_object) && bool(p_object->call("_is_editable_3d_polygon")); } -void CollisionPolygonEditorPlugin::make_visible(bool p_visible) { +void Polygon3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { collision_polygon_editor->show(); @@ -571,14 +598,14 @@ void CollisionPolygonEditorPlugin::make_visible(bool p_visible) { } } -CollisionPolygonEditorPlugin::CollisionPolygonEditorPlugin(EditorNode *p_node) { +Polygon3DEditorPlugin::Polygon3DEditorPlugin(EditorNode *p_node) { editor = p_node; - collision_polygon_editor = memnew(CollisionPolygonEditor(p_node)); + collision_polygon_editor = memnew(Polygon3DEditor(p_node)); SpatialEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor); collision_polygon_editor->hide(); } -CollisionPolygonEditorPlugin::~CollisionPolygonEditorPlugin() { +Polygon3DEditorPlugin::~Polygon3DEditorPlugin() { } diff --git a/editor/plugins/collision_polygon_editor_plugin.h b/editor/plugins/collision_polygon_editor_plugin.h index f1f215b092..4229808e2f 100644 --- a/editor/plugins/collision_polygon_editor_plugin.h +++ b/editor/plugins/collision_polygon_editor_plugin.h @@ -44,9 +44,9 @@ class CanvasItemEditor; -class CollisionPolygonEditor : public HBoxContainer { +class Polygon3DEditor : public HBoxContainer { - GDCLASS(CollisionPolygonEditor, HBoxContainer); + GDCLASS(Polygon3DEditor, HBoxContainer); UndoRedo *undo_redo; enum Mode { @@ -66,7 +66,7 @@ class CollisionPolygonEditor : public HBoxContainer { EditorNode *editor; Panel *panel; - CollisionPolygon *node; + Spatial *node; ImmediateGeometry *imgeom; MeshInstance *pointsm; Ref<ArrayMesh> m; @@ -78,6 +78,7 @@ class CollisionPolygonEditor : public HBoxContainer { Vector<Vector2> pre_move_edit; Vector<Vector2> wip; bool wip_active; + bool snap_ignore; float prev_depth; @@ -85,6 +86,8 @@ class CollisionPolygonEditor : public HBoxContainer { void _polygon_draw(); void _menu_option(int p_option); + float _get_depth(); + protected: void _notification(int p_what); void _node_removed(Node *p_node); @@ -93,28 +96,28 @@ protected: public: virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); void edit(Node *p_collision_polygon); - CollisionPolygonEditor(EditorNode *p_editor); - ~CollisionPolygonEditor(); + Polygon3DEditor(EditorNode *p_editor); + ~Polygon3DEditor(); }; -class CollisionPolygonEditorPlugin : public EditorPlugin { +class Polygon3DEditorPlugin : public EditorPlugin { - GDCLASS(CollisionPolygonEditorPlugin, EditorPlugin); + GDCLASS(Polygon3DEditorPlugin, EditorPlugin); - CollisionPolygonEditor *collision_polygon_editor; + Polygon3DEditor *collision_polygon_editor; EditorNode *editor; public: virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); } - virtual String get_name() const { return "CollisionPolygon"; } + virtual String get_name() const { return "Polygon3DEditor"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_object); virtual bool handles(Object *p_object) const; virtual void make_visible(bool p_visible); - CollisionPolygonEditorPlugin(EditorNode *p_node); - ~CollisionPolygonEditorPlugin(); + Polygon3DEditorPlugin(EditorNode *p_node); + ~Polygon3DEditorPlugin(); }; #endif // COLLISION_POLYGON_EDITOR_PLUGIN_H diff --git a/editor/plugins/cube_grid_theme_editor_plugin.cpp b/editor/plugins/cube_grid_theme_editor_plugin.cpp index 81f45b9f55..68d5ea5247 100644 --- a/editor/plugins/cube_grid_theme_editor_plugin.cpp +++ b/editor/plugins/cube_grid_theme_editor_plugin.cpp @@ -198,7 +198,7 @@ void MeshLibraryEditor::_menu_cbk(int p_option) { } break; case MENU_OPTION_REMOVE_ITEM: { - String p = editor->get_property_editor()->get_selected_path(); + String p = editor->get_inspector()->get_selected_path(); if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) { to_erase = p.get_slice("/", 3).to_int(); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 7c49408c35..49c54ad67d 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -91,7 +91,7 @@ void CurveEditor::set_curve(Ref<Curve> curve) { } Size2 CurveEditor::get_minimum_size() const { - return Vector2(64, 64); + return Vector2(64, 150) * EDSCALE; } void CurveEditor::_notification(int p_what) { @@ -639,7 +639,7 @@ void CurveEditor::_draw() { Ref<Font> font = get_font("font", "Label"); float font_height = font->get_height(); - const Color text_color = get_color("font_color", "Editor"); + Color text_color = get_color("font_color", "Editor"); { // X axis @@ -720,6 +720,7 @@ void CurveEditor::_draw() { // Help text if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) { + text_color.a *= 0.4; draw_string(font, Vector2(50, font_height), TTR("Hold Shift to edit tangents individually"), text_color); } } @@ -750,87 +751,28 @@ void CurveEditor::_bind_methods() { //--------------- -CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { - _editor_node = p_node; - - _view = memnew(CurveEditor); - _view->set_custom_minimum_size(Size2(100, 128 * EDSCALE)); - _view->hide(); - - _toggle_button = _editor_node->add_bottom_panel_item(get_name(), _view); - _toggle_button->hide(); - - get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); -} - -CurveEditorPlugin::~CurveEditorPlugin() { -} - -void CurveEditorPlugin::edit(Object *p_object) { - - Ref<Curve> curve_ref; - - if (_current_ref.is_valid()) { - CurveTexture *ct = Object::cast_to<CurveTexture>(*_current_ref); - if (ct) - ct->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_texture_changed"); - } - - if (p_object) { - Resource *res = Object::cast_to<Resource>(p_object); - ERR_FAIL_COND(res == NULL); - ERR_FAIL_COND(!handles(p_object)); - - _current_ref = Ref<Resource>(Object::cast_to<Resource>(p_object)); - - if (_current_ref.is_valid()) { - Curve *curve = Object::cast_to<Curve>(*_current_ref); - if (curve) - curve_ref = Ref<Curve>(curve); - else { - CurveTexture *ct = Object::cast_to<CurveTexture>(*_current_ref); - if (ct) { - ct->connect(CoreStringNames::get_singleton()->changed, this, "_curve_texture_changed"); - curve_ref = ct->get_curve(); - } - } - } +bool EditorInspectorPluginCurve::can_handle(Object *p_object) { - } else { - _current_ref = Ref<Resource>(); - } - - _view->set_curve(curve_ref); + return Object::cast_to<Curve>(p_object) != NULL; } -bool CurveEditorPlugin::handles(Object *p_object) const { - // Both handled so that we can keep the curve editor open - return Object::cast_to<Curve>(p_object) || Object::cast_to<CurveTexture>(p_object); -} +void EditorInspectorPluginCurve::parse_begin(Object *p_object) { -void CurveEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - _toggle_button->show(); - _editor_node->make_bottom_panel_item_visible(_view); - } else { - _toggle_button->hide(); - if (_view->is_visible_in_tree()) - _editor_node->hide_bottom_panel(); - } -} + Curve *curve = Object::cast_to<Curve>(p_object); + ERR_FAIL_COND(!curve); + Ref<Curve> c(curve); -void CurveEditorPlugin::_curve_texture_changed() { - // If the curve is shown indirectly as a CurveTexture is edited, - // we need to monitor when the curve property gets assigned - CurveTexture *ct = Object::cast_to<CurveTexture>(*_current_ref); - if (ct) { - _view->set_curve(ct->get_curve()); - } + CurveEditor *editor = memnew(CurveEditor); + editor->set_curve(curve); + add_custom_control(editor); } -void CurveEditorPlugin::_bind_methods() { +CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { + Ref<EditorInspectorPluginCurve> curve_plugin; + curve_plugin.instance(); + EditorInspector::add_inspector_plugin(curve_plugin); - ClassDB::bind_method(D_METHOD("_curve_texture_changed"), &CurveEditorPlugin::_curve_texture_changed); + get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); } //----------------------------------- @@ -852,13 +794,13 @@ Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from) { img_ref.instance(); Image &im = **img_ref; - im.create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8); + im.create(thumbnail_size, thumbnail_size / 2, 0, Image::FORMAT_RGBA8); im.lock(); Color bg_color(0.1, 0.1, 0.1, 1.0); for (int i = 0; i < thumbnail_size; i++) { - for (int j = 0; j < thumbnail_size; j++) { + for (int j = 0; j < thumbnail_size / 2; j++) { im.set_pixel(i, j, bg_color); } } diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index 97f1ba2fa1..255f359ed2 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -119,28 +119,19 @@ private: float _tangents_length; }; +class EditorInspectorPluginCurve : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginCurve, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); +}; + class CurveEditorPlugin : public EditorPlugin { GDCLASS(CurveEditorPlugin, EditorPlugin) public: CurveEditorPlugin(EditorNode *p_node); - ~CurveEditorPlugin(); String get_name() const { return "Curve"; } - bool has_main_screen() const { return false; } - void edit(Object *p_object); - bool handles(Object *p_object) const; - void make_visible(bool p_visible); - -private: - static void _bind_methods(); - - void _curve_texture_changed(); - -private: - CurveEditor *_view; - Ref<Resource> _current_ref; - EditorNode *_editor_node; - ToolButton *_toggle_button; }; class CurvePreviewGenerator : public EditorResourcePreviewGenerator { diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 8542296bde..d76c515c1f 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -467,15 +467,6 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) { Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color"); Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color"); - if (EditorSettings::get_singleton()->get("text_editor/theme/color_theme") == "Adaptive") { - Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme(); - - bg_color = tm->get_color("text_editor/highlighting/background_color", "Editor"); - keyword_color = tm->get_color("text_editor/highlighting/keyword_color", "Editor"); - text_color = tm->get_color("text_editor/highlighting/text_color", "Editor"); - symbol_color = tm->get_color("text_editor/highlighting/symbol_color", "Editor"); - } - img->lock(); if (bg_color.a == 0) diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index e89cb68935..442bd52ea7 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -33,77 +33,70 @@ #include "canvas_item_editor_plugin.h" #include "spatial_editor_plugin.h" -GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { - - editor = p_node; - ramp_editor = memnew(GradientEdit); - - add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, ramp_editor); - - ramp_editor->set_custom_minimum_size(Size2(100, 48)); - ramp_editor->hide(); - ramp_editor->connect("ramp_changed", this, "ramp_changed"); +Size2 GradientEditor::get_minimum_size() const { + return Size2(0, 60) * EDSCALE; } +void GradientEditor::_gradient_changed() { -void GradientEditorPlugin::edit(Object *p_object) { - - Gradient *gradient = Object::cast_to<Gradient>(p_object); - if (!gradient) + if (editing) return; - gradient_ref = Ref<Gradient>(gradient); - ramp_editor->set_points(gradient_ref->get_points()); -} -bool GradientEditorPlugin::handles(Object *p_object) const { + editing = true; + Vector<Gradient::Point> points = gradient->get_points(); + set_points(points); + editing = false; +} - return p_object->is_class("Gradient"); +void GradientEditor::_ramp_changed() { + + editing = true; + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action("Gradient Edited"); + undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); + undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); + undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets()); + undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors()); + undo_redo->commit_action(); + editing = false; } -void GradientEditorPlugin::make_visible(bool p_visible) { +void GradientEditor::_bind_methods() { - if (p_visible) { - ramp_editor->show(); - } else { - ramp_editor->hide(); - } + ClassDB::bind_method("_gradient_changed", &GradientEditor::_gradient_changed); + ClassDB::bind_method("_ramp_changed", &GradientEditor::_ramp_changed); } -void GradientEditorPlugin::_ramp_changed() { - - if (gradient_ref.is_valid()) { +void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) { + gradient = p_gradient; + connect("ramp_changed", this, "_ramp_changed"); + gradient->connect("changed", this, "_gradient_changed"); + set_points(gradient->get_points()); +} - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); +GradientEditor::GradientEditor() { + editing = false; +} - //Not sure if I should convert this data to PoolVector - Vector<float> new_offsets = ramp_editor->get_offsets(); - Vector<Color> new_colors = ramp_editor->get_colors(); - Vector<float> old_offsets = gradient_ref->get_offsets(); - Vector<Color> old_colors = gradient_ref->get_colors(); +/////////////////////// - if (old_offsets.size() != new_offsets.size()) - ur->create_action(TTR("Add/Remove Color Ramp Point")); - else - ur->create_action(TTR("Modify Color Ramp"), UndoRedo::MERGE_ENDS); - ur->add_do_method(this, "undo_redo_gradient", new_offsets, new_colors); - ur->add_undo_method(this, "undo_redo_gradient", old_offsets, old_colors); - ur->commit_action(); +bool EditorInspectorPluginGradient::can_handle(Object *p_object) { - //color_ramp_ref->set_points(ramp_editor->get_points()); - } + return Object::cast_to<Gradient>(p_object) != NULL; } -void GradientEditorPlugin::_undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors) { +void EditorInspectorPluginGradient::parse_begin(Object *p_object) { - gradient_ref->set_offsets(offsets); - gradient_ref->set_colors(colors); - ramp_editor->set_points(gradient_ref->get_points()); - ramp_editor->update(); -} + Gradient *gradient = Object::cast_to<Gradient>(p_object); + Ref<Gradient> g(gradient); -GradientEditorPlugin::~GradientEditorPlugin() { + GradientEditor *editor = memnew(GradientEditor); + editor->set_gradient(g); + add_custom_control(editor); } -void GradientEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("ramp_changed"), &GradientEditorPlugin::_ramp_changed); - ClassDB::bind_method(D_METHOD("undo_redo_gradient", "offsets", "colors"), &GradientEditorPlugin::_undo_redo_gradient); +GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { + + Ref<EditorInspectorPluginGradient> plugin; + plugin.instance(); + add_inspector_plugin(plugin); } diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index 52f4c59575..0c878b168f 100644 --- a/editor/plugins/gradient_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -35,28 +35,39 @@ #include "editor/editor_plugin.h" #include "scene/gui/gradient_edit.h" -class GradientEditorPlugin : public EditorPlugin { +class GradientEditor : public GradientEdit { + GDCLASS(GradientEditor, GradientEdit) - GDCLASS(GradientEditorPlugin, EditorPlugin); + bool editing; + Ref<Gradient> gradient; - Ref<Gradient> gradient_ref; - GradientEdit *ramp_editor; - EditorNode *editor; + void _gradient_changed(); + void _ramp_changed(); protected: static void _bind_methods(); - void _ramp_changed(); - void _undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors); + +public: + virtual Size2 get_minimum_size() const; + void set_gradient(const Ref<Gradient> &p_gradient); + GradientEditor(); +}; + +class EditorInspectorPluginGradient : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginGradient, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); +}; + +class GradientEditorPlugin : public EditorPlugin { + + GDCLASS(GradientEditorPlugin, EditorPlugin); public: virtual String get_name() const { return "ColorRamp"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); GradientEditorPlugin(EditorNode *p_node); - ~GradientEditorPlugin(); }; #endif /* TOOLS_EDITOR_PLUGINS_COLOR_RAMP_EDITOR_PLUGIN_H_ */ diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp index 8b44f672b0..f75fb0d109 100644 --- a/editor/plugins/item_list_editor_plugin.cpp +++ b/editor/plugins/item_list_editor_plugin.cpp @@ -388,7 +388,7 @@ ItemListEditor::ItemListEditor() { vbc->add_child(property_editor); property_editor->set_v_size_flags(SIZE_EXPAND_FILL); - tree = property_editor->get_scene_tree(); + tree = property_editor->get_property_tree(); } ItemListEditor::~ItemListEditor() { diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp index 47d5a73078..ba6452c1d1 100644 --- a/editor/plugins/line_2d_editor_plugin.cpp +++ b/editor/plugins/line_2d_editor_plugin.cpp @@ -64,6 +64,7 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con Line2DEditor::Line2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; } Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 7ea2b27744..74b6f14c2e 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -400,7 +400,7 @@ MeshInstanceEditor::MeshInstanceEditor() { options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH); + options->get_popup()->add_item(TTR("Create Outline Mesh..."), MENU_OPTION_CREATE_OUTLINE_MESH); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1); options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); diff --git a/editor/plugins/navigation_mesh_generator.cpp b/editor/plugins/navigation_mesh_generator.cpp index 5d4e5520f4..0537c5c31f 100644 --- a/editor/plugins/navigation_mesh_generator.cpp +++ b/editor/plugins/navigation_mesh_generator.cpp @@ -280,26 +280,20 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) _build_recast_navigation_mesh(p_nav_mesh, &ep, hf, chf, cset, poly_mesh, detail_mesh, vertices, indices); - if (hf) { - rcFreeHeightField(hf); - hf = 0; - } - if (chf) { - rcFreeCompactHeightfield(chf); - chf = 0; - } - if (cset) { - rcFreeContourSet(cset); - cset = 0; - } - if (poly_mesh) { - rcFreePolyMesh(poly_mesh); - poly_mesh = 0; - } - if (detail_mesh) { - rcFreePolyMeshDetail(detail_mesh); - detail_mesh = 0; - } + rcFreeHeightField(hf); + hf = 0; + + rcFreeCompactHeightfield(chf); + chf = 0; + + rcFreeContourSet(cset); + cset = 0; + + rcFreePolyMesh(poly_mesh); + poly_mesh = 0; + + rcFreePolyMeshDetail(detail_mesh); + detail_mesh = 0; } ep.step(TTR("Done!"), 11); } diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index d1edf1ae10..0332e15b0e 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -123,6 +123,7 @@ void NavigationPolygonEditor::_create_resource() { NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; } NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index abee9a9893..6d11079759 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -94,7 +94,7 @@ void Particles2DEditorPlugin::_generate_visibility_rect() { while (running < time) { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); - ep.step("Generating..", int(running), true); + ep.step("Generating...", int(running), true); OS::get_singleton()->delay_usec(1000); Rect2 capture = particles->capture_rect(); @@ -229,7 +229,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { valid_normals.resize(vpc); } - ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image..")); + ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); ERR_FAIL_COND(valid_positions.size() == 0); PoolVector<uint8_t> texdata; diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index d129b6c5c3..7728995a99 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -129,7 +129,7 @@ void ParticlesEditor::_generate_aabb() { while (running < time) { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); - ep.step("Generating..", int(running), true); + ep.step("Generating...", int(running), true); OS::get_singleton()->delay_usec(1000); AABB capture = node->capture_aabb(); diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 056219a575..6dde639c54 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -167,18 +167,12 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p Vector3 ofs; - if (p_cancel) { - - return; - } - if (t == 0) { - if (p_cancel) { - c->set_point_in(p_idx, p_restore); return; } + ur->create_action(TTR("Set Curve In Position")); ur->add_do_method(c.ptr(), "set_point_in", idx, c->get_point_in(idx)); ur->add_undo_method(c.ptr(), "set_point_in", idx, p_restore); @@ -186,10 +180,11 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p } else { if (p_cancel) { - c->set_point_out(idx, p_restore); + return; } + ur->create_action(TTR("Set Curve Out Position")); ur->add_do_method(c.ptr(), "set_point_out", idx, c->get_point_out(idx)); ur->add_undo_method(c.ptr(), "set_point_out", idx, p_restore); diff --git a/editor/plugins/physical_bone_plugin.cpp b/editor/plugins/physical_bone_plugin.cpp new file mode 100644 index 0000000000..42f1adcadf --- /dev/null +++ b/editor/plugins/physical_bone_plugin.cpp @@ -0,0 +1,123 @@ +/*************************************************************************/ +/* physical_bone_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "physical_bone_plugin.h" +#include "editor/plugins/spatial_editor_plugin.h" +#include "scene/3d/physics_body.h" + +void PhysicalBoneEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_on_toggle_button_transform_joint", "is_pressed"), &PhysicalBoneEditor::_on_toggle_button_transform_joint); +} + +void PhysicalBoneEditor::_on_toggle_button_transform_joint(bool p_is_pressed) { + + _set_move_joint(); +} + +void PhysicalBoneEditor::_set_move_joint() { + if (selected) { + selected->_set_gizmo_move_joint(button_transform_joint->is_pressed()); + } +} + +PhysicalBoneEditor::PhysicalBoneEditor(EditorNode *p_editor) : + editor(p_editor), + selected(NULL) { + + spatial_editor_hb = memnew(HBoxContainer); + spatial_editor_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + spatial_editor_hb->set_alignment(BoxContainer::ALIGN_BEGIN); + SpatialEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb); + + spatial_editor_hb->add_child(memnew(VSeparator)); + + button_transform_joint = memnew(ToolButton); + spatial_editor_hb->add_child(button_transform_joint); + + button_transform_joint->set_text(TTR("Move joint")); + button_transform_joint->set_icon(SpatialEditor::get_singleton()->get_icon("PhysicalBone", "EditorIcons")); + button_transform_joint->set_toggle_mode(true); + button_transform_joint->connect("toggled", this, "_on_toggle_button_transform_joint"); + + hide(); +} + +PhysicalBoneEditor::~PhysicalBoneEditor() { + // TODO the spatial_editor_hb should be removed from SpatialEditor, but in this moment it's not possible + for (int i = spatial_editor_hb->get_child_count() - 1; 0 <= i; --i) { + Node *n = spatial_editor_hb->get_child(i); + spatial_editor_hb->remove_child(n); + memdelete(n); + } + memdelete(spatial_editor_hb); +} + +void PhysicalBoneEditor::set_selected(PhysicalBone *p_pb) { + + button_transform_joint->set_pressed(false); + + _set_move_joint(); + selected = p_pb; + _set_move_joint(); +} + +void PhysicalBoneEditor::hide() { + spatial_editor_hb->hide(); +} + +void PhysicalBoneEditor::show() { + spatial_editor_hb->show(); +} + +PhysicalBonePlugin::PhysicalBonePlugin(EditorNode *p_editor) : + editor(p_editor), + selected(NULL) { + + physical_bone_editor = memnew(PhysicalBoneEditor(editor)); +} + +void PhysicalBonePlugin::make_visible(bool p_visible) { + if (p_visible) { + + physical_bone_editor->show(); + } else { + + physical_bone_editor->hide(); + physical_bone_editor->set_selected(NULL); + selected = NULL; + } +} + +void PhysicalBonePlugin::edit(Object *p_node) { + selected = static_cast<PhysicalBone *>(p_node); // Trust it + ERR_FAIL_COND(!selected); + + physical_bone_editor->set_selected(selected); +} diff --git a/editor/plugins/physical_bone_plugin.h b/editor/plugins/physical_bone_plugin.h new file mode 100644 index 0000000000..9e7a50307a --- /dev/null +++ b/editor/plugins/physical_bone_plugin.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* physical_bone_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PHYSICAL_BONE_PLUGIN_H +#define PHYSICAL_BONE_PLUGIN_H + +#include "editor/editor_node.h" + +class PhysicalBoneEditor : public Object { + GDCLASS(PhysicalBoneEditor, Object); + + EditorNode *editor; + HBoxContainer *spatial_editor_hb; + ToolButton *button_transform_joint; + + PhysicalBone *selected; + +protected: + static void _bind_methods(); + +private: + void _on_toggle_button_transform_joint(bool p_is_pressed); + void _set_move_joint(); + +public: + PhysicalBoneEditor(EditorNode *p_editor); + ~PhysicalBoneEditor(); + + void set_selected(PhysicalBone *p_pb); + + void hide(); + void show(); +}; + +class PhysicalBonePlugin : public EditorPlugin { + GDCLASS(PhysicalBonePlugin, EditorPlugin); + + EditorNode *editor; + PhysicalBone *selected; + PhysicalBoneEditor *physical_bone_editor; + +public: + virtual String get_name() const { return "PhysicalBone"; } + virtual bool handles(Object *p_object) const { return p_object->is_class("PhysicalBone"); } + virtual void make_visible(bool p_visible); + virtual void edit(Object *p_node); + + PhysicalBonePlugin(EditorNode *p_editor); +}; + +#endif diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 3a169bd780..ed41e1931e 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -35,7 +35,7 @@ #include "os/file_access.h" #include "os/input.h" #include "os/keyboard.h" - +#include "scene/2d/skeleton_2d.h" Node2D *Polygon2DEditor::_get_node() const { return node; @@ -66,6 +66,8 @@ void Polygon2DEditor::_notification(int p_what) { uv_button[UV_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); uv_button[UV_MODE_ADD_SPLIT]->set_icon(get_icon("AddSplit", "EditorIcons")); uv_button[UV_MODE_REMOVE_SPLIT]->set_icon(get_icon("DeleteSplit", "EditorIcons")); + uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_icon("PaintVertex", "EditorIcons")); + uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_icon("UnpaintVertex", "EditorIcons")); b_snap_grid->set_icon(get_icon("Grid", "EditorIcons")); b_snap_enable->set_icon(get_icon("SnapGrid", "EditorIcons")); @@ -78,31 +80,167 @@ void Polygon2DEditor::_notification(int p_what) { } } +void Polygon2DEditor::_sync_bones() { + + print_line("syncinc"); + if (!node->has_node(node->get_skeleton())) { + error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node")); + error->popup_centered_minsize(); + return; + } + + Node *sn = node->get_node(node->get_skeleton()); + Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(sn); + + if (!skeleton) { + error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node")); + error->popup_centered_minsize(); + return; + } + + Array prev_bones = node->call("_get_bones"); + node->clear_bones(); + + print_line("bones in skeleton: " + itos(skeleton->get_bone_count())); + + for (int i = 0; i < skeleton->get_bone_count(); i++) { + NodePath path = skeleton->get_path_to(skeleton->get_bone(i)); + PoolVector<float> weights; + int wc = node->get_polygon().size(); + + for (int j = 0; j < prev_bones.size(); j += 2) { + NodePath pvp = prev_bones[j]; + PoolVector<float> pv = prev_bones[j + 1]; + if (pvp == path && pv.size() == wc) { + weights = pv; + } + } + + if (weights.size() == 0) { //create them + weights.resize(node->get_polygon().size()); + PoolVector<float>::Write w = weights.write(); + for (int j = 0; j < wc; j++) { + w[j] = 0.0; + } + } + + node->add_bone(path, weights); + } + Array new_bones = node->call("_get_bones"); + + undo_redo->create_action(TTR("Sync bones")); + undo_redo->add_do_method(node, "_set_bones", new_bones); + undo_redo->add_undo_method(node, "_set_bones", prev_bones); + undo_redo->add_do_method(uv_edit_draw, "update"); + undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(this, "_update_bone_list"); + undo_redo->add_undo_method(this, "_update_bone_list"); + undo_redo->commit_action(); +} + +void Polygon2DEditor::_update_bone_list() { + + NodePath selected; + while (bone_scroll_vb->get_child_count()) { + CheckBox *cb = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(0)); + if (cb && cb->is_pressed()) { + selected = cb->get_meta("bone_path"); + } + memdelete(bone_scroll_vb->get_child(0)); + } + + Ref<ButtonGroup> bg; + bg.instance(); + for (int i = 0; i < node->get_bone_count(); i++) { + CheckBox *cb = memnew(CheckBox); + NodePath np = node->get_bone_path(i); + String name; + if (np.get_name_count()) { + name = np.get_name(np.get_name_count() - 1); + } + if (name == String()) { + name = "Bone " + itos(i); + } + cb->set_text(name); + cb->set_button_group(bg); + cb->set_meta("bone_path", np); + bone_scroll_vb->add_child(cb); + + if (np == selected) + cb->set_pressed(true); + + cb->connect("pressed", this, "_bone_paint_selected", varray(i)); + } + + uv_edit_draw->update(); +} + +void Polygon2DEditor::_bone_paint_selected(int p_index) { + uv_edit_draw->update(); +} + void Polygon2DEditor::_uv_edit_mode_select(int p_mode) { - if (p_mode == 0) { + if (p_mode == 0) { //uv uv_button[UV_MODE_CREATE]->hide(); for (int i = UV_MODE_MOVE; i <= UV_MODE_SCALE; i++) { uv_button[i]->show(); } uv_button[UV_MODE_ADD_SPLIT]->hide(); uv_button[UV_MODE_REMOVE_SPLIT]->hide(); + uv_button[UV_MODE_PAINT_WEIGHT]->hide(); + uv_button[UV_MODE_CLEAR_WEIGHT]->hide(); _uv_mode(UV_MODE_EDIT_POINT); - } else if (p_mode == 1) { + bone_scroll_main_vb->hide(); + bone_paint_strength->hide(); + bone_paint_radius->hide(); + bone_paint_radius_label->hide(); + + } else if (p_mode == 1) { //poly for (int i = 0; i <= UV_MODE_SCALE; i++) { uv_button[i]->show(); } uv_button[UV_MODE_ADD_SPLIT]->hide(); uv_button[UV_MODE_REMOVE_SPLIT]->hide(); + uv_button[UV_MODE_PAINT_WEIGHT]->hide(); + uv_button[UV_MODE_CLEAR_WEIGHT]->hide(); _uv_mode(UV_MODE_EDIT_POINT); - } else { + + bone_scroll_main_vb->hide(); + bone_paint_strength->hide(); + bone_paint_radius->hide(); + bone_paint_radius_label->hide(); + + } else if (p_mode == 2) { //splits for (int i = 0; i <= UV_MODE_SCALE; i++) { uv_button[i]->hide(); } uv_button[UV_MODE_ADD_SPLIT]->show(); uv_button[UV_MODE_REMOVE_SPLIT]->show(); + uv_button[UV_MODE_PAINT_WEIGHT]->hide(); + uv_button[UV_MODE_CLEAR_WEIGHT]->hide(); _uv_mode(UV_MODE_ADD_SPLIT); + + bone_scroll_main_vb->hide(); + bone_paint_strength->hide(); + bone_paint_radius->hide(); + bone_paint_radius_label->hide(); + + } else if (p_mode == 3) { //bones´ + for (int i = 0; i <= UV_MODE_REMOVE_SPLIT; i++) { + uv_button[i]->hide(); + } + uv_button[UV_MODE_PAINT_WEIGHT]->show(); + uv_button[UV_MODE_CLEAR_WEIGHT]->show(); + _uv_mode(UV_MODE_PAINT_WEIGHT); + + bone_scroll_main_vb->show(); + bone_paint_strength->show(); + bone_paint_radius->show(); + bone_paint_radius_label->show(); + _update_bone_list(); + bone_paint_pos = Vector2(-100000, -100000); //send brush away when switching } uv_edit_draw->update(); @@ -176,6 +314,9 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->commit_action(); } break; + case UVEDIT_GRID_SETTINGS: { + grid_settings->popup_centered_minsize(); + } break; default: { AbstractPolygon2DEditor::_menu_option(p_option); } break; @@ -239,41 +380,44 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_drag_from = Vector2(mb->get_position().x, mb->get_position().y); uv_drag = true; - uv_prev = node->get_uv(); + points_prev = node->get_uv(); if (uv_edit_mode[0]->is_pressed()) { //edit uv - uv_prev = node->get_uv(); + points_prev = node->get_uv(); } else { //edit polygon - uv_prev = node->get_polygon(); + points_prev = node->get_polygon(); } uv_move_current = uv_mode; if (uv_move_current == UV_MODE_CREATE) { if (!uv_create) { - uv_prev.resize(0); + points_prev.resize(0); Vector2 tuv = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); - uv_prev.push_back(tuv); + points_prev.push_back(tuv); uv_create_to = tuv; - uv_drag_index = 0; + point_drag_index = 0; uv_drag_from = tuv; uv_drag = true; uv_create = true; uv_create_uv_prev = node->get_uv(); uv_create_poly_prev = node->get_polygon(); + uv_create_bones_prev = node->call("_get_bones"); splits_prev = node->get_splits(); - node->set_polygon(uv_prev); - node->set_uv(uv_prev); + node->set_polygon(points_prev); + node->set_uv(points_prev); } else { Vector2 tuv = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); - if (uv_prev.size() > 3 && tuv.distance_to(uv_prev[0]) < 8) { + if (points_prev.size() > 3 && tuv.distance_to(points_prev[0]) < 8) { undo_redo->create_action(TTR("Create Polygon & UV")); undo_redo->add_do_method(node, "set_uv", node->get_uv()); - undo_redo->add_undo_method(node, "set_uv", uv_prev); + undo_redo->add_undo_method(node, "set_uv", points_prev); undo_redo->add_do_method(node, "set_polygon", node->get_polygon()); - undo_redo->add_undo_method(node, "set_polygon", uv_prev); + undo_redo->add_undo_method(node, "set_polygon", points_prev); + undo_redo->add_do_method(node, "clear_bones"); + undo_redo->add_undo_method(node, "_set_bones", node->call("_get_bones")); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -281,12 +425,12 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_create = false; _uv_mode(UV_MODE_EDIT_POINT); } else { - uv_prev.push_back(tuv); - uv_drag_index = uv_prev.size() - 1; + points_prev.push_back(tuv); + point_drag_index = points_prev.size() - 1; uv_drag_from = tuv; } - node->set_polygon(uv_prev); - node->set_uv(uv_prev); + node->set_polygon(points_prev); + node->set_uv(points_prev); } } @@ -302,34 +446,34 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (uv_move_current == UV_MODE_EDIT_POINT) { - uv_drag_index = -1; - for (int i = 0; i < uv_prev.size(); i++) { + point_drag_index = -1; + for (int i = 0; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(uv_prev[i]); + Vector2 tuv = mtx.xform(points_prev[i]); if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) { uv_drag_from = tuv; - uv_drag_index = i; + point_drag_index = i; } } - if (uv_drag_index == -1) { + if (point_drag_index == -1) { uv_drag = false; } } if (uv_move_current == UV_MODE_ADD_SPLIT) { - int drag_index = -1; - drag_index = -1; - for (int i = 0; i < uv_prev.size(); i++) { + int split_to_index = -1; + split_to_index = -1; + for (int i = 0; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(uv_prev[i]); + Vector2 tuv = mtx.xform(points_prev[i]); if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) { - drag_index = i; + split_to_index = i; } } - if (drag_index == -1) { + if (split_to_index == -1) { split_create = false; return; } @@ -337,41 +481,65 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (split_create) { split_create = false; - if (drag_index < uv_drag_index) { - SWAP(drag_index, uv_drag_index); + if (split_to_index < point_drag_index) { + SWAP(split_to_index, point_drag_index); } bool valid = true; - if (drag_index == uv_drag_index) { + String split_error; + if (split_to_index == point_drag_index) { + split_error = TTR("Split point with itself."); valid = false; } - if (drag_index + 1 == uv_drag_index) { + if (split_to_index + 1 == point_drag_index) { //not a split,goes along the edge + split_error = TTR("Split can't form an existing edge."); valid = false; } - if (drag_index == uv_prev.size() - 1 && uv_drag_index == 0) { + if (split_to_index == points_prev.size() - 1 && point_drag_index == 0) { //not a split,goes along the edge + split_error = TTR("Split can't form an existing edge."); valid = false; } + for (int i = 0; i < splits_prev.size(); i += 2) { - if (splits_prev[i] == uv_drag_index && splits_prev[i + 1] == drag_index) { + + if (splits_prev[i] == point_drag_index && splits_prev[i + 1] == split_to_index) { //already exists + split_error = TTR("Split already exists."); valid = false; + break; } - if (splits_prev[i] > uv_drag_index && splits_prev[i + 1] > drag_index) { - //crossing - valid = false; + + int a_state; //-1, outside split, 0 split point, +1, inside split + if (point_drag_index == splits_prev[i] || point_drag_index == splits_prev[i + 1]) { + a_state = 0; + } else if (point_drag_index < splits_prev[i] || point_drag_index > splits_prev[i + 1]) { + a_state = -1; + } else { + a_state = 1; } - if (splits_prev[i] < uv_drag_index && splits_prev[i + 1] < drag_index) { - //crossing opposite direction + int b_state; //-1, outside split, 0 split point, +1, inside split + if (split_to_index == splits_prev[i] || split_to_index == splits_prev[i + 1]) { + b_state = 0; + } else if (split_to_index < splits_prev[i] || split_to_index > splits_prev[i + 1]) { + b_state = -1; + } else { + b_state = 1; + } + + if (b_state * a_state < 0) { + //crossing + split_error = "Split crosses another split."; valid = false; + break; } } if (valid) { - splits_prev.push_back(uv_drag_index); - splits_prev.push_back(drag_index); + splits_prev.push_back(point_drag_index); + splits_prev.push_back(split_to_index); undo_redo->create_action(TTR("Add Split")); @@ -381,13 +549,14 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); } else { - error->set_text(TTR("Invalid Split")); + error->set_text(TTR("Invalid Split: ") + split_error); error->popup_centered_minsize(); } } else { - uv_drag_index = drag_index; + point_drag_index = split_to_index; split_create = true; + splits_prev = node->get_splits(); uv_create_to = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); } } @@ -395,11 +564,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (uv_move_current == UV_MODE_REMOVE_SPLIT) { for (int i = 0; i < splits_prev.size(); i += 2) { - if (splits_prev[i] < 0 || splits_prev[i] >= uv_prev.size()) + if (splits_prev[i] < 0 || splits_prev[i] >= points_prev.size()) continue; - if (splits_prev[i + 1] < 0 || splits_prev[i] >= uv_prev.size()) + if (splits_prev[i + 1] < 0 || splits_prev[i] >= points_prev.size()) continue; - Vector2 e[2] = { mtx.xform(uv_prev[splits_prev[i]]), mtx.xform(uv_prev[splits_prev[i + 1]]) }; + Vector2 e[2] = { mtx.xform(points_prev[splits_prev[i]]), mtx.xform(points_prev[splits_prev[i + 1]]) }; Vector2 mp = Vector2(mb->get_position().x, mb->get_position().y); Vector2 cp = Geometry::get_closest_point_to_segment_2d(mp, e); if (cp.distance_to(mp) < 8) { @@ -419,22 +588,50 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } + if (uv_move_current == UV_MODE_PAINT_WEIGHT || uv_move_current == UV_MODE_CLEAR_WEIGHT) { + + int bone_selected = -1; + for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) { + CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i)); + if (c && c->is_pressed()) { + bone_selected = i; + break; + } + } + + if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == points_prev.size()) { + + prev_weights = node->get_bone_weights(bone_selected); + bone_painting = true; + bone_painting_bone = bone_selected; + } + } + } else if (uv_drag && !uv_create) { undo_redo->create_action(TTR("Transform UV Map")); if (uv_edit_mode[0]->is_pressed()) { //edit uv undo_redo->add_do_method(node, "set_uv", node->get_uv()); - undo_redo->add_undo_method(node, "set_uv", uv_prev); + undo_redo->add_undo_method(node, "set_uv", points_prev); } else if (uv_edit_mode[1]->is_pressed()) { //edit polygon undo_redo->add_do_method(node, "set_polygon", node->get_polygon()); - undo_redo->add_undo_method(node, "set_polygon", uv_prev); + undo_redo->add_undo_method(node, "set_polygon", points_prev); } undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); uv_drag = false; + } else if (bone_painting) { + + undo_redo->create_action(TTR("Paint bone weights")); + undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone)); + undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights); + undo_redo->add_do_method(uv_edit_draw, "update"); + undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->commit_action(); + bone_painting = false; } } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { @@ -445,20 +642,23 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_create = false; node->set_uv(uv_create_uv_prev); node->set_polygon(uv_create_poly_prev); + node->call("_set_bones", uv_create_bones_prev); node->set_splits(splits_prev); uv_edit_draw->update(); } else if (uv_drag) { uv_drag = false; if (uv_edit_mode[0]->is_pressed()) { //edit uv - node->set_uv(uv_prev); + node->set_uv(points_prev); } else if (uv_edit_mode[1]->is_pressed()) { //edit polygon - node->set_polygon(uv_prev); + node->set_polygon(points_prev); } uv_edit_draw->update(); } else if (split_create) { split_create = false; uv_edit_draw->update(); + } else if (bone_painting) { + node->set_bone_weights(bone_painting_bone, prev_weights); } } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { @@ -494,8 +694,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } break; case UV_MODE_EDIT_POINT: { - PoolVector<Vector2> uv_new = uv_prev; - uv_new.set(uv_drag_index, uv_new[uv_drag_index] + drag); + PoolVector<Vector2> uv_new = points_prev; + uv_new.set(point_drag_index, uv_new[point_drag_index] + drag); if (uv_edit_mode[0]->is_pressed()) { //edit uv node->set_uv(uv_new); @@ -505,7 +705,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } break; case UV_MODE_MOVE: { - PoolVector<Vector2> uv_new = uv_prev; + PoolVector<Vector2> uv_new = points_prev; for (int i = 0; i < uv_new.size(); i++) uv_new.set(i, uv_new[i] + drag); @@ -519,16 +719,16 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { case UV_MODE_ROTATE: { Vector2 center; - PoolVector<Vector2> uv_new = uv_prev; + PoolVector<Vector2> uv_new = points_prev; for (int i = 0; i < uv_new.size(); i++) - center += uv_prev[i]; + center += points_prev[i]; center /= uv_new.size(); float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized()); for (int i = 0; i < uv_new.size(); i++) { - Vector2 rel = uv_prev[i] - center; + Vector2 rel = points_prev[i] - center; rel = rel.rotated(angle); uv_new.set(i, center + rel); } @@ -543,10 +743,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { case UV_MODE_SCALE: { Vector2 center; - PoolVector<Vector2> uv_new = uv_prev; + PoolVector<Vector2> uv_new = points_prev; for (int i = 0; i < uv_new.size(); i++) - center += uv_prev[i]; + center += points_prev[i]; center /= uv_new.size(); float from_dist = uv_drag_from.distance_to(mtx.xform(center)); @@ -557,7 +757,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { float scale = to_dist / from_dist; for (int i = 0; i < uv_new.size(); i++) { - Vector2 rel = uv_prev[i] - center; + Vector2 rel = points_prev[i] - center; rel = rel * scale; uv_new.set(i, center + rel); } @@ -569,10 +769,40 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } break; } + + if (bone_painting) { + bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); + PoolVector<float> painted_weights = node->get_bone_weights(bone_painting_bone); + + { + int pc = painted_weights.size(); + float amount = bone_paint_strength->get_value(); + float radius = bone_paint_radius->get_value() * EDSCALE; + + if (uv_mode == UV_MODE_CLEAR_WEIGHT) { + amount = -amount; + } + + PoolVector<float>::Write w = painted_weights.write(); + PoolVector<float>::Read r = prev_weights.read(); + PoolVector<Vector2>::Read rv = points_prev.read(); + + for (int i = 0; i < pc; i++) { + if (mtx.xform(rv[i]).distance_to(bone_paint_pos) < radius) { + w[i] = CLAMP(r[i] + amount, 0, 1); + } + } + } + + node->set_bone_weights(bone_painting_bone, painted_weights); + } uv_edit_draw->update(); } else if (split_create) { uv_create_to = mtx.affine_inverse().xform(Vector2(mm->get_position().x, mm->get_position().y)); uv_edit_draw->update(); + } else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) { + bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); + uv_edit_draw->update(); } } @@ -607,6 +837,8 @@ void Polygon2DEditor::_uv_draw() { if (base_tex.is_null()) return; + String warning; + Transform2D mtx; mtx.elements[2] = -uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); @@ -649,6 +881,24 @@ void Polygon2DEditor::_uv_draw() { uvs = node->get_polygon(); } + PoolVector<float>::Read weight_r; + + if (uv_edit_mode[3]->is_pressed()) { + int bone_selected = -1; + for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) { + CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i)); + if (c && c->is_pressed()) { + bone_selected = i; + break; + } + } + + if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == uvs.size()) { + + weight_r = node->get_bone_weights(bone_selected).read(); + } + } + Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); Rect2 rect(Point2(), mtx.basis_xform(base_tex->get_size())); @@ -662,12 +912,19 @@ void Polygon2DEditor::_uv_draw() { next_point = uv_create_to; } uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(next_point), Color(0.9, 0.5, 0.5), 2); - uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5); + if (weight_r.ptr()) { + + Vector2 draw_pos = mtx.xform(uvs[i]); + float weight = weight_r[i]; + uv_edit_draw->draw_rect(Rect2(draw_pos - Vector2(2, 2) * EDSCALE, Vector2(5, 5) * EDSCALE), Color(weight, weight, weight, 1.0)); + } else { + uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5); + } rect.expand_to(mtx.basis_xform(uvs[i])); } if (split_create) { - Vector2 from = uvs[uv_drag_index]; + Vector2 from = uvs[point_drag_index]; Vector2 to = uv_create_to; uv_edit_draw->draw_line(mtx.xform(from), mtx.xform(to), Color(0.9, 0.5, 0.5), 2); } @@ -682,6 +939,55 @@ void Polygon2DEditor::_uv_draw() { uv_edit_draw->draw_line(mtx.xform(uvs[idx_from]), mtx.xform(uvs[idx_to]), Color(0.9, 0.5, 0.5), 2); } + if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) { + + NodePath bone_path; + for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) { + CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i)); + if (c && c->is_pressed()) { + bone_path = node->get_bone_path(i); + break; + } + } + + //draw skeleton + NodePath skeleton_path = node->get_skeleton(); + if (node->has_node(skeleton_path)) { + Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(node->get_node(skeleton_path)); + if (skeleton) { + for (int i = 0; i < skeleton->get_bone_count(); i++) { + + Bone2D *bone = skeleton->get_bone(i); + if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) + continue; //not set + + bool current = bone_path == skeleton->get_path_to(bone); + + for (int j = 0; j < bone->get_child_count(); j++) { + + Node2D *n = Object::cast_to<Node2D>(bone->get_child(j)); + if (!n) + continue; + + bool edit_bone = n->has_meta("_edit_bone_") && n->get_meta("_edit_bone_"); + if (edit_bone) { + + Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest()); + Transform2D endpoint_xform = bone_xform * n->get_transform(); + + Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), current ? 5 : 4); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, current ? 3 : 2); + } + } + } + } + } + + //draw paint circle + uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1)); + } + rect = rect.grow(200); updating_uv_scroll = true; uv_hscroll->set_min(rect.position.x); @@ -711,6 +1017,10 @@ void Polygon2DEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_snap_step_x"), &Polygon2DEditor::_set_snap_step_x); ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &Polygon2DEditor::_set_snap_step_y); ClassDB::bind_method(D_METHOD("_uv_edit_mode_select"), &Polygon2DEditor::_uv_edit_mode_select); + ClassDB::bind_method(D_METHOD("_sync_bones"), &Polygon2DEditor::_sync_bones); + ClassDB::bind_method(D_METHOD("_update_bone_list"), &Polygon2DEditor::_update_bone_list); + + ClassDB::bind_method(D_METHOD("_bone_paint_selected"), &Polygon2DEditor::_bone_paint_selected); } Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { @@ -725,6 +1035,7 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; snap_step = Vector2(10, 10); use_snap = false; snap_show_grid = false; @@ -755,19 +1066,25 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_edit_mode[2] = memnew(ToolButton); uv_mode_hb->add_child(uv_edit_mode[2]); uv_edit_mode[2]->set_toggle_mode(true); + uv_edit_mode[3] = memnew(ToolButton); + uv_mode_hb->add_child(uv_edit_mode[3]); + uv_edit_mode[3]->set_toggle_mode(true); uv_edit_mode[0]->set_text(TTR("UV")); uv_edit_mode[0]->set_pressed(true); uv_edit_mode[1]->set_text(TTR("Poly")); uv_edit_mode[2]->set_text(TTR("Splits")); + uv_edit_mode[3]->set_text(TTR("Bones")); uv_edit_mode[0]->set_button_group(uv_edit_group); uv_edit_mode[1]->set_button_group(uv_edit_group); uv_edit_mode[2]->set_button_group(uv_edit_group); + uv_edit_mode[3]->set_button_group(uv_edit_group); uv_edit_mode[0]->connect("pressed", this, "_uv_edit_mode_select", varray(0)); uv_edit_mode[1]->connect("pressed", this, "_uv_edit_mode_select", varray(1)); uv_edit_mode[2]->connect("pressed", this, "_uv_edit_mode_select", varray(2)); + uv_edit_mode[3]->connect("pressed", this, "_uv_edit_mode_select", varray(3)); uv_mode_hb->add_child(memnew(VSeparator)); @@ -788,11 +1105,38 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_button[4]->set_tooltip(TTR("Scale Polygon")); uv_button[5]->set_tooltip(TTR("Connect two points to make a split")); uv_button[6]->set_tooltip(TTR("Select a split to erase it")); + uv_button[7]->set_tooltip(TTR("Paint weights with specified intensity")); + uv_button[8]->set_tooltip(TTR("UnPaint weights with specified intensity")); uv_button[0]->hide(); uv_button[5]->hide(); uv_button[6]->hide(); + uv_button[7]->hide(); + uv_button[8]->hide(); uv_button[1]->set_pressed(true); + + bone_paint_strength = memnew(HSlider); + uv_mode_hb->add_child(bone_paint_strength); + bone_paint_strength->set_custom_minimum_size(Size2(75 * EDSCALE, 0)); + bone_paint_strength->set_v_size_flags(SIZE_SHRINK_CENTER); + bone_paint_strength->set_min(0); + bone_paint_strength->set_max(1); + bone_paint_strength->set_step(0.01); + bone_paint_strength->set_value(0.5); + + bone_paint_radius_label = memnew(Label(" " + TTR("Radius:") + " ")); + uv_mode_hb->add_child(bone_paint_radius_label); + bone_paint_radius = memnew(SpinBox); + uv_mode_hb->add_child(bone_paint_radius); + + bone_paint_strength->hide(); + bone_paint_radius->hide(); + bone_paint_radius_label->hide(); + bone_paint_radius->set_min(1); + bone_paint_radius->set_max(100); + bone_paint_radius->set_step(1); + bone_paint_radius->set_value(32); + HBoxContainer *uv_main_hb = memnew(HBoxContainer); uv_main_vb->add_child(uv_main_hb); uv_edit_draw = memnew(Control); @@ -806,6 +1150,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_menu->get_popup()->add_item(TTR("UV->Polygon"), UVEDIT_UV_TO_POLYGON); uv_menu->get_popup()->add_separator(); uv_menu->get_popup()->add_item(TTR("Clear UV"), UVEDIT_UV_CLEAR); + uv_menu->get_popup()->add_separator(); + uv_menu->get_popup()->add_item(TTR("Grid Settings"), UVEDIT_GRID_SETTINGS); uv_menu->get_popup()->connect("id_pressed", this, "_menu_option"); uv_mode_hb->add_child(memnew(VSeparator)); @@ -828,8 +1174,11 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : b_snap_grid->set_tooltip(TTR("Show Grid")); b_snap_grid->connect("toggled", this, "_set_show_grid"); - uv_mode_hb->add_child(memnew(VSeparator)); - uv_mode_hb->add_child(memnew(Label(TTR("Grid Offset:")))); + grid_settings = memnew(AcceptDialog); + grid_settings->set_title(TTR("Configure Grid:")); + add_child(grid_settings); + VBoxContainer *grid_settings_vb = memnew(VBoxContainer); + grid_settings->add_child(grid_settings_vb); SpinBox *sb_off_x = memnew(SpinBox); sb_off_x->set_min(-256); @@ -838,7 +1187,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_x->set_value(snap_offset.x); sb_off_x->set_suffix("px"); sb_off_x->connect("value_changed", this, "_set_snap_off_x"); - uv_mode_hb->add_child(sb_off_x); + grid_settings_vb->add_margin_child(TTR("Grid Offset X:"), sb_off_x); SpinBox *sb_off_y = memnew(SpinBox); sb_off_y->set_min(-256); @@ -847,10 +1196,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_y->set_value(snap_offset.y); sb_off_y->set_suffix("px"); sb_off_y->connect("value_changed", this, "_set_snap_off_y"); - uv_mode_hb->add_child(sb_off_y); - - uv_mode_hb->add_child(memnew(VSeparator)); - uv_mode_hb->add_child(memnew(Label(TTR("Grid Step:")))); + grid_settings_vb->add_margin_child(TTR("Grid Offset Y:"), sb_off_y); SpinBox *sb_step_x = memnew(SpinBox); sb_step_x->set_min(-256); @@ -859,7 +1205,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_x->set_value(snap_step.x); sb_step_x->set_suffix("px"); sb_step_x->connect("value_changed", this, "_set_snap_step_x"); - uv_mode_hb->add_child(sb_step_x); + grid_settings_vb->add_margin_child(TTR("Grid Step X:"), sb_step_x); SpinBox *sb_step_y = memnew(SpinBox); sb_step_y->set_min(-256); @@ -868,7 +1214,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_y->set_value(snap_step.y); sb_step_y->set_suffix("px"); sb_step_y->connect("value_changed", this, "_set_snap_step_y"); - uv_mode_hb->add_child(sb_step_y); + grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y); uv_mode_hb->add_child(memnew(VSeparator)); uv_icon_zoom = memnew(TextureRect); @@ -878,8 +1224,10 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_zoom->set_max(4); uv_zoom->set_value(1); uv_zoom->set_step(0.01); + uv_zoom->set_v_size_flags(SIZE_SHRINK_CENTER); + uv_mode_hb->add_child(uv_zoom); - uv_zoom->set_custom_minimum_size(Size2(200, 0)); + uv_zoom->set_custom_minimum_size(Size2(80 * EDSCALE, 0)); uv_zoom_value = memnew(SpinBox); uv_zoom->share(uv_zoom_value); uv_zoom_value->set_custom_minimum_size(Size2(50, 0)); @@ -893,14 +1241,29 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_main_vb->add_child(uv_hscroll); uv_hscroll->connect("value_changed", this, "_uv_scroll_changed"); + bone_scroll_main_vb = memnew(VBoxContainer); + bone_scroll_main_vb->hide(); + sync_bones = memnew(Button(TTR("Sync Bones to Polygon"))); + bone_scroll_main_vb->add_child(sync_bones); + uv_main_hb->add_child(bone_scroll_main_vb); + bone_scroll = memnew(ScrollContainer); + bone_scroll->set_v_scroll(true); + bone_scroll->set_h_scroll(false); + bone_scroll_main_vb->add_child(bone_scroll); + bone_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + bone_scroll_vb = memnew(VBoxContainer); + bone_scroll->add_child(bone_scroll_vb); + sync_bones->connect("pressed", this, "_sync_bones"); + uv_edit_draw->connect("draw", this, "_uv_draw"); uv_edit_draw->connect("gui_input", this, "_uv_input"); uv_draw_zoom = 1.0; - uv_drag_index = -1; + point_drag_index = -1; uv_drag = false; uv_create = false; updating_uv_scroll = false; split_create = false; + bone_painting = false; error = memnew(AcceptDialog); add_child(error); diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index 8631ffb9a7..f9b42a21c2 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -32,7 +32,7 @@ #define POLYGON_2D_EDITOR_PLUGIN_H #include "editor/plugins/abstract_polygon_2d_editor.h" - +#include "scene/gui/scroll_container.h" /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -45,7 +45,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { MODE_EDIT_UV = MODE_CONT, UVEDIT_POLYGON_TO_UV, UVEDIT_UV_TO_POLYGON, - UVEDIT_UV_CLEAR + UVEDIT_UV_CLEAR, + UVEDIT_GRID_SETTINGS }; @@ -57,10 +58,12 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { UV_MODE_SCALE, UV_MODE_ADD_SPLIT, UV_MODE_REMOVE_SPLIT, + UV_MODE_PAINT_WEIGHT, + UV_MODE_CLEAR_WEIGHT, UV_MODE_MAX }; - ToolButton *uv_edit_mode[3]; + ToolButton *uv_edit_mode[4]; Ref<ButtonGroup> uv_edit_group; Polygon2D *node; @@ -78,15 +81,32 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { MenuButton *uv_menu; TextureRect *uv_icon_zoom; + VBoxContainer *bone_scroll_main_vb; + ScrollContainer *bone_scroll; + VBoxContainer *bone_scroll_vb; + Button *sync_bones; + HSlider *bone_paint_strength; + SpinBox *bone_paint_radius; + Label *bone_paint_radius_label; + bool bone_painting; + int bone_painting_bone; + PoolVector<float> prev_weights; + Vector2 bone_paint_pos; + AcceptDialog *grid_settings; + + void _sync_bones(); + void _update_bone_list(); + Vector2 uv_draw_ofs; float uv_draw_zoom; - PoolVector<Vector2> uv_prev; + PoolVector<Vector2> points_prev; PoolVector<Vector2> uv_create_uv_prev; PoolVector<Vector2> uv_create_poly_prev; + Array uv_create_bones_prev; PoolVector<int> splits_prev; Vector2 uv_create_to; - int uv_drag_index; + int point_drag_index; bool uv_drag; bool uv_create; bool split_create; @@ -118,6 +138,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { void _set_snap_step_y(float p_val); void _uv_edit_mode_select(int p_mode); + void _bone_paint_selected(int p_index); protected: virtual Node2D *_get_node() const; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 9193b3fbbf..94dcbd8e18 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -884,7 +884,7 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog->add_filter("*.tet"); file_dialog->set_current_path(EditorSettings::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); file_dialog->popup_centered_ratio(); - file_dialog->set_title(TTR("Save Theme As..")); + file_dialog->set_title(TTR("Save Theme As...")); } break; case SEARCH_HELP: { @@ -1182,12 +1182,13 @@ void ScriptEditor::_notification(int p_what) { script_forward->set_icon(get_icon("Forward", "EditorIcons")); script_back->set_icon(get_icon("Back", "EditorIcons")); + members_overview_alphabeta_sort_button->set_icon(get_icon("Sort", "EditorIcons")); } break; case NOTIFICATION_READY: { get_tree()->connect("tree_changed", this, "_tree_changed"); - editor->connect("request_help", this, "_request_help"); + editor->get_inspector_dock()->connect("request_help", this, "_request_help"); editor->connect("request_help_search", this, "_help_search"); editor->connect("request_help_index", this, "_help_index"); } break; @@ -1403,17 +1404,25 @@ void ScriptEditor::_update_members_overview_visibility() { ScriptEditorBase *se = _get_current_editor(); if (!se) { + members_overview_buttons_hbox->set_visible(false); members_overview->set_visible(false); return; } if (members_overview_enabled && se->show_members_overview()) { + members_overview_buttons_hbox->set_visible(true); members_overview->set_visible(true); } else { + members_overview_buttons_hbox->set_visible(false); members_overview->set_visible(false); } } +void ScriptEditor::_toggle_members_overview_alpha_sort(bool p_alphabetic_sort) { + EditorSettings::get_singleton()->set("text_editor/tools/sort_members_outline_alphabetically", p_alphabetic_sort); + _update_members_overview(); +} + void ScriptEditor::_update_members_overview() { members_overview->clear(); @@ -1423,6 +1432,10 @@ void ScriptEditor::_update_members_overview() { } Vector<String> functions = se->get_functions(); + if (EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically")) { + functions.sort(); + } + for (int i = 0; i < functions.size(); i++) { members_overview->add_item(functions[i].get_slice(":", 0)); members_overview->set_item_metadata(i, functions[i].get_slice(":", 1).to_int() - 1); @@ -1445,6 +1458,7 @@ void ScriptEditor::_update_help_overview_visibility() { } if (help_overview_enabled) { + members_overview_buttons_hbox->set_visible(false); help_overview->set_visible(true); } else { help_overview->set_visible(false); @@ -1536,9 +1550,10 @@ void ScriptEditor::_update_script_names() { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - String name = se->get_name(); Ref<Texture> icon = se->get_icon(); String path = se->get_edited_script()->get_path(); + bool built_in = !path.is_resource_file(); + String name = built_in ? path.get_file() : se->get_name(); _ScriptEditorItemData sd; sd.icon = icon; @@ -2596,6 +2611,8 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts); ClassDB::bind_method("_unhandled_input", &ScriptEditor::_unhandled_input); ClassDB::bind_method("_script_list_gui_input", &ScriptEditor::_script_list_gui_input); + ClassDB::bind_method("_toggle_members_overview_alpha_sort", &ScriptEditor::_toggle_members_overview_alpha_sort); + ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview); ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed); ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts); ClassDB::bind_method("_on_find_in_files_requested", &ScriptEditor::_on_find_in_files_requested); @@ -2656,14 +2673,33 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { add_child(context_menu); context_menu->connect("id_pressed", this, "_menu_option"); + members_overview_vbox = memnew(VBoxContainer); + members_overview_vbox->set_custom_minimum_size(Size2(0, 90)); + members_overview_vbox->set_v_size_flags(SIZE_EXPAND_FILL); + + list_split->add_child(members_overview_vbox); + members_overview_buttons_hbox = memnew(HBoxContainer); + members_overview_vbox->add_child(members_overview_buttons_hbox); + + members_overview_alphabeta_sort_button = memnew(ToolButton); + members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list.")); + members_overview_alphabeta_sort_button->set_toggle_mode(true); + members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically")); + members_overview_alphabeta_sort_button->connect("toggled", this, "_toggle_members_overview_alpha_sort"); + + members_overview_buttons_hbox->add_child(members_overview_alphabeta_sort_button); + members_overview = memnew(ItemList); - list_split->add_child(members_overview); + members_overview_vbox->add_child(members_overview); + members_overview->set_allow_reselect(true); members_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing members_overview->set_v_size_flags(SIZE_EXPAND_FILL); + members_overview->set_allow_rmb_select(true); + members_overview->set_drag_forwarding(this); help_overview = memnew(ItemList); - list_split->add_child(help_overview); + members_overview_vbox->add_child(help_overview); help_overview->set_allow_reselect(true); help_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing help_overview->set_v_size_flags(SIZE_EXPAND_FILL); @@ -2696,7 +2732,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT | KEY_MASK_CMD | KEY_S), FILE_SAVE); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As..")), FILE_SAVE_AS); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT); @@ -2725,7 +2761,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_search_menu = memnew(MenuButton); menu_hb->add_child(script_search_menu); script_search_menu->set_text(TTR("Search")); - script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND); script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT); script_search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); script_search_menu->hide(); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 9f37b18d7d..a2ff47cd99 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -199,6 +199,9 @@ class ScriptEditor : public PanelContainer { ItemList *script_list; HSplitContainer *script_split; ItemList *members_overview; + VBoxContainer *members_overview_vbox; + HBoxContainer *members_overview_buttons_hbox; + ToolButton *members_overview_alphabeta_sort_button; bool members_overview_enabled; ItemList *help_overview; bool help_overview_enabled; @@ -318,6 +321,7 @@ class ScriptEditor : public PanelContainer { void _update_members_overview_visibility(); void _update_members_overview(); + void _toggle_members_overview_alpha_sort(bool p_alphabetic_sort); void _update_script_names(); bool _sort_list_on_update; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index bcc575a7ac..45f5e667fa 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -746,6 +746,8 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c _goto_line(p_row); + result.class_name = result.class_name.trim_prefix("_"); + switch (result.type) { case ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION: { @@ -1007,6 +1009,10 @@ void ScriptTextEditor::_edit_option(int p_op) { } int next_line = to_line + 1; + if (to_line >= tx->get_line_count() - 1) { + tx->set_line(to_line, tx->get_line(to_line) + "\n"); + } + tx->begin_complex_operation(); for (int i = from_line; i <= to_line; i++) { @@ -1753,15 +1759,15 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Convert To Lowercase"), KEY_MASK_SHIFT | KEY_F3); ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F2); - ED_SHORTCUT("script_text_editor/find", TTR("Find.."), KEY_MASK_CMD | KEY_F); + ED_SHORTCUT("script_text_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F); ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3); ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3); - ED_SHORTCUT("script_text_editor/replace", TTR("Replace.."), KEY_MASK_CMD | KEY_R); + ED_SHORTCUT("script_text_editor/replace", TTR("Replace..."), KEY_MASK_CMD | KEY_R); ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F); - ED_SHORTCUT("script_text_editor/goto_function", TTR("Goto Function.."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F); - ED_SHORTCUT("script_text_editor/goto_line", TTR("Goto Line.."), KEY_MASK_CMD | KEY_L); + ED_SHORTCUT("script_text_editor/goto_function", TTR("Goto Function..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F); + ED_SHORTCUT("script_text_editor/goto_line", TTR("Goto Line..."), KEY_MASK_CMD | KEY_L); ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_SHIFT | KEY_F1); diff --git a/editor/plugins/shader_graph_editor_plugin.cpp b/editor/plugins/shader_graph_editor_plugin.cpp index e1d28cc215..1a9d980feb 100644 --- a/editor/plugins/shader_graph_editor_plugin.cpp +++ b/editor/plugins/shader_graph_editor_plugin.cpp @@ -1478,7 +1478,7 @@ void ShaderGraphView::_create_node(int p_id) { case ShaderGraph::NODE_XFORM_CONST: { gn->set_title("XForm"); ToolButton *edit = memnew( ToolButton ); - edit->set_text("edit.."); + edit->set_text("edit..."); edit->connect("pressed",this,"_xform_const_changed",varray(p_id,edit)); gn->add_child(edit); gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]); @@ -2289,7 +2289,7 @@ void ShaderGraphView::_create_node(int p_id) { le->set_text(graph->input_node_get_name(type,p_id)); le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); ToolButton *edit = memnew( ToolButton ); - edit->set_text("edit.."); + edit->set_text("edit..."); edit->connect("pressed",this,"_xform_input_changed",varray(p_id,edit)); gn->add_child(edit); gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]); @@ -2310,7 +2310,7 @@ void ShaderGraphView::_create_node(int p_id) { tex->set_mouse_filter(MOUSE_FILTER_PASS); tex->set_texture(graph->texture_input_node_get_value(type,p_id)); ToolButton *edit = memnew( ToolButton ); - edit->set_text("edit.."); + edit->set_text("edit..."); edit->connect("pressed",this,"_tex_edited",varray(p_id,edit)); gn->add_child(edit); @@ -2345,7 +2345,7 @@ void ShaderGraphView::_create_node(int p_id) { le->connect("text_entered",this,"_input_name_changed",varray(p_id,le)); ToolButton *edit = memnew( ToolButton ); - edit->set_text("edit.."); + edit->set_text("edit..."); edit->connect("pressed",this,"_cube_edited",varray(p_id,edit)); gn->add_child(edit); diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index e372f792d6..08bfebefbd 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #include "skeleton_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h index bbe2a3a6f2..26ab4328b0 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.h +++ b/editor/plugins/skeleton_2d_editor_plugin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef SKELETON_2D_EDITOR_PLUGIN_H #define SKELETON_2D_EDITOR_PLUGIN_H diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp new file mode 100644 index 0000000000..40a696119e --- /dev/null +++ b/editor/plugins/skeleton_editor_plugin.cpp @@ -0,0 +1,183 @@ +/*************************************************************************/ +/* skeleton_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "skeleton_editor_plugin.h" +#include "scene/3d/collision_shape.h" +#include "scene/3d/physics_body.h" +#include "scene/3d/physics_joint.h"; +#include "scene/resources/capsule_shape.h" +#include "scene/resources/sphere_shape.h" +#include "spatial_editor_plugin.h" + +void SkeletonEditor::_on_click_option(int p_option) { + if (!skeleton) { + return; + } + + switch (p_option) { + case MENU_OPTION_CREATE_PHYSICAL_SKELETON: { + create_physical_skeleton(); + } break; + } +} + +void SkeletonEditor::create_physical_skeleton() { + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner(); + + const int bc = skeleton->get_bone_count(); + + if (!bc) { + return; + } + + Vector<BoneInfo> bones_infos; + bones_infos.resize(bc); + + for (int bone_id = 0; bc > bone_id; ++bone_id) { + + const int parent = skeleton->get_bone_parent(bone_id); + const int parent_parent = skeleton->get_bone_parent(parent); + + if (parent < 0) { + + bones_infos[bone_id].relative_rest = skeleton->get_bone_rest(bone_id); + + } else { + + bones_infos[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id); + + /// create physical bone on parent + if (!bones_infos[parent].physical_bone) { + + bones_infos[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); + + ur->create_action(TTR("Create physical bones")); + ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone); + ur->add_do_reference(bones_infos[parent].physical_bone); + ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone); + ur->commit_action(); + + bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent)); + bones_infos[parent].physical_bone->set_owner(owner); + bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner + + /// Create joint between parent of parent + if (-1 != parent_parent) { + + bones_infos[parent].physical_bone->set_joint_type(PhysicalBone::JOINT_TYPE_PIN); + } + } + } + } +} + +PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) { + + real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5); + real_t radius(half_height * 0.2); + + CapsuleShape *bone_shape_capsule = memnew(CapsuleShape); + bone_shape_capsule->set_height((half_height - radius) * 2); + bone_shape_capsule->set_radius(radius); + + CollisionShape *bone_shape = memnew(CollisionShape); + bone_shape->set_shape(bone_shape_capsule); + + Transform body_transform; + body_transform.origin = Vector3(0, 0, -half_height); + + Transform joint_transform; + joint_transform.origin = Vector3(0, 0, half_height); + + PhysicalBone *physical_bone = memnew(PhysicalBone); + physical_bone->add_child(bone_shape); + physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id)); + physical_bone->set_body_offset(body_transform); + physical_bone->set_joint_offset(joint_transform); + return physical_bone; +} + +void SkeletonEditor::edit(Skeleton *p_node) { + skeleton = p_node; +} + +void SkeletonEditor::_node_removed(Node *p_node) { + + if (p_node == skeleton) { + skeleton = NULL; + options->hide(); + } +} + +void SkeletonEditor::_bind_methods() { + ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option); +} + +SkeletonEditor::SkeletonEditor() { + options = memnew(MenuButton); + SpatialEditor::get_singleton()->add_control_to_menu_panel(options); + + options->set_text(TTR("Skeleton")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons")); + + options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON); + + options->get_popup()->connect("id_pressed", this, "_on_click_option"); + options->hide(); +} + +SkeletonEditor::~SkeletonEditor() {} + +void SkeletonEditorPlugin::edit(Object *p_object) { + skeleton_editor->edit(Object::cast_to<Skeleton>(p_object)); +} + +bool SkeletonEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("Skeleton"); +} + +void SkeletonEditorPlugin::make_visible(bool p_visible) { + if (p_visible) { + skeleton_editor->options->show(); + } else { + + skeleton_editor->options->hide(); + skeleton_editor->edit(NULL); + } +} + +SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) { + editor = p_node; + skeleton_editor = memnew(SkeletonEditor); + editor->get_viewport()->add_child(skeleton_editor); +} + +SkeletonEditorPlugin::~SkeletonEditorPlugin() {} diff --git a/editor/plugins/skeleton_editor_plugin.h b/editor/plugins/skeleton_editor_plugin.h new file mode 100644 index 0000000000..b9bdf91902 --- /dev/null +++ b/editor/plugins/skeleton_editor_plugin.h @@ -0,0 +1,95 @@ +/*************************************************************************/ +/* skeleton_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SKELETON_EDITOR_PLUGIN_H +#define SKELETON_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/3d/skeleton.h" + +class PhysicalBone; +class Joint; + +class SkeletonEditor : public Node { + GDCLASS(SkeletonEditor, Node); + + enum Menu { + MENU_OPTION_CREATE_PHYSICAL_SKELETON + }; + + struct BoneInfo { + PhysicalBone *physical_bone; + Transform relative_rest; // Relative to skeleton node + BoneInfo() : + physical_bone(NULL) {} + }; + + Skeleton *skeleton; + + MenuButton *options; + + void _on_click_option(int p_option); + + friend class SkeletonEditorPlugin; + +protected: + void _node_removed(Node *p_node); + static void _bind_methods(); + + void create_physical_skeleton(); + PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos); + +public: + void edit(Skeleton *p_mesh); + + SkeletonEditor(); + ~SkeletonEditor(); +}; + +class SkeletonEditorPlugin : public EditorPlugin { + + GDCLASS(SkeletonEditorPlugin, EditorPlugin); + + EditorNode *editor; + SkeletonEditor *skeleton_editor; + +public: + virtual String get_name() const { return "Skeleton"; } + virtual bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + SkeletonEditorPlugin(EditorNode *p_node); + ~SkeletonEditorPlugin(); +}; + +#endif // SKELETON_EDITOR_PLUGIN_H diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 9d7c582e0e..5b713ef3c4 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -72,6 +72,14 @@ #define MIN_FOV 0.01 #define MAX_FOV 179 +#ifdef TOOLS_ENABLED +#define get_global_gizmo_transform get_global_gizmo_transform +#define get_local_gizmo_transform get_local_gizmo_transform +#else +#define get_global_gizmo_transform get_global_transform +#define get_local_gizmo_transform get_transform +#endif + void SpatialEditorViewport::_update_camera(float p_interp_delta) { bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; @@ -584,8 +592,8 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) { if (!se) continue; - se->original = se->sp->get_global_transform(); - se->original_local = se->sp->get_transform(); + se->original = se->sp->get_global_gizmo_transform(); + se->original_local = se->sp->get_local_gizmo_transform(); } } @@ -1184,7 +1192,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (!se) continue; - undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_transform()); + undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform()); undo_redo->add_undo_method(sp, "set_global_transform", se->original); } undo_redo->commit_action(); @@ -2150,7 +2158,7 @@ void SpatialEditorViewport::_notification(int p_what) { se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4)); } - Transform t = sp->get_global_transform(); + Transform t = sp->get_global_gizmo_transform(); t.translate(se->aabb.position); // apply AABB scaling before item's global transform @@ -2503,7 +2511,7 @@ void SpatialEditorViewport::_menu_option(int p_option) { xform.scale_basis(sp->get_scale()); undo_redo->add_do_method(sp, "set_global_transform", xform); - undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform()); + undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform()); } undo_redo->commit_action(); } break; @@ -2961,7 +2969,7 @@ void SpatialEditorViewport::focus_selection() { if (!se) continue; - center += sp->get_global_transform().origin; + center += sp->get_global_gizmo_transform().origin; count++; } @@ -3043,7 +3051,7 @@ AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, c MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(child); if (mesh_instance) { AABB mesh_instance_bounds = mesh_instance->get_aabb(); - mesh_instance_bounds.position += mesh_instance->get_global_transform().origin - p_parent->get_global_transform().origin; + mesh_instance_bounds.position += mesh_instance->get_global_gizmo_transform().origin - p_parent->get_global_gizmo_transform().origin; bounds.merge_with(mesh_instance_bounds); } bounds = _calculate_spatial_bounds(child, bounds); @@ -3121,7 +3129,7 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P if (!scene.is_valid()) { // invalid scene return false; } else { - instanced_scene = scene->instance(); + instanced_scene = scene->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); } } } @@ -3154,7 +3162,7 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P Transform global_transform; Spatial *parent_spatial = Object::cast_to<Spatial>(parent); if (parent_spatial) - global_transform = parent_spatial->get_global_transform(); + global_transform = parent_spatial->get_global_gizmo_transform(); global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point)); @@ -3283,7 +3291,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p } } if (list.size() != 1) { - accept->get_ok()->set_text(TTR("I see..")); + accept->get_ok()->set_text(TTR("I see...")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); _remove_preview(); @@ -3787,7 +3795,8 @@ void SpatialEditor::update_transform_gizmo() { if (!se) continue; - Transform xf = se->sp->get_global_transform(); + Transform xf = se->sp->get_global_gizmo_transform(); + if (first) { center.position = xf.origin; first = false; @@ -4054,7 +4063,7 @@ void SpatialEditor::_xform_dialog_action() { bool post = xform_type->get_selected() > 0; - Transform tr = sp->get_global_transform(); + Transform tr = sp->get_global_gizmo_transform(); if (post) tr = tr * t; else { @@ -4064,7 +4073,7 @@ void SpatialEditor::_xform_dialog_action() { } undo_redo->add_do_method(sp, "set_global_transform", tr); - undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform()); + undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform()); } undo_redo->commit_action(); } @@ -4598,7 +4607,10 @@ void SpatialEditor::_init_grid() { PoolVector<Color> grid_colors[3]; PoolVector<Vector3> grid_points[3]; - Color grid_color = EditorSettings::get_singleton()->get("editors/3d/grid_color"); + Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color"); + Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color"); + int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size"); + int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps"); for (int i = 0; i < 3; i++) { Vector3 axis; @@ -4608,19 +4620,17 @@ void SpatialEditor::_init_grid() { Vector3 axis_n2; axis_n2[(i + 2) % 3] = 1; -#define ORIGIN_GRID_SIZE 50 - - for (int j = -ORIGIN_GRID_SIZE; j <= ORIGIN_GRID_SIZE; j++) { - Vector3 p1 = axis_n1 * j + axis_n2 * -ORIGIN_GRID_SIZE; + for (int j = -grid_size; j <= grid_size; j++) { + Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size; Vector3 p1_dest = p1 * (-axis_n2 + axis_n1); - Vector3 p2 = axis_n2 * j + axis_n1 * -ORIGIN_GRID_SIZE; + Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size; Vector3 p2_dest = p2 * (-axis_n1 + axis_n2); - Color line_color = grid_color; + Color line_color = secondary_grid_color; if (j == 0) { continue; - } else if (j % 10 == 0) { - line_color *= 1.5; + } else if (j % primary_grid_steps == 0) { + line_color = primary_grid_color; } grid_points[i].push_back(p1); @@ -5082,8 +5092,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Tool Rotate"), KEY_E); ED_SHORTCUT("spatial_editor/tool_scale", TTR("Tool Scale"), KEY_R); - ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe"), KEY_Z); - ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F); PopupMenu *p; @@ -5093,9 +5101,9 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(transform_menu); p = transform_menu->get_popup(); - p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap..")), MENU_TRANSFORM_CONFIGURE_SNAP); + p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP); p->add_separator(); - p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog..")), MENU_TRANSFORM_DIALOG); + p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG); p->connect("id_pressed", this, "_menu_item_pressed"); diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 49816fe2ae..66673cca00 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* sprite_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #include "sprite_editor_plugin.h" #include "canvas_item_editor_plugin.h" diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h index 17aa3eb1f9..238227e4a0 100644 --- a/editor/plugins/sprite_editor_plugin.h +++ b/editor/plugins/sprite_editor_plugin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* sprite_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef SPRITE_EDITOR_PLUGIN_H #define SPRITE_EDITOR_PLUGIN_H diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 71a3c90795..a9afc7a670 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -45,6 +45,12 @@ void SpriteFramesEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { load->set_icon(get_icon("Load", "EditorIcons")); + copy->set_icon(get_icon("ActionCopy", "EditorIcons")); + paste->set_icon(get_icon("ActionPaste", "EditorIcons")); + empty->set_icon(get_icon("InsertBefore", "EditorIcons")); + empty2->set_icon(get_icon("InsertAfter", "EditorIcons")); + move_up->set_icon(get_icon("MoveLeft", "EditorIcons")); + move_down->set_icon(get_icon("MoveRight", "EditorIcons")); _delete->set_icon(get_icon("Remove", "EditorIcons")); new_anim->set_icon(get_icon("New", "EditorIcons")); remove_anim->set_icon(get_icon("Remove", "EditorIcons")); @@ -736,27 +742,35 @@ SpriteFramesEditor::SpriteFramesEditor() { hbc->add_child(load); copy = memnew(Button); - copy->set_text(TTR("Copy")); + copy->set_flat(true); + copy->set_tooltip(TTR("Copy")); hbc->add_child(copy); paste = memnew(Button); - paste->set_text(TTR("Paste")); + paste->set_flat(true); + paste->set_tooltip(TTR("Paste")); hbc->add_child(paste); empty = memnew(Button); - empty->set_text(TTR("Insert Empty (Before)")); + empty->set_flat(true); + empty->set_tooltip(TTR("Insert Empty (Before)")); hbc->add_child(empty); empty2 = memnew(Button); - empty2->set_text(TTR("Insert Empty (After)")); + empty2->set_flat(true); + empty2->set_tooltip(TTR("Insert Empty (After)")); hbc->add_child(empty2); + hbc->add_spacer(false); + move_up = memnew(Button); - move_up->set_text(TTR("Move (Before)")); + move_up->set_flat(true); + move_up->set_tooltip(TTR("Move (Before)")); hbc->add_child(move_up); move_down = memnew(Button); - move_down->set_text(TTR("Move (After)")); + move_down->set_flat(true); + move_down->set_tooltip(TTR("Move (After)")); hbc->add_child(move_down); _delete = memnew(Button); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index f4faab69ed..f6d98cb4c7 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -30,7 +30,26 @@ #include "style_box_editor_plugin.h" -void StyleBoxEditor::edit(const Ref<StyleBox> &p_stylebox) { +bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) { + + return Object::cast_to<StyleBox>(p_object) != NULL; +} + +void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) { + + Ref<StyleBox> sb = Ref<StyleBox>(Object::cast_to<StyleBox>(p_object)); + + StyleBoxPreview *preview = memnew(StyleBoxPreview); + preview->edit(sb); + add_custom_control(preview); +} +bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { + return false; //do not want +} +void EditorInspectorPluginStyleBox::parse_end() { +} + +void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) { if (stylebox.is_valid()) stylebox->disconnect("changed", this, "_sb_changed"); @@ -39,71 +58,33 @@ void StyleBoxEditor::edit(const Ref<StyleBox> &p_stylebox) { preview->add_style_override("panel", stylebox); stylebox->connect("changed", this, "_sb_changed"); } + _sb_changed(); } -void StyleBoxEditor::_sb_changed() { +void StyleBoxPreview::_sb_changed() { preview->update(); + if (stylebox.is_valid()) { + Size2 ms = stylebox->get_minimum_size() * 4 / 3; + ms.height = MAX(ms.height, 150 * EDSCALE); + preview->set_custom_minimum_size(ms); + } } -void StyleBoxEditor::_bind_methods() { +void StyleBoxPreview::_bind_methods() { - ClassDB::bind_method("_sb_changed", &StyleBoxEditor::_sb_changed); - //ClassDB::bind_method("_import",&StyleBoxEditor::_import); - //ClassDB::bind_method("_import_accept",&StyleBoxEditor::_import_accept); - //ClassDB::bind_method("_preview_text_changed",&StyleBoxEditor::_preview_text_changed); + ClassDB::bind_method("_sb_changed", &StyleBoxPreview::_sb_changed); } -StyleBoxEditor::StyleBoxEditor() { - - panel = memnew(Panel); - add_child(panel); - panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - - Label *l = memnew(Label); - l->set_text(TTR("StyleBox Preview:")); - l->set_position(Point2(5, 5)); - panel->add_child(l); +StyleBoxPreview::StyleBoxPreview() { preview = memnew(Panel); - panel->add_child(preview); - preview->set_position(Point2(50, 50)); - preview->set_size(Size2(200, 100)); -} - -void StyleBoxEditorPlugin::edit(Object *p_node) { - - if (Object::cast_to<StyleBox>(p_node)) { - stylebox_editor->edit(Object::cast_to<StyleBox>(p_node)); - stylebox_editor->show(); - } else - stylebox_editor->hide(); -} - -bool StyleBoxEditorPlugin::handles(Object *p_node) const { - - return p_node->is_class("StyleBox"); -} - -void StyleBoxEditorPlugin::make_visible(bool p_visible) { - - if (p_visible) { - button->show(); - EditorNode::get_singleton()->make_bottom_panel_item_visible(stylebox_editor); - - } else { - if (stylebox_editor->is_visible_in_tree()) - EditorNode::get_singleton()->hide_bottom_panel(); - button->hide(); - } + add_margin_child(TTR("Preview:"), preview); } StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) { - stylebox_editor = memnew(StyleBoxEditor); - stylebox_editor->set_custom_minimum_size(Size2(0, 250)); - - //p_node->get_viewport()->add_child(stylebox_editor); - button = p_node->add_bottom_panel_item(TTR("StyleBox"), stylebox_editor); - button->hide(); + Ref<EditorInspectorPluginStyleBox> inspector_plugin; + inspector_plugin.instance(); + add_inspector_plugin(inspector_plugin); } diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index 34d8caaeb6..6b0d7e57a8 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -31,18 +31,17 @@ #ifndef STYLE_BOX_EDITOR_PLUGIN_H #define STYLE_BOX_EDITOR_PLUGIN_H +#include "editor/editor_inspector.h" #include "editor/editor_node.h" #include "scene/gui/option_button.h" #include "scene/gui/texture_rect.h" #include "scene/resources/style_box.h" -class StyleBoxEditor : public Control { +class StyleBoxPreview : public VBoxContainer { - GDCLASS(StyleBoxEditor, Control); + GDCLASS(StyleBoxPreview, VBoxContainer); - Panel *panel; Panel *preview; - Ref<StyleBox> stylebox; void _sb_changed(); @@ -53,23 +52,24 @@ protected: public: void edit(const Ref<StyleBox> &p_stylebox); - StyleBoxEditor(); + StyleBoxPreview(); +}; + +class EditorInspectorPluginStyleBox : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginStyleBox, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); + virtual void parse_end(); }; class StyleBoxEditorPlugin : public EditorPlugin { GDCLASS(StyleBoxEditorPlugin, EditorPlugin); - StyleBoxEditor *stylebox_editor; - EditorNode *editor; - Button *button; - public: virtual String get_name() const { return "StyleBox"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); StyleBoxEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 5ba3931689..e4fdd1f251 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -601,6 +601,17 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { void TextureRegionEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_PROCESS: { + if (node_sprite) { + if (node_sprite->is_region()) { + + set_process(false); + EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + } + } else { + set_process(false); + } + } break; case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_READY: { zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); @@ -640,6 +651,23 @@ void TextureRegionEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_zoom_out"), &TextureRegionEditor::_zoom_out); } +bool TextureRegionEditor::is_stylebox() { + return obj_styleBox.is_valid(); +} + +bool TextureRegionEditor::is_atlas_texture() { + + return atlas_tex.is_valid(); +} + +bool TextureRegionEditor::is_ninepatch() { + return node_ninepatch != NULL; +} + +Sprite *TextureRegionEditor::get_sprite() { + return node_sprite; +} + void TextureRegionEditor::edit(Object *p_obj) { if (node_sprite) node_sprite->remove_change_receptor(this); @@ -670,6 +698,12 @@ void TextureRegionEditor::edit(Object *p_obj) { tile_set = Ref<TileSet>(NULL); } edit_draw->update(); + if (node_sprite && !node_sprite->is_region()) { + set_process(true); + } + if (!p_obj) { + set_process(false); + } } void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_prop) { @@ -932,8 +966,12 @@ bool TextureRegionEditorPlugin::handles(Object *p_object) const { void TextureRegionEditorPlugin::make_visible(bool p_visible) { if (p_visible) { texture_region_button->show(); - if (texture_region_button->is_pressed()) - region_editor->show(); + if (region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region())) { + editor->make_bottom_panel_item_visible(region_editor); + } else { + if (texture_region_button->is_pressed()) + region_editor->show(); + } } else { texture_region_button->hide(); region_editor->edit(NULL); @@ -989,10 +1027,10 @@ TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) { editor = p_node; region_editor = memnew(TextureRegionEditor(p_node)); - texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), region_editor); + texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor); texture_region_button->set_tooltip(TTR("Texture Region Editor")); - region_editor->set_custom_minimum_size(Size2(0, 200)); + region_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); region_editor->hide(); texture_region_button->hide(); } diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 1244953a3f..eeba1987a6 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -131,6 +131,10 @@ public: void _region_draw(); void _region_input(const Ref<InputEvent> &p_input); void _scroll_changed(float); + bool is_stylebox(); + bool is_atlas_texture(); + bool is_ninepatch(); + Sprite *get_sprite(); void edit(Object *p_obj); TextureRegionEditor(EditorNode *p_editor); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 550dfb3ae1..92b95963f9 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -632,7 +632,7 @@ ThemeEditor::ThemeEditor() { main_vb->add_child(hb_menu); theme_menu = memnew(MenuButton); - theme_menu->set_text(TTR("Edit theme..")); + theme_menu->set_text(TTR("Edit theme...")); theme_menu->set_flat(false); theme_menu->set_tooltip(TTR("Theme editing menu.")); theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD); @@ -691,11 +691,11 @@ ThemeEditor::ThemeEditor() { test_menu_button->get_popup()->add_separator(); test_menu_button->get_popup()->add_check_item(TTR("Check Item")); test_menu_button->get_popup()->add_check_item(TTR("Checked Item")); - test_menu_button->get_popup()->set_item_checked(2, true); + test_menu_button->get_popup()->set_item_checked(3, true); test_menu_button->get_popup()->add_separator(); - test_menu_button->get_popup()->add_check_item(TTR("Radio Item")); + test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item")); test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item")); - test_menu_button->get_popup()->set_item_checked(5, true); + test_menu_button->get_popup()->set_item_checked(6, true); first_vb->add_child(test_menu_button); OptionButton *test_option_button = memnew(OptionButton); @@ -744,7 +744,7 @@ ThemeEditor::ThemeEditor() { item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); item->set_editable(0, true); - item->set_text(0, "check"); + item->set_text(0, "Check"); item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); item->set_editable(0, true); @@ -753,7 +753,7 @@ ThemeEditor::ThemeEditor() { item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); item->set_editable(0, true); - item->set_text(0, TTR("Have,Many,Several,Options!")); + item->set_text(0, TTR("Has,Many,Options")); item->set_range(0, 2); VBoxContainer *third_vb = memnew(VBoxContainer); @@ -784,58 +784,6 @@ ThemeEditor::ThemeEditor() { main_hb->add_constant_override("separation", 20 * EDSCALE); - /* - test_h_scroll = memnew( HScrollBar ); - test_h_scroll->set_position( Point2( 25, 225 ) ); - test_h_scroll->set_size( Point2( 150, 5 ) ); - panel->add_child(test_h_scroll); - - line_edit = memnew( LineEdit ); - line_edit->set_position( Point2( 25, 275 ) ); - line_edit->set_size( Point2( 150, 5 ) ); - line_edit->set_text("Line Edit"); - panel->add_child(line_edit); - - test_v_scroll = memnew( VScrollBar ); - test_v_scroll->set_position( Point2( 200, 25 ) ); - test_v_scroll->set_size( Point2( 5, 150 ) ); - panel->add_child(test_v_scroll); - - test_tree = memnew(Tree); - test_tree->set_position( Point2( 300, 25 ) ); - test_tree->set_size( Point2( 200, 200 ) ); - panel->add_child(test_tree); - - - TreeItem *item = test_tree->create_item(); - item->set_editable(0,true); - item->set_text(0,"root"); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0,true); - item->set_text(0,"check"); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0,true); - item->set_range_config(0,0,20,0.1); - item->set_range(0,2); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0,true); - item->set_text(0,"Have,Many,Several,Options!")); - item->set_range(0,2); - - Button *fd_button= memnew( Button ); - fd_button->set_position(Point2(300,275)); - fd_button->set_text("Open File Dialog"); - panel->add_child(fd_button); - - test_file_dialog = memnew( EditorFileDialog ); - panel->add_child(test_file_dialog); - - fd_button->connect("pressed", this,"_open_file_dialog"); -*/ - add_del_dialog = memnew(ConfirmationDialog); add_del_dialog->hide(); add_child(add_del_dialog); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 14c584fa35..72b3af5a09 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -724,7 +724,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (mb->get_shift()) { +#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) +#else if (mb->get_control()) +#endif tool = TOOL_RECTANGLE_PAINT; else tool = TOOL_LINE_PAINT; @@ -734,9 +738,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } - +#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) { +#else if (mb->get_control()) { - +#endif tool = TOOL_PICKING; _pick_tile(over_tile); @@ -940,8 +946,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); if (mb->get_shift()) { - +#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) +#else if (mb->get_control()) +#endif tool = TOOL_RECTANGLE_ERASE; else tool = TOOL_LINE_ERASE; diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 3257901c88..642870aec0 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -125,12 +125,11 @@ class TileMapEditor : public VBoxContainer { bool yf; bool tr; - CellOp() { - idx = -1; - xf = false; - yf = false; - tr = false; - } + CellOp() : + idx(TileMap::INVALID_CELL), + xf(false), + yf(false), + tr(false) {} }; Map<Point2i, CellOp> paint_undo; @@ -141,8 +140,12 @@ class TileMapEditor : public VBoxContainer { bool flip_h; bool flip_v; bool transpose; - int auto_x; - int auto_y; + + TileData() : + cell(TileMap::INVALID_CELL), + flip_h(false), + flip_v(false), + transpose(false) {} }; List<TileData> copydata; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 41692e805f..c79cf02062 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -126,7 +126,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { Transform2D shape_transform = sb->shape_owner_get_transform(E->get()); bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get()); - shape_transform.set_origin(shape_transform.get_origin() - phys_offset); + shape_transform[2] -= phys_offset - sb->get_transform().xform(shape_transform[2]); for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { @@ -149,6 +149,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { p_library->tile_set_light_occluder(id, occluder); p_library->tile_set_occluder_offset(id, -phys_offset); p_library->tile_set_navigation_polygon_offset(id, -phys_offset); + p_library->tile_set_z_index(id, mi->get_z_index()); } } @@ -666,7 +667,7 @@ void TileSetEditor::_on_workspace_draw() { if (mask & TileSet::BIND_BOTTOMRIGHT) { workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c); } - } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else { if (mask & TileSet::BIND_TOPLEFT) { workspace->draw_rect(Rect2(anchor, size / 3), c); } @@ -805,7 +806,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); pos = mb->get_position() - pos; - uint16_t bit; + uint16_t bit = 0; if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (pos.x < size.x / 2) { if (pos.y < size.y / 2) { @@ -820,7 +821,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { bit = TileSet::BIND_BOTTOMRIGHT; } } - } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else { if (pos.x < size.x / 3) { if (pos.y < size.y / 3) { bit = TileSet::BIND_TOPLEFT; @@ -868,7 +869,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { Vector2 coord((int)(mm->get_position().x / (spacing + size.x)), (int)(mm->get_position().y / (spacing + size.y))); Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); pos = mm->get_position() - pos; - uint16_t bit; + uint16_t bit = 0; if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (pos.x < size.x / 2) { if (pos.y < size.y / 2) { @@ -883,7 +884,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { bit = TileSet::BIND_BOTTOMRIGHT; } } - } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else { if (pos.x < size.x / 3) { if (pos.y < size.y / 3) { bit = TileSet::BIND_TOPLEFT; @@ -1146,7 +1147,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { case EDITMODE_COLLISION: { if (!edited_collision_shape.is_null()) { Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); - int index; + int index = -1; for (int i = 0; i < sd.size(); i++) { if (sd[i].shape == edited_collision_shape) { index = i; @@ -1848,7 +1849,7 @@ void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const { if (selected_tile < 0 || tileset.is_null()) return; - p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3")); + p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3 (minimal),3x3")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "layout/tile_size")); p_list->push_back(PropertyInfo(Variant::INT, "layout/spacing", PROPERTY_HINT_RANGE, "0,256,1")); } |