From 83d85048ea34e67a2fbd44b4d960b3193e1a6f98 Mon Sep 17 00:00:00 2001 From: Ninni Pipping Date: Fri, 24 Feb 2023 16:00:28 +0100 Subject: [PATCH] Improve SpriteFrameEditor frame addition ordering --- .../plugins/sprite_frames_editor_plugin.cpp | 397 ++++++++++++++---- editor/plugins/sprite_frames_editor_plugin.h | 32 +- 2 files changed, 339 insertions(+), 90 deletions(-) diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 20b3cf36189..8d1aadd095a 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -42,6 +42,7 @@ #include "editor/scene_tree_dock.h" #include "scene/gui/center_container.h" #include "scene/gui/margin_container.h" +#include "scene/gui/option_button.h" #include "scene/gui/panel_container.h" #include "scene/gui/separator.h" @@ -131,8 +132,14 @@ void SpriteFramesEditor::_sheet_preview_draw() { Color accent = get_theme_color("accent_color", "Editor"); - for (const int &E : frames_selected) { - const int idx = E; + _sheet_sort_frames(); + + Ref font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); + int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); + + for (int i = 0; i < frames_ordered.size(); ++i) { + const int idx = frames_ordered[i].second; + const int x = idx % frame_count.x; const int y = idx / frame_count.x; const Point2 pos = draw_offset + Point2(x, y) * (draw_frame_size + draw_sep); @@ -143,6 +150,15 @@ void SpriteFramesEditor::_sheet_preview_draw() { split_sheet_preview->draw_rect(Rect2(pos + Size2(3, 3), draw_frame_size - Size2(6, 6)), accent, false); split_sheet_preview->draw_rect(Rect2(pos + Size2(4, 4), draw_frame_size - Size2(8, 8)), Color(0, 0, 0, 1), false); split_sheet_preview->draw_rect(Rect2(pos + Size2(5, 5), draw_frame_size - Size2(10, 10)), Color(0, 0, 0, 1), false); + + const String text = itos(i); + const Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + + // Stop rendering text if too large. + if (string_size.x + 6 < draw_frame_size.x && string_size.y / 2 + 10 < draw_frame_size.y) { + split_sheet_preview->draw_string_outline(font, pos + Size2(5, 7) + Size2(0, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_LEFT, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + split_sheet_preview->draw_string(font, pos + Size2(5, 7) + Size2(0, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_LEFT, string_size.x, font_size, Color(1, 1, 1)); + } } split_sheet_dialog->get_ok_button()->set_disabled(false); @@ -156,21 +172,24 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref &p_event) { if (idx != -1) { if (mb->is_shift_pressed() && last_frame_selected >= 0) { - //select multiple - int from = idx; - int to = last_frame_selected; - if (from > to) { - SWAP(from, to); - } + // Select multiple frames. + const int from = last_frame_selected; + const int to = idx; + + const int diff = ABS(to - from); + const int dir = SIGN(to - from); + + for (int i = 0; i <= diff; i++) { + const int this_idx = from + i * dir; - for (int i = from; i <= to; i++) { // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held. - frames_toggled_by_mouse_hover.insert(idx); + frames_toggled_by_mouse_hover.insert(this_idx); if (mb->is_ctrl_pressed()) { - frames_selected.erase(i); - } else { - frames_selected.insert(i); + frames_selected.erase(this_idx); + } else if (!frames_selected.has(this_idx)) { + frames_selected.insert(this_idx, selected_count); + selected_count++; } } } else { @@ -180,13 +199,15 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref &p_event) { if (frames_selected.has(idx)) { frames_selected.erase(idx); } else { - frames_selected.insert(idx); + frames_selected.insert(idx, selected_count); + selected_count++; } } } if (last_frame_selected != idx || idx != -1) { last_frame_selected = idx; + frames_need_sort = true; split_sheet_preview->queue_redraw(); } } @@ -209,13 +230,19 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref &p_event) { if (frames_selected.has(idx)) { frames_selected.erase(idx); } else { - frames_selected.insert(idx); + frames_selected.insert(idx, selected_count); + selected_count++; } last_frame_selected = idx; + frames_need_sort = true; split_sheet_preview->queue_redraw(); } } + + if (frames_selected.is_empty()) { + selected_count = 0; + } } void SpriteFramesEditor::_sheet_scroll_input(const Ref &p_event) { @@ -254,8 +281,11 @@ void SpriteFramesEditor::_sheet_add_frames() { 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) { - int idx = E; + _sheet_sort_frames(); + + for (const Pair &pair : frames_ordered) { + const int idx = pair.second; + const Point2 frame_coords(idx % frame_count.x, idx / frame_count.x); Ref at; @@ -300,21 +330,103 @@ void SpriteFramesEditor::_sheet_zoom_reset() { split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom); } -void SpriteFramesEditor::_sheet_select_clear_all_frames() { - bool should_clear = true; +void SpriteFramesEditor::_sheet_order_selected(int p_option) { + frames_need_sort = true; + split_sheet_preview->queue_redraw(); +} + +void SpriteFramesEditor::_sheet_select_all_frames() { for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) { if (!frames_selected.has(i)) { - frames_selected.insert(i); - should_clear = false; + frames_selected.insert(i, selected_count); + selected_count++; + frames_need_sort = true; } } - if (should_clear) { - frames_selected.clear(); - } split_sheet_preview->queue_redraw(); } +void SpriteFramesEditor::_sheet_clear_all_frames() { + frames_selected.clear(); + selected_count = 0; + + split_sheet_preview->queue_redraw(); +} + +void SpriteFramesEditor::_sheet_sort_frames() { + if (!frames_need_sort) { + return; + } + frames_need_sort = false; + frames_ordered.resize(frames_selected.size()); + if (frames_selected.is_empty()) { + return; + } + + const Size2i frame_count = _get_frame_count(); + const int frame_order = split_sheet_order->get_selected_id(); + int index = 0; + + // Fill based on order. + for (const KeyValue &from_pair : frames_selected) { + const int idx = from_pair.key; + + const int selection_order = from_pair.value; + + // Default to using selection order. + int order_by = selection_order; + + // Extract coordinates for sorting. + const int pos_frame_x = idx % frame_count.x; + const int pos_frame_y = idx / frame_count.x; + + const int neg_frame_x = frame_count.x - (pos_frame_x + 1); + const int neg_frame_y = frame_count.y - (pos_frame_y + 1); + + switch (frame_order) { + case FRAME_ORDER_LEFT_RIGHT_TOP_BOTTOM: { + order_by = frame_count.x * pos_frame_y + pos_frame_x; + } break; + + case FRAME_ORDER_LEFT_RIGHT_BOTTOM_TOP: { + order_by = frame_count.x * neg_frame_y + pos_frame_x; + } break; + + case FRAME_ORDER_RIGHT_LEFT_TOP_BOTTOM: { + order_by = frame_count.x * pos_frame_y + neg_frame_x; + } break; + + case FRAME_ORDER_RIGHT_LEFT_BOTTOM_TOP: { + order_by = frame_count.x * neg_frame_y + neg_frame_x; + } break; + + case FRAME_ORDER_TOP_BOTTOM_LEFT_RIGHT: { + order_by = pos_frame_y + frame_count.y * pos_frame_x; + } break; + + case FRAME_ORDER_TOP_BOTTOM_RIGHT_LEFT: { + order_by = pos_frame_y + frame_count.y * neg_frame_x; + } break; + + case FRAME_ORDER_BOTTOM_TOP_LEFT_RIGHT: { + order_by = neg_frame_y + frame_count.y * pos_frame_x; + } break; + + case FRAME_ORDER_BOTTOM_TOP_RIGHT_LEFT: { + order_by = neg_frame_y + frame_count.y * neg_frame_x; + } break; + } + + // Assign in vector. + frames_ordered.set(index, Pair(order_by, idx)); + index++; + } + + // Sort frames. + frames_ordered.sort_custom>(); +} + void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) { if (updating_split_settings) { return; @@ -367,10 +479,25 @@ void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_para updating_split_settings = false; frames_selected.clear(); + selected_count = 0; last_frame_selected = -1; split_sheet_preview->queue_redraw(); } +void SpriteFramesEditor::_toggle_show_settings() { + split_sheet_settings_vb->set_visible(!split_sheet_settings_vb->is_visible()); + + _update_show_settings(); +} + +void SpriteFramesEditor::_update_show_settings() { + if (is_layout_rtl()) { + toggle_settings_button->set_icon(get_theme_icon(split_sheet_settings_vb->is_visible() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons"))); + } else { + toggle_settings_button->set_icon(get_theme_icon(split_sheet_settings_vb->is_visible() ? SNAME("Forward") : SNAME("Back"), SNAME("EditorIcons"))); + } +} + void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { Ref texture = ResourceLoader::load(p_file); if (texture.is_null()) { @@ -378,6 +505,7 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { ERR_FAIL_COND(texture.is_null()); } frames_selected.clear(); + selected_count = 0; last_frame_selected = -1; bool new_texture = texture != split_sheet_preview->get_texture(); @@ -408,6 +536,7 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { // Reset zoom. _sheet_zoom_reset(); } + split_sheet_dialog->popup_centered_ratio(0.65); } @@ -450,6 +579,8 @@ void SpriteFramesEditor::_notification(int p_what) { split_sheet_zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons"))); split_sheet_zoom_in->set_icon(get_theme_icon(SNAME("ZoomMore"), SNAME("EditorIcons"))); split_sheet_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + + _update_show_settings(); } break; case NOTIFICATION_READY: { @@ -1769,82 +1900,58 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_dialog = memnew(ConfirmationDialog); add_child(split_sheet_dialog); - VBoxContainer *split_sheet_vb = memnew(VBoxContainer); - split_sheet_dialog->add_child(split_sheet_vb); split_sheet_dialog->set_title(TTR("Select Frames")); split_sheet_dialog->connect("confirmed", callable_mp(this, &SpriteFramesEditor::_sheet_add_frames)); HBoxContainer *split_sheet_hb = memnew(HBoxContainer); + split_sheet_dialog->add_child(split_sheet_hb); + split_sheet_hb->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_hb->set_v_size_flags(SIZE_EXPAND_FILL); - split_sheet_hb->add_child(memnew(Label(TTR("Horizontal:")))); - split_sheet_h = memnew(SpinBox); - split_sheet_h->set_min(1); - split_sheet_h->set_max(128); - split_sheet_h->set_step(1); - split_sheet_hb->add_child(split_sheet_h); - split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_FRAME_COUNT)); + VBoxContainer *split_sheet_vb = memnew(VBoxContainer); + split_sheet_hb->add_child(split_sheet_vb); + split_sheet_vb->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_vb->set_v_size_flags(SIZE_EXPAND_FILL); - split_sheet_hb->add_child(memnew(Label(TTR("Vertical:")))); - split_sheet_v = memnew(SpinBox); - split_sheet_v->set_min(1); - split_sheet_v->set_max(128); - split_sheet_v->set_step(1); - split_sheet_hb->add_child(split_sheet_v); - split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_FRAME_COUNT)); + HBoxContainer *split_sheet_menu_hb = memnew(HBoxContainer); - split_sheet_hb->add_child(memnew(VSeparator)); - split_sheet_hb->add_child(memnew(Label(TTR("Size:")))); - split_sheet_size_x = memnew(SpinBox); - split_sheet_size_x->set_min(1); - split_sheet_size_x->set_step(1); - split_sheet_size_x->set_suffix("px"); - split_sheet_size_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_SIZE)); - split_sheet_hb->add_child(split_sheet_size_x); - split_sheet_size_y = memnew(SpinBox); - split_sheet_size_y->set_min(1); - split_sheet_size_y->set_step(1); - split_sheet_size_y->set_suffix("px"); - split_sheet_size_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_SIZE)); - split_sheet_hb->add_child(split_sheet_size_y); + split_sheet_menu_hb->add_child(memnew(Label(TTR("Frame Order")))); - split_sheet_hb->add_child(memnew(VSeparator)); - split_sheet_hb->add_child(memnew(Label(TTR("Separation:")))); - split_sheet_sep_x = memnew(SpinBox); - split_sheet_sep_x->set_min(0); - split_sheet_sep_x->set_step(1); - split_sheet_sep_x->set_suffix("px"); - split_sheet_sep_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); - split_sheet_hb->add_child(split_sheet_sep_x); - split_sheet_sep_y = memnew(SpinBox); - split_sheet_sep_y->set_min(0); - split_sheet_sep_y->set_step(1); - split_sheet_sep_y->set_suffix("px"); - split_sheet_sep_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); - split_sheet_hb->add_child(split_sheet_sep_y); + split_sheet_order = memnew(OptionButton); + split_sheet_order->add_item(TTR("As Selected"), FRAME_ORDER_SELECTION); + split_sheet_order->add_separator(TTR("By Row")); + split_sheet_order->add_item(TTR("Left to Right, Top to Bottom"), FRAME_ORDER_LEFT_RIGHT_TOP_BOTTOM); + split_sheet_order->add_item(TTR("Left to Right, Bottom to Top"), FRAME_ORDER_LEFT_RIGHT_BOTTOM_TOP); + split_sheet_order->add_item(TTR("Right to Left, Top to Bottom"), FRAME_ORDER_RIGHT_LEFT_TOP_BOTTOM); + split_sheet_order->add_item(TTR("Right to Left, Bottom to Top"), FRAME_ORDER_RIGHT_LEFT_BOTTOM_TOP); + split_sheet_order->add_separator(TTR("By Column")); + split_sheet_order->add_item(TTR("Top to Bottom, Left to Right"), FRAME_ORDER_TOP_BOTTOM_LEFT_RIGHT); + split_sheet_order->add_item(TTR("Top to Bottom, Right to Left"), FRAME_ORDER_TOP_BOTTOM_RIGHT_LEFT); + split_sheet_order->add_item(TTR("Bottom to Top, Left to Right"), FRAME_ORDER_BOTTOM_TOP_LEFT_RIGHT); + split_sheet_order->add_item(TTR("Bottom to Top, Right to Left"), FRAME_ORDER_BOTTOM_TOP_RIGHT_LEFT); + split_sheet_order->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_sheet_order_selected)); + split_sheet_menu_hb->add_child(split_sheet_order); - split_sheet_hb->add_child(memnew(VSeparator)); - split_sheet_hb->add_child(memnew(Label(TTR("Offset:")))); - split_sheet_offset_x = memnew(SpinBox); - split_sheet_offset_x->set_min(0); - split_sheet_offset_x->set_step(1); - split_sheet_offset_x->set_suffix("px"); - split_sheet_offset_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); - split_sheet_hb->add_child(split_sheet_offset_x); - split_sheet_offset_y = memnew(SpinBox); - split_sheet_offset_y->set_min(0); - split_sheet_offset_y->set_step(1); - split_sheet_offset_y->set_suffix("px"); - split_sheet_offset_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); - split_sheet_hb->add_child(split_sheet_offset_y); + Button *select_all = memnew(Button); + select_all->set_text(TTR("Select All")); + select_all->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_select_all_frames)); + split_sheet_menu_hb->add_child(select_all); - split_sheet_hb->add_spacer(); + Button *clear_all = memnew(Button); + clear_all->set_text(TTR("Select None")); + clear_all->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_clear_all_frames)); + split_sheet_menu_hb->add_child(clear_all); - Button *select_clear_all = memnew(Button); - select_clear_all->set_text(TTR("Select/Clear All Frames")); - select_clear_all->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_select_clear_all_frames)); - split_sheet_hb->add_child(select_clear_all); + split_sheet_menu_hb->add_spacer(); - split_sheet_vb->add_child(split_sheet_hb); + toggle_settings_button = memnew(Button); + toggle_settings_button->set_h_size_flags(SIZE_SHRINK_END); + toggle_settings_button->set_flat(true); + toggle_settings_button->connect("pressed", callable_mp(this, &SpriteFramesEditor::_toggle_show_settings)); + toggle_settings_button->set_tooltip_text(TTR("Toggle Settings Panel")); + split_sheet_menu_hb->add_child(toggle_settings_button); + + split_sheet_vb->add_child(split_sheet_menu_hb); PanelContainer *split_sheet_panel = memnew(PanelContainer); split_sheet_panel->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1896,6 +2003,120 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in)); split_sheet_zoom_hb->add_child(split_sheet_zoom_in); + split_sheet_settings_vb = memnew(VBoxContainer); + split_sheet_settings_vb->set_v_size_flags(SIZE_EXPAND_FILL); + + HBoxContainer *split_sheet_h_hb = memnew(HBoxContainer); + split_sheet_h_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + Label *split_sheet_h_label = memnew(Label(TTR("Horizontal"))); + split_sheet_h_label->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_h_hb->add_child(split_sheet_h_label); + + split_sheet_h = memnew(SpinBox); + split_sheet_h->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_h->set_min(1); + split_sheet_h->set_max(128); + split_sheet_h->set_step(1); + split_sheet_h_hb->add_child(split_sheet_h); + split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_FRAME_COUNT)); + split_sheet_settings_vb->add_child(split_sheet_h_hb); + + HBoxContainer *split_sheet_v_hb = memnew(HBoxContainer); + split_sheet_v_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + Label *split_sheet_v_label = memnew(Label(TTR("Vertical"))); + split_sheet_v_label->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_v_hb->add_child(split_sheet_v_label); + + split_sheet_v = memnew(SpinBox); + split_sheet_v->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_v->set_min(1); + split_sheet_v->set_max(128); + split_sheet_v->set_step(1); + split_sheet_v_hb->add_child(split_sheet_v); + split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_FRAME_COUNT)); + split_sheet_settings_vb->add_child(split_sheet_v_hb); + + HBoxContainer *split_sheet_size_hb = memnew(HBoxContainer); + split_sheet_size_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + Label *split_sheet_size_label = memnew(Label(TTR("Size"))); + split_sheet_size_label->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_size_label->set_v_size_flags(SIZE_SHRINK_BEGIN); + split_sheet_size_hb->add_child(split_sheet_size_label); + + VBoxContainer *split_sheet_size_vb = memnew(VBoxContainer); + split_sheet_size_vb->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_size_x = memnew(SpinBox); + split_sheet_size_x->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_size_x->set_min(1); + split_sheet_size_x->set_step(1); + split_sheet_size_x->set_suffix("px"); + split_sheet_size_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_SIZE)); + split_sheet_size_vb->add_child(split_sheet_size_x); + split_sheet_size_y = memnew(SpinBox); + split_sheet_size_y->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_size_y->set_min(1); + split_sheet_size_y->set_step(1); + split_sheet_size_y->set_suffix("px"); + split_sheet_size_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_SIZE)); + split_sheet_size_vb->add_child(split_sheet_size_y); + split_sheet_size_hb->add_child(split_sheet_size_vb); + split_sheet_settings_vb->add_child(split_sheet_size_hb); + + HBoxContainer *split_sheet_sep_hb = memnew(HBoxContainer); + split_sheet_sep_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + Label *split_sheet_sep_label = memnew(Label(TTR("Separation"))); + split_sheet_sep_label->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_sep_label->set_v_size_flags(SIZE_SHRINK_BEGIN); + split_sheet_sep_hb->add_child(split_sheet_sep_label); + + VBoxContainer *split_sheet_sep_vb = memnew(VBoxContainer); + split_sheet_sep_vb->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_sep_x = memnew(SpinBox); + split_sheet_sep_x->set_min(0); + split_sheet_sep_x->set_step(1); + split_sheet_sep_x->set_suffix("px"); + split_sheet_sep_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); + split_sheet_sep_vb->add_child(split_sheet_sep_x); + split_sheet_sep_y = memnew(SpinBox); + split_sheet_sep_y->set_min(0); + split_sheet_sep_y->set_step(1); + split_sheet_sep_y->set_suffix("px"); + split_sheet_sep_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); + split_sheet_sep_vb->add_child(split_sheet_sep_y); + split_sheet_sep_hb->add_child(split_sheet_sep_vb); + split_sheet_settings_vb->add_child(split_sheet_sep_hb); + + HBoxContainer *split_sheet_offset_hb = memnew(HBoxContainer); + split_sheet_offset_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + Label *split_sheet_offset_label = memnew(Label(TTR("Offset"))); + split_sheet_offset_label->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_offset_label->set_v_size_flags(SIZE_SHRINK_BEGIN); + split_sheet_offset_hb->add_child(split_sheet_offset_label); + + VBoxContainer *split_sheet_offset_vb = memnew(VBoxContainer); + split_sheet_offset_vb->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_offset_x = memnew(SpinBox); + split_sheet_offset_x->set_min(0); + split_sheet_offset_x->set_step(1); + split_sheet_offset_x->set_suffix("px"); + split_sheet_offset_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); + split_sheet_offset_vb->add_child(split_sheet_offset_x); + split_sheet_offset_y = memnew(SpinBox); + split_sheet_offset_y->set_min(0); + split_sheet_offset_y->set_step(1); + split_sheet_offset_y->set_suffix("px"); + split_sheet_offset_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); + split_sheet_offset_vb->add_child(split_sheet_offset_y); + split_sheet_offset_hb->add_child(split_sheet_offset_vb); + split_sheet_settings_vb->add_child(split_sheet_offset_hb); + + split_sheet_hb->add_child(split_sheet_settings_vb); + file_split_sheet = memnew(EditorFileDialog); file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet")); file_split_sheet->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 1dfb9093880..9317e94be02 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -45,6 +45,7 @@ #include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" +class OptionButton; class EditorFileDialog; class EditorSpriteFramesFrame : public Resource { @@ -68,6 +69,22 @@ class SpriteFramesEditor : public HSplitContainer { }; int dominant_param = PARAM_FRAME_COUNT; + enum { + FRAME_ORDER_SELECTION, // Order frames were selected in. + + // By Row. + FRAME_ORDER_LEFT_RIGHT_TOP_BOTTOM, + FRAME_ORDER_LEFT_RIGHT_BOTTOM_TOP, + FRAME_ORDER_RIGHT_LEFT_TOP_BOTTOM, + FRAME_ORDER_RIGHT_LEFT_BOTTOM_TOP, + + // By Column. + FRAME_ORDER_TOP_BOTTOM_LEFT_RIGHT, + FRAME_ORDER_TOP_BOTTOM_RIGHT_LEFT, + FRAME_ORDER_BOTTOM_TOP_LEFT_RIGHT, + FRAME_ORDER_BOTTOM_TOP_RIGHT_LEFT, + }; + bool read_only = false; Ref autoplay_icon; @@ -121,6 +138,7 @@ class SpriteFramesEditor : public HSplitContainer { ConfirmationDialog *split_sheet_dialog = nullptr; ScrollContainer *split_sheet_scroll = nullptr; TextureRect *split_sheet_preview = nullptr; + VBoxContainer *split_sheet_settings_vb = nullptr; SpinBox *split_sheet_h = nullptr; SpinBox *split_sheet_v = nullptr; SpinBox *split_sheet_size_x = nullptr; @@ -132,9 +150,14 @@ class SpriteFramesEditor : public HSplitContainer { Button *split_sheet_zoom_out = nullptr; Button *split_sheet_zoom_reset = nullptr; Button *split_sheet_zoom_in = nullptr; + Button *toggle_settings_button = nullptr; + OptionButton *split_sheet_order = nullptr; EditorFileDialog *file_split_sheet = nullptr; - HashSet frames_selected; + HashMap frames_selected; // Key is frame index. Value is selection order. HashSet frames_toggled_by_mouse_hover; + Vector> frames_ordered; // First is the index to be ordered by. Second is the actual frame index. + int selected_count = 0; + bool frames_need_sort = false; int last_frame_selected = 0; float scale_ratio; @@ -206,7 +229,12 @@ class SpriteFramesEditor : public HSplitContainer { void _sheet_zoom_in(); void _sheet_zoom_out(); void _sheet_zoom_reset(); - void _sheet_select_clear_all_frames(); + void _sheet_order_selected(int p_option); + void _sheet_select_all_frames(); + void _sheet_clear_all_frames(); + void _sheet_sort_frames(); + void _toggle_show_settings(); + void _update_show_settings(); void _edit(); void _regist_scene_undo(EditorUndoRedoManager *undo_redo);