diff options
Diffstat (limited to 'editor')
58 files changed, 1483 insertions, 642 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 639f5e6de5..8defa04ada 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -1489,32 +1489,21 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } } -void AnimationBezierTrackEdit::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - _pan_callback(-p_scroll_vec * 32); -} - -void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec) { +void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { v_scroll += p_scroll_vec.y * v_zoom; v_scroll = CLAMP(v_scroll, -100000, 100000); timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale()); queue_redraw(); } -void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { +void AnimationBezierTrackEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { const float v_zoom_orig = v_zoom; - if (p_alt) { + Ref<InputEventWithModifiers> iewm = p_event; + if (iewm.is_valid() && iewm->is_alt_pressed()) { // Alternate zoom (doesn't affect timeline). - if (p_scroll_vec.y > 0) { - v_zoom = MIN(v_zoom * 1.2, 100000); - } else { - v_zoom = MAX(v_zoom / 1.2, 0.000001); - } + v_zoom = CLAMP(v_zoom * p_zoom_factor, 0.000001, 100000); } else { - if (p_scroll_vec.y > 0) { - timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05); - } else { - timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05); - } + timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / p_zoom_factor); } v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig); queue_redraw(); @@ -1681,7 +1670,7 @@ void AnimationBezierTrackEdit::_bind_methods() { AnimationBezierTrackEdit::AnimationBezierTrackEdit() { panner.instantiate(); - panner->set_callbacks(callable_mp(this, &AnimationBezierTrackEdit::_scroll_callback), callable_mp(this, &AnimationBezierTrackEdit::_pan_callback), callable_mp(this, &AnimationBezierTrackEdit::_zoom_callback)); + panner->set_callbacks(callable_mp(this, &AnimationBezierTrackEdit::_pan_callback), callable_mp(this, &AnimationBezierTrackEdit::_zoom_callback)); play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index e6d6424ef2..dbc231ccac 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -174,9 +174,8 @@ class AnimationBezierTrackEdit : public Control { SelectionSet selection; Ref<ViewPanner> panner; - void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); void _draw_line_clipped(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, int p_clip_left, int p_clip_right); void _draw_track(int p_track, const Color &p_color); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 857a9a664a..338a22c070 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1704,25 +1704,13 @@ Control::CursorShape AnimationTimelineEdit::get_cursor_shape(const Point2 &p_pos } } -void AnimationTimelineEdit::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - // Timeline has no vertical scroll, so we change it to horizontal. - p_scroll_vec.x += p_scroll_vec.y; - _pan_callback(-p_scroll_vec * 32); -} - -void AnimationTimelineEdit::_pan_callback(Vector2 p_scroll_vec) { +void AnimationTimelineEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { set_value(get_value() - p_scroll_vec.x / get_zoom_scale()); } -void AnimationTimelineEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { - double new_zoom_value; +void AnimationTimelineEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { double current_zoom_value = get_zoom()->get_value(); - if (current_zoom_value <= 0.1) { - new_zoom_value = MAX(0.01, current_zoom_value - 0.01 * SIGN(p_scroll_vec.y)); - } else { - new_zoom_value = p_scroll_vec.y > 0 ? MAX(0.01, current_zoom_value / 1.05) : current_zoom_value * 1.05; - } - get_zoom()->set_value(new_zoom_value); + get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor)); } void AnimationTimelineEdit::set_use_fps(bool p_use_fps) { @@ -1798,7 +1786,8 @@ AnimationTimelineEdit::AnimationTimelineEdit() { len_hb->hide(); panner.instantiate(); - panner->set_callbacks(callable_mp(this, &AnimationTimelineEdit::_scroll_callback), callable_mp(this, &AnimationTimelineEdit::_pan_callback), callable_mp(this, &AnimationTimelineEdit::_zoom_callback)); + panner->set_callbacks(callable_mp(this, &AnimationTimelineEdit::_pan_callback), callable_mp(this, &AnimationTimelineEdit::_zoom_callback)); + panner->set_pan_axis(ViewPanner::PAN_AXIS_HORIZONTAL); set_layout_direction(Control::LAYOUT_DIRECTION_LTR); } @@ -5358,32 +5347,23 @@ void AnimationTrackEditor::_toggle_bezier_edit() { } } -void AnimationTrackEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - if (p_alt) { +void AnimationTrackEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { + Ref<InputEventWithModifiers> iewm = p_event; + if (iewm.is_valid() && iewm->is_alt_pressed()) { if (p_scroll_vec.x < 0 || p_scroll_vec.y < 0) { goto_prev_step(true); } else { goto_next_step(true); } } else { - _pan_callback(-p_scroll_vec * 32); + timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale()); + scroll->set_v_scroll(scroll->get_v_scroll() - p_scroll_vec.y); } } -void AnimationTrackEditor::_pan_callback(Vector2 p_scroll_vec) { - timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale()); - scroll->set_v_scroll(scroll->get_v_scroll() - p_scroll_vec.y); -} - -void AnimationTrackEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { - double new_zoom_value; +void AnimationTrackEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { double current_zoom_value = timeline->get_zoom()->get_value(); - if (current_zoom_value <= 0.1) { - new_zoom_value = MAX(0.01, current_zoom_value - 0.01 * SIGN(p_scroll_vec.y)); - } else { - new_zoom_value = p_scroll_vec.y > 0 ? MAX(0.01, current_zoom_value / 1.05) : current_zoom_value * 1.05; - } - timeline->get_zoom()->set_value(new_zoom_value); + timeline->get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor)); } void AnimationTrackEditor::_cancel_bezier_edit() { @@ -6398,7 +6378,7 @@ AnimationTrackEditor::AnimationTrackEditor() { timeline->connect("length_changed", callable_mp(this, &AnimationTrackEditor::_update_length)); panner.instantiate(); - panner->set_callbacks(callable_mp(this, &AnimationTrackEditor::_scroll_callback), callable_mp(this, &AnimationTrackEditor::_pan_callback), callable_mp(this, &AnimationTrackEditor::_zoom_callback)); + panner->set_callbacks(callable_mp(this, &AnimationTrackEditor::_pan_callback), callable_mp(this, &AnimationTrackEditor::_zoom_callback)); scroll = memnew(ScrollContainer); timeline_vbox->add_child(scroll); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index ef06445011..8506d9b80d 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -159,9 +159,8 @@ class AnimationTimelineEdit : public Range { bool use_fps = false; Ref<ViewPanner> panner; - void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); bool dragging_timeline = false; bool dragging_hsize = false; @@ -460,9 +459,8 @@ class AnimationTrackEditor : public VBoxContainer { PropertyInfo _find_hint_for_track(int p_idx, NodePath &r_base_path, Variant *r_current_val = nullptr); Ref<ViewPanner> panner; - void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); void _timeline_value_changed(double); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 9ff480f130..dee130ed0f 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -30,6 +30,7 @@ #include "connections_dialog.h" +#include "core/config/project_settings.h" #include "editor/doc_tools.h" #include "editor/editor_help.h" #include "editor/editor_node.h" @@ -165,6 +166,7 @@ void ConnectDialog::_tree_node_selected() { if (!edit_mode) { set_dst_method(generate_method_callback_name(source, signal, current)); } + _update_method_tree(); _update_ok_enabled(); } @@ -182,6 +184,11 @@ 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)); +} + /* * Adds a new parameter bind to connection. */ @@ -242,14 +249,153 @@ StringName ConnectDialog::generate_method_callback_name(Node *p_source, String p String dst_method; if (p_source == p_target) { - dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_to_self_name")).format(subst); + dst_method = String(GLOBAL_GET("editor/naming/default_signal_callback_to_self_name")).format(subst); } else { - dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst); + dst_method = String(GLOBAL_GET("editor/naming/default_signal_callback_name")).format(subst); } return dst_method; } +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")); + } + } +} + +List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_methods, const MethodInfo &p_signal, const String &p_search_string) const { + bool check_signal = compatible_methods_only->is_pressed(); + List<MethodInfo> ret; + + for (const MethodInfo &mi : p_methods) { + if (!p_search_string.is_empty() && !mi.name.contains(p_search_string)) { + continue; + } + + if (check_signal) { + if (mi.arguments.size() != p_signal.arguments.size()) { + continue; + } + + bool type_mismatch = false; + const List<PropertyInfo>::Element *E = p_signal.arguments.front(); + for (const List<PropertyInfo>::Element *F = mi.arguments.front(); F; F = F->next(), E = E->next()) { + Variant::Type stype = E->get().type; + Variant::Type mtype = F->get().type; + + if (stype != Variant::NIL && mtype != Variant::NIL && stype != mtype) { + type_mismatch = true; + break; + } + } + + if (type_mismatch) { + continue; + } + } + ret.push_back(mi); + } + return ret; +} + +void ConnectDialog::_update_method_tree() { + method_tree->clear(); + + Color disabled_color = get_theme_color(SNAME("accent_color"), SNAME("Editor")) * 0.7; + String search_string = method_search->get_text(); + Node *target = tree->get_selected(); + if (!target) { + return; + } + + MethodInfo signal_info; + if (compatible_methods_only->is_pressed()) { + List<MethodInfo> signals; + source->get_signal_list(&signals); + for (const MethodInfo &mi : signals) { + if (mi.name == signal) { + signal_info = mi; + break; + } + } + } + + TreeItem *root_item = method_tree->create_item(); + root_item->set_text(0, TTR("Methods")); + root_item->set_selectable(0, false); + + // If a script is attached, get methods from it. + ScriptInstance *si = target->get_script_instance(); + if (si) { + TreeItem *si_item = method_tree->create_item(root_item); + si_item->set_text(0, TTR("Attached Script")); + si_item->set_icon(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons"))); + si_item->set_selectable(0, false); + + List<MethodInfo> methods; + si->get_method_list(&methods); + methods = _filter_method_list(methods, signal_info, search_string); + + if (methods.is_empty()) { + si_item->set_custom_color(0, disabled_color); + } else { + _create_method_tree_items(methods, si_item); + } + } + + 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. + StringName current_class = target->get_class_name(); + do { + TreeItem *class_item = method_tree->create_item(root_item); + class_item->set_text(0, current_class); + Ref<Texture2D> icon = get_theme_icon(SNAME("Node"), SNAME("EditorIcons")); + if (has_theme_icon(current_class, SNAME("EditorIcons"))) { + icon = get_theme_icon(current_class, SNAME("EditorIcons")); + } + class_item->set_icon(0, icon); + class_item->set_selectable(0, false); + + List<MethodInfo> methods; + ClassDB::get_method_list(current_class, &methods, true); + methods = _filter_method_list(methods, signal_info, search_string); + + if (methods.is_empty()) { + class_item->set_custom_color(0, disabled_color); + } else { + _create_method_tree_items(methods, class_item); + } + 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) { + if (p_button == script_methods_only) { + EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "show_script_methods_only", p_button->is_pressed()); + } else if (p_button == compatible_methods_only) { + EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "show_compatible_methods_only", p_button->is_pressed()); + } + _update_method_tree(); +} + +void ConnectDialog::_open_method_popup() { + method_popup->popup_centered(); + method_search->clear(); + method_search->grab_focus(); +} + /* * Enables or disables the connect button. The connect button is enabled if a * node is selected and valid in the selected mode. @@ -262,7 +408,7 @@ void ConnectDialog::_update_ok_enabled() { return; } - if (!advanced->is_pressed() && target->get_script().is_null()) { + if (dst_method->get_text().is_empty()) { get_ok_button()->set_disabled(true); return; } @@ -288,14 +434,13 @@ void ConnectDialog::_notification(int p_what) { style->set_content_margin(SIDE_TOP, style->get_content_margin(SIDE_TOP) + 1.0); 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; } } void ConnectDialog::_bind_methods() { - ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed); - ClassDB::bind_method("_update_ok_enabled", &ConnectDialog::_update_ok_enabled); - ADD_SIGNAL(MethodInfo("connected")); } @@ -303,10 +448,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; } @@ -355,11 +508,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); @@ -377,22 +531,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); @@ -402,6 +541,8 @@ 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) { @@ -437,7 +578,6 @@ void ConnectDialog::_advanced_pressed() { error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root())); } - _update_ok_enabled(); EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "use_advanced_connections", advanced->is_pressed()); popup_centered(); @@ -458,8 +598,8 @@ ConnectDialog::ConnectDialog() { vbc_left->set_h_size_flags(Control::SIZE_EXPAND_FILL); from_signal = memnew(LineEdit); - from_signal->set_editable(false); vbc_left->add_margin_child(TTR("From Signal:"), from_signal); + from_signal->set_editable(false); tree = memnew(SceneTreeEditor(false)); tree->set_connecting_signal(true); @@ -476,6 +616,43 @@ ConnectDialog::ConnectDialog() { vbc_left->add_child(error_label); error_label->hide(); + method_popup = memnew(AcceptDialog); + method_popup->set_title(TTR("Select Method")); + method_popup->set_min_size(Vector2(400, 600) * EDSCALE); + add_child(method_popup); + + VBoxContainer *method_vbc = memnew(VBoxContainer); + method_popup->add_child(method_vbc); + + method_search = memnew(LineEdit); + method_vbc->add_child(method_search); + method_search->set_placeholder(TTR("Filter Methods")); + method_search->set_clear_button_enabled(true); + method_search->connect("text_changed", callable_mp(this, &ConnectDialog::_update_method_tree).unbind(1)); + + method_tree = memnew(Tree); + method_vbc->add_child(method_tree); + method_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); + method_tree->set_hide_root(true); + 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); + script_methods_only->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "show_script_methods_only", true)); + script_methods_only->connect("pressed", callable_mp(this, &ConnectDialog::_method_check_button_pressed).bind(script_methods_only)); + + compatible_methods_only = memnew(CheckButton(TTR("Compatible Methods Only"))); + method_vbc->add_child(compatible_methods_only); + compatible_methods_only->set_h_size_flags(Control::SIZE_SHRINK_END); + compatible_methods_only->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "show_compatible_methods_only", true)); + compatible_methods_only->connect("pressed", callable_mp(this, &ConnectDialog::_method_check_button_pressed).bind(compatible_methods_only)); + vbc_right = memnew(VBoxContainer); main_hb->add_child(vbc_right); vbc_right->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -521,14 +698,22 @@ ConnectDialog::ConnectDialog() { vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count); + HBoxContainer *hbc_method = memnew(HBoxContainer); + vbc_left->add_margin_child(TTR("Receiver Method:"), hbc_method); + dst_method = memnew(LineEdit); dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL); + dst_method->connect("text_changed", callable_mp(method_tree, &Tree::deselect_all).unbind(1)); dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted)); - vbc_left->add_margin_child(TTR("Receiver Method:"), dst_method); + hbc_method->add_child(dst_method); + + 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)); @@ -566,7 +751,7 @@ ConnectDialog::~ConnectDialog() { // Originally copied and adapted from EditorProperty, try to keep style in sync. Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const { EditorHelpBit *help_bit = memnew(EditorHelpBit); - help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE); + help_bit->get_rich_text()->set_custom_minimum_size(Size2(360 * EDSCALE, 1)); // p_text is expected to be something like this: // "gui_input::(event: InputEvent)::<Signal description>" @@ -605,9 +790,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); @@ -645,27 +827,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(); } @@ -676,7 +852,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); @@ -700,18 +876,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. @@ -741,7 +914,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(); } @@ -795,7 +968,10 @@ 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"]; + Dictionary sinfo = p_item.get_metadata(0); + String signal_name = sinfo["name"]; + PackedStringArray signal_args = sinfo["args"]; + const String &signal_name_ref = signal_name; Node *dst_node = selected_node->get_owner() ? selected_node->get_owner() : selected_node; @@ -809,22 +985,30 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) { 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->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); } } @@ -899,14 +1083,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; } @@ -957,7 +1141,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(); } } @@ -985,6 +1170,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) { @@ -1076,7 +1265,14 @@ void ConnectionsDock::update_tree() { // 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); + String signame = String(signal_name) + signaldesc; + signal_item->set_text(0, signame); + + if (signame == prev_selected) { + signal_item->select(0); + prev_selected = ""; + } + Dictionary sinfo; sinfo["name"] = signal_name; sinfo["args"] = argnames; @@ -1238,9 +1434,6 @@ ConnectionsDock::ConnectionsDock() { tree->connect("item_mouse_selected", callable_mp(this, &ConnectionsDock::_rmb_pressed)); add_theme_constant_override("separation", 3 * EDSCALE); - - EDITOR_DEF("interface/editors/default_signal_callback_name", "_on_{node_name}_{signal_name}"); - EDITOR_DEF("interface/editors/default_signal_callback_to_self_name", "_on_{signal_name}"); } ConnectionsDock::~ConnectionsDock() { diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 829a98caed..f70970996d 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,16 +107,26 @@ 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; bool first_popup = true; NodePath dst_path; VBoxContainer *vbc_right = nullptr; - 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; + SpinBox *unbind_count = nullptr; EditorInspector *bind_editor = nullptr; OptionButton *type_list = nullptr; @@ -132,6 +142,14 @@ private: void _item_activated(); void _text_submitted(const String &p_text); void _tree_node_selected(); + + void _method_selected(); + void _create_method_tree_items(const List<MethodInfo> &p_methods, TreeItem *p_parent_item); + List<MethodInfo> _filter_method_list(const List<MethodInfo> &p_methods, const MethodInfo &p_signal, const String &p_search_string) const; + void _update_method_tree(); + void _method_check_button_pressed(const CheckButton *p_button); + void _open_method_popup(); + void _unbind_count_changed(double p_count); void _add_bind(); void _remove_bind(); @@ -145,7 +163,9 @@ 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; @@ -157,7 +177,7 @@ public: 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); ConnectDialog(); @@ -203,8 +223,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(); @@ -213,7 +233,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..945a3ef932 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) + "\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/dependency_editor.cpp b/editor/dependency_editor.cpp index a925e2d1d3..c98ec7b2d5 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -536,12 +536,17 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector< } void DependencyRemoveDialog::ok_pressed() { - for (int i = 0; i < files_to_delete.size(); ++i) { - if (ResourceCache::has(files_to_delete[i])) { - Ref<Resource> res = ResourceCache::get_ref(files_to_delete[i]); + for (const KeyValue<String, String> &E : all_remove_files) { + String file = E.key; + + if (ResourceCache::has(file)) { + Ref<Resource> res = ResourceCache::get_ref(file); + emit_signal(SNAME("resource_removed"), res); res->set_path(""); } + } + for (int i = 0; i < files_to_delete.size(); ++i) { // If the file we are deleting for e.g. the main scene, default environment, // or audio bus layout, we must clear its definition in Project Settings. if (files_to_delete[i] == String(GLOBAL_GET("application/config/icon"))) { @@ -621,6 +626,7 @@ void DependencyRemoveDialog::ok_pressed() { } void DependencyRemoveDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("resource_removed", PropertyInfo(Variant::OBJECT, "obj"))); ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file"))); ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder"))); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 4cf947b006..e11251596a 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -2370,7 +2370,7 @@ EditorHelpBit::EditorHelpBit() { rich_text = memnew(RichTextLabel); add_child(rich_text); rich_text->connect("meta_clicked", callable_mp(this, &EditorHelpBit::_meta_clicked)); - rich_text->set_fit_content_height(true); + rich_text->set_fit_content(true); set_custom_minimum_size(Size2(0, 50 * EDSCALE)); } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 4753761f05..0166d4c719 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -886,7 +886,7 @@ void EditorProperty::_update_pin_flags() { static Control *make_help_bit(const String &p_text, bool p_property) { EditorHelpBit *help_bit = memnew(EditorHelpBit); - help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE); + help_bit->get_rich_text()->set_custom_minimum_size(Size2(360 * EDSCALE, 1)); PackedStringArray slices = p_text.split("::", false); if (slices.is_empty()) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index c7ea7dc7cf..0d5c820a3c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3089,7 +3089,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } String EditorNode::adjust_scene_name_casing(const String &root_name) { - switch (GLOBAL_GET("editor/scene/scene_naming").operator int()) { + switch (GLOBAL_GET("editor/naming/scene_name_casing").operator int()) { case SCENE_NAME_CASING_AUTO: // Use casing of the root node. break; @@ -3902,7 +3902,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b Ref<SceneState> state = sdata->get_state(); state->set_path(lpath); new_scene->set_scene_inherited_state(state); - new_scene->set_scene_file_path(lpath); + new_scene->set_scene_file_path(String()); } new_scene->set_scene_instance_state(Ref<SceneState>()); @@ -6113,6 +6113,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins Ref<SceneState> state = current_packed_scene->get_state(); state->set_path(current_packed_scene->get_path()); instantiated_node->set_scene_inherited_state(state); + instantiated_node->set_scene_file_path(String()); } editor_data.set_edited_scene_root(instantiated_node); current_edited_scene = instantiated_node; @@ -6429,7 +6430,7 @@ void EditorNode::_feature_profile_changed() { } void EditorNode::_bind_methods() { - GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/scene/scene_naming", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case"), SCENE_NAME_CASING_SNAKE_CASE); + GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/scene_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case"), SCENE_NAME_CASING_SNAKE_CASE); ClassDB::bind_method("edit_current", &EditorNode::edit_current); ClassDB::bind_method("edit_node", &EditorNode::edit_node); @@ -7261,6 +7262,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_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..21e15bc996 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -474,10 +474,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..5cae3ef3fd 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; } @@ -1492,11 +1492,11 @@ 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)); + 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 +1506,11 @@ 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)); + 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_platform.cpp b/editor/export/editor_export_platform.cpp index 9f79eecfb7..b2a3085c36 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -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/filesystem_dock.cpp b/editor/filesystem_dock.cpp index a078c58e72..378e06b4c9 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1531,6 +1531,10 @@ void FileSystemDock::_make_scene_confirm() { EditorNode::get_singleton()->save_scene_list({ scene_path }); } +void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) { + emit_signal(SNAME("resource_removed"), p_resource); +} + void FileSystemDock::_file_removed(String p_file) { emit_signal(SNAME("file_removed"), p_file); @@ -3095,6 +3099,7 @@ void FileSystemDock::_bind_methods() { ADD_SIGNAL(MethodInfo("inherit", PropertyInfo(Variant::STRING, "file"))); ADD_SIGNAL(MethodInfo("instantiate", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); + ADD_SIGNAL(MethodInfo("resource_removed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file"))); ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder"))); ADD_SIGNAL(MethodInfo("files_moved", PropertyInfo(Variant::STRING, "old_file"), PropertyInfo(Variant::STRING, "new_file"))); @@ -3254,6 +3259,7 @@ FileSystemDock::FileSystemDock() { add_child(owners_editor); remove_dialog = memnew(DependencyRemoveDialog); + remove_dialog->connect("resource_removed", callable_mp(this, &FileSystemDock::_resource_removed)); remove_dialog->connect("file_removed", callable_mp(this, &FileSystemDock::_file_removed)); remove_dialog->connect("folder_removed", callable_mp(this, &FileSystemDock::_folder_removed)); add_child(remove_dialog); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 42a72b7ee8..ede6869eea 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -227,6 +227,7 @@ private: void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const; void _update_project_settings_after_move(const HashMap<String, String> &p_renames) const; + void _resource_removed(const Ref<Resource> &p_resource); void _file_removed(String p_file); void _folder_removed(String p_folder); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 2f543ea02d..b9b6391432 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -322,15 +322,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 +383,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(); } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 06241d07cf..30e06bfcf4 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)) { @@ -1675,7 +1677,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 c0972d201e..9632670658 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1127,7 +1127,7 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action connecting = false; } -void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance, bool p_multi_transitions) { +void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_multi_transitions) { Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label")); Color icon_color(1, 1, 1); Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor")); @@ -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); @@ -1153,12 +1154,18 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co if (p_travel) { linecolor = accent; - linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v()); } state_machine_draw->draw_line(p_from, p_to, linecolor, 2); - Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; + if (p_fade_ratio > 0.0) { + Color fade_linecolor = accent; + 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); + } + 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(); @@ -1327,7 +1334,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } } - _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, false, false); + _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, 0.0, false, false); } Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons")); @@ -1357,6 +1364,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { tl.mode = tr->get_switch_mode(); tl.width = tr_bidi_offset; tl.travel = false; + tl.fade_ratio = 0.0; tl.hidden = false; if (state_machine->has_local_transition(local_to, local_from)) { //offset if same exists @@ -1378,6 +1386,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { if (blend_from == local_from && current == local_to) { tl.travel = true; + tl.fade_ratio = MIN(1.0, fading_pos / fading_time); } if (travel_path.size()) { @@ -1418,7 +1427,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { for (int i = 0; i < transition_lines.size(); i++) { TransitionLine tl = transition_lines[i]; if (!tl.hidden) { - _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.auto_advance, !tl.multi_transitions.is_empty()); + _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.fade_ratio, tl.auto_advance, !tl.multi_transitions.is_empty()); } } @@ -1508,25 +1517,24 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { state_machine_play_pos->queue_redraw(); } -void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { +void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String p_name, float p_ratio) { AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); if (!tree) { return; } Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); - if (!playback.is_valid() || !playback->is_playing()) { return; } - if (playback->get_current_node() == state_machine->start_node || playback->get_current_node() == state_machine->end_node) { + if (p_name == state_machine->start_node || p_name == state_machine->end_node || p_name.is_empty()) { return; } int idx = -1; for (int i = 0; i < node_rects.size(); i++) { - if (node_rects[i].node_name == playback->get_current_node()) { + if (node_rects[i].node_name == p_name) { idx = i; break; } @@ -1550,10 +1558,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { } to.y = from.y; - float len = MAX(0.0001, current_length); - - float pos = CLAMP(play_pos, 0, len); - float c = pos / len; + float c = p_ratio; Color fg = get_theme_color(SNAME("font_color"), SNAME("Label")); Color bg = fg; bg.a *= 0.3; @@ -1565,6 +1570,32 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { state_machine_play_pos->draw_line(from, to, fg, 2); } +void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + + Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + if (!playback.is_valid() || !playback->is_playing()) { + return; + } + + { + float len = MAX(0.0001, current_length); + float pos = CLAMP(current_play_pos, 0, len); + float c = pos / len; + _state_machine_pos_draw_individual(playback->get_current_node(), c); + } + + { + float len = MAX(0.0001, fade_from_length); + float pos = CLAMP(fade_from_current_play_pos, 0, len); + float c = pos / len; + _state_machine_pos_draw_individual(playback->get_fading_from_node(), c); + } +} + void AnimationNodeStateMachineEditor::_update_graph() { if (updating) { return; @@ -1687,17 +1718,28 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { Vector<StringName> tp; bool is_playing = false; StringName current_node; - StringName blend_from_node; - play_pos = 0; + StringName fading_from_node; + + current_play_pos = 0; current_length = 0; + fade_from_current_play_pos = 0; + fade_from_length = 0; + + fading_time = 0; + fading_pos = 0; + if (playback.is_valid()) { tp = playback->get_travel_path(); is_playing = playback->is_playing(); current_node = playback->get_current_node(); - blend_from_node = playback->get_fading_from_node(); - play_pos = playback->get_current_play_pos(); + fading_from_node = playback->get_fading_from_node(); + current_play_pos = playback->get_current_play_pos(); current_length = playback->get_current_length(); + fade_from_current_play_pos = playback->get_fade_from_play_pos(); + fade_from_length = playback->get_fade_from_length(); + fading_time = playback->get_fading_time(); + fading_pos = playback->get_fading_pos(); } { @@ -1714,12 +1756,19 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } //redraw if travel state changed - if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) { + if (!same_travel_path || + last_active != is_playing || + last_current_node != current_node || + last_fading_from_node != fading_from_node || + last_fading_time != fading_time || + last_fading_pos != fading_pos) { state_machine_draw->queue_redraw(); last_travel_path = tp; last_current_node = current_node; last_active = is_playing; - last_blend_from_node = blend_from_node; + last_fading_from_node = fading_from_node; + last_fading_time = fading_time; + last_fading_pos = fading_pos; state_machine_play_pos->queue_redraw(); } @@ -1737,14 +1786,15 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { // when current_node is a state machine, use playback of current_node to set play_pos if (current_node_playback.is_valid()) { - play_pos = current_node_playback->get_current_play_pos(); + current_play_pos = current_node_playback->get_current_play_pos(); current_length = current_node_playback->get_current_length(); } } } - if (last_play_pos != play_pos) { - last_play_pos = play_pos; + if (last_play_pos != current_play_pos || fade_from_last_play_pos != fade_from_current_play_pos) { + last_play_pos = current_play_pos; + fade_from_last_play_pos = fade_from_current_play_pos; state_machine_play_pos->queue_redraw(); } } break; @@ -2048,7 +2098,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { state_machine_draw->add_child(state_machine_play_pos); state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_FULL_RECT); - state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw)); + state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw_all)); v_scroll = memnew(VScrollBar); state_machine_draw->add_child(v_scroll); diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 46fe13ccc1..66338c820e 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -85,9 +85,12 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { static AnimationNodeStateMachineEditor *singleton; void _state_machine_gui_input(const Ref<InputEvent> &p_event); - void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance, bool p_multi_transitions); + void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_multi_transitions); + void _state_machine_draw(); - void _state_machine_pos_draw(); + + void _state_machine_pos_draw_individual(String p_name, float p_ratio); + void _state_machine_pos_draw_all(); void _update_graph(); @@ -150,6 +153,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { float width = 0; bool selected; bool travel; + float fade_ratio; bool hidden; int transition_index; Vector<TransitionLine> multi_transitions; @@ -204,13 +208,23 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { void _delete_tree_draw(); bool last_active = false; - StringName last_blend_from_node; + StringName last_fading_from_node; StringName last_current_node; Vector<StringName> last_travel_path; + + float fade_from_last_play_pos = 0.0f; + float fade_from_current_play_pos = 0.0f; + float fade_from_length = 0.0f; + float last_play_pos = 0.0f; - float play_pos = 0.0f; + float current_play_pos = 0.0f; float current_length = 0.0f; + float last_fading_time = 0.0f; + float last_fading_pos = 0.0f; + float fading_time = 0.0f; + float fading_pos = 0.0f; + float error_time = 0.0f; String error_text; 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 5d0555a10e..e09636d297 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1259,57 +1259,25 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo } } - Ref<InputEventMagnifyGesture> magnify_gesture = p_event; - if (magnify_gesture.is_valid() && !p_already_accepted) { - // Zoom gesture - _zoom_on_position(zoom * magnify_gesture->get_factor(), magnify_gesture->get_position()); - return true; - } - - Ref<InputEventPanGesture> pan_gesture = p_event; - if (pan_gesture.is_valid() && !p_already_accepted) { - // If ctrl key pressed, then zoom instead of pan. - if (pan_gesture->is_ctrl_pressed()) { - const real_t factor = pan_gesture->get_delta().y; - - zoom_widget->set_zoom_by_increments(1); - if (factor != 1.f) { - zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * factor + 1.f)); - } - _zoom_on_position(zoom_widget->get_zoom(), pan_gesture->get_position()); - - return true; - } - - // Pan gesture - const Vector2 delta = (pan_speed / zoom) * pan_gesture->get_delta(); - view_offset.x += delta.x; - view_offset.y += delta.y; - update_viewport(); - return true; - } - return false; } -void CanvasItemEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - _pan_callback(-p_scroll_vec * pan_speed); -} - -void CanvasItemEditor::_pan_callback(Vector2 p_scroll_vec) { +void CanvasItemEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { view_offset.x -= p_scroll_vec.x / zoom; view_offset.y -= p_scroll_vec.y / zoom; update_viewport(); } -void CanvasItemEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { - int scroll_sign = (int)SIGN(p_scroll_vec.y); - // Inverted so that scrolling up (-1) zooms in, scrolling down (+1) zooms out. - zoom_widget->set_zoom_by_increments(-scroll_sign, p_alt); - if (!Math::is_equal_approx(ABS(p_scroll_vec.y), (real_t)1.0)) { - // Handle high-precision (analog) scrolling. - zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * ABS(p_scroll_vec.y) + 1.f)); +void CanvasItemEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + // Special behvior for scroll events, as the zoom_by_increment method can smartly end up on powers of two. + int increment = p_zoom_factor > 1.0 ? 1 : -1; + zoom_widget->set_zoom_by_increments(increment, mb->is_alt_pressed()); + } else { + zoom_widget->set_zoom(zoom_widget->get_zoom() * p_zoom_factor); } + _zoom_on_position(zoom_widget->get_zoom(), p_origin); } @@ -3868,7 +3836,7 @@ void CanvasItemEditor::_update_editor_settings() { context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles"))); panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning"))); - pan_speed = int(EDITOR_GET("editors/panning/2d_editor_pan_speed")); + panner->set_scroll_speed(EDITOR_GET("editors/panning/2d_editor_pan_speed")); warped_panning = bool(EDITOR_GET("editors/panning/warped_mouse_panning")); } @@ -5059,7 +5027,7 @@ CanvasItemEditor::CanvasItemEditor() { zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom)); panner.instantiate(); - panner->set_callbacks(callable_mp(this, &CanvasItemEditor::_scroll_callback), callable_mp(this, &CanvasItemEditor::_pan_callback), callable_mp(this, &CanvasItemEditor::_zoom_callback)); + panner->set_callbacks(callable_mp(this, &CanvasItemEditor::_pan_callback), callable_mp(this, &CanvasItemEditor::_zoom_callback)); viewport = memnew(CanvasItemEditorViewport(this)); viewport_scrollable->add_child(viewport); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 1e01eac82d..ebe87a56f7 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -363,10 +363,8 @@ private: Ref<ViewPanner> panner; bool warped_panning = true; - int pan_speed = 20; - void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); bool _is_node_locked(const Node *p_node) const; bool _is_node_movable(const Node *p_node, bool p_popup_warning = false); 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 bb71c27bff..e11dc1c81d 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -5057,8 +5057,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); @@ -5068,10 +5068,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)); @@ -5082,21 +5082,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)); @@ -5107,16 +5107,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; } } @@ -5125,8 +5125,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); } @@ -5136,7 +5136,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) { @@ -5151,8 +5151,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)) { @@ -5164,11 +5164,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); } } @@ -5177,22 +5177,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/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index c30f0ec62d..fb35668310 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -939,21 +939,13 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } -void Polygon2DEditor::_uv_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - _uv_pan_callback(-p_scroll_vec * 32); -} - -void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec) { +void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { uv_hscroll->set_value(uv_hscroll->get_value() - p_scroll_vec.x); uv_vscroll->set_value(uv_vscroll->get_value() - p_scroll_vec.y); } -void Polygon2DEditor::_uv_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { - if (p_scroll_vec.y < 0) { - uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * Math::abs(p_scroll_vec.y)))); - } else { - uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * Math::abs(p_scroll_vec.y)))); - } +void Polygon2DEditor::_uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { + uv_zoom->set_value(uv_zoom->get_value() * p_zoom_factor); } void Polygon2DEditor::_uv_scroll_changed(real_t) { @@ -1478,7 +1470,7 @@ Polygon2DEditor::Polygon2DEditor() { bone_scroll->add_child(bone_scroll_vb); uv_panner.instantiate(); - uv_panner->set_callbacks(callable_mp(this, &Polygon2DEditor::_uv_scroll_callback), callable_mp(this, &Polygon2DEditor::_uv_pan_callback), callable_mp(this, &Polygon2DEditor::_uv_zoom_callback)); + uv_panner->set_callbacks(callable_mp(this, &Polygon2DEditor::_uv_pan_callback), callable_mp(this, &Polygon2DEditor::_uv_zoom_callback)); uv_edit_draw->connect("draw", callable_mp(this, &Polygon2DEditor::_uv_draw)); uv_edit_draw->connect("gui_input", callable_mp(this, &Polygon2DEditor::_uv_input)); diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index 7246c08bea..2c55a5f631 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -90,9 +90,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { TextureRect *uv_icon_zoom = nullptr; Ref<ViewPanner> uv_panner; - void _uv_scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _uv_pan_callback(Vector2 p_scroll_vec); - void _uv_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); VBoxContainer *bone_scroll_main_vb = nullptr; ScrollContainer *bone_scroll = nullptr; 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..a7b32ce0c3 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,23 @@ 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"))); + 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 +454,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 +488,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 +559,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 +602,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 +626,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 +650,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 +676,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 +699,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 +722,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 +815,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(); - edited_anim = name; + _select_animation(name); + animations->grab_focus(); +} - undo_redo->commit_action(); +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)); + + 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 +867,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 +893,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 +938,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 +952,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 +1004,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 +1045,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 +1079,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)) { @@ -1061,20 +1157,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 +1208,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 +1318,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 +1348,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 +1521,16 @@ 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); + 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 +1540,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); @@ -1319,6 +1576,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 +1664,10 @@ 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_allow_lesser(false); frame_duration->set_allow_greater(true); hbc->add_child(frame_duration); @@ -1616,16 +1912,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; } } diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index a5e0e54fb8..19ecfb00ed 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,17 @@ class SpriteFramesEditor : public HSplitContainer { bool read_only = false; + Ref<Texture2D> autoplay_icon; + Ref<Texture2D> stop_icon; + Ref<Texture2D> pause_icon; + + 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,6 +100,8 @@ class SpriteFramesEditor : public HSplitContainer { Button *add_anim = nullptr; Button *delete_anim = nullptr; + HBoxContainer *autoplay_container = nullptr; + Button *autoplay = nullptr; LineEdit *anim_search_box = nullptr; Tree *animations = nullptr; @@ -95,8 +112,6 @@ class SpriteFramesEditor : public HSplitContainer { AcceptDialog *dialog = nullptr; - SpriteFrames *frames = nullptr; - StringName edited_anim; ConfirmationDialog *delete_dialog = nullptr; @@ -146,7 +161,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 +206,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/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index d7559bc18e..c5aa60c816 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -620,22 +620,14 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } } -void TextureRegionEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - _pan_callback(-p_scroll_vec * 32); -} - -void TextureRegionEditor::_pan_callback(Vector2 p_scroll_vec) { +void TextureRegionEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { p_scroll_vec /= draw_zoom; hscroll->set_value(hscroll->get_value() - p_scroll_vec.x); vscroll->set_value(vscroll->get_value() - p_scroll_vec.y); } -void TextureRegionEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { - if (p_scroll_vec.y < 0) { - _zoom_on_position(draw_zoom * ((0.95 + (0.05 * Math::abs(p_scroll_vec.y))) / 0.95), p_origin); - } else { - _zoom_on_position(draw_zoom * (1 - (0.05 * Math::abs(p_scroll_vec.y))), p_origin); - } +void TextureRegionEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { + _zoom_on_position(draw_zoom * p_zoom_factor, p_origin); } void TextureRegionEditor::_scroll_changed(float) { @@ -748,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()); + } } } @@ -1169,7 +1164,7 @@ TextureRegionEditor::TextureRegionEditor() { hb_grid->hide(); panner.instantiate(); - panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_scroll_callback), callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback)); + panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback)); edit_draw = memnew(Panel); vb->add_child(edit_draw); diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 0325700d25..ba64a04084 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -103,9 +103,8 @@ class TextureRegionEditor : public AcceptDialog { bool request_center = false; Ref<ViewPanner> panner; - void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); void _set_snap_mode(int p_mode); void _set_snap_off_x(float p_val); diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 0ac375407c..fd651dd507 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -47,18 +47,14 @@ void TileAtlasView::gui_input(const Ref<InputEvent> &p_event) { } } -void TileAtlasView::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { - _pan_callback(-p_scroll_vec * 32); -} - -void TileAtlasView::_pan_callback(Vector2 p_scroll_vec) { +void TileAtlasView::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { panning += p_scroll_vec; _update_zoom_and_panning(true); emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning); } -void TileAtlasView::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { - zoom_widget->set_zoom_by_increments(-p_scroll_vec.y * 2); +void TileAtlasView::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { + zoom_widget->set_zoom(zoom_widget->get_zoom() * p_zoom_factor); _update_zoom_and_panning(true); emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning); } @@ -251,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); @@ -326,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); } } } @@ -376,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); } @@ -583,7 +580,7 @@ TileAtlasView::TileAtlasView() { add_child(button_center_view); panner.instantiate(); - panner->set_callbacks(callable_mp(this, &TileAtlasView::_scroll_callback), callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback)); + panner->set_callbacks(callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback)); panner->set_enable_rmb(true); center_container = memnew(CenterContainer); diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h index f719bee704..4a7547f34b 100644 --- a/editor/plugins/tiles/tile_atlas_view.h +++ b/editor/plugins/tiles/tile_atlas_view.h @@ -65,9 +65,8 @@ private: virtual void gui_input(const Ref<InputEvent> &p_event) override; Ref<ViewPanner> panner; - void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); - void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); + void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event); + void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event); HashMap<Vector2, HashMap<int, Rect2i>> alternative_tiles_rect_cache; void _update_alternative_tiles_rect_cache(); 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 2394130ad6..f0a02a3768 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -266,7 +266,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven } Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + if (!tile_set.is_valid() || EditorNode::get_singleton()->is_resource_read_only(tile_set)) { return; } @@ -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; @@ -1277,13 +1277,15 @@ void TileMapEditorTilesPlugin::_stop_dragging() { tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile); } - // Creating a pattern in the pattern list. - select_last_pattern = true; - int new_pattern_index = tile_set->get_patterns_count(); - undo_redo->create_action(TTR("Add TileSet pattern")); - undo_redo->add_do_method(*tile_set, "add_pattern", selection_pattern, new_pattern_index); - undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index); - undo_redo->commit_action(); + if (EditorNode::get_singleton()->is_resource_read_only(tile_set)) { + // Creating a pattern in the pattern list. + select_last_pattern = true; + int new_pattern_index = tile_set->get_patterns_count(); + undo_redo->create_action(TTR("Add TileSet pattern")); + undo_redo->add_do_method(*tile_set, "add_pattern", selection_pattern, new_pattern_index); + undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index); + undo_redo->commit_action(); + } } else { // Get the top-left cell. Vector2i top_left; @@ -1989,6 +1991,15 @@ TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const { void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) { _stop_dragging(); // Avoids staying in a wrong drag state. + // Disable sort button if the tileset is read-only + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + if (tile_map) { + Ref<TileSet> tile_set = tile_map->get_tileset(); + if (tile_set.is_valid()) { + source_sort_button->set_disabled(EditorNode::get_singleton()->is_resource_read_only(tile_set)); + } + } + if (tile_map_id != p_tile_map_id) { tile_map_id = p_tile_map_id; @@ -3986,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); @@ -4001,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 32421daa92..840a3911af 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -585,6 +585,7 @@ void TileSetAtlasSourceEditor::_update_atlas_source_inspector() { // Update visibility. bool inspector_visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button; atlas_source_inspector->set_visible(inspector_visible); + atlas_source_inspector->set_read_only(read_only); } void TileSetAtlasSourceEditor::_update_tile_inspector() { @@ -599,6 +600,7 @@ void TileSetAtlasSourceEditor::_update_tile_inspector() { tile_inspector->hide(); tile_inspector_no_tile_selected_label->hide(); } + tile_inspector->set_read_only(read_only); } void TileSetAtlasSourceEditor::_update_tile_data_editors() { @@ -638,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"); @@ -970,19 +972,19 @@ void TileSetAtlasSourceEditor::_update_toolbar() { current_tile_data_editor_toolbar->hide(); } tools_settings_erase_button->show(); - tool_advanced_menu_buttom->show(); + tool_advanced_menu_button->show(); } else if (tools_button_group->get_pressed_button() == tool_select_button) { if (current_tile_data_editor_toolbar) { current_tile_data_editor_toolbar->hide(); } tools_settings_erase_button->hide(); - tool_advanced_menu_buttom->hide(); + tool_advanced_menu_button->hide(); } else if (tools_button_group->get_pressed_button() == tool_paint_button) { if (current_tile_data_editor_toolbar) { current_tile_data_editor_toolbar->show(); } tools_settings_erase_button->hide(); - tool_advanced_menu_buttom->hide(); + tool_advanced_menu_button->hide(); } } @@ -1862,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); @@ -1885,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); @@ -2037,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); @@ -2061,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); @@ -2188,7 +2190,12 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource ERR_FAIL_COND(p_source_id < 0); ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source); - if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == tile_set_atlas_source_id) { + bool new_read_only_state = false; + if (p_tile_set.is_valid()) { + new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_tile_set); + } + + if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == tile_set_atlas_source_id && new_read_only_state == read_only) { return; } @@ -2205,11 +2212,23 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource tile_set_atlas_source = p_tile_set_atlas_source; tile_set_atlas_source_id = p_source_id; - // Add the listener again. + // Read-only is off by default. + read_only = new_read_only_state; + if (tile_set.is_valid()) { tile_set->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed)); } + if (read_only && tools_button_group->get_pressed_button() == tool_paint_button) { + tool_paint_button->set_pressed(false); + tool_setup_atlas_source_button->set_pressed(true); + } + + // Disable buttons in read-only mode. + tool_paint_button->set_disabled(read_only); + tools_settings_erase_button->set_disabled(read_only); + tool_advanced_menu_button->set_disabled(read_only); + // Update everything. _update_source_inspector(); @@ -2344,7 +2363,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { tools_settings_erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons"))); - tool_advanced_menu_buttom->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); + tool_advanced_menu_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); resize_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons")); resize_handle_disabled = get_theme_icon(SNAME("EditorHandleDisabled"), SNAME("EditorIcons")); @@ -2352,6 +2371,18 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { if (tile_set_changed_needs_update) { + // Read-only is off by default + read_only = false; + // Add the listener again and check for read-only status. + if (tile_set.is_valid()) { + read_only = EditorNode::get_singleton()->is_resource_read_only(tile_set); + } + + // Disable buttons in read-only mode. + tool_paint_button->set_disabled(read_only); + tools_settings_erase_button->set_disabled(read_only); + tool_advanced_menu_button->set_disabled(read_only); + // Update everything. _update_source_inspector(); @@ -2516,12 +2547,12 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tools_settings_erase_button->set_shortcut_context(this); tool_settings->add_child(tools_settings_erase_button); - tool_advanced_menu_buttom = memnew(MenuButton); - tool_advanced_menu_buttom->set_flat(true); - tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES); - tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES); - tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); - tool_settings->add_child(tool_advanced_menu_buttom); + tool_advanced_menu_button = memnew(MenuButton); + tool_advanced_menu_button->set_flat(true); + tool_advanced_menu_button->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES); + tool_advanced_menu_button->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES); + tool_advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); + tool_settings->add_child(tool_advanced_menu_button); _update_toolbar(); @@ -2673,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/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index bcab1296ad..a4826bc56f 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -113,6 +113,8 @@ public: }; private: + bool read_only = false; + Ref<TileSet> tile_set; TileSetAtlasSource *tile_set_atlas_source = nullptr; int tile_set_atlas_source_id = TileSet::INVALID_SOURCE; @@ -209,7 +211,7 @@ private: HBoxContainer *tool_settings = nullptr; HBoxContainer *tool_settings_tile_data_toolbar_container = nullptr; Button *tools_settings_erase_button = nullptr; - MenuButton *tool_advanced_menu_buttom = nullptr; + MenuButton *tool_advanced_menu_button = nullptr; // Selection. RBSet<TileSelection> selection; diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 53c2d4de51..39d17c718e 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -89,6 +89,10 @@ void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data, bool TileSetEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { ERR_FAIL_COND_V(!tile_set.is_valid(), false); + if (read_only) { + return false; + } + if (p_from == sources_list) { Dictionary d = p_data; @@ -223,7 +227,7 @@ void TileSetEditor::_source_selected(int p_source_index) { ERR_FAIL_COND(!tile_set.is_valid()); // Update the selected source. - sources_delete_button->set_disabled(p_source_index < 0); + sources_delete_button->set_disabled(p_source_index < 0 || read_only); if (p_source_index >= 0) { int source_id = sources_list->get_item_metadata(p_source_index); @@ -356,8 +360,19 @@ void TileSetEditor::_notification(int p_what) { if (tile_set.is_valid()) { tile_set->set_edited(true); } + + read_only = false; + if (tile_set.is_valid()) { + read_only = EditorNode::get_singleton()->is_resource_read_only(tile_set); + } + _update_sources_list(); _update_patterns_list(); + + sources_add_button->set_disabled(read_only); + sources_advanced_menu_button->set_disabled(read_only); + source_sort_button->set_disabled(read_only); + tile_set_changed_needs_update = false; } } break; @@ -367,6 +382,10 @@ void TileSetEditor::_notification(int p_what) { void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(!tile_set.is_valid()); + if (EditorNode::get_singleton()->is_resource_read_only(tile_set)) { + return; + } + if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) { Vector<int> selected = patterns_item_list->get_selected_items(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); @@ -667,7 +686,12 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p } void TileSetEditor::edit(Ref<TileSet> p_tile_set) { - if (p_tile_set == tile_set) { + bool new_read_only_state = false; + if (tile_set.is_valid()) { + new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_tile_set); + } + + if (p_tile_set == tile_set && new_read_only_state == read_only) { return; } @@ -679,8 +703,15 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) { // Change the edited object. tile_set = p_tile_set; - // Add the listener again. + // Read-only status is false by default + read_only = new_read_only_state; + + // Add the listener again and check for read-only status. if (tile_set.is_valid()) { + sources_add_button->set_disabled(read_only); + sources_advanced_menu_button->set_disabled(read_only); + source_sort_button->set_disabled(read_only); + tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed)); if (first_edit) { first_edit = false; @@ -690,10 +721,6 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) { } _update_patterns_list(); } - - tile_set_atlas_source_editor->hide(); - tile_set_scenes_collection_source_editor->hide(); - no_source_selected_label->show(); } TileSetEditor::TileSetEditor() { diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h index e3dff11277..d36d3bde41 100644 --- a/editor/plugins/tiles/tile_set_editor.h +++ b/editor/plugins/tiles/tile_set_editor.h @@ -45,6 +45,8 @@ class TileSetEditor : public VBoxContainer { static TileSetEditor *singleton; private: + bool read_only = false; + Ref<TileSet> tile_set; bool tile_set_changed_needs_update = false; HSplitContainer *split_container = nullptr; diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 6251cd18f7..cc276597fa 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -284,7 +284,7 @@ void TileSetScenesCollectionSourceEditor::_update_tile_inspector() { void TileSetScenesCollectionSourceEditor::_update_action_buttons() { Vector<int> selected_indices = scene_tiles_list->get_selected_items(); - scene_tile_delete_button->set_disabled(selected_indices.size() <= 0); + scene_tile_delete_button->set_disabled(selected_indices.size() <= 0 || read_only); } void TileSetScenesCollectionSourceEditor::_update_scenes_list() { @@ -342,6 +342,12 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { if (tile_set_scenes_collection_source_changed_needs_update) { + read_only = false; + // Add the listener again and check for read-only status. + if (tile_set.is_valid()) { + read_only = EditorNode::get_singleton()->is_resource_read_only(tile_set); + } + // Update everything. _update_source_inspector(); _update_scenes_list(); @@ -365,7 +371,12 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS ERR_FAIL_COND(p_source_id < 0); ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source); - if (p_tile_set == tile_set && p_tile_set_scenes_collection_source == tile_set_scenes_collection_source && p_source_id == tile_set_source_id) { + bool new_read_only_state = false; + if (p_tile_set.is_valid()) { + new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_tile_set); + } + + if (p_tile_set == tile_set && p_tile_set_scenes_collection_source == tile_set_scenes_collection_source && p_source_id == tile_set_source_id && new_read_only_state == read_only) { return; } @@ -379,6 +390,16 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS tile_set_scenes_collection_source = p_tile_set_scenes_collection_source; tile_set_source_id = p_source_id; + // Read-only status is false by default + read_only = new_read_only_state; + + if (tile_set.is_valid()) { + scenes_collection_source_inspector->set_read_only(read_only); + tile_inspector->set_read_only(read_only); + + scene_tile_add_button->set_disabled(read_only); + } + // Add the listener again. if (tile_set_scenes_collection_source) { tile_set_scenes_collection_source->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed)); diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h index 0901205a29..2a0e8595c4 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h @@ -91,6 +91,8 @@ private: }; private: + bool read_only = false; + Ref<TileSet> tile_set; TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr; int tile_set_source_id = -1; diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 19ee0ae98d..fad36660d9 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -101,12 +101,12 @@ void TilesEditorPlugin::_thread() { encompassing_rect.expand_to(world_pos); // Texture. - Ref<TileSetAtlasSource> atlas_source = tile_set->get_source(tile_map->get_cell_source_id(0, cell)); + Ref<TileSetAtlasSource> atlas_source = item.tile_set->get_source(tile_map->get_cell_source_id(0, cell)); if (atlas_source.is_valid()) { 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/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 4c5cde926a..af70e64b6a 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/filesystem_dock.h" #include "editor/inspector_dock.h" #include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/shader_editor_plugin.h" @@ -1271,18 +1272,55 @@ Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> return dict; } -void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { - Ref<Script> scr = Ref<Script>(p_resource.ptr()); - if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") { +void VisualShaderEditor::_get_current_mode_limits(int &r_begin_type, int &r_end_type) const { + switch (visual_shader->get_mode()) { + case Shader::MODE_CANVAS_ITEM: + case Shader::MODE_SPATIAL: { + r_begin_type = 0; + r_end_type = 3; + } break; + case Shader::MODE_PARTICLES: { + r_begin_type = 3; + r_end_type = 5 + r_begin_type; + } break; + case Shader::MODE_SKY: { + r_begin_type = 8; + r_end_type = 1 + r_begin_type; + } break; + case Shader::MODE_FOG: { + r_begin_type = 9; + r_end_type = 1 + r_begin_type; + } break; + default: { + } break; + } +} + +void VisualShaderEditor::_script_created(const Ref<Script> &p_script) { + if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") { + return; + } + Ref<VisualShaderNodeCustom> ref; + ref.instantiate(); + ref->set_script(p_script); + + Dictionary dict = get_custom_node_data(ref); + add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]); + + _update_options_menu(); +} + +void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) { + if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") { return; } Ref<VisualShaderNodeCustom> ref; ref.instantiate(); - ref->set_script(scr); + ref->set_script(p_script); if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { for (int i = 0; i < add_options.size(); i++) { - if (add_options[i].is_custom && add_options[i].script == scr) { + if (add_options[i].is_custom && add_options[i].script == p_script) { add_options.remove_at(i); _update_options_menu(); // TODO: Make indication for the existed custom nodes with that script on graph to be disabled. @@ -1296,8 +1334,8 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { bool found_type = false; bool need_rebuild = false; - for (int i = 0; i < add_options.size(); i++) { - if (add_options[i].is_custom && add_options[i].script == scr) { + for (int i = custom_node_option_idx; i < add_options.size(); i++) { + if (add_options[i].script == p_script) { found_type = true; add_options.write[i].name = dict["name"]; @@ -1306,31 +1344,11 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { add_options.write[i].category = dict["category"]; add_options.write[i].highend = dict["highend"]; - int max_type = 0; - int type_offset = 0; - switch (visual_shader->get_mode()) { - case Shader::MODE_CANVAS_ITEM: - case Shader::MODE_SPATIAL: { - max_type = 3; - } break; - case Shader::MODE_PARTICLES: { - max_type = 5; - type_offset = 3; - } break; - case Shader::MODE_SKY: { - max_type = 1; - type_offset = 8; - } break; - case Shader::MODE_FOG: { - max_type = 1; - type_offset = 9; - } break; - default: { - } break; - } - max_type = type_offset + max_type; + int begin_type = 0; + int end_type = 0; + _get_current_mode_limits(begin_type, end_type); - for (int t = type_offset; t < max_type; t++) { + for (int t = begin_type; t < end_type; t++) { VisualShader::Type type = (VisualShader::Type)t; Vector<int> nodes = visual_shader->get_node_list(type); @@ -1339,28 +1357,27 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { List<VisualShader::Connection> custom_node_input_connections; List<VisualShader::Connection> custom_node_output_connections; + for (const VisualShader::Connection &E : node_connections) { int from = E.from_node; - int from_idx = E.from_port; + int from_port = E.from_port; int to = E.to_node; - int to_idx = E.to_port; + int to_port = E.to_port; - if (graph_plugin->get_node_script(from) == scr) { - custom_node_output_connections.push_back({ from, from_idx, to, to_idx }); - } else if (graph_plugin->get_node_script(to) == scr) { - custom_node_input_connections.push_back({ from, from_idx, to, to_idx }); + if (graph_plugin->get_node_script(from) == p_script) { + custom_node_output_connections.push_back({ from, from_port, to, to_port }); + } else if (graph_plugin->get_node_script(to) == p_script) { + custom_node_input_connections.push_back({ from, from_port, to, to_port }); } } - for (int j = 0; j < nodes.size(); j++) { - int node_id = nodes[j]; - + for (int node_id : nodes) { Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id); if (vsnode.is_null()) { continue; } Ref<VisualShaderNodeCustom> custom_node = Ref<VisualShaderNodeCustom>(vsnode.ptr()); - if (custom_node.is_null() || custom_node->get_script() != scr) { + if (custom_node.is_null() || custom_node->get_script() != p_script) { continue; } need_rebuild = true; @@ -1429,6 +1446,89 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { } } +void VisualShaderEditor::_resource_saved(const Ref<Resource> &p_resource) { + _update_custom_script(Ref<Script>(p_resource.ptr())); +} + +void VisualShaderEditor::_resources_removed() { + bool has_any_instance = false; + + for (const Ref<Script> &scr : custom_scripts_to_delete) { + for (int i = custom_node_option_idx; i < add_options.size(); i++) { + if (add_options[i].script == scr) { + add_options.remove_at(i); + + // Removes all node instances using that script from the graph. + { + int begin_type = 0; + int end_type = 0; + _get_current_mode_limits(begin_type, end_type); + + for (int t = begin_type; t < end_type; t++) { + VisualShader::Type type = (VisualShader::Type)t; + + List<VisualShader::Connection> node_connections; + visual_shader->get_node_connections(type, &node_connections); + + for (const VisualShader::Connection &E : node_connections) { + int from = E.from_node; + int from_port = E.from_port; + int to = E.to_node; + int to_port = E.to_port; + + if (graph_plugin->get_node_script(from) == scr || graph_plugin->get_node_script(to) == scr) { + visual_shader->disconnect_nodes(type, from, from_port, to, to_port); + graph_plugin->disconnect_nodes(type, from, from_port, to, to_port); + } + } + + Vector<int> nodes = visual_shader->get_node_list(type); + for (int node_id : nodes) { + Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id); + if (vsnode.is_null()) { + continue; + } + Ref<VisualShaderNodeCustom> custom_node = Ref<VisualShaderNodeCustom>(vsnode.ptr()); + if (custom_node.is_null() || custom_node->get_script() != scr) { + continue; + } + visual_shader->remove_node(type, node_id); + graph_plugin->remove_node(type, node_id, false); + + has_any_instance = true; + } + } + } + + break; + } + } + } + if (has_any_instance) { + EditorUndoRedoManager::get_singleton()->clear_history(); // Need to clear undo history, otherwise it may lead to hard-detected errors and crashes (since the script was removed). + ResourceSaver::save(visual_shader, visual_shader->get_path()); + } + _update_options_menu(); + + custom_scripts_to_delete.clear(); + pending_custom_scripts_to_delete = false; +} + +void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) { + Ref<Script> scr = Ref<Script>(p_resource.ptr()); + if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") { + return; + } + + custom_scripts_to_delete.push_back(scr); + + if (!pending_custom_scripts_to_delete) { + pending_custom_scripts_to_delete = true; + + call_deferred("_resources_removed"); + } +} + void VisualShaderEditor::_update_options_menu_deferred() { _update_options_menu(); @@ -4901,13 +5001,16 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port); ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred); ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred); + ClassDB::bind_method("_resources_removed", &VisualShaderEditor::_resources_removed); ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available); } VisualShaderEditor::VisualShaderEditor() { ShaderLanguage::get_keyword_list(&keyword_list); - EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::update_custom_type)); + EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved)); + FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created)); + FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed)); graph = memnew(GraphEdit); graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index c4f6b4952c..519a390ccc 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -188,6 +188,9 @@ class VisualShaderEditor : public VBoxContainer { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; + bool pending_custom_scripts_to_delete = false; + List<Ref<Script>> custom_scripts_to_delete; + bool _block_update_options_menu = false; bool _block_rebuild_shader = false; @@ -503,6 +506,13 @@ class VisualShaderEditor : public VBoxContainer { void _visibility_changed(); + void _get_current_mode_limits(int &r_begin_type, int &r_end_type) const; + void _update_custom_script(const Ref<Script> &p_script); + void _script_created(const Ref<Script> &p_script); + void _resource_saved(const Ref<Resource> &p_resource); + void _resource_removed(const Ref<Resource> &p_resource); + void _resources_removed(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -517,7 +527,6 @@ public: void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend); Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node); - void update_custom_type(const Ref<Resource> &p_resource); virtual Size2 get_minimum_size() const override; void edit(VisualShader *p_visual_shader); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 727b2c9b4d..f38c8ee39d 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -215,7 +215,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 @@ -1168,6 +1167,7 @@ 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 }, }; @@ -1286,6 +1286,7 @@ static const char *gdscript_signals_renames[][2] = { { "about_to_show", "about_to_popup" }, // Popup { "button_release", "button_released" }, // XRController3D { "cancelled", "canceled" }, // AcceptDialog + { "item_double_clicked", "item_icon_double_clicked" }, // Tree { "network_peer_connected", "peer_connected" }, // MultiplayerAPI { "network_peer_disconnected", "peer_disconnected" }, // MultiplayerAPI { "network_peer_packet", "peer_packet" }, // MultiplayerAPI @@ -2548,14 +2549,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); @@ -4086,13 +4087,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); @@ -4101,13 +4102,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); } } } @@ -4155,25 +4156,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)); } } @@ -4195,9 +4196,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)); } } @@ -4211,9 +4212,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)); } } } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 5d1a2a49c5..86e77fbbbe 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -2191,7 +2191,7 @@ void SceneTreeDock::_do_create(Node *p_parent) { ERR_FAIL_COND(!child); String new_name = p_parent->validate_child_name(child); - if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) { + if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) { new_name = adjust_name_casing(new_name); } child->set_name(new_name); @@ -3613,7 +3613,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec scene_tree->connect("script_dropped", callable_mp(this, &SceneTreeDock::_script_dropped)); scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin)); - scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node)); + scene_tree->get_scene_tree()->connect("item_icon_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node)); editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index e795cc919c..42801cdaf1 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -971,7 +971,7 @@ void SceneTreeEditor::_renamed() { String raw_new_name = which->get_text(0); if (raw_new_name.strip_edges().is_empty()) { // If name is empty, fallback to class name. - if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) { + if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) { raw_new_name = Node::adjust_name_casing(n->get_class()); } else { raw_new_name = n->get_class(); |