Improve SpriteFrameEditor frame addition ordering

This commit is contained in:
Ninni Pipping 2023-02-24 16:00:28 +01:00
parent c29866dbc0
commit 83d85048ea
2 changed files with 339 additions and 90 deletions

View file

@ -42,6 +42,7 @@
#include "editor/scene_tree_dock.h" #include "editor/scene_tree_dock.h"
#include "scene/gui/center_container.h" #include "scene/gui/center_container.h"
#include "scene/gui/margin_container.h" #include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h" #include "scene/gui/panel_container.h"
#include "scene/gui/separator.h" #include "scene/gui/separator.h"
@ -131,8 +132,14 @@ void SpriteFramesEditor::_sheet_preview_draw() {
Color accent = get_theme_color("accent_color", "Editor"); Color accent = get_theme_color("accent_color", "Editor");
for (const int &E : frames_selected) { _sheet_sort_frames();
const int idx = E;
Ref<Font> 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 x = idx % frame_count.x;
const int y = idx / frame_count.x; const int y = idx / frame_count.x;
const Point2 pos = draw_offset + Point2(x, y) * (draw_frame_size + draw_sep); 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(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(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); 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); split_sheet_dialog->get_ok_button()->set_disabled(false);
@ -156,21 +172,24 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
if (idx != -1) { if (idx != -1) {
if (mb->is_shift_pressed() && last_frame_selected >= 0) { if (mb->is_shift_pressed() && last_frame_selected >= 0) {
//select multiple // Select multiple frames.
int from = idx; const int from = last_frame_selected;
int to = last_frame_selected; const int to = idx;
if (from > to) {
SWAP(from, to); 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. // 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()) { if (mb->is_ctrl_pressed()) {
frames_selected.erase(i); frames_selected.erase(this_idx);
} else { } else if (!frames_selected.has(this_idx)) {
frames_selected.insert(i); frames_selected.insert(this_idx, selected_count);
selected_count++;
} }
} }
} else { } else {
@ -180,13 +199,15 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
if (frames_selected.has(idx)) { if (frames_selected.has(idx)) {
frames_selected.erase(idx); frames_selected.erase(idx);
} else { } else {
frames_selected.insert(idx); frames_selected.insert(idx, selected_count);
selected_count++;
} }
} }
} }
if (last_frame_selected != idx || idx != -1) { if (last_frame_selected != idx || idx != -1) {
last_frame_selected = idx; last_frame_selected = idx;
frames_need_sort = true;
split_sheet_preview->queue_redraw(); split_sheet_preview->queue_redraw();
} }
} }
@ -209,13 +230,19 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
if (frames_selected.has(idx)) { if (frames_selected.has(idx)) {
frames_selected.erase(idx); frames_selected.erase(idx);
} else { } else {
frames_selected.insert(idx); frames_selected.insert(idx, selected_count);
selected_count++;
} }
last_frame_selected = idx; last_frame_selected = idx;
frames_need_sort = true;
split_sheet_preview->queue_redraw(); split_sheet_preview->queue_redraw();
} }
} }
if (frames_selected.is_empty()) {
selected_count = 0;
}
} }
void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) { void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &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()); 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 fc = frames->get_frame_count(edited_anim);
for (const int &E : frames_selected) { _sheet_sort_frames();
int idx = E;
for (const Pair<int, int> &pair : frames_ordered) {
const int idx = pair.second;
const Point2 frame_coords(idx % frame_count.x, idx / frame_count.x); const Point2 frame_coords(idx % frame_count.x, idx / frame_count.x);
Ref<AtlasTexture> at; Ref<AtlasTexture> at;
@ -300,21 +330,103 @@ void SpriteFramesEditor::_sheet_zoom_reset() {
split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom); split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
} }
void SpriteFramesEditor::_sheet_select_clear_all_frames() { void SpriteFramesEditor::_sheet_order_selected(int p_option) {
bool should_clear = true; 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++) { for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) {
if (!frames_selected.has(i)) { if (!frames_selected.has(i)) {
frames_selected.insert(i); frames_selected.insert(i, selected_count);
should_clear = false; selected_count++;
frames_need_sort = true;
} }
} }
if (should_clear) {
frames_selected.clear();
}
split_sheet_preview->queue_redraw(); 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<int, int> &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<int, int>(order_by, idx));
index++;
}
// Sort frames.
frames_ordered.sort_custom<PairSort<int, int>>();
}
void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) { void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) {
if (updating_split_settings) { if (updating_split_settings) {
return; return;
@ -367,10 +479,25 @@ void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_para
updating_split_settings = false; updating_split_settings = false;
frames_selected.clear(); frames_selected.clear();
selected_count = 0;
last_frame_selected = -1; last_frame_selected = -1;
split_sheet_preview->queue_redraw(); 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) { void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
Ref<Texture2D> texture = ResourceLoader::load(p_file); Ref<Texture2D> texture = ResourceLoader::load(p_file);
if (texture.is_null()) { if (texture.is_null()) {
@ -378,6 +505,7 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
ERR_FAIL_COND(texture.is_null()); ERR_FAIL_COND(texture.is_null());
} }
frames_selected.clear(); frames_selected.clear();
selected_count = 0;
last_frame_selected = -1; last_frame_selected = -1;
bool new_texture = texture != split_sheet_preview->get_texture(); bool new_texture = texture != split_sheet_preview->get_texture();
@ -408,6 +536,7 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
// Reset zoom. // Reset zoom.
_sheet_zoom_reset(); _sheet_zoom_reset();
} }
split_sheet_dialog->popup_centered_ratio(0.65); 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_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_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"))); split_sheet_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
_update_show_settings();
} break; } break;
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
@ -1769,82 +1900,58 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_dialog = memnew(ConfirmationDialog); split_sheet_dialog = memnew(ConfirmationDialog);
add_child(split_sheet_dialog); 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->set_title(TTR("Select Frames"));
split_sheet_dialog->connect("confirmed", callable_mp(this, &SpriteFramesEditor::_sheet_add_frames)); split_sheet_dialog->connect("confirmed", callable_mp(this, &SpriteFramesEditor::_sheet_add_frames));
HBoxContainer *split_sheet_hb = memnew(HBoxContainer); 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:")))); VBoxContainer *split_sheet_vb = memnew(VBoxContainer);
split_sheet_h = memnew(SpinBox); split_sheet_hb->add_child(split_sheet_vb);
split_sheet_h->set_min(1); split_sheet_vb->set_h_size_flags(SIZE_EXPAND_FILL);
split_sheet_h->set_max(128); split_sheet_vb->set_v_size_flags(SIZE_EXPAND_FILL);
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));
split_sheet_hb->add_child(memnew(Label(TTR("Vertical:")))); HBoxContainer *split_sheet_menu_hb = memnew(HBoxContainer);
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));
split_sheet_hb->add_child(memnew(VSeparator)); split_sheet_menu_hb->add_child(memnew(Label(TTR("Frame Order"))));
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_hb->add_child(memnew(VSeparator)); split_sheet_order = memnew(OptionButton);
split_sheet_hb->add_child(memnew(Label(TTR("Separation:")))); split_sheet_order->add_item(TTR("As Selected"), FRAME_ORDER_SELECTION);
split_sheet_sep_x = memnew(SpinBox); split_sheet_order->add_separator(TTR("By Row"));
split_sheet_sep_x->set_min(0); split_sheet_order->add_item(TTR("Left to Right, Top to Bottom"), FRAME_ORDER_LEFT_RIGHT_TOP_BOTTOM);
split_sheet_sep_x->set_step(1); split_sheet_order->add_item(TTR("Left to Right, Bottom to Top"), FRAME_ORDER_LEFT_RIGHT_BOTTOM_TOP);
split_sheet_sep_x->set_suffix("px"); split_sheet_order->add_item(TTR("Right to Left, Top to Bottom"), FRAME_ORDER_RIGHT_LEFT_TOP_BOTTOM);
split_sheet_sep_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); split_sheet_order->add_item(TTR("Right to Left, Bottom to Top"), FRAME_ORDER_RIGHT_LEFT_BOTTOM_TOP);
split_sheet_hb->add_child(split_sheet_sep_x); split_sheet_order->add_separator(TTR("By Column"));
split_sheet_sep_y = memnew(SpinBox); split_sheet_order->add_item(TTR("Top to Bottom, Left to Right"), FRAME_ORDER_TOP_BOTTOM_LEFT_RIGHT);
split_sheet_sep_y->set_min(0); split_sheet_order->add_item(TTR("Top to Bottom, Right to Left"), FRAME_ORDER_TOP_BOTTOM_RIGHT_LEFT);
split_sheet_sep_y->set_step(1); split_sheet_order->add_item(TTR("Bottom to Top, Left to Right"), FRAME_ORDER_BOTTOM_TOP_LEFT_RIGHT);
split_sheet_sep_y->set_suffix("px"); split_sheet_order->add_item(TTR("Bottom to Top, Right to Left"), FRAME_ORDER_BOTTOM_TOP_RIGHT_LEFT);
split_sheet_sep_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed).bind(PARAM_USE_CURRENT)); split_sheet_order->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_sheet_order_selected));
split_sheet_hb->add_child(split_sheet_sep_y); split_sheet_menu_hb->add_child(split_sheet_order);
split_sheet_hb->add_child(memnew(VSeparator)); Button *select_all = memnew(Button);
split_sheet_hb->add_child(memnew(Label(TTR("Offset:")))); select_all->set_text(TTR("Select All"));
split_sheet_offset_x = memnew(SpinBox); select_all->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_select_all_frames));
split_sheet_offset_x->set_min(0); split_sheet_menu_hb->add_child(select_all);
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);
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); split_sheet_menu_hb->add_spacer();
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_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); PanelContainer *split_sheet_panel = memnew(PanelContainer);
split_sheet_panel->set_h_size_flags(SIZE_EXPAND_FILL); 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_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in));
split_sheet_zoom_hb->add_child(split_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 = memnew(EditorFileDialog);
file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet")); file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet"));
file_split_sheet->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); file_split_sheet->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);

