diff options
Diffstat (limited to 'editor')
64 files changed, 1368 insertions, 759 deletions
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index ae54c20fe2..146b5a794c 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -198,6 +198,14 @@ void ActionMapEditor::_tree_button_pressed(Object *p_item, int p_column, int p_i emit_signal(SNAME("action_edited"), action_name, action); } break; + case ActionMapEditor::BUTTON_REVERT_ACTION: { + ERR_FAIL_COND_MSG(!item->has_meta("__action_initial"), "Tree Item for action which can be reverted is expected to have meta value with initial value of action."); + + Dictionary action = item->get_meta("__action_initial").duplicate(); + String action_name = item->get_meta("__name"); + + emit_signal(SNAME("action_edited"), action_name, action); + } break; default: break; } @@ -427,6 +435,13 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info action_item->set_range(1, deadzone); // Third column - buttons + if (action_info.has_initial) { + bool deadzone_eq = action_info.action_initial["deadzone"] == action_info.action["deadzone"]; + bool events_eq = Shortcut::is_event_array_equal(action_info.action_initial["events"], action_info.action["events"]); + bool action_eq = deadzone_eq && events_eq; + action_item->set_meta("__action_initial", action_info.action_initial); + action_item->add_button(2, action_tree->get_theme_icon(SNAME("ReloadSmall"), SNAME("EditorIcons")), BUTTON_REVERT_ACTION, action_eq, action_eq ? TTR("Cannot Revert - Action is same as initial") : TTR("Revert Action")); + } action_item->add_button(2, action_tree->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), BUTTON_ADD_EVENT, false, TTR("Add Event")); action_item->add_button(2, action_tree->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_ACTION, !action_info.editable, action_info.editable ? TTR("Remove Action") : TTR("Cannot Remove Action")); diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h index 433a72a807..2848d23e83 100644 --- a/editor/action_map_editor.h +++ b/editor/action_map_editor.h @@ -49,6 +49,8 @@ public: struct ActionInfo { String name; Dictionary action; + bool has_initial = false; + Dictionary action_initial; Ref<Texture2D> icon = Ref<Texture2D>(); bool editable = true; @@ -60,6 +62,7 @@ private: BUTTON_EDIT_EVENT, BUTTON_REMOVE_ACTION, BUTTON_REMOVE_EVENT, + BUTTON_REVERT_ACTION, }; Vector<ActionInfo> actions_cache; diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 338a22c070..8dd087451c 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1954,6 +1954,10 @@ void AnimationTrackEdit::_notification(int p_what) { get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")) }; + Ref<Texture2D> blend_icon[2] = { + get_theme_icon(SNAME("UseBlendEnable"), SNAME("EditorIcons")), + get_theme_icon(SNAME("UseBlendDisable"), SNAME("EditorIcons")), + }; int ofs = get_size().width - timeline->get_buttons_width(); @@ -1982,6 +1986,11 @@ void AnimationTrackEdit::_notification(int p_what) { if (!animation->track_is_compressed(track) && animation->track_get_type(track) == Animation::TYPE_VALUE) { draw_texture(update_icon, update_mode_rect.position); } + if (animation->track_get_type(track) == Animation::TYPE_AUDIO) { + Ref<Texture2D> use_blend_icon = blend_icon[animation->audio_track_is_use_blend(track) ? 0 : 1]; + Vector2 use_blend_icon_pos = update_mode_rect.position + (update_mode_rect.size - use_blend_icon->get_size()) / 2; + draw_texture(use_blend_icon, use_blend_icon_pos); + } // Make it easier to click. update_mode_rect.position.y = 0; update_mode_rect.size.y = get_size().height; @@ -1990,13 +1999,12 @@ void AnimationTrackEdit::_notification(int p_what) { update_mode_rect.size.x += hsep / 2; if (!read_only) { - if (animation->track_get_type(track) == Animation::TYPE_VALUE) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_AUDIO) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); update_mode_rect.size.x += down_icon->get_width(); } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) { Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")); update_mode_rect.size.x += down_icon->get_width(); - update_mode_rect = Rect2(); } else { update_mode_rect = Rect2(); @@ -2439,7 +2447,11 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { } if (update_mode_rect.has_point(p_pos)) { - return TTR("Update Mode (How this property is set)"); + if (animation->track_get_type(track) == Animation::TYPE_AUDIO) { + return TTR("Use Blend"); + } else { + return TTR("Update Mode (How this property is set)"); + } } if (interp_mode_rect.has_point(p_pos)) { @@ -2641,9 +2653,14 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); } menu->clear(); - menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS); - menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE); - menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE); + if (animation->track_get_type(track) == Animation::TYPE_AUDIO) { + menu->add_icon_item(get_theme_icon(SNAME("UseBlendEnable"), SNAME("EditorIcons")), TTR("Use Blend"), MENU_USE_BLEND_ENABLED); + menu->add_icon_item(get_theme_icon(SNAME("UseBlendDisable"), SNAME("EditorIcons")), TTR("Don't Use Blend"), MENU_USE_BLEND_DISABLED); + } else { + menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS); + menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE); + menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE); + } menu->reset_size(); Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height); @@ -2662,7 +2679,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR); menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC); - // Check is angle property. + // Check whether it is angle property. AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton(); if (ape) { AnimationPlayer *ap = ape->get_player(); @@ -3055,6 +3072,16 @@ void AnimationTrackEdit::_menu_selected(int p_index) { emit_signal(SNAME("delete_request")); } break; + case MENU_USE_BLEND_ENABLED: + case MENU_USE_BLEND_DISABLED: { + bool use_blend = p_index == MENU_USE_BLEND_ENABLED; + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Change Animation Use Blend")); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_use_blend", track, use_blend); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_use_blend", track, animation->audio_track_is_use_blend(track)); + undo_redo->commit_action(); + queue_redraw(); + } break; } } @@ -3488,6 +3515,9 @@ void AnimationTrackEditor::_animation_track_remove_request(int p_track, Ref<Anim if (p_from_animation->track_get_type(idx) == Animation::TYPE_VALUE) { undo_redo->add_undo_method(p_from_animation.ptr(), "value_track_set_update_mode", idx, p_from_animation->value_track_get_update_mode(idx)); } + if (animation->track_get_type(idx) == Animation::TYPE_AUDIO) { + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_use_blend", idx, animation->audio_track_is_use_blend(idx)); + } undo_redo->commit_action(); } @@ -5618,6 +5648,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { if (tc.track_type == Animation::TYPE_VALUE) { tc.update_mode = animation->value_track_get_update_mode(idx); } + if (tc.track_type == Animation::TYPE_AUDIO) { + tc.use_blend = animation->audio_track_is_use_blend(idx); + } tc.loop_wrap = animation->track_get_interpolation_loop_wrap(idx); tc.enabled = animation->track_is_enabled(idx); for (int i = 0; i < animation->track_get_key_count(idx); i++) { @@ -5662,6 +5695,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { if (track_clipboard[i].track_type == Animation::TYPE_VALUE) { undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", base_track, track_clipboard[i].update_mode); } + if (track_clipboard[i].track_type == Animation::TYPE_AUDIO) { + undo_redo->add_do_method(animation.ptr(), "audio_track_set_use_blend", base_track, track_clipboard[i].use_blend); + } for (int j = 0; j < track_clipboard[i].keys.size(); j++) { undo_redo->add_do_method(animation.ptr(), "track_insert_key", base_track, track_clipboard[i].keys[j].time, track_clipboard[i].keys[j].value, track_clipboard[i].keys[j].transition); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 8506d9b80d..2a59bda2a4 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -220,7 +220,9 @@ class AnimationTrackEdit : public Control { MENU_KEY_INSERT, MENU_KEY_DUPLICATE, MENU_KEY_ADD_RESET, - MENU_KEY_DELETE + MENU_KEY_DELETE, + MENU_USE_BLEND_ENABLED, + MENU_USE_BLEND_DISABLED, }; AnimationTimelineEdit *timeline = nullptr; @@ -566,6 +568,7 @@ class AnimationTrackEditor : public VBoxContainer { Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG; bool loop_wrap = false; bool enabled = false; + bool use_blend = false; struct Key { float time = 0; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 644735a4d8..28d687488c 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -143,7 +143,9 @@ void FindReplaceBar::unhandled_input(const Ref<InputEvent> &p_event) { } bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) { - text_editor->remove_secondary_carets(); + if (!preserve_cursor) { + text_editor->remove_secondary_carets(); + } String text = get_search_text(); Point2i pos = text_editor->search(text, p_flags, p_from_line, p_from_col); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index db12dbc72b..aaa07e98c8 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -186,7 +186,7 @@ void ConnectDialog::_unbind_count_changed(double p_count) { void ConnectDialog::_method_selected() { TreeItem *selected_item = method_tree->get_selected(); - dst_method->set_text(selected_item->get_text(0)); + dst_method->set_text(selected_item->get_metadata(0)); } /* @@ -260,12 +260,8 @@ StringName ConnectDialog::generate_method_callback_name(Node *p_source, String p void ConnectDialog::_create_method_tree_items(const List<MethodInfo> &p_methods, TreeItem *p_parent_item) { for (const MethodInfo &mi : p_methods) { TreeItem *method_item = method_tree->create_item(p_parent_item); - method_item->set_text(0, mi.name); - if (mi.return_val.type == Variant::NIL) { - method_item->set_icon(0, get_theme_icon(SNAME("Variant"), "EditorIcons")); - } else { - method_item->set_icon(0, get_theme_icon(Variant::get_type_name(mi.return_val.type), "EditorIcons")); - } + method_item->set_text(0, get_signature(mi)); + method_item->set_metadata(0, mi.name); } } @@ -293,6 +289,11 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me type_mismatch = true; break; } + + if (stype == Variant::OBJECT && mtype == Variant::OBJECT && E->get().class_name != F->get().class_name) { + type_mismatch = true; + break; + } } if (type_mismatch) { @@ -350,10 +351,11 @@ void ConnectDialog::_update_method_tree() { } if (script_methods_only->is_pressed()) { + empty_tree_label->set_visible(root_item->get_first_child() == nullptr); return; } - // Get methods from each class in the heirarchy. + // Get methods from each class in the hierarchy. StringName current_class = target->get_class_name(); do { TreeItem *class_item = method_tree->create_item(root_item); @@ -376,6 +378,8 @@ void ConnectDialog::_update_method_tree() { } current_class = ClassDB::get_parent_class_nocheck(current_class); } while (current_class != StringName()); + + empty_tree_label->set_visible(root_item->get_first_child() == nullptr); } void ConnectDialog::_method_check_button_pressed(const CheckButton *p_button) { @@ -432,6 +436,7 @@ void ConnectDialog::_notification(int p_what) { from_signal->add_theme_style_override("normal", style); } method_search->set_right_icon(get_theme_icon("Search", "EditorIcons")); + open_method_tree->set_icon(get_theme_icon("Edit", "EditorIcons")); } break; } } @@ -444,10 +449,18 @@ Node *ConnectDialog::get_source() const { return source; } +ConnectDialog::ConnectionData ConnectDialog::get_source_connection_data() const { + return source_connection_data; +} + StringName ConnectDialog::get_signal_name() const { return signal; } +PackedStringArray ConnectDialog::get_signal_args() const { + return signal_args; +} + NodePath ConnectDialog::get_dst_path() const { return dst_path; } @@ -476,6 +489,34 @@ Vector<Variant> ConnectDialog::get_binds() const { return cdbinds->params; } +String ConnectDialog::get_signature(const MethodInfo &p_method, PackedStringArray *r_arg_names) { + PackedStringArray signature; + signature.append(p_method.name); + signature.append("("); + + for (int i = 0; i < p_method.arguments.size(); i++) { + if (i > 0) { + signature.append(", "); + } + + const PropertyInfo &pi = p_method.arguments[i]; + String tname = "var"; + if (pi.type == Variant::OBJECT && pi.class_name != StringName()) { + tname = pi.class_name.operator String(); + } else if (pi.type != Variant::NIL) { + tname = Variant::get_type_name(pi.type); + } + + signature.append((pi.name.is_empty() ? String("arg " + itos(i)) : pi.name) + ": " + tname); + if (r_arg_names) { + r_arg_names->push_back(pi.name + ":" + tname); + } + } + + signature.append(")"); + return String().join(signature); +} + bool ConnectDialog::get_deferred() const { return deferred->is_pressed(); } @@ -496,11 +537,12 @@ bool ConnectDialog::is_editing() const { * If creating a connection from scratch, sensible defaults are used. * If editing an existing connection, previous data is retained. */ -void ConnectDialog::init(ConnectionData p_cd, bool p_edit) { +void ConnectDialog::init(const ConnectionData &p_cd, const PackedStringArray &p_signal_args, bool p_edit) { set_hide_on_ok(false); source = static_cast<Node *>(p_cd.source); signal = p_cd.signal; + signal_args = p_signal_args; tree->set_selected(nullptr); tree->set_marked(source, true); @@ -518,22 +560,7 @@ void ConnectDialog::init(ConnectionData p_cd, bool p_edit) { deferred->set_pressed(b_deferred); one_shot->set_pressed(b_oneshot); - MethodInfo r_signal; - Ref<Script> source_script = source->get_script(); - if (source_script.is_valid() && source_script->has_script_signal(signal)) { - List<MethodInfo> signals; - source_script->get_script_signal_list(&signals); - for (MethodInfo &mi : signals) { - if (mi.name == signal) { - r_signal = mi; - break; - } - } - } else { - ClassDB::get_signal(source->get_class(), signal, &r_signal); - } - - unbind_count->set_max(r_signal.arguments.size()); + unbind_count->set_max(p_signal_args.size()); unbind_count->set_value(p_cd.unbinds); _unbind_count_changed(p_cd.unbinds); @@ -543,9 +570,11 @@ void ConnectDialog::init(ConnectionData p_cd, bool p_edit) { cdbinds->notify_changed(); edit_mode = p_edit; + + source_connection_data = p_cd; } -void ConnectDialog::popup_dialog(const String &p_for_signal) { +void ConnectDialog::popup_dialog(const String p_for_signal) { from_signal->set_text(p_for_signal); error_label->add_theme_color_override("font_color", error_label->get_theme_color(SNAME("error_color"), SNAME("Editor"))); if (!advanced->is_pressed()) { @@ -597,18 +626,9 @@ ConnectDialog::ConnectDialog() { main_hb->add_child(vbc_left); vbc_left->set_h_size_flags(Control::SIZE_EXPAND_FILL); - HBoxContainer *from_signal_hb = memnew(HBoxContainer); - from_signal = memnew(LineEdit); + vbc_left->add_margin_child(TTR("From Signal:"), from_signal); from_signal->set_editable(false); - from_signal->set_h_size_flags(Control::SIZE_EXPAND_FILL); - from_signal_hb->add_child(from_signal); - - advanced = memnew(CheckButton(TTR("Advanced"))); - from_signal_hb->add_child(advanced); - advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed)); - - vbc_left->add_margin_child(TTR("From Signal:"), from_signal_hb); tree = memnew(SceneTreeEditor(false)); tree->set_connecting_signal(true); @@ -646,6 +666,10 @@ ConnectDialog::ConnectDialog() { method_tree->connect("item_selected", callable_mp(this, &ConnectDialog::_method_selected)); method_tree->connect("item_activated", callable_mp((Window *)method_popup, &Window::hide)); + empty_tree_label = memnew(Label(TTR("No method found matching given filters."))); + method_tree->add_child(empty_tree_label); + empty_tree_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER); + script_methods_only = memnew(CheckButton(TTR("Script Methods Only"))); method_vbc->add_child(script_methods_only); script_methods_only->set_h_size_flags(Control::SIZE_SHRINK_END); @@ -712,15 +736,13 @@ ConnectDialog::ConnectDialog() { dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted)); hbc_method->add_child(dst_method); - Button *open_tree_button = memnew(Button); - open_tree_button->set_flat(false); - open_tree_button->set_text("..."); - open_tree_button->connect("pressed", callable_mp(this, &ConnectDialog::_open_method_popup)); - hbc_method->add_child(open_tree_button); + open_method_tree = memnew(Button); + hbc_method->add_child(open_method_tree); + open_method_tree->set_text("Pick"); + open_method_tree->connect("pressed", callable_mp(this, &ConnectDialog::_open_method_popup)); - advanced = memnew(CheckButton); + advanced = memnew(CheckButton(TTR("Advanced"))); vbc_left->add_child(advanced); - advanced->set_text(TTR("Advanced")); advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND); advanced->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "use_advanced_connections", false)); advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed)); @@ -797,9 +819,6 @@ void ConnectionsDock::_filter_changed(const String &p_text) { * Creates or edits connections based on state of the ConnectDialog when "Connect" is pressed. */ void ConnectionsDock::_make_or_edit_connection() { - TreeItem *it = tree->get_selected(); - ERR_FAIL_COND(!it); - NodePath dst_path = connect_dialog->get_dst_path(); Node *target = selected_node->get_node(dst_path); ERR_FAIL_COND(!target); @@ -837,27 +856,21 @@ void ConnectionsDock::_make_or_edit_connection() { add_script_function = !found_inherited_function; } - PackedStringArray script_function_args; - if (add_script_function) { - // Pick up args here before "it" is deleted by update_tree. - script_function_args = it->get_metadata(0).operator Dictionary()["args"]; - script_function_args.resize(script_function_args.size() - cd.unbinds); - for (int i = 0; i < cd.binds.size(); i++) { - script_function_args.push_back("extra_arg_" + itos(i) + ":" + Variant::get_type_name(cd.binds[i].get_type())); - } - } if (connect_dialog->is_editing()) { - _disconnect(*it); + _disconnect(connect_dialog->get_source_connection_data()); _connect(cd); } else { _connect(cd); } - // IMPORTANT NOTE: _disconnect and _connect cause an update_tree, which will delete the object "it" is pointing to. - it = nullptr; - if (add_script_function) { + PackedStringArray script_function_args = connect_dialog->get_signal_args(); + script_function_args.resize(script_function_args.size() - cd.unbinds); + for (int i = 0; i < cd.binds.size(); i++) { + script_function_args.push_back("extra_arg_" + itos(i) + ":" + Variant::get_type_name(cd.binds[i].get_type())); + } + EditorNode::get_singleton()->emit_signal(SNAME("script_add_function_request"), target, cd.method, script_function_args); hide(); } @@ -868,7 +881,7 @@ void ConnectionsDock::_make_or_edit_connection() { /* * Creates single connection w/ undo-redo functionality. */ -void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_cd) { +void ConnectionsDock::_connect(const ConnectDialog::ConnectionData &p_cd) { Node *source = Object::cast_to<Node>(p_cd.source); Node *target = Object::cast_to<Node>(p_cd.target); @@ -892,18 +905,15 @@ void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_cd) { /* * Break single connection w/ undo-redo functionality. */ -void ConnectionsDock::_disconnect(TreeItem &p_item) { - Connection connection = p_item.get_metadata(0); - ConnectDialog::ConnectionData cd = connection; - - ERR_FAIL_COND(cd.source != selected_node); // Shouldn't happen but... Bugcheck. +void ConnectionsDock::_disconnect(const ConnectDialog::ConnectionData &p_cd) { + ERR_FAIL_COND(p_cd.source != selected_node); // Shouldn't happen but... Bugcheck. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), cd.signal, cd.method)); + undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), p_cd.signal, p_cd.method)); - Callable callable = cd.get_callable(); - undo_redo->add_do_method(selected_node, "disconnect", cd.signal, callable); - undo_redo->add_undo_method(selected_node, "connect", cd.signal, callable, cd.binds, cd.flags); + Callable callable = p_cd.get_callable(); + undo_redo->add_do_method(selected_node, "disconnect", p_cd.signal, callable); + undo_redo->add_undo_method(selected_node, "connect", p_cd.signal, callable, p_cd.flags); undo_redo->add_do_method(this, "update_tree"); undo_redo->add_undo_method(this, "update_tree"); undo_redo->add_do_method(SceneTreeDock::get_singleton()->get_tree_editor(), "update_tree"); // To force redraw of scene tree. @@ -933,7 +943,7 @@ void ConnectionsDock::_disconnect_all() { if (!_is_connection_inherited(connection)) { ConnectDialog::ConnectionData cd = connection; undo_redo->add_do_method(selected_node, "disconnect", cd.signal, cd.get_callable()); - undo_redo->add_undo_method(selected_node, "connect", cd.signal, cd.get_callable(), cd.binds, cd.flags); + undo_redo->add_undo_method(selected_node, "connect", cd.signal, cd.get_callable(), cd.flags); } child = child->get_next(); } @@ -987,8 +997,9 @@ bool ConnectionsDock::_is_connection_inherited(Connection &p_connection) { * Open connection dialog with TreeItem data to CREATE a brand-new connection. */ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) { - String signal_name = p_item.get_metadata(0).operator Dictionary()["name"]; - const String &signal_name_ref = signal_name; + Dictionary sinfo = p_item.get_metadata(0); + String signal_name = sinfo["name"]; + PackedStringArray signal_args = sinfo["args"]; Node *dst_node = selected_node->get_owner() ? selected_node->get_owner() : selected_node; if (!dst_node || dst_node->get_script().is_null()) { @@ -997,26 +1008,34 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) { ConnectDialog::ConnectionData cd; cd.source = selected_node; - cd.signal = StringName(signal_name_ref); + cd.signal = StringName(signal_name); cd.target = dst_node; cd.method = ConnectDialog::generate_method_callback_name(cd.source, signal_name, cd.target); - connect_dialog->popup_dialog(signal_name_ref); - connect_dialog->init(cd); + connect_dialog->popup_dialog(signal_name + "(" + String(", ").join(signal_args) + ")"); + connect_dialog->init(cd, signal_args); connect_dialog->set_title(TTR("Connect a Signal to a Method")); } /* * Open connection dialog with Connection data to EDIT an existing connection. */ -void ConnectionsDock::_open_connection_dialog(ConnectDialog::ConnectionData p_cd) { - Node *src = Object::cast_to<Node>(p_cd.source); - Node *dst = Object::cast_to<Node>(p_cd.target); +void ConnectionsDock::_open_edit_connection_dialog(TreeItem &p_item) { + TreeItem *signal_item = p_item.get_parent(); + ERR_FAIL_COND(!signal_item); + + Connection connection = p_item.get_metadata(0); + ConnectDialog::ConnectionData cd = connection; + + Node *src = Object::cast_to<Node>(cd.source); + Node *dst = Object::cast_to<Node>(cd.target); if (src && dst) { - const String &signal_name_ref = p_cd.signal; - connect_dialog->set_title(TTR("Edit Connection:") + p_cd.signal); + const String &signal_name_ref = cd.signal; + PackedStringArray signal_args = signal_item->get_metadata(0).operator Dictionary()["args"]; + + connect_dialog->set_title(vformat(TTR("Edit Connection: '%s'"), cd.signal)); connect_dialog->popup_dialog(signal_name_ref); - connect_dialog->init(p_cd, true); + connect_dialog->init(cd, signal_args, true); } } @@ -1091,14 +1110,14 @@ void ConnectionsDock::_handle_slot_menu_option(int p_option) { switch (p_option) { case EDIT: { - Connection connection = item->get_metadata(0); - _open_connection_dialog(connection); + _open_edit_connection_dialog(*item); } break; case GO_TO_SCRIPT: { _go_to_script(*item); } break; case DISCONNECT: { - _disconnect(*item); + Connection connection = item->get_metadata(0); + _disconnect(connection); update_tree(); } break; } @@ -1149,7 +1168,8 @@ void ConnectionsDock::_connect_pressed() { if (_is_item_signal(*item)) { _open_connection_dialog(*item); } else { - _disconnect(*item); + Connection connection = item->get_metadata(0); + _disconnect(connection); update_tree(); } } @@ -1177,6 +1197,10 @@ void ConnectionsDock::set_node(Node *p_node) { } void ConnectionsDock::update_tree() { + String prev_selected; + if (tree->is_anything_selected()) { + prev_selected = tree->get_selected()->get_text(0); + } tree->clear(); if (!selected_node) { @@ -1238,37 +1262,22 @@ void ConnectionsDock::update_tree() { } for (MethodInfo &mi : node_signals2) { - StringName signal_name = mi.name; - String signaldesc = "("; - PackedStringArray argnames; - - String filter_text = search_box->get_text(); - if (!filter_text.is_subsequence_ofn(signal_name)) { + const StringName signal_name = mi.name; + if (!search_box->get_text().is_subsequence_ofn(signal_name)) { continue; } + PackedStringArray argnames; - if (mi.arguments.size()) { - for (int i = 0; i < mi.arguments.size(); i++) { - PropertyInfo &pi = mi.arguments[i]; + // Create the children of the subsection - the actual list of signals. + TreeItem *signal_item = tree->create_item(section_item); + String signame = connect_dialog->get_signature(mi, &argnames); + signal_item->set_text(0, signame); - if (i > 0) { - signaldesc += ", "; - } - String tname = "var"; - if (pi.type == Variant::OBJECT && pi.class_name != StringName()) { - tname = pi.class_name.operator String(); - } else if (pi.type != Variant::NIL) { - tname = Variant::get_type_name(pi.type); - } - signaldesc += (pi.name.is_empty() ? String("arg " + itos(i)) : pi.name) + ": " + tname; - argnames.push_back(pi.name + ":" + tname); - } + if (signame == prev_selected) { + signal_item->select(0); + prev_selected = ""; } - signaldesc += ")"; - // Create the children of the subsection - the actual list of signals. - TreeItem *signal_item = tree->create_item(section_item); - signal_item->set_text(0, String(signal_name) + signaldesc); Dictionary sinfo; sinfo["name"] = signal_name; sinfo["args"] = argnames; @@ -1309,7 +1318,7 @@ void ConnectionsDock::update_tree() { } // "::" separators used in make_custom_tooltip for formatting. - signal_item->set_tooltip_text(0, String(signal_name) + "::" + signaldesc + "::" + descr); + signal_item->set_tooltip_text(0, String(signal_name) + "::" + signame.trim_prefix(mi.name) + "::" + descr); } // List existing connections. diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 0bea897976..277ea03cf7 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -88,7 +88,7 @@ public: method = base_callable.get_method(); } - Callable get_callable() { + Callable get_callable() const { if (unbinds > 0) { return Callable(target, method).unbind(unbinds); } else if (!binds.is_empty()) { @@ -107,7 +107,9 @@ private: Label *connect_to_label = nullptr; LineEdit *from_signal = nullptr; Node *source = nullptr; + ConnectionData source_connection_data; StringName signal; + PackedStringArray signal_args; LineEdit *dst_method = nullptr; ConnectDialogBinds *cdbinds = nullptr; bool edit_mode = false; @@ -117,8 +119,10 @@ private: SceneTreeEditor *tree = nullptr; AcceptDialog *error = nullptr; + Button *open_method_tree = nullptr; AcceptDialog *method_popup = nullptr; Tree *method_tree = nullptr; + Label *empty_tree_label = nullptr; LineEdit *method_search = nullptr; CheckButton *script_methods_only = nullptr; CheckButton *compatible_methods_only = nullptr; @@ -159,21 +163,24 @@ protected: public: static StringName generate_method_callback_name(Node *p_source, String p_signal_name, Node *p_target); Node *get_source() const; + ConnectionData get_source_connection_data() const; StringName get_signal_name() const; + PackedStringArray get_signal_args() const; NodePath get_dst_path() const; void set_dst_node(Node *p_node); StringName get_dst_method_name() const; void set_dst_method(const StringName &p_method); int get_unbinds() const; Vector<Variant> get_binds() const; + String get_signature(const MethodInfo &p_method, PackedStringArray *r_arg_names = nullptr); bool get_deferred() const; bool get_one_shot() const; bool is_editing() const; - void init(ConnectionData p_cd, bool p_edit = false); + void init(const ConnectionData &p_cd, const PackedStringArray &p_signal_args, bool p_edit = false); - void popup_dialog(const String &p_for_signal); + void popup_dialog(const String p_for_signal); ConnectDialog(); ~ConnectDialog(); }; @@ -217,8 +224,8 @@ class ConnectionsDock : public VBoxContainer { void _filter_changed(const String &p_text); void _make_or_edit_connection(); - void _connect(ConnectDialog::ConnectionData p_cd); - void _disconnect(TreeItem &p_item); + void _connect(const ConnectDialog::ConnectionData &p_cd); + void _disconnect(const ConnectDialog::ConnectionData &p_cd); void _disconnect_all(); void _tree_item_selected(); @@ -227,7 +234,7 @@ class ConnectionsDock : public VBoxContainer { bool _is_connection_inherited(Connection &p_connection); void _open_connection_dialog(TreeItem &p_item); - void _open_connection_dialog(ConnectDialog::ConnectionData p_cd); + void _open_edit_connection_dialog(TreeItem &p_item); void _go_to_script(TreeItem &p_item); void _handle_signal_menu_option(int p_option); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 0814d5b5ca..aee907854c 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -122,7 +122,7 @@ bool CreateDialog::_should_hide_type(const String &p_type) const { return true; } - if (base_type == "Node" && p_type.begins_with("Editor")) { + if (is_base_type_node && p_type.begins_with("Editor")) { return true; // Do not show editor nodes. } @@ -508,6 +508,11 @@ String CreateDialog::get_selected_type() { return selected->get_text(0); } +void CreateDialog::set_base_type(const String &p_base) { + base_type = p_base; + is_base_type_node = ClassDB::is_parent_class(p_base, "Node"); +} + Variant CreateDialog::instantiate_selected() { TreeItem *selected = search_options->get_selected(); diff --git a/editor/create_dialog.h b/editor/create_dialog.h index ad63346a02..37579812cf 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -51,6 +51,7 @@ class CreateDialog : public ConfirmationDialog { Tree *search_options = nullptr; String base_type; + bool is_base_type_node = false; String icon_fallback; String preferred_search_result_type; @@ -113,7 +114,7 @@ public: Variant instantiate_selected(); String get_selected_type(); - void set_base_type(const String &p_base) { base_type = p_base; } + void set_base_type(const String &p_base); String get_base_type() const { return base_type; } void select_base(); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 2c6b9990ed..32952a367d 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -519,7 +519,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da String error_title; if (oe.callstack.size() > 0) { // If available, use the script's stack in the error title. - error_title = oe.callstack[oe.callstack.size() - 1].func + ": "; + error_title = _format_frame_text(&oe.callstack[0]) + ": "; } else if (!oe.source_func.is_empty()) { // Otherwise try to use the C++ source function. error_title += oe.source_func + ": "; @@ -530,13 +530,25 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da error->set_text(1, error_title); tooltip += " " + error_title + "\n"; + // Find the language of the error's source file. + String source_language_name = "C++"; // Default value is the old hard-coded one. + const String source_file_extension = oe.source_file.get_extension(); + for (int i = 0; i < ScriptServer::get_language_count(); ++i) { + ScriptLanguage *script_language = ScriptServer::get_language(i); + if (source_file_extension == script_language->get_extension()) { + source_language_name = script_language->get_name(); + break; + } + } + if (!oe.error_descr.is_empty()) { // Add item for C++ error condition. TreeItem *cpp_cond = error_tree->create_item(error); - cpp_cond->set_text(0, "<" + TTR("C++ Error") + ">"); + // TRANSLATORS: %s is the name of a language, e.g. C++. + cpp_cond->set_text(0, "<" + vformat(TTR("%s Error"), source_language_name) + ">"); cpp_cond->set_text(1, oe.error); cpp_cond->set_text_alignment(0, HORIZONTAL_ALIGNMENT_LEFT); - tooltip += TTR("C++ Error:") + " " + oe.error + "\n"; + tooltip += vformat(TTR("%s Error:"), source_language_name) + " " + oe.error + "\n"; if (source_is_project_file) { cpp_cond->set_metadata(0, source_meta); } @@ -547,14 +559,18 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da // Source of the error. String source_txt = (source_is_project_file ? oe.source_file.get_file() : oe.source_file) + ":" + itos(oe.source_line); if (!oe.source_func.is_empty()) { - source_txt += " @ " + oe.source_func + "()"; + source_txt += " @ " + oe.source_func; + if (!oe.source_func.ends_with(")")) { + source_txt += "()"; + } } TreeItem *cpp_source = error_tree->create_item(error); - cpp_source->set_text(0, "<" + (source_is_project_file ? TTR("Source") : TTR("C++ Source")) + ">"); + // TRANSLATORS: %s is the name of a language, e.g. C++. + cpp_source->set_text(0, "<" + vformat(TTR("%s Source"), source_language_name) + ">"); cpp_source->set_text(1, source_txt); cpp_source->set_text_alignment(0, HORIZONTAL_ALIGNMENT_LEFT); - tooltip += (source_is_project_file ? TTR("Source:") : TTR("C++ Source:")) + " " + source_txt + "\n"; + tooltip += vformat(TTR("%s Source:"), source_language_name) + " " + source_txt + "\n"; // Set metadata to highlight error line in scripts. if (source_is_project_file) { @@ -581,7 +597,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da tooltip += TTR("Stack Trace:") + "\n"; } - String frame_txt = infos[i].file.get_file() + ":" + itos(infos[i].line) + " @ " + infos[i].func + "()"; + String frame_txt = _format_frame_text(&infos[i]); tooltip += frame_txt + "\n"; stack_trace->set_text(1, frame_txt); } @@ -901,6 +917,14 @@ void ScriptEditorDebugger::_breakpoint_tree_clicked() { } } +String ScriptEditorDebugger::_format_frame_text(const ScriptLanguage::StackInfo *info) { + String text = info->file.get_file() + ":" + itos(info->line) + " @ " + info->func; + if (!text.ends_with(")")) { + text += "()"; + } + return text; +} + void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) { _clear_errors_list(); stop(); diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h index e31b3af3d9..a0c420522a 100644 --- a/editor/debugger/script_editor_debugger.h +++ b/editor/debugger/script_editor_debugger.h @@ -210,6 +210,8 @@ private: void _breakpoint_tree_clicked(); + String _format_frame_text(const ScriptLanguage::StackInfo *info); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 5bdef32c60..d71ef78d88 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -461,7 +461,7 @@ void DocTools::generate(bool p_basic_types) { } if (default_value_valid && default_value.get_type() != Variant::OBJECT) { - prop.default_value = default_value.get_construct_string().replace("\n", " "); + prop.default_value = DocData::get_default_value_string(default_value); } StringName setter = ClassDB::get_property_setter(name, E.name); @@ -591,7 +591,7 @@ void DocTools::generate(bool p_basic_types) { tid.name = E; tid.type = "Color"; tid.data_type = "color"; - tid.default_value = Variant(ThemeDB::get_singleton()->get_default_theme()->get_color(E, cname)).get_construct_string().replace("\n", " "); + tid.default_value = DocData::get_default_value_string(ThemeDB::get_singleton()->get_default_theme()->get_color(E, cname)); c.theme_properties.push_back(tid); } @@ -772,8 +772,7 @@ void DocTools::generate(bool p_basic_types) { int darg_idx = mi.default_arguments.size() - mi.arguments.size() + j; if (darg_idx >= 0) { - Variant default_arg = mi.default_arguments[darg_idx]; - ad.default_value = default_arg.get_construct_string().replace("\n", " "); + ad.default_value = DocData::get_default_value_string(mi.default_arguments[darg_idx]); } method.arguments.push_back(ad); @@ -817,7 +816,7 @@ void DocTools::generate(bool p_basic_types) { DocData::PropertyDoc property; property.name = pi.name; property.type = Variant::get_type_name(pi.type); - property.default_value = v.get(pi.name).get_construct_string().replace("\n", " "); + property.default_value = DocData::get_default_value_string(v.get(pi.name)); c.properties.push_back(property); } @@ -948,8 +947,7 @@ void DocTools::generate(bool p_basic_types) { int darg_idx = j - (mi.arguments.size() - mi.default_arguments.size()); if (darg_idx >= 0) { - Variant default_arg = mi.default_arguments[darg_idx]; - ad.default_value = default_arg.get_construct_string().replace("\n", " "); + ad.default_value = DocData::get_default_value_string(mi.default_arguments[darg_idx]); } md.arguments.push_back(ad); @@ -993,8 +991,7 @@ void DocTools::generate(bool p_basic_types) { int darg_idx = j - (ai.arguments.size() - ai.default_arguments.size()); if (darg_idx >= 0) { - Variant default_arg = ai.default_arguments[darg_idx]; - ad.default_value = default_arg.get_construct_string().replace("\n", " "); + ad.default_value = DocData::get_default_value_string(ai.default_arguments[darg_idx]); } atd.arguments.push_back(ad); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index ef33b82390..644c32e8a4 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1591,6 +1591,11 @@ void EditorFileSystem::_update_script_classes() { void EditorFileSystem::_update_pending_script_classes() { if (!update_script_paths.is_empty()) { _update_script_classes(); + } else { + // In case the class cache file was removed somehow, regenerate it. + if (!FileAccess::exists(ScriptServer::get_global_class_cache_file_path())) { + ScriptServer::save_global_classes(); + } } } diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 1690302e6e..6a1c77d376 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -47,11 +47,7 @@ class TextureRect; class EditorPropertyRevert { public: - static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true); - static bool is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig); - static bool is_property_value_different(const Variant &p_a, const Variant &p_b); static Variant get_property_revert_value(Object *p_object, const StringName &p_property, bool *r_is_valid); - static bool can_property_revert(Object *p_object, const StringName &p_property, const Variant *p_custom_current_value = nullptr); }; @@ -331,7 +327,7 @@ class EditorInspectorArray : public EditorInspectorSection { AcceptDialog *resize_dialog = nullptr; SpinBox *new_size_spin_box = nullptr; - // Pagination + // Pagination. int page_length = 5; int page = 0; int max_page = 0; @@ -495,7 +491,7 @@ class EditorInspector : public ScrollContainer { HashMap<ObjectID, int> scroll_cache; - String property_prefix; //used for sectioned inspector + String property_prefix; // Used for sectioned inspector. String object_class; Variant property_clipboard; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 173cbc6893..0405749147 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -581,6 +581,7 @@ void EditorNode::_notification(int p_what) { ResourceImporterTexture::get_singleton()->update_imports(); + bottom_panel_updating = false; } break; case NOTIFICATION_ENTER_TREE: { @@ -643,7 +644,7 @@ void EditorNode::_notification(int p_what) { } RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true); - RenderingServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(), true); + RenderingServer::get_singleton()->viewport_set_environment_mode(get_viewport()->get_viewport_rid(), RenderingServer::VIEWPORT_ENVIRONMENT_DISABLED); feature_profile_manager->notify_changed(); @@ -2096,14 +2097,25 @@ void EditorNode::edit_item(Object *p_object, Object *p_editing_owner) { if (!item_plugins.is_empty()) { ObjectID owner_id = p_editing_owner->get_instance_id(); + List<EditorPlugin *> to_remove; for (EditorPlugin *plugin : active_plugins[owner_id]) { if (!item_plugins.has(plugin)) { + // Remove plugins no longer used by this editing owner. + to_remove.push_back(plugin); plugin->make_visible(false); plugin->edit(nullptr); } } + for (EditorPlugin *plugin : to_remove) { + active_plugins[owner_id].erase(plugin); + } + for (EditorPlugin *plugin : item_plugins) { + if (active_plugins[owner_id].has(plugin)) { + continue; + } + for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) { if (kv.key != owner_id) { EditorPropertyResource *epres = Object::cast_to<EditorPropertyResource>(ObjectDB::get_instance(kv.key)); @@ -5590,12 +5602,16 @@ void EditorNode::remove_bottom_panel_item(Control *p_item) { } void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { + if (bottom_panel_updating) { + return; + } ERR_FAIL_INDEX(p_idx, bottom_panel_items.size()); if (bottom_panel_items[p_idx].control->is_visible() == p_enable) { return; } + bottom_panel_updating = true; if (p_enable) { for (int i = 0; i < bottom_panel_items.size(); i++) { bottom_panel_items[i].button->set_pressed(i == p_idx); @@ -6195,7 +6211,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins List<PropertyInfo> pinfo; modifiable_node->get_property_list(&pinfo); - // Get names of all valid property names (TODO: make this more efficent). + // Get names of all valid property names (TODO: make this more efficient). List<String> property_names; for (const PropertyInfo &E2 : pinfo) { if (E2.usage & PROPERTY_USAGE_STORAGE) { @@ -6213,7 +6229,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins for (const ConnectionWithNodePath &E2 : E.value.connections_to) { Connection conn = E2.connection; - // Get the node the callable is targetting. + // Get the node the callable is targeting. Node *target_node = cast_to<Node>(conn.callable.get_object()); // If the callable object no longer exists or is marked for deletion, @@ -7262,6 +7278,7 @@ EditorNode::EditorNode() { project_title->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); project_title->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); project_title->set_h_size_flags(Control::SIZE_EXPAND_FILL); + project_title->set_mouse_filter(Control::MOUSE_FILTER_PASS); left_spacer->add_child(project_title); } diff --git a/editor/editor_node.h b/editor/editor_node.h index bb10abb589..3967f64c6b 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -460,6 +460,7 @@ private: EditorToaster *editor_toaster = nullptr; LinkButton *version_btn = nullptr; Button *bottom_panel_raise = nullptr; + bool bottom_panel_updating = false; Tree *disk_changed_list = nullptr; ConfirmationDialog *disk_changed = nullptr; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 152e77acb7..f022027e65 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1323,10 +1323,12 @@ void EditorPropertyObjectID::update_property() { ObjectID id = get_edited_object()->get(get_edited_property()); if (id.is_valid()) { edit->set_text(type + " ID: " + uitos(id)); + edit->set_tooltip_text(type + " ID: " + uitos(id)); edit->set_disabled(false); edit->set_icon(EditorNode::get_singleton()->get_class_icon(type)); } else { edit->set_text(TTR("<empty>")); + edit->set_tooltip_text(""); edit->set_disabled(true); edit->set_icon(Ref<Texture2D>()); } @@ -1343,6 +1345,7 @@ EditorPropertyObjectID::EditorPropertyObjectID() { edit = memnew(Button); add_child(edit); add_focusable(edit); + edit->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); edit->connect("pressed", callable_mp(this, &EditorPropertyObjectID::_edit_pressed)); } diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 28c0b047d8..b96ac9dbcb 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -158,17 +158,32 @@ EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() { ///////////////////// ARRAY /////////////////////////// +void EditorPropertyArray::initialize_array(Variant &p_array) { + if (array_type == Variant::ARRAY && subtype != Variant::NIL) { + Array array; + StringName subtype_class; + Ref<Script> subtype_script; + if (subtype == Variant::OBJECT && !subtype_hint_string.is_empty()) { + if (ClassDB::class_exists(subtype_hint_string)) { + subtype_class = subtype_hint_string; + } + } + array.set_typed(subtype, subtype_class, subtype_script); + p_array = array; + } else { + VariantInternal::initialize(&p_array, array_type); + } +} + void EditorPropertyArray::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("indices")) { int index = p_property.get_slice("/", 1).to_int(); - Variant array = object->get_array(); + + Variant array = object->get_array().duplicate(); array.set(index, p_value); - emit_changed(get_edited_property(), array, "", true); - if (array.get_type() == Variant::ARRAY) { - array = array.call("duplicate"); // Duplicate, so undo/redo works better. - } object->set_array(array); + emit_changed(get_edited_property(), array, "", true); } } @@ -188,18 +203,12 @@ void EditorPropertyArray::_change_type_menu(int p_index) { } Variant value; - Callable::CallError ce; - Variant::construct(Variant::Type(p_index), value, nullptr, 0, ce); - Variant array = object->get_array(); + VariantInternal::initialize(&value, Variant::Type(p_index)); + + Variant array = object->get_array().duplicate(); array.set(changing_type_index, value); emit_changed(get_edited_property(), array, "", true); - - if (array.get_type() == Variant::ARRAY) { - array = array.call("duplicate"); // Duplicate, so undo/redo works better. - } - - object->set_array(array); update_property(); } @@ -234,6 +243,8 @@ void EditorPropertyArray::update_property() { return; } + object->set_array(array); + int size = array.call("size"); int max_page = MAX(0, size - 1) / page_length; page_index = MIN(page_index, max_page); @@ -305,12 +316,6 @@ void EditorPropertyArray::update_property() { paginator->update(page_index, max_page); paginator->set_visible(max_page > 0); - if (array.get_type() == Variant::ARRAY) { - array = array.call("duplicate"); - } - - object->set_array(array); - int amount = MIN(size - offset, page_length); for (int i = 0; i < amount; i++) { bool reorder_is_from_current_page = reorder_from_index / page_length == page_index; @@ -401,7 +406,7 @@ void EditorPropertyArray::update_property() { } void EditorPropertyArray::_remove_pressed(int p_index) { - Variant array = object->get_array(); + Variant array = object->get_array().duplicate(); array.call("remove_at", p_index); emit_changed(get_edited_property(), array, "", false); @@ -469,8 +474,9 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d // Handle the case where array is not initialized yet. if (!array.is_array()) { - Callable::CallError ce; - Variant::construct(array_type, array, nullptr, 0, ce); + initialize_array(array); + } else { + array = array.duplicate(); } // Loop the file array and add to existing array. @@ -483,13 +489,7 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d } } - if (array.get_type() == Variant::ARRAY) { - array = array.call("duplicate"); - } - emit_changed(get_edited_property(), array, "", false); - object->set_array(array); - update_property(); } } @@ -536,10 +536,8 @@ void EditorPropertyArray::_notification(int p_what) { void EditorPropertyArray::_edit_pressed() { Variant array = get_edited_object()->get(get_edited_property()); - if (!array.is_array()) { - Callable::CallError ce; - Variant::construct(array_type, array, nullptr, 0, ce); - + if (!array.is_array() && edit->is_pressed()) { + initialize_array(array); get_edited_object()->set(get_edited_property(), array); } @@ -560,37 +558,10 @@ void EditorPropertyArray::_length_changed(double p_page) { return; } - Variant array = object->get_array(); - int previous_size = array.call("size"); - + Variant array = object->get_array().duplicate(); array.call("resize", int(p_page)); - if (array.get_type() == Variant::ARRAY) { - if (subtype != Variant::NIL) { - int size = array.call("size"); - for (int i = previous_size; i < size; i++) { - if (array.get(i).get_type() == Variant::NIL) { - Callable::CallError ce; - Variant r; - Variant::construct(subtype, r, nullptr, 0, ce); - array.set(i, r); - } - } - } - array = array.call("duplicate"); // Duplicate, so undo/redo works better. - } else { - int size = array.call("size"); - // Pool*Array don't initialize their elements, have to do it manually. - for (int i = previous_size; i < size; i++) { - Callable::CallError ce; - Variant r; - Variant::construct(array.get(i).get_type(), r, nullptr, 0, ce); - array.set(i, r); - } - } - emit_changed(get_edited_property(), array, "", false); - object->set_array(array); update_property(); } @@ -677,14 +648,13 @@ void EditorPropertyArray::_reorder_button_up() { if (reorder_from_index != reorder_to_index) { // Move the element. - Variant array = object->get_array(); + Variant array = object->get_array().duplicate(); Variant value_to_move = array.get(reorder_from_index); array.call("remove_at", reorder_from_index); array.call("insert", reorder_to_index, value_to_move); emit_changed(get_edited_property(), array, "", false); - object->set_array(array); update_property(); } @@ -742,14 +712,13 @@ void EditorPropertyDictionary::_property_changed(const String &p_property, Varia object->set_new_item_value(p_value); } else if (p_property.begins_with("indices")) { int index = p_property.get_slice("/", 1).to_int(); - Dictionary dict = object->get_dict(); + + Dictionary dict = object->get_dict().duplicate(); Variant key = dict.get_key_at_index(index); dict[key] = p_value; - emit_changed(get_edited_property(), dict, "", true); - - dict = dict.duplicate(); // Duplicate, so undo/redo works better. object->set_dict(dict); + emit_changed(get_edited_property(), dict, "", true); } } @@ -769,24 +738,19 @@ void EditorPropertyDictionary::_add_key_value() { return; } - Dictionary dict = object->get_dict(); - + Dictionary dict = object->get_dict().duplicate(); dict[object->get_new_item_key()] = object->get_new_item_value(); object->set_new_item_key(Variant()); object->set_new_item_value(Variant()); emit_changed(get_edited_property(), dict, "", false); - - dict = dict.duplicate(); // Duplicate, so undo/redo works better. - object->set_dict(dict); update_property(); } void EditorPropertyDictionary::_change_type_menu(int p_index) { if (changing_type_index < 0) { Variant value; - Callable::CallError ce; - Variant::construct(Variant::Type(p_index), value, nullptr, 0, ce); + VariantInternal::initialize(&value, Variant::Type(p_index)); if (changing_type_index == -1) { object->set_new_item_key(value); } else { @@ -796,12 +760,10 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) { return; } - Dictionary dict = object->get_dict(); - + Dictionary dict = object->get_dict().duplicate(); if (p_index < Variant::VARIANT_MAX) { Variant value; - Callable::CallError ce; - Variant::construct(Variant::Type(p_index), value, nullptr, 0, ce); + VariantInternal::initialize(&value, Variant::Type(p_index)); Variant key = dict.get_key_at_index(changing_type_index); dict[key] = value; } else { @@ -810,9 +772,6 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) { } emit_changed(get_edited_property(), dict, "", false); - - dict = dict.duplicate(); // Duplicate, so undo/redo works better. - object->set_dict(dict); update_property(); } @@ -836,6 +795,7 @@ void EditorPropertyDictionary::update_property() { } Dictionary dict = updated_val; + object->set_dict(updated_val); edit->set_text(vformat(TTR("Dictionary (size %d)"), dict.size())); @@ -883,9 +843,6 @@ void EditorPropertyDictionary::update_property() { int amount = MIN(size - offset, page_length); int total_amount = page_index == max_page ? amount + 2 : amount; // For the "Add Key/Value Pair" box on last page. - dict = dict.duplicate(); - - object->set_dict(dict); VBoxContainer *add_vbox = nullptr; double default_float_step = EDITOR_GET("interface/inspector/default_float_step"); @@ -1225,9 +1182,8 @@ void EditorPropertyDictionary::_notification(int p_what) { void EditorPropertyDictionary::_edit_pressed() { Variant prop_val = get_edited_object()->get(get_edited_property()); - if (prop_val.get_type() == Variant::NIL) { - Callable::CallError ce; - Variant::construct(Variant::DICTIONARY, prop_val, nullptr, 0, ce); + if (prop_val.get_type() == Variant::NIL && edit->is_pressed()) { + VariantInternal::initialize(&prop_val, Variant::DICTIONARY); get_edited_object()->set(get_edited_property(), prop_val); } @@ -1272,14 +1228,13 @@ EditorPropertyDictionary::EditorPropertyDictionary() { void EditorPropertyLocalizableString::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("indices")) { int index = p_property.get_slice("/", 1).to_int(); - Dictionary dict = object->get_dict(); + + Dictionary dict = object->get_dict().duplicate(); Variant key = dict.get_key_at_index(index); dict[key] = p_value; - emit_changed(get_edited_property(), dict, "", true); - - dict = dict.duplicate(); // Duplicate, so undo/redo works better. object->set_dict(dict); + emit_changed(get_edited_property(), dict, "", true); } } @@ -1288,29 +1243,22 @@ void EditorPropertyLocalizableString::_add_locale_popup() { } void EditorPropertyLocalizableString::_add_locale(const String &p_locale) { - Dictionary dict = object->get_dict(); - + Dictionary dict = object->get_dict().duplicate(); object->set_new_item_key(p_locale); object->set_new_item_value(String()); dict[object->get_new_item_key()] = object->get_new_item_value(); emit_changed(get_edited_property(), dict, "", false); - - dict = dict.duplicate(); // Duplicate, so undo/redo works better. - object->set_dict(dict); update_property(); } void EditorPropertyLocalizableString::_remove_item(Object *p_button, int p_index) { - Dictionary dict = object->get_dict(); + Dictionary dict = object->get_dict().duplicate(); Variant key = dict.get_key_at_index(p_index); dict.erase(key); emit_changed(get_edited_property(), dict, "", false); - - dict = dict.duplicate(); // Duplicate, so undo/redo works better. - object->set_dict(dict); update_property(); } @@ -1330,6 +1278,7 @@ void EditorPropertyLocalizableString::update_property() { } Dictionary dict = updated_val; + object->set_dict(dict); edit->set_text(vformat(TTR("Localizable String (size %d)"), dict.size())); @@ -1376,10 +1325,6 @@ void EditorPropertyLocalizableString::update_property() { int amount = MIN(size - offset, page_length); - dict = dict.duplicate(); - - object->set_dict(dict); - for (int i = 0; i < amount; i++) { String prop_name; Variant key; @@ -1451,9 +1396,8 @@ void EditorPropertyLocalizableString::_notification(int p_what) { void EditorPropertyLocalizableString::_edit_pressed() { Variant prop_val = get_edited_object()->get(get_edited_property()); - if (prop_val.get_type() == Variant::NIL) { - Callable::CallError ce; - Variant::construct(Variant::DICTIONARY, prop_val, nullptr, 0, ce); + if (prop_val.get_type() == Variant::NIL && edit->is_pressed()) { + VariantInternal::initialize(&prop_val, Variant::DICTIONARY); get_edited_object()->set(get_edited_property(), prop_val); } diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index 73a16e3687..3b880c60a8 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -102,6 +102,8 @@ class EditorPropertyArray : public EditorProperty { HBoxContainer *reorder_selected_element_hbox = nullptr; Button *reorder_selected_button = nullptr; + void initialize_array(Variant &p_array); + void _page_changed(int p_page); void _reorder_button_gui_input(const Ref<InputEvent> &p_event); diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index 18ba19f5f6..5380fddde2 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -115,6 +115,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["arm64-v8a"] = "arm64-v8a"; capitalize_string_remaps["armeabi-v7a"] = "armeabi-v7a"; capitalize_string_remaps["arvr"] = "ARVR"; + capitalize_string_remaps["astc"] = "ASTC"; capitalize_string_remaps["bg"] = "BG"; capitalize_string_remaps["bidi"] = "BiDi"; capitalize_string_remaps["bp"] = "BP"; diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index 4bcd91376a..d3cceee1a3 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -272,7 +272,9 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) { OS::ProcessID pid = 0; Error err = OS::get_singleton()->create_instance(args, &pid); ERR_FAIL_COND_V(err, err); - pids.push_back(pid); + if (pid != 0) { + pids.push_back(pid); + } } status = STATUS_PLAY; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 4879790b74..1c988840ac 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -453,6 +453,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Theme EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom") + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/enable_touchscreen_touch_area", DisplayServer::get_singleton()->is_touchscreen_available(), "") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "") @@ -474,10 +475,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { /* Filesystem */ // External Programs - EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/raster_image_editor", "", "") - EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/vector_image_editor", "", "") - EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/audio_editor", "", "") - EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/3d_model_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/raster_image_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/vector_image_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/audio_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/3d_model_editor", "", "") // Directories EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/autoscan_project_path", "", "") diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 745acca04b..d2c82ad013 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -198,7 +198,7 @@ static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(p_texture); style->set_texture_margin_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE); - style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); + style->set_content_margin_individual((p_left + p_margin_left) * EDSCALE, (p_top + p_margin_top) * EDSCALE, (p_right + p_margin_right) * EDSCALE, (p_bottom + p_margin_bottom) * EDSCALE); style->set_draw_center(p_draw_center); return style; } @@ -394,6 +394,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color accent_color = EDITOR_GET("interface/theme/accent_color"); Color base_color = EDITOR_GET("interface/theme/base_color"); float contrast = EDITOR_GET("interface/theme/contrast"); + bool enable_touchscreen_touch_area = EDITOR_GET("interface/theme/enable_touchscreen_touch_area"); bool draw_extra_borders = EDITOR_GET("interface/theme/draw_extra_borders"); float icon_saturation = EDITOR_GET("interface/theme/icon_saturation"); float relationship_line_opacity = EDITOR_GET("interface/theme/relationship_line_opacity"); @@ -1492,11 +1493,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // HScrollBar Ref<Texture2D> empty_icon = memnew(ImageTexture); - theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("scroll_focus", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("grabber", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 2, 2, 2)); - theme->set_stylebox("grabber_highlight", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberHl"), SNAME("EditorIcons")), 5, 5, 5, 5, 2, 2, 2, 2)); - theme->set_stylebox("grabber_pressed", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberPressed"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 2, 2, 2)); + if (enable_touchscreen_touch_area) { + theme->set_stylebox("scroll", "HScrollBar", make_line_stylebox(separator_color, 50)); + } else { + theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1)); + } + theme->set_stylebox("scroll_focus", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1)); + theme->set_stylebox("grabber", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), SNAME("EditorIcons")), 6, 6, 6, 6, 1, 1, 1, 1)); + theme->set_stylebox("grabber_highlight", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberHl"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1)); + theme->set_stylebox("grabber_pressed", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberPressed"), SNAME("EditorIcons")), 6, 6, 6, 6, 1, 1, 1, 1)); theme->set_icon("increment", "HScrollBar", empty_icon); theme->set_icon("increment_highlight", "HScrollBar", empty_icon); @@ -1506,11 +1511,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("decrement_pressed", "HScrollBar", empty_icon); // VScrollBar - theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("scroll_focus", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("grabber", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 2, 2, 2)); - theme->set_stylebox("grabber_highlight", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberHl"), SNAME("EditorIcons")), 5, 5, 5, 5, 2, 2, 2, 2)); - theme->set_stylebox("grabber_pressed", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberPressed"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 2, 2, 2)); + if (enable_touchscreen_touch_area) { + theme->set_stylebox("scroll", "VScrollBar", make_line_stylebox(separator_color, 50, 1, 1, true)); + } else { + theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1)); + } + theme->set_stylebox("scroll_focus", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1)); + theme->set_stylebox("grabber", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), SNAME("EditorIcons")), 6, 6, 6, 6, 1, 1, 1, 1)); + theme->set_stylebox("grabber_highlight", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberHl"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1)); + theme->set_stylebox("grabber_pressed", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabberPressed"), SNAME("EditorIcons")), 6, 6, 6, 6, 1, 1, 1, 1)); theme->set_icon("increment", "VScrollBar", empty_icon); theme->set_icon("increment_highlight", "VScrollBar", empty_icon); diff --git a/editor/editor_title_bar.cpp b/editor/editor_title_bar.cpp index 0271bbd64a..ae5cdfd72b 100644 --- a/editor/editor_title_bar.cpp +++ b/editor/editor_title_bar.cpp @@ -30,7 +30,7 @@ #include "editor/editor_title_bar.h" -void EditorTitleBar::input(const Ref<InputEvent> &p_event) { +void EditorTitleBar::gui_input(const Ref<InputEvent> &p_event) { if (!can_move) { return; } diff --git a/editor/editor_title_bar.h b/editor/editor_title_bar.h index 6cac163830..4055476b82 100644 --- a/editor/editor_title_bar.h +++ b/editor/editor_title_bar.h @@ -42,7 +42,7 @@ class EditorTitleBar : public HBoxContainer { bool can_move = false; protected: - virtual void input(const Ref<InputEvent> &p_event) override; + virtual void gui_input(const Ref<InputEvent> &p_event) override; static void _bind_methods(){}; public: diff --git a/editor/editor_zoom_widget.cpp b/editor/editor_zoom_widget.cpp index 5a334bdaa6..3998b33a53 100644 --- a/editor/editor_zoom_widget.cpp +++ b/editor/editor_zoom_widget.cpp @@ -41,12 +41,12 @@ void EditorZoomWidget::_update_zoom_label() { // lower the editor scale to increase the available real estate, // even if their display doesn't have a particularly low DPI. if (zoom >= 10) { - // Don't show a decimal when the zoom level is higher than 1000 %. - zoom_text = TS->format_number(rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100))) + " " + TS->percent_sign(); + zoom_text = TS->format_number(rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100))); } else { - zoom_text = TS->format_number(rtos(Math::snapped((zoom / MAX(1, EDSCALE)) * 100, 0.1))) + " " + TS->percent_sign(); + // 2 decimal places if the zoom is below 10%, 1 decimal place if it's below 1000%. + zoom_text = TS->format_number(rtos(Math::snapped((zoom / MAX(1, EDSCALE)) * 100, (zoom >= 0.1) ? 0.1 : 0.01))); } - + zoom_text += " " + TS->percent_sign(); zoom_reset->set_text(zoom_text); } @@ -134,7 +134,7 @@ void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_inte float new_zoom_index = closest_zoom_index + p_increment_count; float new_zoom = Math::pow(2.f, new_zoom_index / 12.f); - // Restore Editor scale transformation + // Restore Editor scale transformation. new_zoom *= MAX(1, EDSCALE); set_zoom(new_zoom); @@ -179,8 +179,12 @@ EditorZoomWidget::EditorZoomWidget() { zoom_reset = memnew(Button); zoom_reset->set_flat(true); + zoom_reset->add_theme_style_override("normal", memnew(StyleBoxEmpty)); + zoom_reset->add_theme_style_override("hover", memnew(StyleBoxEmpty)); + zoom_reset->add_theme_style_override("focus", memnew(StyleBoxEmpty)); + zoom_reset->add_theme_style_override("pressed", memnew(StyleBoxEmpty)); add_child(zoom_reset); - zoom_reset->add_theme_constant_override("outline_size", 1); + zoom_reset->add_theme_constant_override("outline_size", Math::ceil(2 * EDSCALE)); zoom_reset->add_theme_color_override("font_outline_color", Color(0, 0, 0)); zoom_reset->add_theme_color_override("font_color", Color(1, 1, 1)); zoom_reset->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_reset)); @@ -189,7 +193,7 @@ EditorZoomWidget::EditorZoomWidget() { zoom_reset->set_focus_mode(FOCUS_NONE); zoom_reset->set_text_alignment(HORIZONTAL_ALIGNMENT_CENTER); // Prevent the button's size from changing when the text size changes - zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0)); + zoom_reset->set_custom_minimum_size(Size2(56 * EDSCALE, 0)); zoom_plus = memnew(Button); zoom_plus->set_flat(true); @@ -201,5 +205,5 @@ EditorZoomWidget::EditorZoomWidget() { _update_zoom_label(); - add_theme_constant_override("separation", Math::round(-8 * EDSCALE)); + add_theme_constant_override("separation", 0); } diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 4900ced2e4..bc429e1111 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -129,10 +129,20 @@ void EditorExport::add_export_preset(const Ref<EditorExportPreset> &p_preset, in } String EditorExportPlatform::test_etc2() const { - const bool etc2_supported = GLOBAL_GET("rendering/textures/vram_compression/import_etc2"); + const bool etc2_supported = GLOBAL_GET("rendering/textures/vram_compression/import_etc2_astc"); if (!etc2_supported) { - return TTR("Target platform requires 'ETC2' texture compression. Enable 'Import Etc 2' in Project Settings."); + return TTR("Target platform requires 'ETC2/ASTC' texture compression. Enable 'Import ETC2 ASTC' in Project Settings."); + } + + return String(); +} + +String EditorExportPlatform::test_bc() const { + const bool bc_supported = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc_bptc"); + + if (!bc_supported) { + return TTR("Target platform requires 'S3TC/BPTC' texture compression. Enable 'Import S3TC BPTC' in Project Settings."); } return String(); diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 9f79eecfb7..a46484bb0e 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -785,10 +785,10 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector break; } } - } - if (_export_customize_object(res.ptr(), customize_resources_plugins)) { - modified = true; + if (_export_customize_object(res.ptr(), customize_resources_plugins)) { + modified = true; + } } if (modified || p_force_save) { @@ -814,7 +814,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & HashSet<String> paths; Vector<String> path_remaps; - paths.insert(ProjectSettings::get_singleton()->get_project_data_path().path_join("global_script_class_cache.cfg")); + paths.insert(ProjectSettings::get_singleton()->get_global_class_list_path()); if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_ALL_RESOURCES) { //find stuff _export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths); @@ -1802,6 +1802,13 @@ Error EditorExportPlatform::ssh_run_on_remote(const String &p_host, const String List<String> args; args.push_back("-p"); args.push_back(p_port); + args.push_back("-q"); + args.push_back("-o"); + args.push_back("LogLevel=error"); + args.push_back("-o"); + args.push_back("BatchMode=yes"); + args.push_back("-o"); + args.push_back("StrictHostKeyChecking=no"); for (const String &E : p_ssh_args) { args.push_back(E); } @@ -1852,6 +1859,13 @@ Error EditorExportPlatform::ssh_run_on_remote_no_wait(const String &p_host, cons List<String> args; args.push_back("-p"); args.push_back(p_port); + args.push_back("-q"); + args.push_back("-o"); + args.push_back("LogLevel=error"); + args.push_back("-o"); + args.push_back("BatchMode=yes"); + args.push_back("-o"); + args.push_back("StrictHostKeyChecking=no"); for (const String &E : p_ssh_args) { args.push_back(E); } @@ -1882,6 +1896,13 @@ Error EditorExportPlatform::ssh_push_to_remote(const String &p_host, const Strin List<String> args; args.push_back("-P"); args.push_back(p_port); + args.push_back("-q"); + args.push_back("-o"); + args.push_back("LogLevel=error"); + args.push_back("-o"); + args.push_back("BatchMode=yes"); + args.push_back("-o"); + args.push_back("StrictHostKeyChecking=no"); for (const String &E : p_scp_args) { args.push_back(E); } diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index 3b4e92c9bd..05d985eb6a 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -229,6 +229,7 @@ public: virtual Ref<Texture2D> get_run_icon() const { return get_logo(); } String test_etc2() const; + String test_bc() const; bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0; virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const = 0; diff --git a/editor/icons/UseBlendDisable.svg b/editor/icons/UseBlendDisable.svg new file mode 100644 index 0000000000..449dc2d0c8 --- /dev/null +++ b/editor/icons/UseBlendDisable.svg @@ -0,0 +1 @@ +<svg enable-background="new -595.5 420.5 16 16" height="16" viewBox="-595.5 420.5 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-591 421.5h7v14h-7z" fill="#a3e595" opacity=".5"/><g fill="none" stroke="#a3e595" stroke-linecap="square" stroke-width="2"><path d="m-585 434.5v-12"/><path d="m-590 422.5v12"/><path d="m-581.5 422.5h-12"/></g></svg> diff --git a/editor/icons/UseBlendEnable.svg b/editor/icons/UseBlendEnable.svg new file mode 100644 index 0000000000..5567b2d8c6 --- /dev/null +++ b/editor/icons/UseBlendEnable.svg @@ -0,0 +1 @@ +<svg enable-background="new -595.5 420.5 16 16" height="16" viewBox="-595.5 420.5 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-587.5 423.244c-3.995 2.354-7 6.775-7 11.256v1h14v-1c0-4.48-3.005-8.901-7-11.256z" fill="#95c6e8" opacity=".5"/><g fill="none" stroke="#95c6e8" stroke-linecap="square" stroke-width="2"><path d="m-581.5 422.5c-6 0-12 6-12 12"/><path d="m-581.5 434.5c0-6-6-12-12-12"/></g></svg> diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index bc4ced7ea2..10a0c2662f 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -123,6 +123,9 @@ bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_path, if (p_option == "compress/lossy_quality" && p_options.has("compress/mode")) { return int(p_options["compress/mode"]) == COMPRESS_LOSSY; } + if ((p_option == "compress/high_quality" || p_option == "compress/hdr_compression") && p_options.has("compress/mode")) { + return int(p_options["compress/mode"]) == COMPRESS_VRAM_COMPRESSED; + } return true; } @@ -136,9 +139,9 @@ String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const { void ResourceImporterLayeredTexture::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized,Normal Map (RG Channels)"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1)); @@ -283,8 +286,8 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { int compress_mode = p_options["compress/mode"]; float lossy = p_options["compress/lossy_quality"]; + float high_quality = p_options["compress/high_quality"]; int hdr_compression = p_options["compress/hdr_compression"]; - int bptc_ldr = p_options["compress/bptc_ldr"]; bool mipmaps = p_options["mipmaps/generate"]; int channel_pack = p_options["compress/channel_pack"]; @@ -389,9 +392,10 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const texture_import->compress_mode = compress_mode; texture_import->lossy = lossy; texture_import->hdr_compression = hdr_compression; - texture_import->bptc_ldr = bptc_ldr; texture_import->mipmaps = mipmaps; texture_import->used_channels = used_channels; + texture_import->high_quality = high_quality; + _check_compress_ctex(p_source_file, texture_import); if (r_metadata) { Dictionary meta; @@ -406,12 +410,11 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const } const char *ResourceImporterLayeredTexture::compression_formats[] = { - "bptc", - "s3tc", - "etc", - "etc2", + "s3tc_bptc", + "etc2_astc", nullptr }; + String ResourceImporterLayeredTexture::get_import_settings_string() const { String s; @@ -450,12 +453,16 @@ bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_p bool valid = true; while (compression_formats[index]) { String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]); - bool test = GLOBAL_GET(setting_path); - if (test) { - if (!formats_imported.has(compression_formats[index])) { - valid = false; - break; + if (ProjectSettings::get_singleton()->has_setting(setting_path)) { + bool test = GLOBAL_GET(setting_path); + if (test) { + if (!formats_imported.has(compression_formats[index])) { + valid = false; + break; + } } + } else { + WARN_PRINT("Setting for imported format not found: " + setting_path); } index++; } @@ -484,64 +491,83 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source // Must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). // Android, GLES 2.x - bool can_bptc = GLOBAL_GET("rendering/textures/vram_compression/import_bptc"); - if (can_bptc) { - r_texture_import->formats_imported.push_back("bptc"); // BPTC needs to be added anyway. + const bool can_s3tc_bptc = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc_bptc") || OS::get_singleton()->get_preferred_texture_format() == OS::PREFERRED_TEXTURE_FORMAT_S3TC_BPTC; + const bool can_etc2_astc = GLOBAL_GET("rendering/textures/vram_compression/import_etc2_astc") || OS::get_singleton()->get_preferred_texture_format() == OS::PREFERRED_TEXTURE_FORMAT_ETC2_ASTC; + + // Add list of formats imported + if (can_s3tc_bptc) { + r_texture_import->formats_imported.push_back("s3tc_bptc"); } + if (can_etc2_astc) { + r_texture_import->formats_imported.push_back("etc2_astc"); + } + bool can_compress_hdr = r_texture_import->hdr_compression > 0; ERR_FAIL_NULL(r_texture_import->image); bool is_hdr = (r_texture_import->image->get_format() >= Image::FORMAT_RF && r_texture_import->image->get_format() <= Image::FORMAT_RGBE9995); - bool is_ldr = (r_texture_import->image->get_format() >= Image::FORMAT_L8 && r_texture_import->image->get_format() <= Image::FORMAT_RGB565); - bool can_s3tc = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc"); ERR_FAIL_NULL(r_texture_import->slices); // Can compress hdr, but hdr with alpha is not compressible. - if (r_texture_import->hdr_compression == 2) { - // The user selected to compress hdr anyway, so force an alpha-less format. - if (r_texture_import->image->get_format() == Image::FORMAT_RGBAF) { - for (int i = 0; i < r_texture_import->slices->size(); i++) { - r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBF); - } + bool use_uncompressed = false; + + if (is_hdr) { + if (r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA) { + if (r_texture_import->hdr_compression == 2) { + // The user selected to compress hdr anyway, so force an alpha-less format. + if (r_texture_import->image->get_format() == Image::FORMAT_RGBAF) { + for (int i = 0; i < r_texture_import->slices->size(); i++) { + r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBF); + } - } else if (r_texture_import->image->get_format() == Image::FORMAT_RGBAH) { - for (int i = 0; i < r_texture_import->slices->size(); i++) { - r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBH); + } else if (r_texture_import->image->get_format() == Image::FORMAT_RGBAH) { + for (int i = 0; i < r_texture_import->slices->size(); i++) { + r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBH); + } + } + } else { + can_compress_hdr = false; } } - } else { - can_compress_hdr = false; - } - if (is_hdr && can_compress_hdr) { - if (!can_bptc) { + if (!can_compress_hdr) { //default to rgbe if (r_texture_import->image->get_format() != Image::FORMAT_RGBE9995) { for (int i = 0; i < r_texture_import->slices->size(); i++) { r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBE9995); } } + use_uncompressed = true; } - } else { - can_bptc = false; } - if (is_ldr && can_bptc) { - if (r_texture_import->bptc_ldr == 0 || (r_texture_import->bptc_ldr == 1 && !(r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA))) { - can_bptc = false; - } - } - if (!(r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA)) { - if (GLOBAL_GET("rendering/textures/vram_compression/import_etc2")) { - _save_tex(*r_texture_import->slices, r_texture_import->save_path + ".etc2." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_ETC2, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true); - r_texture_import->platform_variants->push_back("etc2"); - r_texture_import->formats_imported.push_back("etc2"); + if (use_uncompressed) { + _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, COMPRESS_VRAM_UNCOMPRESSED, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); + } else { + if (can_s3tc_bptc) { + Image::CompressMode image_compress_mode; + String image_compress_format; + if (r_texture_import->high_quality || is_hdr) { + image_compress_mode = Image::COMPRESS_BPTC; + image_compress_format = "bptc"; + } else { + image_compress_mode = Image::COMPRESS_S3TC; + image_compress_format = "s3tc"; + } + _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true); + r_texture_import->platform_variants->push_back(image_compress_format); } - if (can_bptc || can_s3tc) { - _save_tex(*r_texture_import->slices, r_texture_import->save_path + ".s3tc." + extension, r_texture_import->compress_mode, r_texture_import->lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); - r_texture_import->platform_variants->push_back("s3tc"); - r_texture_import->formats_imported.push_back("s3tc"); + if (can_etc2_astc) { + Image::CompressMode image_compress_mode; + String image_compress_format; + if (r_texture_import->high_quality || is_hdr) { + image_compress_mode = Image::COMPRESS_ASTC; + image_compress_format = "astc"; + } else { + image_compress_mode = Image::COMPRESS_ETC2; + image_compress_format = "etc2"; + } + _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true); + r_texture_import->platform_variants->push_back(image_compress_format); } - return; } - EditorNode::add_io_error(vformat(TTR("%s: No suitable PC VRAM compression algorithm enabled in Project Settings (S3TC or BPTC). This texture may not display correctly on desktop platforms."), p_source_file)); } diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h index 5118ad7ba4..52fd37639d 100644 --- a/editor/import/resource_importer_layered_texture.h +++ b/editor/import/resource_importer_layered_texture.h @@ -51,8 +51,8 @@ public: int compress_mode = 0; float lossy = 1.0; int hdr_compression = 0; - int bptc_ldr = 0; bool mipmaps = true; + bool high_quality = false; Image::UsedChannels used_channels = Image::USED_CHANNELS_RGBA; virtual ~LayeredTextureImport() {} }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 102fa903b8..6c6c89bcc0 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1085,10 +1085,10 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co return p_node; } -Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) { +Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale) { // children first for (int i = 0; i < p_node->get_child_count(); i++) { - Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_occluder_arrays, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps); + Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_occluder_arrays, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps, p_applied_root_scale); if (!r) { i--; //was erased } @@ -1231,7 +1231,8 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< } else { shapes = get_collision_shapes( m->get_mesh(), - node_settings); + node_settings, + p_applied_root_scale); } if (shapes.size()) { @@ -1242,6 +1243,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< p_node->add_child(col, true); col->set_owner(p_node->get_owner()); col->set_transform(get_collision_shapes_transform(node_settings)); + col->set_position(p_applied_root_scale * col->get_position()); base = col; } break; case MESH_PHYSICS_RIGID_BODY_AND_MESH: { @@ -1249,6 +1251,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< rigid_body->set_name(p_node->get_name()); p_node->replace_by(rigid_body); rigid_body->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings)); + rigid_body->set_position(p_applied_root_scale * rigid_body->get_position()); p_node = rigid_body; mi->set_transform(Transform3D()); rigid_body->add_child(mi, true); @@ -1258,6 +1261,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< case MESH_PHYSICS_STATIC_COLLIDER_ONLY: { StaticBody3D *col = memnew(StaticBody3D); col->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings)); + col->set_position(p_applied_root_scale * col->get_position()); col->set_name(p_node->get_name()); p_node->replace_by(col); memdelete(p_node); @@ -1267,6 +1271,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< case MESH_PHYSICS_AREA_ONLY: { Area3D *area = memnew(Area3D); area->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings)); + area->set_position(p_applied_root_scale * area->get_position()); area->set_name(p_node->get_name()); p_node->replace_by(area); memdelete(p_node); @@ -1865,6 +1870,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/remove_immutable_tracks"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary())); @@ -2397,7 +2403,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p fps = (float)p_options[SNAME("animation/fps")]; } _pre_fix_animations(scene, scene, node_data, animation_data, fps); - _post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps); + _post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps, apply_root ? root_scale : 1.0); _post_fix_animations(scene, scene, node_data, animation_data, fps); String root_type = p_options["nodes/root_type"]; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 2d08d4df50..aa057d3404 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -279,7 +279,7 @@ public: Node *_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames); Node *_pre_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps); - Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps); + Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale); Node *_post_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps); Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks); @@ -298,7 +298,7 @@ public: ResourceImporterScene(bool p_animation_import = false); template <class M> - static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options); + static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options, float p_applied_root_scale); template <class M> static Transform3D get_collision_shapes_transform(const M &p_options); @@ -314,7 +314,7 @@ public: }; template <class M> -Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options) { +Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options, float p_applied_root_scale) { ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX; if (p_options.has(SNAME("physics/shape_type"))) { generate_shape_type = (ShapeType)p_options[SNAME("physics/shape_type")].operator int(); @@ -409,7 +409,7 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> Ref<BoxShape3D> box; box.instantiate(); if (p_options.has(SNAME("primitive/size"))) { - box->set_size(p_options[SNAME("primitive/size")]); + box->set_size(p_options[SNAME("primitive/size")].operator Vector3() * p_applied_root_scale); } Vector<Ref<Shape3D>> shapes; @@ -420,7 +420,7 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> Ref<SphereShape3D> sphere; sphere.instantiate(); if (p_options.has(SNAME("primitive/radius"))) { - sphere->set_radius(p_options[SNAME("primitive/radius")]); + sphere->set_radius(p_options[SNAME("primitive/radius")].operator float() * p_applied_root_scale); } Vector<Ref<Shape3D>> shapes; @@ -430,10 +430,10 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> Ref<CylinderShape3D> cylinder; cylinder.instantiate(); if (p_options.has(SNAME("primitive/height"))) { - cylinder->set_height(p_options[SNAME("primitive/height")]); + cylinder->set_height(p_options[SNAME("primitive/height")].operator float() * p_applied_root_scale); } if (p_options.has(SNAME("primitive/radius"))) { - cylinder->set_radius(p_options[SNAME("primitive/radius")]); + cylinder->set_radius(p_options[SNAME("primitive/radius")].operator float() * p_applied_root_scale); } Vector<Ref<Shape3D>> shapes; @@ -443,10 +443,10 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> Ref<CapsuleShape3D> capsule; capsule.instantiate(); if (p_options.has(SNAME("primitive/height"))) { - capsule->set_height(p_options[SNAME("primitive/height")]); + capsule->set_height(p_options[SNAME("primitive/height")].operator float() * p_applied_root_scale); } if (p_options.has(SNAME("primitive/radius"))) { - capsule->set_radius(p_options[SNAME("primitive/radius")]); + capsule->set_radius(p_options[SNAME("primitive/radius")].operator float() * p_applied_root_scale); } Vector<Ref<Shape3D>> shapes; diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 2f543ea02d..c05e7582eb 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -169,9 +169,14 @@ String ResourceImporterTexture::get_resource_type() const { } bool ResourceImporterTexture::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { - if (p_option == "compress/lossy_quality") { + if (p_option == "compress/high_quality" || p_option == "compress/hdr_compression") { int compress_mode = int(p_options["compress/mode"]); - if (compress_mode != COMPRESS_LOSSY && compress_mode != COMPRESS_VRAM_COMPRESSED) { + if (compress_mode != COMPRESS_VRAM_COMPRESSED) { + return false; + } + } else if (p_option == "compress/lossy_quality") { + int compress_mode = int(p_options["compress/mode"]); + if (compress_mode != COMPRESS_LOSSY) { return false; } } else if (p_option == "compress/hdr_mode") { @@ -186,15 +191,6 @@ bool ResourceImporterTexture::get_option_visibility(const String &p_path, const } } else if (p_option == "mipmaps/limit") { return p_options["mipmaps/generate"]; - - } else if (p_option == "compress/bptc_ldr") { - int compress_mode = int(p_options["compress/mode"]); - if (compress_mode < COMPRESS_VRAM_COMPRESSED) { - return false; - } - if (!GLOBAL_GET("rendering/textures/vram_compression/import_bptc")) { - return false; - } } return true; @@ -216,9 +212,9 @@ String ResourceImporterTexture::get_preset_name(int p_idx) const { void ResourceImporterTexture::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 2 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/normal_map", PROPERTY_HINT_ENUM, "Detect,Enable,Disabled"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), (p_preset == PRESET_3D ? true : false))); @@ -289,7 +285,7 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I case COMPRESS_VRAM_COMPRESSED: { Ref<Image> image = p_image->duplicate(); - image->compress_from_channels(p_compress_format, p_channels, p_lossy_quality); + image->compress_from_channels(p_compress_format, p_channels); f->store_32(CompressedTexture2D::DATA_FORMAT_IMAGE); f->store_16(image->get_width()); @@ -322,15 +318,11 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); f->store_32(p_image->get_format()); - - for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) { - Vector<uint8_t> data = Image::basis_universal_packer(p_image->get_image_from_mipmap(i), p_channels); - int data_len = data.size(); - f->store_32(data_len); - - const uint8_t *r = data.ptr(); - f->store_buffer(r, data_len); - } + Vector<uint8_t> data = Image::basis_universal_packer(p_image, p_channels); + int data_len = data.size(); + f->store_32(data_len); + const uint8_t *r = data.ptr(); + f->store_buffer(r, data_len); } break; } } @@ -387,7 +379,7 @@ void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String Ref<Image> image = p_image->duplicate(); - if (((p_compress_mode == COMPRESS_BASIS_UNIVERSAL) || (p_compress_mode == COMPRESS_VRAM_COMPRESSED && p_force_po2_for_compressed)) && p_mipmaps) { + if (p_force_po2_for_compressed && p_mipmaps && ((p_compress_mode == COMPRESS_BASIS_UNIVERSAL) || (p_compress_mode == COMPRESS_VRAM_COMPRESSED))) { image->resize_to_po2(); } @@ -425,7 +417,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String const int pack_channels = p_options["compress/channel_pack"]; const int normal = p_options["compress/normal_map"]; const int hdr_compression = p_options["compress/hdr_compression"]; - const int bptc_ldr = p_options["compress/bptc_ldr"]; + const int high_quality = p_options["compress/high_quality"]; // Mipmaps. const bool mipmaps = p_options["mipmaps/generate"]; @@ -598,19 +590,22 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String // Android, GLES 2.x const bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995); - bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565); - const bool can_bptc = GLOBAL_GET("rendering/textures/vram_compression/import_bptc"); - const bool can_s3tc = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc"); + const bool can_s3tc_bptc = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc_bptc") || OS::get_singleton()->get_preferred_texture_format() == OS::PREFERRED_TEXTURE_FORMAT_S3TC_BPTC; + const bool can_etc2_astc = GLOBAL_GET("rendering/textures/vram_compression/import_etc2_astc") || OS::get_singleton()->get_preferred_texture_format() == OS::PREFERRED_TEXTURE_FORMAT_ETC2_ASTC; - if (can_bptc) { - // Add to the list anyway. - formats_imported.push_back("bptc"); + // Add list of formats imported + if (can_s3tc_bptc) { + formats_imported.push_back("s3tc_bptc"); + } + if (can_etc2_astc) { + formats_imported.push_back("etc2_astc"); } bool can_compress_hdr = hdr_compression > 0; bool has_alpha = image->detect_alpha() != Image::ALPHA_NONE; + bool use_uncompressed = false; - if (is_hdr && can_compress_hdr) { + if (is_hdr) { if (has_alpha) { // Can compress HDR, but HDR with alpha is not compressible. if (hdr_compression == 2) { @@ -629,36 +624,41 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String // Fallback to RGBE99995. if (image->get_format() != Image::FORMAT_RGBE9995) { image->convert(Image::FORMAT_RGBE9995); + use_uncompressed = true; } } } - bool ok_on_pc = false; - if (can_bptc || can_s3tc) { - ok_on_pc = true; - Image::CompressMode image_compress_mode = Image::COMPRESS_BPTC; - if (!bptc_ldr && can_s3tc && is_ldr) { - image_compress_mode = Image::COMPRESS_S3TC; + if (use_uncompressed) { + _save_ctex(image, p_save_path + ".ctex", COMPRESS_VRAM_UNCOMPRESSED, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); + } else { + if (can_s3tc_bptc) { + Image::CompressMode image_compress_mode; + String image_compress_format; + if (high_quality || is_hdr) { + image_compress_mode = Image::COMPRESS_BPTC; + image_compress_format = "bptc"; + } else { + image_compress_mode = Image::COMPRESS_S3TC; + image_compress_format = "s3tc"; + } + _save_ctex(image, p_save_path + "." + image_compress_format + ".ctex", compress_mode, lossy, image_compress_mode, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); + r_platform_variants->push_back(image_compress_format); } - _save_ctex(image, p_save_path + ".s3tc.ctex", compress_mode, lossy, image_compress_mode, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); - r_platform_variants->push_back("s3tc"); - formats_imported.push_back("s3tc"); - } - - if (GLOBAL_GET("rendering/textures/vram_compression/import_etc2")) { - _save_ctex(image, p_save_path + ".etc2.ctex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); - r_platform_variants->push_back("etc2"); - formats_imported.push_back("etc2"); - } - if (GLOBAL_GET("rendering/textures/vram_compression/import_etc")) { - _save_ctex(image, p_save_path + ".etc.ctex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); - r_platform_variants->push_back("etc"); - formats_imported.push_back("etc"); - } - - if (!ok_on_pc) { - EditorNode::add_io_error(vformat(TTR("%s: No suitable desktop VRAM compression algorithm enabled in Project Settings (S3TC or BPTC). This texture may not display correctly on desktop platforms."), p_source_file)); + if (can_etc2_astc) { + Image::CompressMode image_compress_mode; + String image_compress_format; + if (high_quality || is_hdr) { + image_compress_mode = Image::COMPRESS_ASTC; + image_compress_format = "astc"; + } else { + image_compress_mode = Image::COMPRESS_ETC2; + image_compress_format = "etc2"; + } + _save_ctex(image, p_save_path + "." + image_compress_format + ".ctex", compress_mode, lossy, image_compress_mode, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); + r_platform_variants->push_back(image_compress_format); + } } } else { // Import normally. @@ -692,10 +692,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String } const char *ResourceImporterTexture::compression_formats[] = { - "bptc", - "s3tc", - "etc", - "etc2", + "s3tc_bptc", + "etc2_astc", nullptr }; String ResourceImporterTexture::get_import_settings_string() const { @@ -745,12 +743,16 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co bool valid = true; while (compression_formats[index]) { String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]); - bool test = GLOBAL_GET(setting_path); - if (test) { - if (!formats_imported.has(compression_formats[index])) { - valid = false; - break; + if (ProjectSettings::get_singleton()->has_setting(setting_path)) { + bool test = GLOBAL_GET(setting_path); + if (test) { + if (!formats_imported.has(compression_formats[index])) { + valid = false; + break; + } } + } else { + WARN_PRINT("Setting for imported format not found: " + setting_path); } index++; } diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 044f7475c2..8d26feebf4 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -441,7 +441,7 @@ void SceneImportSettings::_update_view_gizmos() { // This collider_view doesn't have a mesh so we need to generate a new one. // Generate the mesh collider. - Vector<Ref<Shape3D>> shapes = ResourceImporterScene::get_collision_shapes(mesh_node->get_mesh(), e.value.settings); + Vector<Ref<Shape3D>> shapes = ResourceImporterScene::get_collision_shapes(mesh_node->get_mesh(), e.value.settings, 1.0); const Transform3D transform = ResourceImporterScene::get_collision_shapes_transform(e.value.settings); Ref<ArrayMesh> collider_view_mesh; diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index 48e3759e57..fb450a41d3 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -201,7 +201,7 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven } if (k.is_valid()) { - k->set_pressed(false); // To avoid serialisation of 'pressed' property - doesn't matter for actions anyway. + k->set_pressed(false); // To avoid serialization of 'pressed' property - doesn't matter for actions anyway. if (key_mode->get_selected_id() == KEYMODE_KEYCODE) { k->set_physical_keycode(Key::NONE); k->set_key_label(Key::NONE); @@ -685,9 +685,9 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { // Key Mode Selection key_mode = memnew(OptionButton); - key_mode->add_item("Keycode (Latin equvialent)", KEYMODE_KEYCODE); - key_mode->add_item("Physical Keycode (poistion of US QWERTY keyboard)", KEYMODE_PHY_KEYCODE); - key_mode->add_item("Unicode (case-insencetive)", KEYMODE_UNICODE); + key_mode->add_item(TTR("Keycode (Latin Equivalent)"), KEYMODE_KEYCODE); + key_mode->add_item(TTR("Physical Keycode (Position on US QWERTY Keyboard)"), KEYMODE_PHY_KEYCODE); + key_mode->add_item(TTR("Key Label (Unicode, Case-Insensitive)"), KEYMODE_UNICODE); key_mode->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_key_mode_selected)); key_mode->hide(); additional_options_container->add_child(key_mode); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 33aebe5883..df94815105 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/gui/check_box.h" +#include "scene/gui/option_button.h" #include "scene/gui/panel_container.h" StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { @@ -335,6 +336,7 @@ void AnimationNodeBlendSpace1DEditor::_update_space() { min_value->set_value(blend_space->get_min_space()); sync->set_pressed(blend_space->is_using_sync()); + interpolation->select(blend_space->get_blend_mode()); label_value->set_text(blend_space->get_value_label()); @@ -361,6 +363,8 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) { undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap()); undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed()); undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync()); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected()); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode()); undo_redo->add_do_method(this, "_update_space"); undo_redo->add_undo_method(this, "_update_space"); undo_redo->commit_action(); @@ -579,6 +583,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons"))); open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons"))); + interpolation->clear(); + interpolation->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), "", 0); + interpolation->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), "", 1); + interpolation->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), "", 2); } break; case NOTIFICATION_PROCESS: { @@ -639,6 +647,7 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) { min_value->set_editable(!read_only); max_value->set_editable(!read_only); sync->set_disabled(read_only); + interpolation->set_disabled(read_only); } AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr; @@ -707,6 +716,13 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { top_hb->add_child(sync); sync->connect("toggled", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed)); + top_hb->add_child(memnew(VSeparator)); + + top_hb->add_child(memnew(Label(TTR("Blend:")))); + interpolation = memnew(OptionButton); + top_hb->add_child(interpolation); + interpolation->connect("item_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed)); + edit_hb = memnew(HBoxContainer); top_hb->add_child(edit_hb); edit_hb->add_child(memnew(VSeparator)); diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h index e71a4bd1b9..90104fc310 100644 --- a/editor/plugins/animation_blend_space_1d_editor.h +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -41,6 +41,7 @@ #include "scene/gui/tree.h" class CheckBox; +class OptionButton; class PanelContainer; class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { @@ -66,6 +67,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { SpinBox *min_value = nullptr; CheckBox *sync = nullptr; + OptionButton *interpolation = nullptr; HBoxContainer *edit_hb = nullptr; SpinBox *edit_value = nullptr; diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 06241d07cf..b33ad67f23 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -245,7 +245,7 @@ void AnimationPlayerEditor::_play_bw_pressed() { player->stop(); //so it won't blend with itself } ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); - player->play(current, -1, -1, true); + player->play_backwards(current); } //unstop @@ -262,7 +262,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { } ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); player->seek(time); - player->play(current, -1, -1, true); + player->play_backwards(current); } //unstop @@ -452,7 +452,9 @@ float AnimationPlayerEditor::_get_editor_step() const { } void AnimationPlayerEditor::_animation_name_edited() { - player->stop(); + if (player->is_playing()) { + player->stop(); + } String new_name = name->get_text(); if (!AnimationLibrary::is_valid_animation_name(new_name)) { @@ -1103,9 +1105,24 @@ void AnimationPlayerEditor::_animation_duplicate() { return; } + int count = 2; String new_name = current; - while (player->has_animation(new_name)) { - new_name = new_name + " (copy)"; + PackedStringArray split = new_name.split("_"); + int last_index = split.size() - 1; + if (last_index > 0 && split[last_index].is_valid_int() && split[last_index].to_int() >= 0) { + count = split[last_index].to_int(); + split.remove_at(last_index); + new_name = String("_").join(split); + } + while (true) { + String attempt = new_name; + attempt += vformat("_%d", count); + if (player->has_animation(attempt)) { + count++; + continue; + } + new_name = attempt; + break; } if (new_name.contains("/")) { @@ -1675,7 +1692,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug stop = memnew(Button); stop->set_flat(true); hb->add_child(stop); - stop->set_tooltip_text(TTR("Stop animation playback. (S)")); + stop->set_tooltip_text(TTR("Pause/stop animation playback. (S)")); play = memnew(Button); play->set_flat(true); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 7ede0bd68c..9632670658 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1138,7 +1138,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co accent.a *= 0.6; } - const Ref<Texture2D> icons[6] = { + const Ref<Texture2D> icons[] = { get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons")), get_theme_icon(SNAME("TransitionSyncBig"), SNAME("EditorIcons")), get_theme_icon(SNAME("TransitionEndBig"), SNAME("EditorIcons")), @@ -1146,6 +1146,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co get_theme_icon(SNAME("TransitionSyncAutoBig"), SNAME("EditorIcons")), get_theme_icon(SNAME("TransitionEndAutoBig"), SNAME("EditorIcons")) }; + const int ICON_COUNT = sizeof(icons) / sizeof(*icons); if (p_selected) { state_machine_draw->draw_line(p_from, p_to, accent, 6); @@ -1162,7 +1163,9 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co fade_linecolor.set_hsv(1.0, fade_linecolor.get_s(), fade_linecolor.get_v()); state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_linecolor, 2); } - Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; + int icon_index = p_mode + (p_auto_advance ? ICON_COUNT / 2 : 0); + ERR_FAIL_COND(icon_index >= ICON_COUNT); + Ref<Texture2D> icon = icons[icon_index]; Transform2D xf; xf.columns[0] = (p_to - p_from).normalized(); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 720deb0b92..ab46e8f04a 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -65,13 +65,14 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) { tree = p_tree; Vector<String> path; - if (tree && tree->has_meta("_tree_edit_path")) { - path = tree->get_meta("_tree_edit_path"); - } else { - current_root = ObjectID(); + if (tree) { + if (tree->has_meta("_tree_edit_path")) { + path = tree->get_meta("_tree_edit_path"); + } else { + current_root = ObjectID(); + } + edit_path(path); } - - edit_path(path); } void AnimationTreeEditor::_node_removed(Node *p_node) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index e09636d297..0f9ce89f02 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5401,11 +5401,13 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) { canvas_item_editor->show(); canvas_item_editor->set_physics_process(true); RenderingServer::get_singleton()->viewport_set_disable_2d(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), false); + RenderingServer::get_singleton()->viewport_set_environment_mode(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), RS::VIEWPORT_ENVIRONMENT_ENABLED); } else { canvas_item_editor->hide(); canvas_item_editor->set_physics_process(false); RenderingServer::get_singleton()->viewport_set_disable_2d(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), true); + RenderingServer::get_singleton()->viewport_set_environment_mode(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), RS::VIEWPORT_ENVIRONMENT_DISABLED); } } diff --git a/editor/plugins/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp index 21a1d839f0..dff92ced27 100644 --- a/editor/plugins/navigation_link_2d_editor_plugin.cpp +++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp @@ -65,20 +65,20 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { if (mb->is_pressed()) { - // Start location - if (xform.xform(node->get_start_location()).distance_to(mb->get_position()) < grab_threshold) { + // Start position + if (xform.xform(node->get_start_position()).distance_to(mb->get_position()) < grab_threshold) { start_grabbed = true; - original_start_location = node->get_start_location(); + original_start_position = node->get_start_position(); return true; } else { start_grabbed = false; } - // End location - if (xform.xform(node->get_end_location()).distance_to(mb->get_position()) < grab_threshold) { + // End position + if (xform.xform(node->get_end_position()).distance_to(mb->get_position()) < grab_threshold) { end_grabbed = true; - original_end_location = node->get_end_location(); + original_end_position = node->get_end_position(); return true; } else { @@ -87,10 +87,10 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e } else { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (start_grabbed) { - undo_redo->create_action(TTR("Set start_location")); - undo_redo->add_do_method(node, "set_start_location", node->get_start_location()); + undo_redo->create_action(TTR("Set start_position")); + undo_redo->add_do_method(node, "set_start_position", node->get_start_position()); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(node, "set_start_location", original_start_location); + undo_redo->add_undo_method(node, "set_start_position", original_start_position); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); undo_redo->commit_action(); @@ -100,10 +100,10 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e } if (end_grabbed) { - undo_redo->create_action(TTR("Set end_location")); - undo_redo->add_do_method(node, "set_end_location", node->get_end_location()); + undo_redo->create_action(TTR("Set end_position")); + undo_redo->add_do_method(node, "set_end_position", node->get_end_position()); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(node, "set_end_location", original_end_location); + undo_redo->add_undo_method(node, "set_end_position", original_end_position); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); undo_redo->commit_action(); @@ -120,14 +120,14 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e point = node->get_global_transform().affine_inverse().xform(point); if (start_grabbed) { - node->set_start_location(point); + node->set_start_position(point); canvas_item_editor->update_viewport(); return true; } if (end_grabbed) { - node->set_end_location(point); + node->set_end_position(point); canvas_item_editor->update_viewport(); return true; @@ -143,13 +143,13 @@ void NavigationLink2DEditor::forward_canvas_draw_over_viewport(Control *p_overla } Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - Vector2 global_start_location = gt.xform(node->get_start_location()); - Vector2 global_end_location = gt.xform(node->get_end_location()); + Vector2 global_start_position = gt.xform(node->get_start_position()); + Vector2 global_end_position = gt.xform(node->get_end_position()); // Only drawing the handles here, since the debug rendering will fill in the rest. const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons")); - p_overlay->draw_texture(handle, global_start_location - handle->get_size() / 2); - p_overlay->draw_texture(handle, global_end_location - handle->get_size() / 2); + p_overlay->draw_texture(handle, global_start_position - handle->get_size() / 2); + p_overlay->draw_texture(handle, global_end_position - handle->get_size() / 2); } void NavigationLink2DEditor::edit(NavigationLink2D *p_node) { diff --git a/editor/plugins/navigation_link_2d_editor_plugin.h b/editor/plugins/navigation_link_2d_editor_plugin.h index 76444403d0..ea731ca2cd 100644 --- a/editor/plugins/navigation_link_2d_editor_plugin.h +++ b/editor/plugins/navigation_link_2d_editor_plugin.h @@ -43,10 +43,10 @@ class NavigationLink2DEditor : public Control { NavigationLink2D *node = nullptr; bool start_grabbed = false; - Vector2 original_start_location; + Vector2 original_start_position; bool end_grabbed = false; - Vector2 original_end_location; + Vector2 original_end_position; protected: void _notification(int p_what); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 814fbb6d8e..e48a5bb95d 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -5058,8 +5058,8 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map); Vector3::Axis up_axis = up_vector.max_axis_index(); - Vector3 start_location = link->get_start_location(); - Vector3 end_location = link->get_end_location(); + Vector3 start_position = link->get_start_position(); + Vector3 end_position = link->get_end_position(); Ref<Material> link_material = get_material("navigation_link_material", p_gizmo); Ref<Material> link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo); @@ -5069,10 +5069,10 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { // Draw line between the points. Vector<Vector3> lines; - lines.append(start_location); - lines.append(end_location); + lines.append(start_position); + lines.append(end_position); - // Draw start location search radius + // Draw start position search radius for (int i = 0; i < 30; i++) { // Create a circle const float ra = Math::deg_to_rad((float)(i * 12)); @@ -5083,21 +5083,21 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { // Draw axis-aligned circle switch (up_axis) { case Vector3::AXIS_X: - lines.append(start_location + Vector3(0, a.x, a.y)); - lines.append(start_location + Vector3(0, b.x, b.y)); + lines.append(start_position + Vector3(0, a.x, a.y)); + lines.append(start_position + Vector3(0, b.x, b.y)); break; case Vector3::AXIS_Y: - lines.append(start_location + Vector3(a.x, 0, a.y)); - lines.append(start_location + Vector3(b.x, 0, b.y)); + lines.append(start_position + Vector3(a.x, 0, a.y)); + lines.append(start_position + Vector3(b.x, 0, b.y)); break; case Vector3::AXIS_Z: - lines.append(start_location + Vector3(a.x, a.y, 0)); - lines.append(start_location + Vector3(b.x, b.y, 0)); + lines.append(start_position + Vector3(a.x, a.y, 0)); + lines.append(start_position + Vector3(b.x, b.y, 0)); break; } } - // Draw end location search radius + // Draw end position search radius for (int i = 0; i < 30; i++) { // Create a circle const float ra = Math::deg_to_rad((float)(i * 12)); @@ -5108,16 +5108,16 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { // Draw axis-aligned circle switch (up_axis) { case Vector3::AXIS_X: - lines.append(end_location + Vector3(0, a.x, a.y)); - lines.append(end_location + Vector3(0, b.x, b.y)); + lines.append(end_position + Vector3(0, a.x, a.y)); + lines.append(end_position + Vector3(0, b.x, b.y)); break; case Vector3::AXIS_Y: - lines.append(end_location + Vector3(a.x, 0, a.y)); - lines.append(end_location + Vector3(b.x, 0, b.y)); + lines.append(end_position + Vector3(a.x, 0, a.y)); + lines.append(end_position + Vector3(b.x, 0, b.y)); break; case Vector3::AXIS_Z: - lines.append(end_location + Vector3(a.x, a.y, 0)); - lines.append(end_location + Vector3(b.x, b.y, 0)); + lines.append(end_position + Vector3(a.x, a.y, 0)); + lines.append(end_position + Vector3(b.x, b.y, 0)); break; } } @@ -5126,8 +5126,8 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_collision_segments(lines); Vector<Vector3> handles; - handles.append(start_location); - handles.append(end_location); + handles.append(start_position); + handles.append(end_position); p_gizmo->add_handles(handles, handles_material); } @@ -5137,7 +5137,7 @@ String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_node_3d()); - return p_id == 0 ? link->get_start_location() : link->get_end_location(); + return p_id == 0 ? link->get_start_position() : link->get_end_position(); } void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { @@ -5152,8 +5152,8 @@ void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); - Vector3 location = p_id == 0 ? link->get_start_location() : link->get_end_location(); - Plane move_plane = Plane(cam_dir, gt.xform(location)); + Vector3 position = p_id == 0 ? link->get_start_position() : link->get_end_position(); + Plane move_plane = Plane(cam_dir, gt.xform(position)); Vector3 intersection; if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) { @@ -5165,11 +5165,11 @@ void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i intersection.snap(Vector3(snap, snap, snap)); } - location = gi.xform(intersection); + position = gi.xform(intersection); if (p_id == 0) { - link->set_start_location(location); + link->set_start_position(position); } else if (p_id == 1) { - link->set_end_location(location); + link->set_end_position(position); } } @@ -5178,22 +5178,22 @@ void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo if (p_cancel) { if (p_id == 0) { - link->set_start_location(p_restore); + link->set_start_position(p_restore); } else { - link->set_end_location(p_restore); + link->set_end_position(p_restore); } return; } EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (p_id == 0) { - ur->create_action(TTR("Change Start Location")); - ur->add_do_method(link, "set_start_location", link->get_start_location()); - ur->add_undo_method(link, "set_start_location", p_restore); + ur->create_action(TTR("Change Start Position")); + ur->add_do_method(link, "set_start_position", link->get_start_position()); + ur->add_undo_method(link, "set_start_position", p_restore); } else { - ur->create_action(TTR("Change End Location")); - ur->add_do_method(link, "set_end_location", link->get_end_location()); - ur->add_undo_method(link, "set_end_location", p_restore); + ur->create_action(TTR("Change End Position")); + ur->add_do_method(link, "set_end_position", link->get_end_position()); + ur->add_undo_method(link, "set_end_position", p_restore); } ur->commit_action(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index f1b7ed73b8..36d1e54246 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1414,7 +1414,7 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const // Recalculate orthogonalized scale without moving origin. if (p_orthogonal) { - s.basis = p_original_local.basis.scaled_orthogonal(p_motion + Vector3(1, 1, 1)); + s.basis = p_original.basis.scaled_orthogonal(p_motion + Vector3(1, 1, 1)); // The scaled_orthogonal() does not require orthogonal Basis, // but it may make a bit skew by precision problems. s.basis.orthogonalize(); @@ -4611,7 +4611,9 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) { // TRANSLATORS: Refers to changing the scale of a node in the 3D editor. set_message(TTR("Scaling:") + " (" + String::num(motion_snapped.x, snap_step_decimals) + ", " + String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); - motion = _edit.original.basis.inverse().xform(motion); + if (local_coords) { + motion = _edit.original.basis.inverse().xform(motion); + } List<Node *> &selection = editor_selection->get_selected_node_list(); for (Node *E : selection) { @@ -4639,7 +4641,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) { se->gizmo->set_subgizmo_transform(GE.key, new_xform); } } else { - Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS); + Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS && _edit.plane != TRANSFORM_VIEW); _transform_gizmo_apply(se->sp, new_xform, local_coords); } } @@ -4712,7 +4714,9 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) { // TRANSLATORS: Refers to changing the position of a node in the 3D editor. set_message(TTR("Translating:") + " (" + String::num(motion_snapped.x, snap_step_decimals) + ", " + String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); - motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion); + if (local_coords) { + motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion); + } List<Node *> &selection = editor_selection->get_selected_node_list(); for (Node *E : selection) { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index b719a2ce30..6b4e7184d9 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -252,12 +252,14 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) { } else if (p_line.get_type() == Variant::DICTIONARY) { Dictionary meta = p_line.operator Dictionary(); const int line = meta["line"].operator int64_t() - 1; + const String code = meta["code"].operator String(); + const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; CodeEdit *text_editor = code_editor->get_text_editor(); String prev_line = line > 0 ? text_editor->get_line(line - 1) : ""; if (prev_line.contains("@warning_ignore")) { const int closing_bracket_idx = prev_line.find(")"); - const String text_to_insert = ", " + meta["code"].operator String(); + const String text_to_insert = ", " + code.quote(quote_style); prev_line = prev_line.insert(closing_bracket_idx, text_to_insert); text_editor->set_line(line - 1, prev_line); } else { @@ -268,7 +270,7 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) { } else { annotation_indent = String(" ").repeat(text_editor->get_indent_size() * indent); } - text_editor->insert_line_at(line, annotation_indent + "@warning_ignore(" + meta["code"].operator String() + ")"); + text_editor->insert_line_at(line, annotation_indent + "@warning_ignore(" + code.quote(quote_style) + ")"); } _validate_script(); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 74c9286325..14b5f7cefb 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -40,7 +40,6 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" -#include "scene/3d/sprite_3d.h" #include "scene/gui/center_container.h" #include "scene/gui/margin_container.h" #include "scene/gui/panel_container.h" @@ -252,8 +251,7 @@ void SpriteFramesEditor::_sheet_add_frames() { const Size2i separation = _get_separation(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Add Frame")); - + undo_redo->create_action(TTR("Add Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); int fc = frames->get_frame_count(edited_anim); for (const int &E : frames_selected) { @@ -265,8 +263,8 @@ void SpriteFramesEditor::_sheet_add_frames() { at->set_atlas(split_sheet_preview->get_texture()); at->set_region(Rect2(offset + frame_coords * (frame_size + separation), frame_size)); - undo_redo->add_do_method(frames, "add_frame", edited_anim, at, 1.0, -1); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, at, 1.0, -1); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, fc); } undo_redo->add_do_method(this, "_update_library"); @@ -415,8 +413,24 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { void SpriteFramesEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { + get_tree()->connect("node_removed", callable_mp(this, &SpriteFramesEditor::_node_removed)); + + [[fallthrough]]; + } case NOTIFICATION_THEME_CHANGED: { + autoplay_icon = get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")); + stop_icon = get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")); + pause_icon = get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")); + _update_stop_icon(); + + autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons"))); + anim_loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons"))); + play->set_icon(get_theme_icon(SNAME("PlayStart"), SNAME("EditorIcons"))); + play_from->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); + play_bw->set_icon(get_theme_icon(SNAME("PlayStartBackwards"), SNAME("EditorIcons"))); + play_bw_from->set_icon(get_theme_icon(SNAME("PlayBackwards"), SNAME("EditorIcons"))); + load->set_icon(get_theme_icon(SNAME("Load"), SNAME("EditorIcons"))); load_sheet->set_icon(get_theme_icon(SNAME("SpriteSheet"), SNAME("EditorIcons"))); copy->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons"))); @@ -441,6 +455,10 @@ void SpriteFramesEditor::_notification(int p_what) { case NOTIFICATION_READY: { add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up. } break; + + case NOTIFICATION_EXIT_TREE: { + get_tree()->disconnect("node_removed", callable_mp(this, &SpriteFramesEditor::_node_removed)); + } break; } } @@ -471,14 +489,14 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_ } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Add Frame")); + undo_redo->create_action(TTR("Add Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); int fc = frames->get_frame_count(edited_anim); int count = 0; for (const Ref<Texture2D> &E : resources) { - undo_redo->add_do_method(frames, "add_frame", edited_anim, E, 1.0, p_at_pos == -1 ? -1 : p_at_pos + count); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, p_at_pos == -1 ? fc : p_at_pos); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, E, 1.0, p_at_pos == -1 ? -1 : p_at_pos + count); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, p_at_pos == -1 ? fc : p_at_pos); count++; } undo_redo->add_do_method(this, "_update_library"); @@ -542,9 +560,9 @@ void SpriteFramesEditor::_paste_pressed() { } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Paste Frame")); - undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, frames->get_frame_count(edited_anim)); + undo_redo->create_action(TTR("Paste Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, duration); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, frames->get_frame_count(edited_anim)); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -585,9 +603,9 @@ void SpriteFramesEditor::_empty_pressed() { Ref<Texture2D> texture; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Add Empty")); - undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from); + undo_redo->create_action(TTR("Add Empty"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, 1.0, from); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, from); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -609,9 +627,9 @@ void SpriteFramesEditor::_empty2_pressed() { Ref<Texture2D> texture; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Add Empty")); - undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from + 1); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from + 1); + undo_redo->create_action(TTR("Add Empty"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, 1.0, from + 1); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, from + 1); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -633,11 +651,11 @@ void SpriteFramesEditor::_up_pressed() { sel -= 1; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Move Frame")); - undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1)); - undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); - undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); - undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1)); + undo_redo->create_action(TTR("Move Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1)); + undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); + undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); + undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1)); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -659,11 +677,11 @@ void SpriteFramesEditor::_down_pressed() { sel += 1; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Move Frame")); - undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1)); - undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); - undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); - undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1)); + undo_redo->create_action(TTR("Move Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1)); + undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); + undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); + undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1)); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -682,15 +700,15 @@ void SpriteFramesEditor::_delete_pressed() { } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Delete Resource")); - undo_redo->add_do_method(frames, "remove_frame", edited_anim, to_delete); - undo_redo->add_undo_method(frames, "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete); + undo_redo->create_action(TTR("Delete Resource"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "remove_frame", edited_anim, to_delete); + undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); } -void SpriteFramesEditor::_animation_select() { +void SpriteFramesEditor::_animation_selected() { if (updating) { return; } @@ -705,9 +723,42 @@ void SpriteFramesEditor::_animation_select() { TreeItem *selected = animations->get_selected(); ERR_FAIL_COND(!selected); edited_anim = selected->get_text(0); + + if (animated_sprite) { + sprite_node_updating = true; + animated_sprite->call("set_animation", edited_anim); + sprite_node_updating = false; + } + _update_library(true); } +void SpriteFramesEditor::_sync_animation() { + if (!animated_sprite || sprite_node_updating) { + return; + } + _select_animation(animated_sprite->call("get_animation"), false); + _update_stop_icon(); +} + +void SpriteFramesEditor::_select_animation(const String &p_name, bool p_update_node) { + TreeItem *selected = nullptr; + selected = animations->get_item_with_text(p_name); + if (!selected) { + return; + }; + + edited_anim = selected->get_text(0); + + if (animated_sprite) { + if (p_update_node) { + animated_sprite->call("set_animation", edited_anim); + } + } + + _update_library(); +} + static void _find_anim_sprites(Node *p_node, List<Node *> *r_nodes, Ref<SpriteFrames> p_sfames) { Node *edited = EditorNode::get_singleton()->get_edited_scene(); if (!edited) { @@ -765,26 +816,48 @@ void SpriteFramesEditor::_animation_name_edited() { name = new_name + " " + itos(counter); } - List<Node *> nodes; - _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames)); - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Rename Animation")); - undo_redo->add_do_method(frames, "rename_animation", edited_anim, name); - undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim); - - for (Node *E : nodes) { - String current = E->call("get_animation"); - undo_redo->add_do_method(E, "set_animation", name); - undo_redo->add_undo_method(E, "set_animation", edited_anim); - } - + undo_redo->create_action(TTR("Rename Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + _rename_node_animation(undo_redo, false, edited_anim, "", ""); + undo_redo->add_do_method(frames.ptr(), "rename_animation", edited_anim, name); + undo_redo->add_undo_method(frames.ptr(), "rename_animation", name, edited_anim); + _rename_node_animation(undo_redo, false, edited_anim, name, name); + _rename_node_animation(undo_redo, true, edited_anim, edited_anim, edited_anim); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); + undo_redo->commit_action(); + + _select_animation(name); + animations->grab_focus(); +} - edited_anim = name; +void SpriteFramesEditor::_rename_node_animation(EditorUndoRedoManager *undo_redo, bool is_undo, const String &p_filter, const String &p_new_animation, const String &p_new_autoplay) { + List<Node *> nodes; + _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames)); - undo_redo->commit_action(); + if (is_undo) { + for (Node *E : nodes) { + String current_name = E->call("get_animation"); + if (current_name == p_filter) { + undo_redo->add_undo_method(E, "set_animation", p_new_animation); + } + String autoplay_name = E->call("get_autoplay"); + if (autoplay_name == p_filter) { + undo_redo->add_undo_method(E, "set_autoplay", p_new_autoplay); + } + } + } else { + for (Node *E : nodes) { + String current_name = E->call("get_animation"); + if (current_name == p_filter) { + undo_redo->add_do_method(E, "set_animation", p_new_animation); + } + String autoplay_name = E->call("get_autoplay"); + if (autoplay_name == p_filter) { + undo_redo->add_do_method(E, "set_autoplay", p_new_autoplay); + } + } + } } void SpriteFramesEditor::_animation_add() { @@ -795,25 +868,15 @@ void SpriteFramesEditor::_animation_add() { name = vformat("new_animation_%d", counter); } - List<Node *> nodes; - _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames)); - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Add Animation")); - undo_redo->add_do_method(frames, "add_animation", name); - undo_redo->add_undo_method(frames, "remove_animation", name); + undo_redo->create_action(TTR("Add Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "add_animation", name); + undo_redo->add_undo_method(frames.ptr(), "remove_animation", name); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); - - for (Node *E : nodes) { - String current = E->call("get_animation"); - undo_redo->add_do_method(E, "set_animation", name); - undo_redo->add_undo_method(E, "set_animation", current); - } - - edited_anim = name; - undo_redo->commit_action(); + + _select_animation(name); animations->grab_focus(); } @@ -831,24 +894,39 @@ void SpriteFramesEditor::_animation_remove() { } void SpriteFramesEditor::_animation_remove_confirmed() { + StringName new_edited; + List<StringName> anim_names; + frames->get_animation_list(&anim_names); + anim_names.sort_custom<StringName::AlphCompare>(); + if (anim_names.size() >= 2) { + if (edited_anim == anim_names[0]) { + new_edited = anim_names[1]; + } else { + new_edited = anim_names[0]; + } + } else { + new_edited = StringName(); + } + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Remove Animation")); - undo_redo->add_do_method(frames, "remove_animation", edited_anim); - undo_redo->add_undo_method(frames, "add_animation", edited_anim); - undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim)); - undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim)); + undo_redo->create_action(TTR("Remove Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + _rename_node_animation(undo_redo, false, edited_anim, new_edited, ""); + undo_redo->add_do_method(frames.ptr(), "remove_animation", edited_anim); + undo_redo->add_undo_method(frames.ptr(), "add_animation", edited_anim); + _rename_node_animation(undo_redo, true, edited_anim, edited_anim, edited_anim); + undo_redo->add_undo_method(frames.ptr(), "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim)); + undo_redo->add_undo_method(frames.ptr(), "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim)); int fc = frames->get_frame_count(edited_anim); for (int i = 0; i < fc; i++) { Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, i); float duration = frames->get_frame_duration(edited_anim, i); - undo_redo->add_undo_method(frames, "add_frame", edited_anim, texture, duration); + undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, texture, duration); } undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); - - edited_anim = StringName(); - undo_redo->commit_action(); + + _select_animation(new_edited); } void SpriteFramesEditor::_animation_search_text_changed(const String &p_text) { @@ -861,9 +939,9 @@ void SpriteFramesEditor::_animation_loop_changed() { } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Change Animation Loop")); - undo_redo->add_do_method(frames, "set_animation_loop", edited_anim, anim_loop->is_pressed()); - undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim)); + undo_redo->create_action(TTR("Change Animation Loop"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "set_animation_loop", edited_anim, anim_loop->is_pressed()); + undo_redo->add_undo_method(frames.ptr(), "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim)); undo_redo->add_do_method(this, "_update_library", true); undo_redo->add_undo_method(this, "_update_library", true); undo_redo->commit_action(); @@ -875,9 +953,9 @@ void SpriteFramesEditor::_animation_speed_changed(double p_value) { } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_method(frames, "set_animation_speed", edited_anim, p_value); - undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim)); + undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "set_animation_speed", edited_anim, p_value); + undo_redo->add_undo_method(frames.ptr(), "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim)); undo_redo->add_do_method(this, "_update_library", true); undo_redo->add_undo_method(this, "_update_library", true); undo_redo->commit_action(); @@ -927,9 +1005,9 @@ void SpriteFramesEditor::_frame_duration_changed(double p_value) { float old_duration = frames->get_frame_duration(edited_anim, index); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action(TTR("Set Frame Duration")); - undo_redo->add_do_method(frames, "set_frame", edited_anim, index, texture, p_value); - undo_redo->add_undo_method(frames, "set_frame", edited_anim, index, texture, old_duration); + undo_redo->create_action(TTR("Set Frame Duration"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, index, texture, p_value); + undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, index, texture, old_duration); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -968,6 +1046,10 @@ void SpriteFramesEditor::_zoom_reset() { } void SpriteFramesEditor::_update_library(bool p_skip_selector) { + if (frames.is_null()) { + return; + } + updating = true; frame_duration->set_value(1.0); // Default. @@ -998,12 +1080,27 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { it->set_text(0, name); it->set_editable(0, true); + if (animated_sprite) { + if (name == String(animated_sprite->call("get_autoplay"))) { + it->set_icon(0, autoplay_icon); + } + } + if (E == edited_anim) { it->select(0); } } } + if (animated_sprite) { + String autoplay_name = animated_sprite->call("get_autoplay"); + if (autoplay_name.is_empty()) { + autoplay->set_pressed(false); + } else { + autoplay->set_pressed(String(edited_anim) == autoplay_name); + } + } + frame_list->clear(); if (!frames->has_animation(edited_anim)) { @@ -1018,18 +1115,19 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { } for (int i = 0; i < frames->get_frame_count(edited_anim); i++) { - String name; + String name = itos(i); Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, i); float duration = frames->get_frame_duration(edited_anim, i); - String duration_string; - if (duration != 1.0f) { - duration_string = String::utf8(" [ ×") + String::num_real(frames->get_frame_duration(edited_anim, i)) + " ]"; - } if (texture.is_null()) { - name = itos(i) + ": " + TTR("(empty)") + duration_string; - } else { - name = itos(i) + ": " + texture->get_name() + duration_string; + texture = empty_icon; + name += ": " + TTR("(empty)"); + } else if (!texture->get_name().is_empty()) { + name += ": " + texture->get_name(); + } + + if (duration != 1.0f) { + name += String::utf8(" [× ") + String::num(duration, 2) + "]"; } frame_list->add_item(name, texture); @@ -1061,20 +1159,25 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { updating = false; } -void SpriteFramesEditor::edit(SpriteFrames *p_frames) { - bool new_read_only_state = false; - if (p_frames) { - new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_frames); +void SpriteFramesEditor::_edit() { + if (!animated_sprite) { + return; } + edit(animated_sprite->call("get_sprite_frames")); +} + +void SpriteFramesEditor::edit(Ref<SpriteFrames> p_frames) { + _update_stop_icon(); - if (frames == p_frames && new_read_only_state == read_only) { + if (!p_frames.is_valid()) { + frames.unref(); return; } frames = p_frames; - read_only = new_read_only_state; + read_only = EditorNode::get_singleton()->is_resource_read_only(p_frames); - if (p_frames) { + if (p_frames.is_valid()) { if (!p_frames->has_animation(edited_anim)) { List<StringName> anim_names; frames->get_animation_list(&anim_names); @@ -1107,6 +1210,8 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) { move_up->set_disabled(read_only); move_down->set_disabled(read_only); delete_frame->set_disabled(read_only); + + _fetch_sprite_node(); // Fetch node after set frames. } Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { @@ -1215,18 +1320,18 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da duration = frames->get_frame_duration(edited_anim, from_frame); } - undo_redo->create_action(TTR("Move Frame")); - undo_redo->add_do_method(frames, "remove_frame", edited_anim, from_frame == -1 ? frames->get_frame_count(edited_anim) : from_frame); - undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration, at_pos == -1 ? -1 : at_pos); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) - 1 : at_pos); - undo_redo->add_undo_method(frames, "add_frame", edited_anim, texture, duration, from_frame); + undo_redo->create_action(TTR("Move Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "remove_frame", edited_anim, from_frame == -1 ? frames->get_frame_count(edited_anim) : from_frame); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, duration, at_pos == -1 ? -1 : at_pos); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) - 1 : at_pos); + undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, texture, duration, from_frame); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); } else { - undo_redo->create_action(TTR("Add Frame")); - undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, at_pos == -1 ? -1 : at_pos); - undo_redo->add_undo_method(frames, "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) : at_pos); + undo_redo->create_action(TTR("Add Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, 1.0, at_pos == -1 ? -1 : at_pos); + undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) : at_pos); undo_redo->add_do_method(this, "_update_library"); undo_redo->add_undo_method(this, "_update_library"); undo_redo->commit_action(); @@ -1245,10 +1350,156 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } } +void SpriteFramesEditor::_update_stop_icon() { + bool is_playing = false; + if (animated_sprite) { + is_playing = animated_sprite->call("is_playing"); + } + if (is_playing) { + stop->set_icon(pause_icon); + } else { + stop->set_icon(stop_icon); + } +} + +void SpriteFramesEditor::_remove_sprite_node() { + if (!animated_sprite) { + return; + } + if (animated_sprite->is_connected("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit))) { + animated_sprite->disconnect("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit)); + } + if (animated_sprite->is_connected("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation))) { + animated_sprite->disconnect("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation)); + } + if (animated_sprite->is_connected("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon))) { + animated_sprite->disconnect("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon)); + } + animated_sprite = nullptr; +} + +void SpriteFramesEditor::_fetch_sprite_node() { + Node *selected = nullptr; + EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection(); + if (editor_selection->get_selected_node_list().size() == 1) { + selected = editor_selection->get_selected_node_list()[0]; + } + + bool show_node_edit = false; + AnimatedSprite2D *as2d = Object::cast_to<AnimatedSprite2D>(selected); + AnimatedSprite3D *as3d = Object::cast_to<AnimatedSprite3D>(selected); + if (as2d || as3d) { + if (frames != selected->call("get_sprite_frames")) { + _remove_sprite_node(); + } else { + animated_sprite = selected; + if (!animated_sprite->is_connected("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit))) { + animated_sprite->connect("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit)); + } + if (!animated_sprite->is_connected("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation))) { + animated_sprite->connect("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation), CONNECT_DEFERRED); + } + if (!animated_sprite->is_connected("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon))) { + animated_sprite->connect("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon)); + } + show_node_edit = true; + } + } else { + _remove_sprite_node(); + } + + if (show_node_edit) { + _sync_animation(); + autoplay_container->show(); + playback_container->show(); + } else { + _update_library(); // To init autoplay icon. + autoplay_container->hide(); + playback_container->hide(); + } +} + +void SpriteFramesEditor::_play_pressed() { + if (animated_sprite) { + animated_sprite->call("stop"); + animated_sprite->call("play", animated_sprite->call("get_animation")); + } + _update_stop_icon(); +} + +void SpriteFramesEditor::_play_from_pressed() { + if (animated_sprite) { + animated_sprite->call("play", animated_sprite->call("get_animation")); + } + _update_stop_icon(); +} + +void SpriteFramesEditor::_play_bw_pressed() { + if (animated_sprite) { + animated_sprite->call("stop"); + animated_sprite->call("play_backwards", animated_sprite->call("get_animation")); + } + _update_stop_icon(); +} + +void SpriteFramesEditor::_play_bw_from_pressed() { + if (animated_sprite) { + animated_sprite->call("play_backwards", animated_sprite->call("get_animation")); + } + _update_stop_icon(); +} + +void SpriteFramesEditor::_stop_pressed() { + if (animated_sprite) { + if (animated_sprite->call("is_playing")) { + animated_sprite->call("pause"); + } else { + animated_sprite->call("stop"); + } + } + _update_stop_icon(); +} + +void SpriteFramesEditor::_autoplay_pressed() { + if (updating) { + return; + } + + if (animated_sprite) { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Toggle Autoplay"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + String current = animated_sprite->call("get_animation"); + String current_auto = animated_sprite->call("get_autoplay"); + if (current == current_auto) { + //unset + undo_redo->add_do_method(animated_sprite, "set_autoplay", ""); + undo_redo->add_undo_method(animated_sprite, "set_autoplay", current_auto); + } else { + //set + undo_redo->add_do_method(animated_sprite, "set_autoplay", current); + undo_redo->add_undo_method(animated_sprite, "set_autoplay", current_auto); + } + undo_redo->add_do_method(this, "_update_library"); + undo_redo->add_undo_method(this, "_update_library"); + undo_redo->commit_action(); + } + + _update_library(); +} + void SpriteFramesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false)); } +void SpriteFramesEditor::_node_removed(Node *p_node) { + if (animated_sprite) { + if (animated_sprite != p_node) { + return; + } + _remove_sprite_node(); + } +} + SpriteFramesEditor::SpriteFramesEditor() { VBoxContainer *vbc_animlist = memnew(VBoxContainer); add_child(vbc_animlist); @@ -1272,8 +1523,37 @@ SpriteFramesEditor::SpriteFramesEditor() { delete_anim->set_disabled(true); delete_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove)); + autoplay_container = memnew(HBoxContainer); + hbc_animlist->add_child(autoplay_container); + + autoplay_container->add_child(memnew(VSeparator)); + + autoplay = memnew(Button); + autoplay->set_flat(true); + autoplay->set_tooltip_text(TTR("Autoplay on Load")); + autoplay_container->add_child(autoplay); + + hbc_animlist->add_child(memnew(VSeparator)); + + anim_loop = memnew(Button); + anim_loop->set_toggle_mode(true); + anim_loop->set_flat(true); + anim_loop->set_tooltip_text(TTR("Animation Looping")); + anim_loop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_loop_changed)); + hbc_animlist->add_child(anim_loop); + + anim_speed = memnew(SpinBox); + anim_speed->set_suffix(TTR("FPS")); + anim_speed->set_min(0); + anim_speed->set_max(120); + anim_speed->set_step(0.01); + anim_speed->set_custom_arrow_step(1); + anim_speed->set_tooltip_text(TTR("Animation Speed")); + anim_speed->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_animation_speed_changed)); + hbc_animlist->add_child(anim_speed); + anim_search_box = memnew(LineEdit); - hbc_animlist->add_child(anim_search_box); + sub_vb->add_child(anim_search_box); anim_search_box->set_h_size_flags(SIZE_EXPAND_FILL); anim_search_box->set_placeholder(TTR("Filter Animations")); anim_search_box->set_clear_button_enabled(true); @@ -1283,7 +1563,7 @@ SpriteFramesEditor::SpriteFramesEditor() { sub_vb->add_child(animations); animations->set_v_size_flags(SIZE_EXPAND_FILL); animations->set_hide_root(true); - animations->connect("cell_selected", callable_mp(this, &SpriteFramesEditor::_animation_select)); + animations->connect("cell_selected", callable_mp(this, &SpriteFramesEditor::_animation_selected)); animations->connect("item_edited", callable_mp(this, &SpriteFramesEditor::_animation_name_edited)); animations->set_allow_reselect(true); @@ -1292,23 +1572,6 @@ SpriteFramesEditor::SpriteFramesEditor() { delete_anim->set_shortcut_context(animations); delete_anim->set_shortcut(ED_SHORTCUT("sprite_frames/delete_animation", TTR("Delete Animation"), Key::KEY_DELETE)); - HBoxContainer *hbc_anim_speed = memnew(HBoxContainer); - hbc_anim_speed->add_child(memnew(Label(TTR("Speed:")))); - vbc_animlist->add_child(hbc_anim_speed); - anim_speed = memnew(SpinBox); - anim_speed->set_suffix(TTR("FPS")); - anim_speed->set_min(0); - anim_speed->set_max(120); - anim_speed->set_step(0.01); - anim_speed->set_h_size_flags(SIZE_EXPAND_FILL); - hbc_anim_speed->add_child(anim_speed); - anim_speed->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_animation_speed_changed)); - - anim_loop = memnew(CheckButton); - anim_loop->set_text(TTR("Loop")); - vbc_animlist->add_child(anim_loop); - anim_loop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_loop_changed)); - VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); vbc->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1319,6 +1582,44 @@ SpriteFramesEditor::SpriteFramesEditor() { HBoxContainer *hbc = memnew(HBoxContainer); sub_vb->add_child(hbc); + playback_container = memnew(HBoxContainer); + hbc->add_child(playback_container); + + play_bw_from = memnew(Button); + play_bw_from->set_flat(true); + play_bw_from->set_tooltip_text(TTR("Play selected animation backwards from current pos. (A)")); + playback_container->add_child(play_bw_from); + + play_bw = memnew(Button); + play_bw->set_flat(true); + play_bw->set_tooltip_text(TTR("Play selected animation backwards from end. (Shift+A)")); + playback_container->add_child(play_bw); + + stop = memnew(Button); + stop->set_flat(true); + stop->set_tooltip_text(TTR("Pause/stop animation playback. (S)")); + playback_container->add_child(stop); + + play = memnew(Button); + play->set_flat(true); + play->set_tooltip_text(TTR("Play selected animation from start. (Shift+D)")); + playback_container->add_child(play); + + play_from = memnew(Button); + play_from->set_flat(true); + play_from->set_tooltip_text(TTR("Play selected animation from current pos. (D)")); + playback_container->add_child(play_from); + + playback_container->add_child(memnew(VSeparator)); + + autoplay->connect("pressed", callable_mp(this, &SpriteFramesEditor::_autoplay_pressed)); + autoplay->set_toggle_mode(true); + play->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_pressed)); + play_from->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_from_pressed)); + play_bw->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_bw_pressed)); + play_bw_from->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_bw_from_pressed)); + stop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_stop_pressed)); + load = memnew(Button); load->set_flat(true); hbc->add_child(load); @@ -1369,9 +1670,11 @@ SpriteFramesEditor::SpriteFramesEditor() { frame_duration = memnew(SpinBox); frame_duration->set_prefix(String::utf8("×")); - frame_duration->set_min(0); + frame_duration->set_min(SPRITE_FRAME_MINIMUM_DURATION); // Avoid zero div. frame_duration->set_max(10); frame_duration->set_step(0.01); + frame_duration->set_custom_arrow_step(0.1); + frame_duration->set_allow_lesser(false); frame_duration->set_allow_greater(true); hbc->add_child(frame_duration); @@ -1616,16 +1919,16 @@ SpriteFramesEditor::SpriteFramesEditor() { } void SpriteFramesEditorPlugin::edit(Object *p_object) { - SpriteFrames *s; + Ref<SpriteFrames> s; AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object); if (animated_sprite) { - s = *animated_sprite->get_sprite_frames(); + s = animated_sprite->get_sprite_frames(); } else { AnimatedSprite3D *animated_sprite_3d = Object::cast_to<AnimatedSprite3D>(p_object); if (animated_sprite_3d) { - s = *animated_sprite_3d->get_sprite_frames(); + s = animated_sprite_3d->get_sprite_frames(); } else { - s = Object::cast_to<SpriteFrames>(p_object); + s = p_object; } } @@ -1650,9 +1953,7 @@ void SpriteFramesEditorPlugin::make_visible(bool p_visible) { EditorNode::get_singleton()->make_bottom_panel_item_visible(frames_editor); } else { button->hide(); - if (frames_editor->is_visible_in_tree()) { - EditorNode::get_singleton()->hide_bottom_panel(); - } + frames_editor->edit(Ref<SpriteFrames>()); } } diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index a5e0e54fb8..1dfb909388 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -33,6 +33,7 @@ #include "editor/editor_plugin.h" #include "scene/2d/animated_sprite_2d.h" +#include "scene/3d/sprite_3d.h" #include "scene/gui/button.h" #include "scene/gui/check_button.h" #include "scene/gui/dialogs.h" @@ -57,6 +58,9 @@ public: class SpriteFramesEditor : public HSplitContainer { GDCLASS(SpriteFramesEditor, HSplitContainer); + Ref<SpriteFrames> frames; + Node *animated_sprite = nullptr; + enum { PARAM_USE_CURRENT, // Used in callbacks to indicate `dominant_param` should be not updated. PARAM_FRAME_COUNT, // Keep "Horizontal" & "Vertical" values. @@ -66,6 +70,18 @@ class SpriteFramesEditor : public HSplitContainer { bool read_only = false; + Ref<Texture2D> autoplay_icon; + Ref<Texture2D> stop_icon; + Ref<Texture2D> pause_icon; + Ref<Texture2D> empty_icon = memnew(ImageTexture); + + HBoxContainer *playback_container = nullptr; + Button *stop = nullptr; + Button *play = nullptr; + Button *play_from = nullptr; + Button *play_bw = nullptr; + Button *play_bw_from = nullptr; + Button *load = nullptr; Button *load_sheet = nullptr; Button *delete_frame = nullptr; @@ -85,18 +101,19 @@ class SpriteFramesEditor : public HSplitContainer { Button *add_anim = nullptr; Button *delete_anim = nullptr; - LineEdit *anim_search_box = nullptr; + SpinBox *anim_speed = nullptr; + Button *anim_loop = nullptr; + + HBoxContainer *autoplay_container = nullptr; + Button *autoplay = nullptr; + LineEdit *anim_search_box = nullptr; Tree *animations = nullptr; - SpinBox *anim_speed = nullptr; - CheckButton *anim_loop = nullptr; EditorFileDialog *file = nullptr; AcceptDialog *dialog = nullptr; - SpriteFrames *frames = nullptr; - StringName edited_anim; ConfirmationDialog *delete_dialog = nullptr; @@ -146,7 +163,15 @@ class SpriteFramesEditor : public HSplitContainer { void _frame_duration_changed(double p_value); void _update_library(bool p_skip_selector = false); - void _animation_select(); + void _update_stop_icon(); + void _play_pressed(); + void _play_from_pressed(); + void _play_bw_pressed(); + void _play_bw_from_pressed(); + void _autoplay_pressed(); + void _stop_pressed(); + + void _animation_selected(); void _animation_name_edited(); void _animation_add(); void _animation_remove(); @@ -183,12 +208,24 @@ class SpriteFramesEditor : public HSplitContainer { void _sheet_zoom_reset(); void _sheet_select_clear_all_frames(); + void _edit(); + void _regist_scene_undo(EditorUndoRedoManager *undo_redo); + void _fetch_sprite_node(); + void _remove_sprite_node(); + + bool sprite_node_updating = false; + void _sync_animation(); + + void _select_animation(const String &p_name, bool p_update_node = true); + void _rename_node_animation(EditorUndoRedoManager *undo_redo, bool is_undo, const String &p_filter, const String &p_new_animation, const String &p_new_autoplay); + protected: void _notification(int p_what); + void _node_removed(Node *p_node); static void _bind_methods(); public: - void edit(SpriteFrames *p_frames); + void edit(Ref<SpriteFrames> p_frames); SpriteFramesEditor(); }; diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 1b29999796..ffd9564816 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -383,11 +383,12 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa List<ScriptLanguage::CodeCompletionOption> pp_defines; ShaderPreprocessor preprocessor; String code; - complete_from_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path()).get_base_dir(); + String resource_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path()); + complete_from_path = resource_path.get_base_dir(); if (!complete_from_path.ends_with("/")) { complete_from_path += "/"; } - preprocessor.preprocess(p_code, "", code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths); + preprocessor.preprocess(p_code, resource_path, code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths); complete_from_path = String(); if (pp_options.size()) { for (const ScriptLanguage::CodeCompletionOption &E : pp_options) { diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 76f2bb7bb5..c5aa60c816 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -740,6 +740,9 @@ void TextureRegionEditor::_update_rect() { } } else if (obj_styleBox.is_valid()) { rect = obj_styleBox->get_region_rect(); + if (rect == Rect2()) { + rect = Rect2(Vector2(), obj_styleBox->get_texture()->get_size()); + } } } diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index e430848875..fd651dd507 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -247,7 +247,7 @@ void TileAtlasView::_draw_base_tiles() { for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) { // Update the y to max value. Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame); - Vector2i offset_pos = base_frame_rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0); + Vector2i offset_pos = base_frame_rect.get_center() + tile_set_atlas_source->get_tile_data(atlas_coords, 0)->get_texture_origin(); // Draw the tile. TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame); @@ -322,18 +322,19 @@ void TileAtlasView::_draw_base_tiles_shape_grid() { Vector2i tile_shape_size = tile_set->get_tile_size(); for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i tile_id = tile_set_atlas_source->get_tile_id(i); - Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0); - - for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) { - Color color = grid_color; - if (frame > 0) { - color.a *= 0.3; + Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_data(tile_id, 0)->get_texture_origin(); + if (tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, -tile_shape_size / 2) && tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, tile_shape_size / 2 - Vector2(1, 1))) { + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) { + Color color = grid_color; + if (frame > 0) { + color.a *= 0.3; + } + Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id, frame); + Transform2D tile_xform; + tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset); + tile_xform.set_scale(tile_shape_size); + tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, color); } - Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id); - Transform2D tile_xform; - tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset); - tile_xform.set_scale(tile_shape_size); - tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, color); } } } @@ -372,10 +373,10 @@ void TileAtlasView::_draw_alternatives() { // Update the y to max value. Vector2i offset_pos; if (transposed) { - offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id)); + offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_data->get_texture_origin()); y_increment = MAX(y_increment, texture_region_size.x); } else { - offset_pos = (current_pos + texture_region_size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id)); + offset_pos = (current_pos + texture_region_size / 2 + tile_data->get_texture_origin()); y_increment = MAX(y_increment, texture_region_size.y); } diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 1a4223e9e6..3dd0c84ee7 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1122,14 +1122,15 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 return; } + Vector2 texture_origin = tile_data->get_texture_origin(); if (value.get_type() == Variant::BOOL) { Ref<Texture2D> texture = (bool)value ? tile_bool_checked : tile_bool_unchecked; int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3; - Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size))); + Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2) - texture_origin, Vector2(size, size))); p_canvas_item->draw_texture_rect(texture, rect); } else if (value.get_type() == Variant::COLOR) { int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3; - Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size))); + Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2) - texture_origin, Vector2(size, size))); p_canvas_item->draw_rect(rect, value); } else { Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts")); @@ -1166,8 +1167,8 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 } Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); - p_canvas_item->draw_string_outline(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); - p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); + p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); } } @@ -1241,20 +1242,38 @@ TileDataDefaultEditor::~TileDataDefaultEditor() { memdelete(dummy_object); } -void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { +void TileDataTextureOriginEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { TileData *tile_data = _get_tile_data(p_cell); ERR_FAIL_COND(!tile_data); Vector2i tile_set_tile_size = tile_set->get_tile_size(); - Color color = Color(1.0, 0.0, 0.0); + Color color = Color(1.0, 1.0, 1.0); if (p_selected) { Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color"); Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); color = selection_color; } - Transform2D tile_xform; - tile_xform.set_scale(tile_set_tile_size); - tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color); + + TileSetSource *source = *(tile_set->get_source(p_cell.source_id)); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, -tile_set_tile_size / 2) && atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, tile_set_tile_size / 2 - Vector2(1, 1))) { + Transform2D tile_xform; + tile_xform.set_scale(tile_set_tile_size); + tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color); + } + + if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2())) { + Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons")); + p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2()) - (position_icon->get_size() / 2), color); + } else { + Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts")); + int font_size = TileSetEditor::get_singleton()->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); + Vector2 texture_origin = tile_data->get_texture_origin(); + String text = vformat("%s", texture_origin); + Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); + } } void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { @@ -1288,8 +1307,21 @@ void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); color = selection_color; } - Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons")); - p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, tile_data->get_y_sort_origin())) - position_icon->get_size() / 2, color); + Vector2 texture_origin = tile_data->get_texture_origin(); + TileSetSource *source = *(tile_set->get_source(p_cell.source_id)); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2(0, tile_data->get_y_sort_origin()))) { + Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons")); + p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, tile_data->get_y_sort_origin())) - position_icon->get_size() / 2, color); + } else { + Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts")); + int font_size = TileSetEditor::get_singleton()->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); + String text = vformat("%s", tile_data->get_y_sort_origin()); + + Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); + } } void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { @@ -1333,7 +1365,7 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile if (occluder_polygon.is_valid()) { polygon_editor->add_polygon(occluder_polygon->get_polygon()); } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { @@ -1342,7 +1374,7 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl Ref<OccluderPolygon2D> occluder_polygon = p_value; tile_data->set_occluder(occlusion_layer, occluder_polygon); - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { @@ -1489,7 +1521,7 @@ void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_ E.value->update_property(); } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { @@ -1508,7 +1540,7 @@ void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_so tile_data->set_collision_polygon_one_way_margin(physics_layer, i, polygon_dict["one_way_margin"]); } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { @@ -1741,7 +1773,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas TileData *tile_data = p_tile_set_atlas_source->get_tile_data(hovered_coords, 0); int terrain_set = tile_data->get_terrain_set(); Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(hovered_coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); if (terrain_set >= 0 && terrain_set == int(dummy_object->get("terrain_set"))) { // Draw hovered bit. @@ -1792,7 +1824,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas // Text p_canvas_item->draw_set_transform_matrix(Transform2D()); Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Color color = Color(1, 1, 1); String text; @@ -1885,7 +1917,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas Vector2i coords = E.get_atlas_coords(); Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_data(coords, 0)->get_texture_origin(); Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set); for (int j = 0; j < polygon.size(); j++) { @@ -1930,7 +1962,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til TileData *tile_data = p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative); int terrain_set = tile_data->get_terrain_set(); Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(hovered_coords, hovered_alternative); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); if (terrain_set == int(dummy_object->get("terrain_set"))) { // Draw hovered bit. @@ -1984,7 +2016,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til // Text p_canvas_item->draw_set_transform_matrix(Transform2D()); Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Color color = Color(1, 1, 1); String text; @@ -2069,7 +2101,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t // Set the terrains bits. Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set()); if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) { @@ -2103,7 +2135,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0); int terrain_set = tile_data->get_terrain_set(); Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); dummy_object->set("terrain_set", terrain_set); dummy_object->set("terrain", -1); @@ -2218,7 +2250,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t // Set the terrain bit. Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set); if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) { @@ -2365,7 +2397,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0); Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set); for (int j = 0; j < polygon.size(); j++) { @@ -2465,7 +2497,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi // Set the terrains bits. Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set()); if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) { @@ -2501,7 +2533,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, alternative_tile); int terrain_set = tile_data->get_terrain_set(); Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); dummy_object->set("terrain_set", terrain_set); dummy_object->set("terrain", -1); @@ -2591,7 +2623,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi // Set the terrain bit. Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); - Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + Vector2i position = texture_region.get_center() + tile_data->get_texture_origin(); Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set); if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) { @@ -2741,7 +2773,7 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set polygon_editor->add_polygon(nav_polygon->get_outline(i)); } } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { @@ -2750,7 +2782,7 @@ void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_s Ref<NavigationPolygon> nav_polygon = p_value; tile_data->set_navigation_polygon(navigation_layer, nav_polygon); - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 02d4584428..1ebf30aecd 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -242,8 +242,8 @@ public: ~TileDataDefaultEditor(); }; -class TileDataTextureOffsetEditor : public TileDataDefaultEditor { - GDCLASS(TileDataTextureOffsetEditor, TileDataDefaultEditor); +class TileDataTextureOriginEditor : public TileDataDefaultEditor { + GDCLASS(TileDataTextureOriginEditor, TileDataDefaultEditor); public: virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 3dc42b4481..f0a02a3768 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -897,7 +897,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over // Compute the offset Rect2i source_rect = atlas_source->get_tile_texture_region(E.value.get_atlas_coords()); - Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(E.value.get_atlas_coords(), E.value.alternative_tile); + Vector2i tile_offset = tile_data->get_texture_origin(); // Compute the destination rectangle in the CanvasItem. Rect2 dest_rect; @@ -3997,7 +3997,7 @@ TileMapEditor::TileMapEditor() { tabs_bar->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed)); // --- TileMap toolbar --- - tile_map_toolbar = memnew(HBoxContainer); + tile_map_toolbar = memnew(HFlowContainer); tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL); add_child(tile_map_toolbar); @@ -4012,8 +4012,11 @@ TileMapEditor::TileMapEditor() { } } - // Wide empty separation control. - tile_map_toolbar->add_spacer(); + // Wide empty separation control. (like BoxContainer::add_spacer()) + Control *c = memnew(Control); + c->set_mouse_filter(MOUSE_FILTER_PASS); + c->set_h_size_flags(SIZE_EXPAND_FILL); + tile_map_toolbar->add_child(c); // Layer selector. layers_selection_button = memnew(OptionButton); diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index fb9c2f3689..1cab1d1500 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -38,6 +38,7 @@ #include "scene/2d/tile_map.h" #include "scene/gui/box_container.h" #include "scene/gui/check_box.h" +#include "scene/gui/flow_container.h" #include "scene/gui/item_list.h" #include "scene/gui/menu_button.h" #include "scene/gui/option_button.h" @@ -323,7 +324,7 @@ private: Vector<TileMapEditorPlugin *> tile_map_editor_plugins; // Toolbar. - HBoxContainer *tile_map_toolbar = nullptr; + HFlowContainer *tile_map_toolbar = nullptr; OptionButton *layers_selection_button = nullptr; Button *toggle_highlight_selected_layer_button = nullptr; diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index a12a647e99..840a3911af 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -640,14 +640,14 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { // --- Rendering --- ADD_TILE_DATA_EDITOR_GROUP("Rendering"); - ADD_TILE_DATA_EDITOR(group, "Texture Offset", "texture_offset"); - if (!tile_data_editors.has("texture_offset")) { - TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor); - tile_data_texture_offset_editor->hide(); - tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset"); - tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); - tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); - tile_data_editors["texture_offset"] = tile_data_texture_offset_editor; + ADD_TILE_DATA_EDITOR(group, "Texture Origin", "texture_origin"); + if (!tile_data_editors.has("texture_origin")) { + TileDataTextureOriginEditor *tile_data_texture_origin_editor = memnew(TileDataTextureOriginEditor); + tile_data_texture_origin_editor->hide(); + tile_data_texture_origin_editor->setup_property_editor(Variant::VECTOR2, "texture_origin"); + tile_data_texture_origin_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_texture_origin_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); + tile_data_editors["texture_origin"] = tile_data_texture_origin_editor; } ADD_TILE_DATA_EDITOR(group, "Modulate", "modulate"); @@ -1864,7 +1864,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() { for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i coords = tile_set_atlas_source->get_tile_id(i); Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords); - Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_data(coords, 0)->get_texture_origin(); Transform2D xform = tile_atlas_control->get_parent_control()->get_transform(); xform.translate_local(position); @@ -1887,7 +1887,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() { continue; } Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E.tile); - Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E.tile, 0); + Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_data(E.tile, 0)->get_texture_origin(); Transform2D xform = tile_atlas_control->get_parent_control()->get_transform(); xform.translate_local(position); @@ -2039,7 +2039,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() { continue; } Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); - Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_data(coords, alternative_tile)->get_texture_origin(); Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform(); xform.translate_local(position); @@ -2063,7 +2063,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() { continue; } Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E.tile, E.alternative); - Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E.tile, E.alternative); + Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_data(E.tile, E.alternative)->get_texture_origin(); Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform(); xform.translate_local(position); @@ -2704,7 +2704,7 @@ void EditorPropertyTilePolygon::update_property() { Vector2i coords = atlas_tile_proxy_object->get_edited_tiles().front()->get().tile; int alternative = atlas_tile_proxy_object->get_edited_tiles().front()->get().alternative; TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative); - generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); // Reset the polygons. generic_tile_polygon_editor->clear_polygons(); diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 77dd0f7793..fad36660d9 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -106,7 +106,7 @@ void TilesEditorPlugin::_thread() { Vector2i coords = tile_map->get_cell_atlas_coords(0, cell); int alternative = tile_map->get_cell_alternative_tile(0, cell); - Vector2 center = world_pos - atlas_source->get_tile_effective_texture_offset(coords, alternative); + Vector2 center = world_pos - atlas_source->get_tile_data(coords, alternative)->get_texture_origin(); encompassing_rect.expand_to(center - atlas_source->get_tile_texture_region(coords).size / 2); encompassing_rect.expand_to(center + atlas_source->get_tile_texture_region(coords).size / 2); } diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index 37f941c7b2..9695a7042d 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -257,6 +257,7 @@ ProgressDialog::ProgressDialog() { add_child(main); main->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); set_exclusive(true); + set_flag(Window::FLAG_POPUP, false); last_progress_tick = 0; singleton = this; cancel_hb = memnew(HBoxContainer); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 88fb88de98..d3e16211f7 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -32,10 +32,11 @@ #include "modules/modules_enabled.gen.h" -const int ERROR_CODE = 77; - +#ifndef DISABLE_DEPRECATED #ifdef MODULE_REGEX_ENABLED +const int ERROR_CODE = 77; + #include "modules/regex/regex.h" #include "core/io/dir_access.h" @@ -44,7 +45,7 @@ const int ERROR_CODE = 77; #include "core/templates/list.h" #include "core/templates/local_vector.h" -static const char *enum_renames[][2] = { +const char *ProjectConverter3To4::enum_renames[][2] = { //// constants { "TYPE_COLOR_ARRAY", "TYPE_PACKED_COLOR_ARRAY" }, { "TYPE_FLOAT64_ARRAY", "TYPE_PACKED_FLOAT64_ARRAY" }, @@ -164,7 +165,7 @@ static const char *enum_renames[][2] = { { nullptr, nullptr }, }; -static const char *gdscript_function_renames[][2] = { +const char *ProjectConverter3To4::gdscript_function_renames[][2] = { // { "_set_name", "get_tracker_name"}, // XRPositionalTracker - CameraFeed use this // { "_unhandled_input", "_unhandled_key_input"}, // BaseButton, ViewportContainer broke Node, FileDialog,SubViewportContainer // { "create_gizmo", "_create_gizmo"}, // EditorNode3DGizmoPlugin - may be used @@ -215,7 +216,6 @@ static const char *gdscript_function_renames[][2] = { { "_get_configuration_warning", "_get_configuration_warnings" }, // Node { "_set_current", "set_current" }, // Camera2D { "_set_editor_description", "set_editor_description" }, // Node - { "_set_playing", "set_playing" }, // AnimatedSprite3D { "_toplevel_raise_self", "_top_level_raise_self" }, // CanvasItem { "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit { "add_animation", "add_animation_library" }, // AnimationPlayer @@ -241,6 +241,9 @@ static const char *gdscript_function_renames[][2] = { { "can_generate_small_preview", "_can_generate_small_preview" }, // EditorResourcePreviewGenerator { "can_instance", "can_instantiate" }, // PackedScene, Script { "canvas_light_set_scale", "canvas_light_set_texture_scale" }, // RenderingServer + { "capture_get_device", "get_input_device" }, // AudioServer + { "capture_get_device_list", "get_input_device_list" }, // AudioServer + { "capture_set_device", "set_input_device" }, // AudioServer { "center_viewport_to_cursor", "center_viewport_to_caret" }, // TextEdit { "change_scene", "change_scene_to_file" }, // SceneTree { "change_scene_to", "change_scene_to_packed" }, // SceneTree @@ -301,6 +304,8 @@ static const char *gdscript_function_renames[][2] = { { "get_cursor_position", "get_caret_column" }, // LineEdit { "get_d", "get_distance" }, // LineShape2D { "get_depth_bias_enable", "get_depth_bias_enabled" }, // RDPipelineRasterizationState + { "get_device", "get_output_device" }, // AudioServer + { "get_device_list", "get_output_device_list" }, // AudioServer { "get_drag_data", "_get_drag_data" }, // Control { "get_editor_viewport", "get_editor_main_screen" }, // EditorPlugin { "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton @@ -312,8 +317,8 @@ static const char *gdscript_function_renames[][2] = { { "get_font_types", "get_font_type_list" }, // Theme { "get_frame_color", "get_color" }, // ColorRect { "get_global_rate_scale", "get_playback_speed_scale" }, // AudioServer - { "get_gravity_distance_scale", "get_gravity_point_distance_scale" }, //Area2D - { "get_gravity_vector", "get_gravity_direction" }, //Area2D + { "get_gravity_distance_scale", "get_gravity_point_unit_distance" }, // Area(2D/3D) + { "get_gravity_vector", "get_gravity_direction" }, // Area(2D/3D) { "get_h_scrollbar", "get_h_scroll_bar" }, //ScrollContainer { "get_hand", "get_tracker_hand" }, // XRPositionalTracker { "get_handle_name", "_get_handle_name" }, // EditorNode3DGizmo @@ -499,6 +504,7 @@ static const char *gdscript_function_renames[][2] = { { "set_cursor_position", "set_caret_column" }, // LineEdit { "set_d", "set_distance" }, // WorldMarginShape2D { "set_depth_bias_enable", "set_depth_bias_enabled" }, // RDPipelineRasterizationState + { "set_device", "set_output_device" }, // AudioServer { "set_doubleclick", "set_double_click" }, // InputEventMouseButton { "set_draw_red", "set_draw_warning" }, // EditorProperty { "set_enable_follow_smoothing", "set_position_smoothing_enabled" }, // Camera2D @@ -510,8 +516,8 @@ static const char *gdscript_function_renames[][2] = { { "set_follow_smoothing", "set_position_smoothing_speed" }, // Camera2D { "set_frame_color", "set_color" }, // ColorRect { "set_global_rate_scale", "set_playback_speed_scale" }, // AudioServer - { "set_gravity_distance_scale", "set_gravity_point_distance_scale" }, // Area2D - { "set_gravity_vector", "set_gravity_direction" }, // Area2D + { "set_gravity_distance_scale", "set_gravity_point_unit_distance" }, // Area(2D/3D) + { "set_gravity_vector", "set_gravity_direction" }, // Area(2D/3D) { "set_h_drag_enabled", "set_drag_horizontal_enabled" }, // Camera2D { "set_icon_align", "set_icon_alignment" }, // Button { "set_interior_ambient", "set_ambient_color" }, // ReflectionProbe @@ -620,7 +626,7 @@ static const char *gdscript_function_renames[][2] = { }; // gdscript_function_renames clone with CamelCase -static const char *csharp_function_renames[][2] = { +const char *ProjectConverter3To4::csharp_function_renames[][2] = { // { "_SetName", "GetTrackerName"}, // XRPositionalTracker - CameraFeed use this // { "_UnhandledInput", "_UnhandledKeyInput"}, // BaseButton, ViewportContainer broke Node, FileDialog,SubViewportContainer // { "CreateGizmo", "_CreateGizmo"}, // EditorNode3DGizmoPlugin - may be used @@ -697,6 +703,9 @@ static const char *csharp_function_renames[][2] = { { "CanGenerateSmallPreview", "_CanGenerateSmallPreview" }, // EditorResourcePreviewGenerator { "CanInstance", "CanInstantiate" }, // PackedScene, Script { "CanvasLightSetScale", "CanvasLightSetTextureScale" }, // RenderingServer + { "CaptureGetDevice", "GetInputDevice" }, // AudioServer + { "CaptureGetDeviceList", "GetInputDeviceList" }, // AudioServer + { "CaptureSetDevice", "SetInputDevice" }, // AudioServer { "CenterViewportToCursor", "CenterViewportToCaret" }, // TextEdit { "ChangeScene", "ChangeSceneToFile" }, // SceneTree { "ChangeSceneTo", "ChangeSceneToPacked" }, // SceneTree @@ -754,6 +763,8 @@ static const char *csharp_function_renames[][2] = { { "GetCursorPosition", "GetCaretColumn" }, // LineEdit { "GetD", "GetDistance" }, // LineShape2D { "GetDepthBiasEnable", "GetDepthBiasEnabled" }, // RDPipelineRasterizationState + { "GetDevice", "GetOutputDevice" }, // AudioServer + { "GetDeviceList", "GetOutputDeviceList" }, // AudioServer { "GetDragDataFw", "_GetDragDataFw" }, // ScriptEditor { "GetEditorViewport", "GetViewport" }, // EditorPlugin { "GetEnabledFocusMode", "GetFocusMode" }, // BaseButton @@ -942,6 +953,7 @@ static const char *csharp_function_renames[][2] = { { "SetCursorPosition", "SetCaretColumn" }, // LineEdit { "SetD", "SetDistance" }, // WorldMarginShape2D { "SetDepthBiasEnable", "SetDepthBiasEnabled" }, // RDPipelineRasterizationState + { "SetDevice", "SetOutputDevice" }, // AudioServer { "SetDoubleclick", "SetDoubleClick" }, // InputEventMouseButton { "SetEnableFollowSmoothing", "SetFollowSmoothingEnabled" }, // Camera2D { "SetEnabledFocusMode", "SetFocusMode" }, // BaseButton @@ -1057,7 +1069,7 @@ static const char *csharp_function_renames[][2] = { }; // Some needs to be disabled, because users can use this names as variables -static const char *gdscript_properties_renames[][2] = { +const char *ProjectConverter3To4::gdscript_properties_renames[][2] = { // // { "d", "distance" }, //WorldMarginShape2D - TODO, looks that polish letters ą ę are treaten as space, not as letter, so `będą` are renamed to `będistanceą` // // {"alt","alt_pressed"}, // This may broke a lot of comments and user variables // // {"command","command_pressed"},// This may broke a lot of comments and user variables @@ -1070,6 +1082,7 @@ static const char *gdscript_properties_renames[][2] = { // // {"shift","shift_pressed"},// This may broke a lot of comments and user variables // { "autowrap", "autowrap_mode" }, // Label // { "cast_to", "target_position" }, // RayCast2D, RayCast3D + // { "device", "output_device"}, // AudioServer - Too vague, most likely breaks comments & variables // { "doubleclick", "double_click" }, // InputEventMouseButton // { "group", "button_group" }, // BaseButton // { "process_mode", "process_callback" }, // AnimationTree, Camera2D @@ -1085,6 +1098,7 @@ static const char *gdscript_properties_renames[][2] = { { "bbcode_text", "text" }, // RichTextLabel { "bg", "panel" }, // Theme { "bg_focus", "focus" }, // Theme + { "capture_device", "input_device" }, // AudioServer { "caret_blink_speed", "caret_blink_interval" }, // TextEdit, LineEdit { "caret_moving_by_right_click", "caret_move_on_right_click" }, // TextEdit { "caret_position", "caret_column" }, // LineEdit @@ -1112,8 +1126,8 @@ static const char *gdscript_properties_renames[][2] = { { "files_disabled", "file_disabled_color" }, // Theme { "folder_icon_modulate", "folder_icon_color" }, // Theme { "global_rate_scale", "playback_speed_scale" }, // AudioServer - { "gravity_distance_scale", "gravity_point_distance_scale" }, // Area2D - { "gravity_vec", "gravity_direction" }, // Area2D + { "gravity_distance_scale", "gravity_point_unit_distance" }, // Area(2D/3D) + { "gravity_vec", "gravity_direction" }, // Area(2D/3D) { "hint_tooltip", "tooltip_text" }, // Control { "hseparation", "h_separation" }, // Theme { "icon_align", "icon_alignment" }, // Button @@ -1168,12 +1182,13 @@ static const char *gdscript_properties_renames[][2] = { { "unit_db", "volume_db" }, // AudioStreamPlayer3D { "unit_offset", "progress_ratio" }, // PathFollow2D, PathFollow3D { "vseparation", "v_separation" }, // Theme + { "frames", "sprite_frames" }, // AnimatedSprite2D, AnimatedSprite3D { nullptr, nullptr }, }; // Some needs to be disabled, because users can use this names as variables -static const char *csharp_properties_renames[][2] = { +const char *ProjectConverter3To4::csharp_properties_renames[][2] = { // // { "D", "Distance" }, //WorldMarginShape2D - TODO, looks that polish letters ą ę are treaten as space, not as letter, so `będą` are renamed to `będistanceą` // // {"Alt","AltPressed"}, // This may broke a lot of comments and user variables // // {"Command","CommandPressed"},// This may broke a lot of comments and user variables @@ -1278,7 +1293,7 @@ static const char *csharp_properties_renames[][2] = { { nullptr, nullptr }, }; -static const char *gdscript_signals_renames[][2] = { +const char *ProjectConverter3To4::gdscript_signals_renames[][2] = { // {"instantiate","instance"}, // FileSystemDock // { "hide", "hidden" }, // CanvasItem - function with same name exists // { "tween_all_completed","loop_finished"}, // Tween - TODO, not sure @@ -1303,7 +1318,7 @@ static const char *gdscript_signals_renames[][2] = { { nullptr, nullptr }, }; -static const char *csharp_signals_renames[][2] = { +const char *ProjectConverter3To4::csharp_signals_renames[][2] = { // {"Instantiate","Instance"}, // FileSystemDock // { "Hide", "Hidden" }, // CanvasItem - function with same name exists // { "TweenAllCompleted","LoopFinished"}, // Tween - TODO, not sure @@ -1327,7 +1342,7 @@ static const char *csharp_signals_renames[][2] = { }; -static const char *project_settings_renames[][2] = { +const char *ProjectConverter3To4::project_settings_renames[][2] = { { "audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db" }, { "audio/channel_disable_time", "audio/buses/channel_disable_time" }, { "audio/default_bus_layout", "audio/buses/default_bus_layout" }, @@ -1362,16 +1377,17 @@ static const char *project_settings_renames[][2] = { { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_3_subdiv" }, { "rendering/quality/shadow_atlas/size", "rendering/lights_and_shadows/shadow_atlas/size" }, { "rendering/quality/shadow_atlas/size.mobile", "rendering/lights_and_shadows/shadow_atlas/size.mobile" }, - { "rendering/vram_compression/import_bptc", "rendering/textures/vram_compression/import_bptc" }, - { "rendering/vram_compression/import_etc", "rendering/textures/vram_compression/import_etc" }, - { "rendering/vram_compression/import_etc2", "rendering/textures/vram_compression/import_etc2" }, - { "rendering/vram_compression/import_pvrtc", "rendering/textures/vram_compression/import_pvrtc" }, - { "rendering/vram_compression/import_s3tc", "rendering/textures/vram_compression/import_s3tc" }, + { "rendering/vram_compression/import_etc2", "rendering/textures/vram_compression/import_etc2_astc" }, + { "rendering/vram_compression/import_s3tc", "rendering/textures/vram_compression/import_s3tc_bptc" }, + { "window/size/width", "window/size/viewport_width" }, + { "window/size/height", "window/size/viewport_height" }, + { "window/size/test_width", "window/size/window_width_override" }, + { "window/size/test_height", "window/size/window_height_override" }, { nullptr, nullptr }, }; -static const char *input_map_renames[][2] = { +const char *ProjectConverter3To4::input_map_renames[][2] = { { ",\"alt\":", ",\"alt_pressed\":" }, { ",\"shift\":", ",\"shift_pressed\":" }, { ",\"control\":", ",\"ctrl_pressed\":" }, @@ -1383,7 +1399,7 @@ static const char *input_map_renames[][2] = { { nullptr, nullptr }, }; -static const char *builtin_types_renames[][2] = { +const char *ProjectConverter3To4::builtin_types_renames[][2] = { { "PoolByteArray", "PackedByteArray" }, { "PoolColorArray", "PackedColorArray" }, { "PoolIntArray", "PackedInt32Array" }, @@ -1397,7 +1413,7 @@ static const char *builtin_types_renames[][2] = { { nullptr, nullptr }, }; -static const char *shaders_renames[][2] = { +const char *ProjectConverter3To4::shaders_renames[][2] = { { "ALPHA_SCISSOR", "ALPHA_SCISSOR_THRESHOLD" }, { "CAMERA_MATRIX", "INV_VIEW_MATRIX" }, { "INV_CAMERA_MATRIX", "VIEW_MATRIX" }, @@ -1415,7 +1431,7 @@ static const char *shaders_renames[][2] = { { nullptr, nullptr }, }; -static const char *class_renames[][2] = { +const char *ProjectConverter3To4::class_renames[][2] = { // { "BulletPhysicsDirectBodyState", "BulletPhysicsDirectBodyState3D" }, // Class is not visible in ClassDB // { "BulletPhysicsServer", "BulletPhysicsServer3D" }, // Class is not visible in ClassDB // { "GDScriptFunctionState", "Node3D" }, // TODO - not sure to which should be changed @@ -1640,7 +1656,7 @@ static const char *class_renames[][2] = { { nullptr, nullptr }, }; -static const char *color_renames[][2] = { +const char *ProjectConverter3To4::ProjectConverter3To4::color_renames[][2] = { { "aliceblue", "ALICE_BLUE" }, { "antiquewhite", "ANTIQUE_WHITE" }, { "aqua", "AQUA" }, @@ -2549,14 +2565,14 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { valid = valid && test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_with_regex("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); - valid = valid && test_conversion_with_regex("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); - valid = valid && test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); - valid = valid && test_conversion_with_regex("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid && test_conversion_with_regex("\n\nremote func", "\n\n@rpc(\"any_peer\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid && test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(\"any_peer\", \"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid && test_conversion_with_regex("\n\nsync func", "\n\n@rpc(\"any_peer\", \"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_with_regex("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_with_regex("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); - valid = valid && test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid && test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(\"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_with_regex("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); - valid = valid && test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid && test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(\"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() : get = get_function, set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() : set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); @@ -4087,13 +4103,13 @@ void ProjectConverter3To4::rename_gdscript_keywords(Vector<String> &lines, const line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true); } if (line.contains("remote")) { - line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true); + line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(\"any_peer\") func", true); } if (line.contains("remote")) { - line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local) func", true); + line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(\"any_peer\", \"call_local\") func", true); } if (line.contains("sync")) { - line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local) func", true); + line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(\"any_peer\", \"call_local\") func", true); } if (line.contains("slave")) { line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true); @@ -4102,13 +4118,13 @@ void ProjectConverter3To4::rename_gdscript_keywords(Vector<String> &lines, const line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true); } if (line.contains("puppet")) { - line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true); + line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(\"call_local\") func", true); } if (line.contains("master")) { line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true); } if (line.contains("master")) { - line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(call_local) func", true); + line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(\"call_local\") func", true); } } } @@ -4156,25 +4172,25 @@ Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<S if (line.contains("remote")) { old = line; - line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true); + line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(\"any_peer\") func", true); if (old != line) { - found_renames.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line)); + found_renames.append(line_formatter(current_line, "remote func", "@rpc(\"any_peer\") func", line)); } } if (line.contains("remote")) { old = line; - line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local)) func", true); + line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(\"any_peer\", \"call_local\")) func", true); if (old != line) { - found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line)); + found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(\"any_peer\", \"call_local\")) func", line)); } } if (line.contains("sync")) { old = line; - line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local)) func", true); + line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(\"any_peer\", \"call_local\")) func", true); if (old != line) { - found_renames.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line)); + found_renames.append(line_formatter(current_line, "sync func", "@rpc(\"any_peer\", \"call_local\")) func", line)); } } @@ -4196,9 +4212,9 @@ Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<S if (line.contains("puppet")) { old = line; - line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true); + line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(\"call_local\") func", true); if (old != line) { - found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line)); + found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(\"call_local\") func", line)); } } @@ -4212,9 +4228,9 @@ Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<S if (line.contains("master")) { old = line; - line = reg_container.keyword_gdscript_master.sub(line, "@rpc(call_local) func", true); + line = reg_container.keyword_gdscript_master.sub(line, "@rpc(\"call_local\") func", true); if (old != line) { - found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line)); + found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(\"call_local\") func", line)); } } } @@ -4349,3 +4365,4 @@ int ProjectConverter3To4::validate_conversion() { } #endif // MODULE_REGEX_ENABLED +#endif // DISABLE_DEPRECATED diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index b3aa52f1e3..6ec2dd188d 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -29,6 +29,7 @@ /**************************************************************************/ #ifndef PROJECT_CONVERTER_3_TO_4_H +#ifndef DISABLE_DEPRECATED #define PROJECT_CONVERTER_3_TO_4_H #include "core/io/file_access.h" @@ -41,6 +42,19 @@ class RegEx; class ProjectConverter3To4 { public: class RegExContainer; + static const char *enum_renames[][2]; + static const char *gdscript_function_renames[][2]; + static const char *csharp_function_renames[][2]; + static const char *gdscript_properties_renames[][2]; + static const char *csharp_properties_renames[][2]; + static const char *gdscript_signals_renames[][2]; + static const char *csharp_signals_renames[][2]; + static const char *project_settings_renames[][2]; + static const char *input_map_renames[][2]; + static const char *builtin_types_renames[][2]; + static const char *shaders_renames[][2]; + static const char *class_renames[][2]; + static const char *color_renames[][2]; private: uint64_t maximum_file_size; @@ -97,4 +111,6 @@ public: int convert(); }; +#endif // DISABLE_DEPRECATED + #endif // PROJECT_CONVERTER_3_TO_4_H diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 560549d249..a43745b70f 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -370,17 +370,7 @@ void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionar } else { // Events changed - int act_event_count = ((Array)p_action["events"]).size(); - int old_event_count = ((Array)old_val["events"]).size(); - - if (act_event_count == old_event_count) { - undo_redo->create_action(TTR("Edit Input Action Event")); - } else if (act_event_count > old_event_count) { - undo_redo->create_action(TTR("Add Input Action Event")); - } else { - undo_redo->create_action(TTR("Remove Input Action Event")); - } - + undo_redo->create_action(TTR("Change Input Action Event(s)")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", property_name, p_action); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val); } @@ -527,6 +517,8 @@ void ProjectSettingsEditor::_update_action_map_editor() { if (is_builtin_input) { action_info.editable = false; action_info.icon = builtin_icon; + action_info.has_initial = true; + action_info.action_initial = ProjectSettings::get_singleton()->property_get_revert(property_name); } actions.push_back(action_info); |