diff options
Diffstat (limited to 'editor')
28 files changed, 511 insertions, 298 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 4991b2cfaf..e64fc6e9e3 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -52,13 +52,9 @@ public: bool setting = false; bool animation_read_only = false; - bool _hide_script_from_inspector() { - return true; - } - - bool _dont_undo_redo() { - return true; - } + bool _hide_script_from_inspector() { return true; } + bool _hide_metadata_from_inspector() { return true; } + bool _dont_undo_redo() { return true; } bool _is_read_only() { return animation_read_only; @@ -68,6 +64,7 @@ public: ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj); ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed); ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector); + ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_from_inspector); ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path); ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo); ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only); @@ -719,13 +716,9 @@ public: bool setting = false; bool animation_read_only = false; - bool _hide_script_from_inspector() { - return true; - } - - bool _dont_undo_redo() { - return true; - } + bool _hide_script_from_inspector() { return true; } + bool _hide_metadata_from_inspector() { return true; } + bool _dont_undo_redo() { return true; } bool _is_read_only() { return animation_read_only; @@ -735,6 +728,7 @@ public: ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj); ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed); ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); + ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_from_inspector); ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path); ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo); ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only); diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 2e35f21e47..af0cff9ad6 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -231,6 +231,7 @@ EditorHelpSearch::EditorHelpSearch() { filter_combo->add_item(TTR("Methods Only"), SEARCH_METHODS); filter_combo->add_item(TTR("Operators Only"), SEARCH_OPERATORS); filter_combo->add_item(TTR("Signals Only"), SEARCH_SIGNALS); + filter_combo->add_item(TTR("Annotations Only"), SEARCH_ANNOTATIONS); filter_combo->add_item(TTR("Constants Only"), SEARCH_CONSTANTS); filter_combo->add_item(TTR("Properties Only"), SEARCH_PROPERTIES); filter_combo->add_item(TTR("Theme Properties Only"), SEARCH_THEME_ITEMS); @@ -339,8 +340,9 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { match.name = (term.is_empty() && (!class_doc.is_script_doc || class_doc.name[0] != '\"')) || _match_string(term, class_doc.name); } - // Match members if the term is long enough. - if (term.length() > 1) { + // Match members only if the term is long enough, to avoid slow performance from building a large tree. + // Make an exception for annotations, since there are not that many of them. + if (term.length() > 1 || term == "@") { if (search_flags & SEARCH_CONSTRUCTORS) { for (int i = 0; i < class_doc.constructors.size(); i++) { String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower(); @@ -402,6 +404,13 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { } } } + if (search_flags & SEARCH_ANNOTATIONS) { + for (int i = 0; i < class_doc.annotations.size(); i++) { + if (_match_string(term, class_doc.annotations[i].name)) { + match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc.annotations[i])); + } + } + } matches[class_doc.name] = match; } matches[class_doc.name] = match; @@ -485,6 +494,10 @@ bool EditorHelpSearch::Runner::_phase_member_items() { for (int i = 0; i < match.theme_properties.size(); i++) { _create_theme_property_item(parent, match.doc, match.theme_properties[i]); } + for (int i = 0; i < match.annotations.size(); i++) { + // Hide the redundant leading @ symbol. + _create_annotation_item(parent, match.doc, match.annotations[i]->name.substr(1), match.annotations[i]); + } ++iterator_match; return !iterator_match; @@ -523,6 +536,22 @@ void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_tex } } +String EditorHelpSearch::Runner::_build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const { + String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; + for (int i = 0; i < p_doc->arguments.size(); i++) { + const DocData::ArgumentDoc &arg = p_doc->arguments[i]; + tooltip += arg.type + " " + arg.name; + if (!arg.default_value.is_empty()) { + tooltip += " = " + arg.default_value; + } + if (i < p_doc->arguments.size() - 1) { + tooltip += ", "; + } + } + tooltip += ")"; + return tooltip; +} + TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_match) { if (p_match.doc->name.is_empty()) { return nullptr; @@ -576,37 +605,20 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const } TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) { - String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; - for (int i = 0; i < p_doc->arguments.size(); i++) { - const DocData::ArgumentDoc &arg = p_doc->arguments[i]; - tooltip += arg.type + " " + arg.name; - if (!arg.default_value.is_empty()) { - tooltip += " = " + arg.default_value; - } - if (i < p_doc->arguments.size() - 1) { - tooltip += ", "; - } - } - tooltip += ")"; + String tooltip = _build_method_tooltip(p_class_doc, p_doc); return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip); } TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) { - String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; - for (int i = 0; i < p_doc->arguments.size(); i++) { - const DocData::ArgumentDoc &arg = p_doc->arguments[i]; - tooltip += arg.type + " " + arg.name; - if (!arg.default_value.is_empty()) { - tooltip += " = " + arg.default_value; - } - if (i < p_doc->arguments.size() - 1) { - tooltip += ", "; - } - } - tooltip += ")"; + String tooltip = _build_method_tooltip(p_class_doc, p_doc); return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip); } +TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) { + String tooltip = _build_method_tooltip(p_class_doc, p_doc); + return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip); +} + TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) { String tooltip = p_class_doc->name + "." + p_doc->name; return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip); diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index 3f17c992ac..26abaec6e6 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -50,7 +50,8 @@ class EditorHelpSearch : public ConfirmationDialog { SEARCH_CONSTANTS = 1 << 5, SEARCH_PROPERTIES = 1 << 6, SEARCH_THEME_ITEMS = 1 << 7, - SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS, + SEARCH_ANNOTATIONS = 1 << 8, + SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS | SEARCH_ANNOTATIONS, SEARCH_CASE_SENSITIVE = 1 << 29, SEARCH_SHOW_HIERARCHY = 1 << 30 }; @@ -108,9 +109,10 @@ class EditorHelpSearch::Runner : public RefCounted { Vector<DocData::ConstantDoc *> constants; Vector<DocData::PropertyDoc *> properties; Vector<DocData::ThemeItemDoc *> theme_properties; + Vector<DocData::MethodDoc *> annotations; bool required() { - return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size(); + return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size() || annotations.size(); } }; @@ -141,12 +143,15 @@ class EditorHelpSearch::Runner : public RefCounted { bool _phase_member_items(); bool _phase_select_match(); + String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const; + bool _match_string(const String &p_term, const String &p_string) const; void _match_item(TreeItem *p_item, const String &p_text); TreeItem *_create_class_hierarchy(const ClassMatch &p_match); TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray); TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc); TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc); + TreeItem *_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc); TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc); TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc); TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index bdf1c314f8..77110044ec 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2711,6 +2711,11 @@ void EditorInspector::update_tree() { continue; } + // Hide the "MultiNodeEdit" category for MultiNodeEdit. + if (Object::cast_to<MultiNodeEdit>(object) && p.name == "MultiNodeEdit") { + continue; + } + // Iterate over remaining properties. If no properties in category, skip the category. List<PropertyInfo>::Element *N = E_property->next(); bool valid = true; @@ -2819,6 +2824,11 @@ void EditorInspector::update_tree() { continue; } + if (p.name.begins_with("metadata/") && bool(object->call("_hide_metadata_from_inspector"))) { + // Hide metadata from inspector if required. + continue; + } + // Get the path for property. String path = p.name; @@ -3089,6 +3099,8 @@ void EditorInspector::update_tree() { StringName classname = doc_name == "" ? object->get_class_name() : doc_name; if (!object_class.is_empty()) { classname = object_class; + } else if (Object::cast_to<MultiNodeEdit>(object)) { + classname = Object::cast_to<MultiNodeEdit>(object)->get_edited_class_name(); } StringName propname = property_prefix + p.name; @@ -3242,7 +3254,7 @@ void EditorInspector::update_tree() { } } - if (!hide_metadata) { + if (!hide_metadata && !object->call("_hide_metadata_from_inspector")) { // Add 4px of spacing between the "Add Metadata" button and the content above it. Control *spacer = memnew(Control); spacer->set_custom_minimum_size(Size2(0, 4) * EDSCALE); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 58377eef0f..7a7576b241 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -762,11 +762,8 @@ void EditorNode::_notification(int p_what) { gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles"))); scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles"))); - bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); - + bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles"))); tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))); - scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles"))); - scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles"))); main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); } @@ -5475,7 +5472,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { // This is the debug panel which uses tabs, so the top section should be smaller. bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), SNAME("EditorStyles"))); } else { - bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles"))); } center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE); center_split->set_collapsed(false); @@ -5485,7 +5482,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { bottom_panel_raise->show(); } else { - bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles"))); bottom_panel_items[p_idx].button->set_pressed(false); bottom_panel_items[p_idx].control->set_visible(false); center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN); @@ -6528,8 +6525,6 @@ EditorNode::EditorNode() { tabbar_panel->add_child(tabbar_container); scene_tabs = memnew(TabBar); - scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles"))); - scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles"))); scene_tabs->set_select_with_rmb(true); scene_tabs->add_tab("unsaved"); scene_tabs->set_tab_close_display_policy((TabBar::CloseButtonDisplayPolicy)EDITOR_GET("interface/scene_tabs/display_close_button").operator int()); @@ -7093,7 +7088,7 @@ EditorNode::EditorNode() { // Bottom panels. bottom_panel = memnew(PanelContainer); - bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles"))); center_split->add_child(bottom_panel); center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index a8f8f7ab97..d1f41dad84 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -33,6 +33,7 @@ #include "editor/editor_data.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/multi_node_edit.h" void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) { if (p_depth > 8) { @@ -121,14 +122,22 @@ void EditorPath::update_path() { continue; } - Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj); + Ref<Texture2D> icon; + if (Object::cast_to<MultiNodeEdit>(obj)) { + icon = EditorNode::get_singleton()->get_class_icon(Object::cast_to<MultiNodeEdit>(obj)->get_edited_class_name()); + } else { + icon = EditorNode::get_singleton()->get_object_icon(obj); + } + if (icon.is_valid()) { current_object_icon->set_texture(icon); } if (i == history->get_path_size() - 1) { String name; - if (Object::cast_to<Resource>(obj)) { + if (obj->has_method("_get_editor_name")) { + name = obj->call("_get_editor_name"); + } else if (Object::cast_to<Resource>(obj)) { Resource *r = Object::cast_to<Resource>(obj); if (r->get_path().is_resource_file()) { name = r->get_path().get_file(); @@ -149,7 +158,7 @@ void EditorPath::update_path() { name = obj->get_class(); } - current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon. + current_object_label->set_text(name); set_tooltip_text(obj->get_class()); } } @@ -161,12 +170,12 @@ void EditorPath::clear_path() { current_object_label->set_text(""); current_object_icon->set_texture(nullptr); - sub_objects_icon->set_visible(false); + sub_objects_icon->hide(); } void EditorPath::enable_path() { set_disabled(false); - sub_objects_icon->set_visible(true); + sub_objects_icon->show(); } void EditorPath::_id_pressed(int p_idx) { @@ -186,7 +195,7 @@ void EditorPath::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { update_path(); - sub_objects_icon->set_texture(get_theme_icon(SNAME("select_arrow"), SNAME("Tree"))); + sub_objects_icon->set_texture(get_theme_icon(SNAME("arrow"), SNAME("OptionButton"))); current_object_label->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts"))); } break; @@ -216,13 +225,12 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) { main_hb->add_child(current_object_icon); current_object_label = memnew(Label); - current_object_label->set_clip_text(true); - current_object_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT); + current_object_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); current_object_label->set_h_size_flags(SIZE_EXPAND_FILL); main_hb->add_child(current_object_label); sub_objects_icon = memnew(TextureRect); - sub_objects_icon->set_visible(false); + sub_objects_icon->hide(); sub_objects_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); main_hb->add_child(sub_objects_icon); diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index 82aeebe14a..ae61418528 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -151,7 +151,7 @@ class EditorPropertyDictionary : public EditorProperty { Button *edit = nullptr; MarginContainer *container = nullptr; VBoxContainer *property_vbox = nullptr; - EditorSpinSlider *size_sliderv; + EditorSpinSlider *size_sliderv = nullptr; Button *button_add_item = nullptr; EditorPaginator *paginator = nullptr; diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 33632649c8..58020cf682 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -42,7 +42,7 @@ String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const { #else Key key = Key::CTRL; #endif - return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers. Hold Shift for more precise changes."), find_keycode_name(key)); + return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers.\nHold Shift for more precise changes."), find_keycode_name(key)); } return TS->format_number(rtos(get_value())); } diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 76d5daadfb..6934c2d13c 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -666,9 +666,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_tab_base->set_corner_radius(CORNER_BOTTOM_LEFT, 0); style_tab_base->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); - // Prevent visible artifacts and cover the top-left rounded corner of the panel below the tab if selected - // We can't prevent them with both rounded corners and non-zero border width, though - style_tab_base->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width); // When using a border width greater than 0, visually line up the left of the selected tab with the underlying panel. style_tab_base->set_expand_margin_size(SIDE_LEFT, -border_width); @@ -1209,17 +1206,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "ItemList", font_color); theme->set_color("font_selected_color", "ItemList", mono_color); theme->set_color("guide_color", "ItemList", guide_color); - theme->set_constant("v_separation", "ItemList", widget_default_margin.y - EDSCALE); + theme->set_constant("v_separation", "ItemList", force_even_vsep * 0.5 * EDSCALE); theme->set_constant("h_separation", "ItemList", 6 * EDSCALE); theme->set_constant("icon_margin", "ItemList", 6 * EDSCALE); theme->set_constant("line_separation", "ItemList", 3 * EDSCALE); // TabBar & TabContainer - Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(dark_color_1, 0, 0, 0, 0); - style_tabbar_background->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width); - style_tabbar_background->set_corner_detail(corner_width); - style_tabbar_background->set_corner_radius(CORNER_TOP_LEFT, corner_radius * EDSCALE); - style_tabbar_background->set_corner_radius(CORNER_TOP_RIGHT, corner_radius * EDSCALE); + Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(dark_color_1, 0, 0, 0, 0, corner_radius * EDSCALE); + style_tabbar_background->set_corner_radius(CORNER_BOTTOM_LEFT, 0); + style_tabbar_background->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); theme->set_stylebox("tabbar_background", "TabContainer", style_tabbar_background); theme->set_stylebox("tab_selected", "TabContainer", style_tab_selected); @@ -1230,8 +1225,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("tab_disabled", "TabBar", style_tab_disabled); theme->set_stylebox("button_pressed", "TabBar", style_menu); theme->set_stylebox("button_highlight", "TabBar", style_menu); - theme->set_stylebox("SceneTabFG", "EditorStyles", style_tab_selected); - theme->set_stylebox("SceneTabBG", "EditorStyles", style_tab_unselected); theme->set_color("font_selected_color", "TabContainer", font_color); theme->set_color("font_unselected_color", "TabContainer", font_disabled_color); theme->set_color("font_selected_color", "TabBar", font_color); @@ -1251,22 +1244,28 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("decrement_highlight", "TabContainer", theme->get_icon(SNAME("GuiScrollArrowLeftHl"), SNAME("EditorIcons"))); theme->set_icon("drop_mark", "TabContainer", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons"))); theme->set_icon("drop_mark", "TabBar", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons"))); + theme->set_constant("side_margin", "TabContainer", 0); theme->set_constant("h_separation", "TabBar", 4 * EDSCALE); - // Content of each tab + // Content of each tab. Ref<StyleBoxFlat> style_content_panel = style_default->duplicate(); style_content_panel->set_border_color(dark_color_3); style_content_panel->set_border_width_all(border_width); style_content_panel->set_border_width(Side::SIDE_TOP, 0); style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0); style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0); - // compensate the border + // Compensate for the border. style_content_panel->set_default_margin(SIDE_TOP, (2 + margin_size_extra) * EDSCALE); style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE); style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE); style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE); theme->set_stylebox("panel", "TabContainer", style_content_panel); + // Bottom panel. + Ref<StyleBoxFlat> style_bottom_panel = style_content_panel->duplicate(); + style_bottom_panel->set_corner_radius_all(corner_radius * EDSCALE); + theme->set_stylebox("BottomPanel", "EditorStyles", style_bottom_panel); + // TabContainerOdd can be used on tabs against the base color background (e.g. nested tabs). theme->set_type_variation("TabContainerOdd", "TabContainer"); @@ -1345,7 +1344,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("normal", "TextEdit", style_line_edit); theme->set_stylebox("focus", "TextEdit", style_widget_focus); theme->set_stylebox("read_only", "TextEdit", style_line_edit_disabled); - theme->set_constant("side_margin", "TabContainer", 0); theme->set_icon("tab", "TextEdit", theme->get_icon(SNAME("GuiTab"), SNAME("EditorIcons"))); theme->set_icon("space", "TextEdit", theme->get_icon(SNAME("GuiSpace"), SNAME("EditorIcons"))); theme->set_color("font_color", "TextEdit", font_color); diff --git a/editor/icons/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg new file mode 100644 index 0000000000..c73ebf7b9b --- /dev/null +++ b/editor/icons/MemberAnnotation.svg @@ -0,0 +1 @@ +<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg> diff --git a/editor/icons/SceneUniqueName.svg b/editor/icons/SceneUniqueName.svg index 34279a14a6..c8aca7b3e6 100644 --- a/editor/icons/SceneUniqueName.svg +++ b/editor/icons/SceneUniqueName.svg @@ -1 +1,2 @@ -<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218L5.677 13.78H4.442Zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" aria-label="%" style="font-weight:600;font-size:16.0277px;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold';letter-spacing:0;word-spacing:0;fill:#e0e0e0;fill-opacity:.996078;stroke-width:.400692"/></svg> +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218l-6.331 11.684h-1.235zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" fill="#e0e0e0" stroke-width=".400692"/></svg> + diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp index 69c0a047e4..72ccb832c7 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.cpp +++ b/editor/import/post_import_plugin_skeleton_renamer.cpp @@ -143,7 +143,7 @@ void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_ // Make unique skeleton. if (bool(p_options["retarget/bone_renamer/unique_node/make_unique"])) { String unique_name = String(p_options["retarget/bone_renamer/unique_node/skeleton_name"]); - ERR_FAIL_COND_MSG(unique_name == String(), "Skeleton unique name cannot be empty."); + ERR_FAIL_COND_MSG(unique_name.is_empty(), "Skeleton unique name cannot be empty."); TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); while (nodes.size()) { diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp index 6f775c7ea8..a5ef2e7f97 100644 --- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp @@ -90,16 +90,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } } - // Apply node transforms. + // Get global transform. + Transform3D global_transform; if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) { - LocalVector<Transform3D> old_skeleton_rest; - LocalVector<Transform3D> old_skeleton_global_rest; - for (int i = 0; i < src_skeleton->get_bone_count(); i++) { - old_skeleton_rest.push_back(src_skeleton->get_bone_rest(i)); - old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i)); - } - - Transform3D global_transform; Node *pr = src_skeleton; while (pr) { Node3D *pr3d = Object::cast_to<Node3D>(pr); @@ -109,6 +102,47 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } pr = pr->get_parent(); } + global_transform.origin = Vector3(); // Translation by a Node is not a bone animation, so the retargeted model should be at the origin. + } + + // Calc IBM difference. + LocalVector<Vector<Transform3D>> ibm_diffs; + { + TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D"); + while (nodes.size()) { + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back()); + ERR_CONTINUE(!mi); + + Ref<Skin> skin = mi->get_skin(); + ERR_CONTINUE(!skin.is_valid()); + + Node *node = mi->get_node(mi->get_skeleton_path()); + ERR_CONTINUE(!node); + + Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node); + if (!mesh_skeleton || mesh_skeleton != src_skeleton) { + continue; + } + + Vector<Transform3D> ibm_diff; + ibm_diff.resize(src_skeleton->get_bone_count()); + Transform3D *ibm_diff_w = ibm_diff.ptrw(); + + int skin_len = skin->get_bind_count(); + for (int i = 0; i < skin_len; i++) { + StringName bn = skin->get_bind_name(i); + int bone_idx = src_skeleton->find_bone(bn); + if (bone_idx >= 0) { + ibm_diff_w[bone_idx] = global_transform * src_skeleton->get_bone_global_rest(bone_idx) * skin->get_bind_pose(i); + } + } + + ibm_diffs.push_back(ibm_diff); + } + } + + // Apply node transforms. + if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) { Vector3 scl = global_transform.basis.get_scale_local(); Vector<int> bones_to_process = src_skeleton->get_parentless_bones(); @@ -148,38 +182,42 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory String track_path = String(anim->track_get_path(i).get_concatenated_names()); Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); - if (node) { - Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); - if (track_skeleton && track_skeleton == src_skeleton) { - StringName bn = anim->track_get_path(i).get_subname(0); - if (bn) { - int bone_idx = src_skeleton->find_bone(bn); - int key_len = anim->track_get_key_count(i); - if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) { - if (bones_to_process.has(bone_idx)) { - for (int j = 0; j < key_len; j++) { - Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin); - } - } else { - for (int j = 0; j < key_len; j++) { - Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, ps * scl); - } - } - } else if (bones_to_process.has(bone_idx)) { - if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) { - for (int j = 0; j < key_len; j++) { - Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt); - } - } else { - for (int j = 0; j < key_len; j++) { - Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j))); - anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale()); - } - } - } + ERR_CONTINUE(!node); + + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (!track_skeleton || track_skeleton != src_skeleton) { + continue; + } + + StringName bn = anim->track_get_path(i).get_subname(0); + if (!bn) { + continue; + } + + int bone_idx = src_skeleton->find_bone(bn); + int key_len = anim->track_get_key_count(i); + if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) { + if (bones_to_process.has(bone_idx)) { + for (int j = 0; j < key_len; j++) { + Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin); + } + } else { + for (int j = 0; j < key_len; j++) { + Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, ps * scl); + } + } + } else if (bones_to_process.has(bone_idx)) { + if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) { + for (int j = 0; j < key_len; j++) { + Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt); + } + } else { + for (int j = 0; j < key_len; j++) { + Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j))); + anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale()); } } } @@ -220,24 +258,26 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } } - if (found_skeleton) { - // Search and insert rot track if it doesn't exist. - for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) { - String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx))); - if (bone_name == String()) { - continue; - } - int src_idx = src_skeleton->find_bone(bone_name); - if (src_idx == -1) { - continue; - } - String insert_path = track_path + ":" + bone_name; - int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D); - if (rot_track == -1) { - int track = anim->add_track(Animation::TYPE_ROTATION_3D); - anim->track_set_path(track, insert_path); - anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion()); - } + if (!found_skeleton) { + continue; + } + + // Search and insert rot track if it doesn't exist. + for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) { + String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx))); + if (bone_name.is_empty()) { + continue; + } + int src_idx = src_skeleton->find_bone(bone_name); + if (src_idx == -1) { + continue; + } + String insert_path = track_path + ":" + bone_name; + int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D); + if (rot_track == -1) { + int track = anim->add_track(Animation::TYPE_ROTATION_3D); + anim->track_set_path(track, insert_path); + anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion()); } } } @@ -385,19 +425,23 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory String track_path = String(anim->track_get_path(i).get_concatenated_names()); Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); - if (node) { - Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); - if (track_skeleton && track_skeleton == src_skeleton) { - StringName bn = anim->track_get_path(i).get_concatenated_subnames(); - if (bn == scale_base_bone_name) { - int key_len = anim->track_get_key_count(i); - for (int j = 0; j < key_len; j++) { - Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); - pos.y += base_adjustment; - anim->track_set_key_value(i, j, pos); - } - } - } + ERR_CONTINUE(!node); + + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (!track_skeleton || track_skeleton != src_skeleton) { + continue; + } + + StringName bn = anim->track_get_path(i).get_concatenated_subnames(); + if (bn != scale_base_bone_name) { + continue; + } + + int key_len = anim->track_get_key_count(i); + for (int j = 0; j < key_len; j++) { + Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); + pos.y += base_adjustment; + anim->track_set_key_value(i, j, pos); } } } @@ -441,16 +485,18 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory String track_path = String(anim->track_get_path(i).get_concatenated_names()); Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); - if (node) { - Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); - if (track_skeleton && track_skeleton == src_skeleton) { - real_t mlt = 1 / src_skeleton->get_motion_scale(); - int key_len = anim->track_get_key_count(i); - for (int j = 0; j < key_len; j++) { - Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, pos * mlt); - } - } + ERR_CONTINUE(!node); + + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (!track_skeleton || track_skeleton != src_skeleton) { + continue; + } + + real_t mlt = 1 / src_skeleton->get_motion_scale(); + int key_len = anim->track_get_key_count(i); + for (int j = 0; j < key_len; j++) { + Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, pos * mlt); } } } @@ -518,6 +564,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); while (nodes.size()) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back()); + ERR_CONTINUE(!ap); List<StringName> anims; ap->get_animation_list(&anims); for (const StringName &name : anims) { @@ -534,53 +581,57 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory String track_path = String(anim->track_get_path(i).get_concatenated_names()); Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); - if (node) { - Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); - if (track_skeleton && track_skeleton == src_skeleton) { - StringName bn = anim->track_get_path(i).get_subname(0); - if (bn) { - int bone_idx = src_skeleton->find_bone(bn); - - Transform3D old_rest = old_skeleton_rest[bone_idx]; - Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx); - Transform3D old_pg; - Transform3D new_pg; - int parent_idx = src_skeleton->get_bone_parent(bone_idx); - if (parent_idx >= 0) { - old_pg = old_skeleton_global_rest[parent_idx]; - new_pg = src_skeleton->get_bone_global_rest(parent_idx); - } - - int key_len = anim->track_get_key_count(i); - if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) { - Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion(); - Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion(); - Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion(); - Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion(); - for (int j = 0; j < key_len; j++) { - Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q); - } - } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) { - Basis old_rest_b = old_rest.basis; - Basis new_rest_b = new_rest.basis; - Basis old_pg_b = old_pg.basis; - Basis new_pg_b = new_pg.basis; - for (int j = 0; j < key_len; j++) { - Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j))); - anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale()); - } - } else { - Vector3 old_rest_o = old_rest.origin; - Vector3 new_rest_o = new_rest.origin; - Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion(); - Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion(); - for (int j = 0; j < key_len; j++) { - Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o); - } - } - } + ERR_CONTINUE(!node); + + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (!track_skeleton || track_skeleton != src_skeleton) { + continue; + } + + StringName bn = anim->track_get_path(i).get_subname(0); + if (!bn) { + continue; + } + + int bone_idx = src_skeleton->find_bone(bn); + + Transform3D old_rest = old_skeleton_rest[bone_idx]; + Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx); + Transform3D old_pg; + Transform3D new_pg; + int parent_idx = src_skeleton->get_bone_parent(bone_idx); + if (parent_idx >= 0) { + old_pg = old_skeleton_global_rest[parent_idx]; + new_pg = src_skeleton->get_bone_global_rest(parent_idx); + } + + int key_len = anim->track_get_key_count(i); + if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) { + Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion(); + Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion(); + Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion(); + Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion(); + for (int j = 0; j < key_len; j++) { + Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q); + } + } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) { + Basis old_rest_b = old_rest.basis; + Basis new_rest_b = new_rest.basis; + Basis old_pg_b = old_pg.basis; + Basis new_pg_b = new_pg.basis; + for (int j = 0; j < key_len; j++) { + Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j))); + anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale()); + } + } else { + Vector3 old_rest_o = old_rest.origin; + Vector3 new_rest_o = new_rest.origin; + Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion(); + Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion(); + for (int j = 0; j < key_len; j++) { + Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o); } } } @@ -595,26 +646,35 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory // Fix skin. { TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D"); + int skin_idx = 0; while (nodes.size()) { ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back()); + ERR_CONTINUE(!mi); + Ref<Skin> skin = mi->get_skin(); - if (skin.is_valid()) { - Node *node = mi->get_node(mi->get_skeleton_path()); - if (node) { - Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node); - if (mesh_skeleton && node == src_skeleton) { - int skin_len = skin->get_bind_count(); - for (int i = 0; i < skin_len; i++) { - StringName bn = skin->get_bind_name(i); - int bone_idx = src_skeleton->find_bone(bn); - if (bone_idx >= 0) { - Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx); - skin->set_bind_pose(i, new_rest.inverse()); - } - } - } + ERR_CONTINUE(!skin.is_valid()); + + Node *node = mi->get_node(mi->get_skeleton_path()); + ERR_CONTINUE(!node); + + Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node); + if (!mesh_skeleton || mesh_skeleton != src_skeleton) { + continue; + } + + Vector<Transform3D> ibm_diff = ibm_diffs[skin_idx]; + + int skin_len = skin->get_bind_count(); + for (int i = 0; i < skin_len; i++) { + StringName bn = skin->get_bind_name(i); + int bone_idx = src_skeleton->find_bone(bn); + if (bone_idx >= 0) { + Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx); + skin->set_bind_pose(i, new_rest.inverse() * ibm_diff[bone_idx]); } } + + skin_idx++; } } diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h index 104a7a9f7e..0e12a83116 100644 --- a/editor/import/scene_import_settings.h +++ b/editor/import/scene_import_settings.h @@ -192,7 +192,7 @@ class SceneImportSettings : public ConfirmationDialog { bool editing_animation = false; - Timer *update_view_timer; + Timer *update_view_timer = nullptr; protected: void _notification(int p_what); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 7af04e17c1..74fdbdebd7 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -311,7 +311,6 @@ void InspectorDock::_prepare_history() { history_menu->get_popup()->clear(); - Ref<Texture2D> base_icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons")); HashSet<ObjectID> already; for (int i = editor_history->get_history_len() - 1; i >= history_to; i--) { ObjectID id = editor_history->get_history_obj(i); @@ -325,13 +324,12 @@ void InspectorDock::_prepare_history() { already.insert(id); - Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj, ""); - if (icon.is_null()) { - icon = base_icon; - } + Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj, "Object"); String text; - if (Object::cast_to<Resource>(obj)) { + if (obj->has_method("_get_editor_name")) { + text = obj->call("_get_editor_name"); + } else if (Object::cast_to<Resource>(obj)) { Resource *r = Object::cast_to<Resource>(obj); if (r->get_path().is_resource_file()) { text = r->get_path().get_file(); @@ -349,14 +347,14 @@ void InspectorDock::_prepare_history() { } if (i == editor_history->get_history_pos() && current) { - text = "[" + text + "]"; + text += " " + TTR("(Current)"); } history_menu->get_popup()->add_icon_item(icon, text, i); } } void InspectorDock::_select_history(int p_idx) { - //push it to the top, it is not correct, but it's more useful + // Push it to the top, it is not correct, but it's more useful. ObjectID id = EditorNode::get_singleton()->get_editor_selection_history()->get_history_obj(p_idx); Object *obj = ObjectDB::get_instance(id); if (!obj) { diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index 70cc54668d..a386fba84d 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -46,7 +46,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, String name = p_name; - if (name == "scripts") { // script set is intercepted at object level (check Variant Object::get() ) ,so use a different name + if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name. name = "script"; } @@ -57,13 +57,9 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); - ur->create_action(TTR("MultiNode Set") + " " + String(name), UndoRedo::MERGE_ENDS); + ur->create_action(vformat(TTR("Set %s on %d nodes"), name, get_node_count()), UndoRedo::MERGE_ENDS); for (const NodePath &E : nodes) { - if (!es->has_node(E)) { - continue; - } - - Node *n = es->get_node(E); + Node *n = es->get_node_or_null(E); if (!n) { continue; } @@ -100,16 +96,12 @@ bool MultiNodeEdit::_get(const StringName &p_name, Variant &r_ret) const { } String name = p_name; - if (name == "scripts") { // script set is intercepted at object level (check Variant Object::get() ) ,so use a different name + if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name. name = "script"; } for (const NodePath &E : nodes) { - if (!es->has_node(E)) { - continue; - } - - const Node *n = es->get_node(E); + const Node *n = es->get_node_or_null(E); if (!n) { continue; } @@ -137,11 +129,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { List<PLData *> data_list; for (const NodePath &E : nodes) { - if (!es->has_node(E)) { - continue; - } - - Node *n = es->get_node(E); + Node *n = es->get_node_or_null(E); if (!n) { continue; } @@ -151,7 +139,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { for (const PropertyInfo &F : plist) { if (F.name == "script") { - continue; //added later manually, since this is intercepted before being set (check Variant Object::get() ) + continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()). } if (!usage.has(F.name)) { PLData pld; @@ -161,7 +149,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { data_list.push_back(usage.getptr(F.name)); } - // Make sure only properties with the same exact PropertyInfo data will appear + // Make sure only properties with the same exact PropertyInfo data will appear. if (usage[F.name].info == F) { usage[F.name].uses++; } @@ -179,6 +167,66 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, "scripts", PROPERTY_HINT_RESOURCE_TYPE, "Script")); } +String MultiNodeEdit::_get_editor_name() const { + return vformat(TTR("%s (%d Selected)"), get_edited_class_name(), get_node_count()); +} + +bool MultiNodeEdit::_property_can_revert(const StringName &p_name) const { + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) { + return false; + } + + if (ClassDB::has_property(get_edited_class_name(), p_name)) { + StringName class_name; + for (const NodePath &E : nodes) { + Node *node = es->get_node_or_null(E); + if (!node) { + continue; + } + + class_name = node->get_class_name(); + } + + Variant default_value = ClassDB::class_get_default_property_value(class_name, p_name); + for (const NodePath &E : nodes) { + Node *node = es->get_node_or_null(E); + if (!node) { + continue; + } + + if (node->get(p_name) != default_value) { + // A node that doesn't have the default value has been found, so show the revert button. + return true; + } + } + + return false; + } + + // Don't show the revert button if the edited class doesn't have the property. + return false; +} + +bool MultiNodeEdit::_property_get_revert(const StringName &p_name, Variant &r_property) const { + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) { + return false; + } + + for (const NodePath &E : nodes) { + Node *node = es->get_node_or_null(E); + if (!node) { + continue; + } + + r_property = ClassDB::class_get_default_property_value(node->get_class_name(), p_name); + return true; + } + + return false; +} + void MultiNodeEdit::add_node(const NodePath &p_node) { nodes.push_back(p_node); } @@ -192,9 +240,69 @@ NodePath MultiNodeEdit::get_node(int p_index) const { return nodes[p_index]; } +StringName MultiNodeEdit::get_edited_class_name() const { + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) { + return SNAME("Node"); + } + + // Get the class name of the first node. + StringName class_name; + for (const NodePath &E : nodes) { + Node *node = es->get_node_or_null(E); + if (!node) { + continue; + } + + class_name = node->get_class_name(); + break; + } + + if (class_name == StringName()) { + return SNAME("Node"); + } + + bool check_again = true; + while (check_again) { + check_again = false; + + if (class_name == SNAME("Node") || class_name == StringName()) { + // All nodes inherit from Node, so no need to continue checking. + return SNAME("Node"); + } + + // Check that all nodes inherit from class_name. + for (const NodePath &E : nodes) { + Node *node = es->get_node_or_null(E); + if (!node) { + continue; + } + + const StringName node_class_name = node->get_class_name(); + if (class_name == node_class_name || ClassDB::is_parent_class(node_class_name, class_name)) { + // class_name is the same or a parent of the node's class. + continue; + } + + // class_name is not a parent of the node's class, so check again with the parent class. + class_name = ClassDB::get_parent_class(class_name); + check_again = true; + break; + } + } + + return class_name; +} + void MultiNodeEdit::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) { _set_impl(p_property, p_value, p_field); } +void MultiNodeEdit::_bind_methods() { + ClassDB::bind_method("_hide_script_from_inspector", &MultiNodeEdit::_hide_script_from_inspector); + ClassDB::bind_method("_hide_metadata_from_inspector", &MultiNodeEdit::_hide_metadata_from_inspector); + ClassDB::bind_method("_get_editor_name", &MultiNodeEdit::_get_editor_name); +} + MultiNodeEdit::MultiNodeEdit() { } diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h index 31678d7b01..9c0ec85e20 100644 --- a/editor/multi_node_edit.h +++ b/editor/multi_node_edit.h @@ -45,15 +45,25 @@ class MultiNodeEdit : public RefCounted { bool _set_impl(const StringName &p_name, const Variant &p_value, const String &p_field); protected: + static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; public: + bool _hide_script_from_inspector() { return true; } + bool _hide_metadata_from_inspector() { return true; } + + bool _property_can_revert(const StringName &p_name) const; + bool _property_get_revert(const StringName &p_name, Variant &r_property) const; + String _get_editor_name() const; + void add_node(const NodePath &p_node); int get_node_count() const; NodePath get_node(int p_index) const; + StringName get_edited_class_name() const; void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 2809eb01cd..6baeaf6273 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -267,6 +267,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected connecting = true; + connection_follows_cursor = true; connecting_from = node_rects[i].node_name; connecting_to = mb->get_position(); connecting_to_node = StringName(); @@ -296,6 +297,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv _open_menu(mb->get_position()); } connecting_to_node = StringName(); + connection_follows_cursor = false; state_machine_draw->queue_redraw(); } @@ -332,7 +334,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } // Move mouse while connecting - if (mm.is_valid() && connecting && !read_only) { + if (mm.is_valid() && connecting && connection_follows_cursor && !read_only) { connecting_to = mm->get_position(); connecting_to_node = StringName(); state_machine_draw->queue_redraw(); @@ -1023,11 +1025,9 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { } updating = true; - undo_redo->create_action(TTR("Add Node")); + undo_redo->create_action(TTR("Add Node and Transition")); undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos); undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); connecting_to_node = name; _add_transition(true); undo_redo->commit_action(); @@ -1051,11 +1051,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { } updating = true; - undo_redo->create_action(TTR("Add Node")); + undo_redo->create_action(TTR("Add Node and Transition")); undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos); undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); connecting_to_node = name; _add_transition(true); undo_redo->commit_action(); @@ -1083,16 +1081,16 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action if (!p_nested_action) { updating = true; + undo_redo->create_action(TTR("Add Transition")); } - undo_redo->create_action(TTR("Add Transition")); undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr); undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); if (!p_nested_action) { + undo_redo->commit_action(); updating = false; } diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 3a59e94a5f..d0828a5f52 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -100,8 +100,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { Vector2 add_node_pos; - ConfirmationDialog *delete_window; - Tree *delete_tree; + ConfirmationDialog *delete_window = nullptr; + Tree *delete_tree = nullptr; bool box_selecting = false; Point2 box_selecting_from; @@ -117,6 +117,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { StringName snap_y; bool connecting = false; + bool connection_follows_cursor = false; StringName connecting_from; Vector2 connecting_to; StringName connecting_to_node; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 41383edafe..6bc443039f 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -591,10 +591,12 @@ void EditorAssetLibrary::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { +#ifndef ANDROID_ENABLED // Focus the search box automatically when switching to the Templates tab (in the Project Manager) // or switching to the AssetLib tab (in the editor). // The Project Manager's project filter box is automatically focused in the project manager code. filter->grab_focus(); +#endif if (initial_loading) { _repository_changed(0); // Update when shown for the first time. diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index 0541ce6eac..55261ab477 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -62,7 +62,7 @@ private: bool selected = false; bool require = false; - TextureRect *circle; + TextureRect *circle = nullptr; void fetch_textures(); @@ -87,8 +87,8 @@ class BoneMapperItem : public VBoxContainer { Ref<BoneMap> bone_map; - EditorPropertyText *skeleton_bone_selector; - Button *picker_button; + EditorPropertyText *skeleton_bone_selector = nullptr; + Button *picker_button = nullptr; void _update_property(); void _open_picker(); @@ -135,24 +135,24 @@ public: class BoneMapper : public VBoxContainer { GDCLASS(BoneMapper, VBoxContainer); - Skeleton3D *skeleton; + Skeleton3D *skeleton = nullptr; Ref<BoneMap> bone_map; - EditorPropertyResource *profile_selector; + EditorPropertyResource *profile_selector = nullptr; Vector<BoneMapperItem *> bone_mapper_items; - Button *clear_mapping_button; + Button *clear_mapping_button = nullptr; - VBoxContainer *mapper_item_vbox; + VBoxContainer *mapper_item_vbox = nullptr; int current_group_idx = 0; int current_bone_idx = -1; - AspectRatioContainer *bone_mapper_field; - EditorPropertyEnum *profile_group_selector; - ColorRect *profile_bg; - TextureRect *profile_texture; + AspectRatioContainer *bone_mapper_field = nullptr; + EditorPropertyEnum *profile_group_selector = nullptr; + ColorRect *profile_bg = nullptr; + TextureRect *profile_texture = nullptr; Vector<BoneMapperButton *> bone_mapper_buttons; void create_editor(); @@ -201,9 +201,9 @@ public: class BoneMapEditor : public VBoxContainer { GDCLASS(BoneMapEditor, VBoxContainer); - Skeleton3D *skeleton; + Skeleton3D *skeleton = nullptr; Ref<BoneMap> bone_map; - BoneMapper *bone_mapper; + BoneMapper *bone_mapper = nullptr; void fetch_objects(); void clear_editors(); @@ -219,7 +219,7 @@ public: class EditorInspectorPluginBoneMap : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginBoneMap, EditorInspectorPlugin); - BoneMapEditor *editor; + BoneMapEditor *editor = nullptr; public: virtual bool can_handle(Object *p_object) override; diff --git a/editor/plugins/cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h index 85ff497bc7..ceed9b9111 100644 --- a/editor/plugins/cast_2d_editor_plugin.h +++ b/editor/plugins/cast_2d_editor_plugin.h @@ -42,7 +42,7 @@ class Cast2DEditor : public Control { Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; - Node2D *node; + Node2D *node = nullptr; bool pressed = false; Point2 original_target_position; diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h index 584d05aab0..22267cbc04 100644 --- a/editor/plugins/control_editor_plugin.h +++ b/editor/plugins/control_editor_plugin.h @@ -186,7 +186,7 @@ public: class SizeFlagPresetPicker : public ControlEditorPresetPicker { GDCLASS(SizeFlagPresetPicker, ControlEditorPresetPicker); - CheckBox *expand_button; + CheckBox *expand_button = nullptr; bool vertical = false; diff --git a/editor/plugins/navigation_link_2d_editor_plugin.h b/editor/plugins/navigation_link_2d_editor_plugin.h index 1c1251bec7..0a3d9b8810 100644 --- a/editor/plugins/navigation_link_2d_editor_plugin.h +++ b/editor/plugins/navigation_link_2d_editor_plugin.h @@ -42,7 +42,7 @@ class NavigationLink2DEditor : public Control { Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; - NavigationLink2D *node; + NavigationLink2D *node = nullptr; bool start_grabbed = false; Vector2 original_start_location; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index fff956a05e..cc955eae76 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -340,7 +340,9 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) { } if (editor_enabled) { +#ifndef ANDROID_ENABLED ensure_focus(); +#endif } } diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 15ae4ffcff..1facf04ca7 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -852,6 +852,20 @@ void Skeleton3DEditor::_notification(int p_what) { update_joint_tree(); } break; + case NOTIFICATION_PREDELETE: { + if (skeleton) { + select_bone(-1); // Requires that the joint_tree has not been deleted. +#ifdef TOOLS_ENABLED + skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); + skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); + skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); + skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties)); + skeleton->set_transform_gizmo_visible(true); +#endif + handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance); + } + edit_mode_toggled(false); + } break; } } @@ -1066,18 +1080,7 @@ void Skeleton3DEditor::select_bone(int p_idx) { } Skeleton3DEditor::~Skeleton3DEditor() { - if (skeleton) { - select_bone(-1); -#ifdef TOOLS_ENABLED - skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); - skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); - skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); - skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties)); - skeleton->set_transform_gizmo_visible(true); -#endif - handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance); - } - edit_mode_toggled(false); + singleton = nullptr; handles_mesh_instance->queue_delete(); @@ -1128,7 +1131,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin() { EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); Node3DEditor *ne = Node3DEditor::get_singleton(); - if (se->is_edit_mode()) { + if (se && se->is_edit_mode()) { const Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) { diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index ed8c7b14c8..a5f6d3f142 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1901,11 +1901,13 @@ void ProjectManager::_notification(int p_what) { filter_option->select(default_sorting); _project_list->set_order_option(default_sorting); +#ifndef ANDROID_ENABLED if (_project_list->get_project_count() >= 1) { // Focus on the search box immediately to allow the user // to search without having to reach for their mouse search_box->grab_focus(); } +#endif if (asset_library) { // Removes extra border margins. @@ -2443,6 +2445,7 @@ void ProjectManager::_on_order_option_changed(int p_idx) { } void ProjectManager::_on_tab_changed(int p_tab) { +#ifndef ANDROID_ENABLED if (p_tab == 0) { // Projects // Automatically grab focus when the user moves from the Templates tab // back to the Projects tab. @@ -2451,6 +2454,7 @@ void ProjectManager::_on_tab_changed(int p_tab) { // The Templates tab's search field is focused on display in the asset // library editor plugin code. +#endif } void ProjectManager::_on_search_term_changed(const String &p_term) { diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index c120468ecb..50bb6496e1 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -387,17 +387,18 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { Ref<Script> script = p_node->get_script(); if (!script.is_null()) { String additional_notes; + Color button_color = Color(1, 1, 1); // Can't set tooltip after adding button, need to do it before. if (script->is_tool()) { additional_notes += "\n" + TTR("This script is currently running in the editor."); + button_color = get_theme_color(SNAME("accent_color"), SNAME("Editor")); } - item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes); if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) { - item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5)); - } - if (script->is_tool()) { - item->set_button_color(0, item->get_button_count(0) - 1, get_theme_color(SNAME("accent_color"), SNAME("Editor"))); + additional_notes += "\n" + TTR("This script is a custom type."); + button_color.a = 0.5; } + item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes); + item->set_button_color(0, item->get_button_count(0) - 1, button_color); } if (p_node->is_class("CanvasItem")) { |