View file

@ -45,6 +45,7 @@
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h" #include "scene/gui/tree.h"
class OptionButton;
class EditorFileDialog; class EditorFileDialog;
class EditorSpriteFramesFrame : public Resource { class EditorSpriteFramesFrame : public Resource {
@ -68,6 +69,22 @@ class SpriteFramesEditor : public HSplitContainer {
}; };
int dominant_param = PARAM_FRAME_COUNT; 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; bool read_only = false;
Ref<Texture2D> autoplay_icon; Ref<Texture2D> autoplay_icon;
@ -121,6 +138,7 @@ class SpriteFramesEditor : public HSplitContainer {
ConfirmationDialog *split_sheet_dialog = nullptr; ConfirmationDialog *split_sheet_dialog = nullptr;
ScrollContainer *split_sheet_scroll = nullptr; ScrollContainer *split_sheet_scroll = nullptr;
TextureRect *split_sheet_preview = nullptr; TextureRect *split_sheet_preview = nullptr;
VBoxContainer *split_sheet_settings_vb = nullptr;
SpinBox *split_sheet_h = nullptr; SpinBox *split_sheet_h = nullptr;
SpinBox *split_sheet_v = nullptr; SpinBox *split_sheet_v = nullptr;
SpinBox *split_sheet_size_x = 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_out = nullptr;
Button *split_sheet_zoom_reset = nullptr; Button *split_sheet_zoom_reset = nullptr;
Button *split_sheet_zoom_in = nullptr; Button *split_sheet_zoom_in = nullptr;
Button *toggle_settings_button = nullptr;
OptionButton *split_sheet_order = nullptr;
EditorFileDialog *file_split_sheet = nullptr; EditorFileDialog *file_split_sheet = nullptr;
HashSet<int> frames_selected; HashMap<int, int> frames_selected; // Key is frame index. Value is selection order.
HashSet<int> frames_toggled_by_mouse_hover; HashSet<int> frames_toggled_by_mouse_hover;
Vector<Pair<int, int>> 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; int last_frame_selected = 0;
float scale_ratio; float scale_ratio;
@ -206,7 +229,12 @@ class SpriteFramesEditor : public HSplitContainer {
void _sheet_zoom_in(); void _sheet_zoom_in();
void _sheet_zoom_out(); void _sheet_zoom_out();
void _sheet_zoom_reset(); 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 _edit();
void _regist_scene_undo(EditorUndoRedoManager *undo_redo); void _regist_scene_undo(EditorUndoRedoManager *undo_redo);