From acdb501fc860ef9075feed39bc3568a5a83be986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Capello?= Date: Tue, 30 Aug 2022 14:45:42 -0300 Subject: [PATCH 1/4] Use layer index to avoid conflicts when exporting sprites with layers that have the same name (fix #2656) --- src/app/commands/cmd_export_sprite_sheet.cpp | 17 ++++++++++++++--- src/app/commands/cmd_save_file.cpp | 3 +++ src/app/ui/export_file_window.cpp | 8 +++++++- src/app/ui/export_file_window.h | 1 + src/app/ui/layer_frame_comboboxes.cpp | 13 +++++++++---- src/app/ui/layer_frame_comboboxes.h | 3 ++- 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp index 22828172f..f20e1e722 100644 --- a/src/app/commands/cmd_export_sprite_sheet.cpp +++ b/src/app/commands/cmd_export_sprite_sheet.cpp @@ -76,6 +76,7 @@ struct ExportSpriteSheetParams : public NewParams { Param mergeDuplicates { this, false, "mergeDuplicates" }; Param openGenerated { this, false, "openGenerated" }; Param layer { this, std::string(), "layer" }; + Param layerIndex { this, -1, "layerIndex" }; Param tag { this, std::string(), "tag" }; Param splitLayers { this, false, "splitLayers" }; Param splitTags { this, false, "splitTags" }; @@ -182,6 +183,7 @@ Doc* generate_sprite_sheet_from_params( const SpriteSheetDataFormat dataFormat = params.dataFormat(); const std::string filenameFormat = params.filenameFormat(); const std::string layerName = params.layer(); + const int layerIndex = params.layerIndex(); const std::string tagName = params.tag(); const int borderPadding = std::clamp(params.borderPadding(), 0, 100); const int shapePadding = std::clamp(params.shapePadding(), 0, 100); @@ -212,13 +214,16 @@ Doc* generate_sprite_sheet_from_params( // If the user choose to render selected layers only, we can // temporaly make them visible and hide the other ones. RestoreVisibleLayers layersVisibility; - calculate_visible_layers(site, layerName, layersVisibility); + calculate_visible_layers(site, layerName, layerIndex, layersVisibility); SelectedLayers selLayers; if (layerName != kSelectedLayers) { // TODO add a getLayerByName + int i = sprite->allLayersCount(); for (const Layer* layer : sprite->allLayers()) { - if (layer->name() == layerName) { + i--; + if (layer->name() == layerName && layerIndex == -1 || + layer->name() == layerName && layerIndex == i) { selLayers.insert(const_cast(layer)); break; } @@ -374,7 +379,7 @@ public: } fill_layers_combobox( - m_sprite, layers(), params.layer()); + m_sprite, layers(), params.layer(), params.layerIndex()); fill_frames_combobox( m_sprite, frames(), params.tag()); @@ -530,6 +535,7 @@ public: params.ignoreEmpty (ignoreEmptyValue()); params.openGenerated (openGeneratedValue()); params.layer (layerValue()); + params.layerIndex (layerIndex()); params.tag (tagValue()); params.splitLayers (splitLayersValue()); params.splitTags (splitTagsValue()); @@ -714,6 +720,11 @@ private: return layers()->getValue(); } + int layerIndex() const { + int i = layers()->getSelectedItemIndex() - 2; + return i < 0 ? -1 : i; + } + std::string tagValue() const { return frames()->getValue(); } diff --git a/src/app/commands/cmd_save_file.cpp b/src/app/commands/cmd_save_file.cpp index 92bf030bb..6966f8cf1 100644 --- a/src/app/commands/cmd_save_file.cpp +++ b/src/app/commands/cmd_save_file.cpp @@ -343,6 +343,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context) Doc* doc = context->activeDocument(); std::string outputFilename = params().filename(); std::string layers = kAllLayers; + int layersIndex = -1; std::string frames = kAllFrames; bool applyPixelRatio = false; double scale = params().scale(); @@ -408,6 +409,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context) win.savePref(); layers = win.layersValue(); + layersIndex = win.layersIndex(); frames = win.framesValue(); scale = win.resizeValue(); applyPixelRatio = win.applyPixelRatio(); @@ -464,6 +466,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context) // Selected layers to export calculate_visible_layers(site, layers, + layersIndex, layersVisibility); // m_selFrames is not empty if fromFrame/toFrame parameters are diff --git a/src/app/ui/export_file_window.cpp b/src/app/ui/export_file_window.cpp index c547e54a0..fdea35909 100644 --- a/src/app/ui/export_file_window.cpp +++ b/src/app/ui/export_file_window.cpp @@ -52,7 +52,7 @@ ExportFileWindow::ExportFileWindow(const Doc* doc) // Default export configuration setResizeScale(m_docPref.saveCopy.resizeScale()); - fill_layers_combobox(m_doc->sprite(), layers(), m_docPref.saveCopy.layer()); + fill_layers_combobox(m_doc->sprite(), layers(), m_docPref.saveCopy.layer(), -1); fill_frames_combobox(m_doc->sprite(), frames(), m_docPref.saveCopy.frameTag()); fill_anidir_combobox(anidir(), m_docPref.saveCopy.aniDir()); pixelRatio()->setSelected(m_docPref.saveCopy.applyPixelRatio()); @@ -121,6 +121,12 @@ std::string ExportFileWindow::layersValue() const return layers()->getValue(); } +int ExportFileWindow::layersIndex() const +{ + int i = layers()->getSelectedItemIndex() - 2; + return i < 0 ? -1 : i; +} + std::string ExportFileWindow::framesValue() const { return frames()->getValue(); diff --git a/src/app/ui/export_file_window.h b/src/app/ui/export_file_window.h index f5670d10b..ae20748bc 100644 --- a/src/app/ui/export_file_window.h +++ b/src/app/ui/export_file_window.h @@ -29,6 +29,7 @@ namespace app { std::string outputFilenameValue() const; double resizeValue() const; std::string layersValue() const; + int layersIndex() const; std::string framesValue() const; doc::AniDir aniDirValue() const; bool applyPixelRatio() const; diff --git a/src/app/ui/layer_frame_comboboxes.cpp b/src/app/ui/layer_frame_comboboxes.cpp index 4da19a6e6..4740ccf6d 100644 --- a/src/app/ui/layer_frame_comboboxes.cpp +++ b/src/app/ui/layer_frame_comboboxes.cpp @@ -57,7 +57,7 @@ FrameListItem::FrameListItem(doc::Tag* tag) setValue(m_tag->name()); } -void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer) +void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer, const int defLayerIndex) { int i = layers->addItem("Visible layers"); dynamic_cast(layers->getItem(i))->setValue(kAllLayers); @@ -71,7 +71,8 @@ void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const for (auto it=layersList.rbegin(), end=layersList.rend(); it!=end; ++it) { doc::Layer* layer = *it; i = layers->addItem(new LayerListItem(layer)); - if (defLayer == layer->name()) + if (defLayer == layer->name() && defLayerIndex == -1 || + defLayer == layer->name() && defLayerIndex == i-2) layers->setSelectedItemIndex(i); } } @@ -112,6 +113,7 @@ void fill_anidir_combobox(ui::ComboBox* anidir, doc::AniDir defAnidir) void calculate_visible_layers(const Site& site, const std::string& layersValue, + const int layersIndex, RestoreVisibleLayers& layersVisibility) { if (layersValue == kSelectedLayers) { @@ -124,10 +126,13 @@ void calculate_visible_layers(const Site& site, layersVisibility.showLayer(const_cast(site.layer())); } } - else if (layersValue != kAllFrames) { + else if (layersValue != kAllLayers) { + int i = site.sprite()->allLayersCount(); // TODO add a getLayerByName for (doc::Layer* layer : site.sprite()->allLayers()) { - if (layer->name() == layersValue) { + i--; + if (layer->name() == layersValue && layersIndex == -1 || + layer->name() == layersValue && layersIndex == i) { layersVisibility.showLayer(layer); break; } diff --git a/src/app/ui/layer_frame_comboboxes.h b/src/app/ui/layer_frame_comboboxes.h index c7d3afd61..365d4a0e1 100644 --- a/src/app/ui/layer_frame_comboboxes.h +++ b/src/app/ui/layer_frame_comboboxes.h @@ -52,12 +52,13 @@ namespace app { doc::Tag* m_tag; }; - void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer); + void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer, const int defLayerIndex); void fill_frames_combobox(const doc::Sprite* sprite, ui::ComboBox* frames, const std::string& defFrame); void fill_anidir_combobox(ui::ComboBox* anidir, doc::AniDir defAnidir); void calculate_visible_layers(const Site& site, const std::string& layersValue, + const int layersIndex, RestoreVisibleLayers& layersVisibility); doc::Tag* calculate_selected_frames(const Site& site, From d5f54da0218135f6a2e4b5d619cb74bc904717a9 Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 30 Aug 2022 17:33:52 -0300 Subject: [PATCH 2/4] Avoid hardcoded number of initial items added in the layers combobox --- src/app/commands/cmd_export_sprite_sheet.cpp | 2 +- src/app/ui/export_file_window.cpp | 2 +- src/app/ui/layer_frame_comboboxes.cpp | 6 +++++- src/app/ui/layer_frame_comboboxes.h | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp index f20e1e722..fe5c58ee4 100644 --- a/src/app/commands/cmd_export_sprite_sheet.cpp +++ b/src/app/commands/cmd_export_sprite_sheet.cpp @@ -721,7 +721,7 @@ private: } int layerIndex() const { - int i = layers()->getSelectedItemIndex() - 2; + int i = layers()->getSelectedItemIndex() - kLayersComboboxExtraInitialItems; return i < 0 ? -1 : i; } diff --git a/src/app/ui/export_file_window.cpp b/src/app/ui/export_file_window.cpp index fdea35909..a0b8a3ee1 100644 --- a/src/app/ui/export_file_window.cpp +++ b/src/app/ui/export_file_window.cpp @@ -123,7 +123,7 @@ std::string ExportFileWindow::layersValue() const int ExportFileWindow::layersIndex() const { - int i = layers()->getSelectedItemIndex() - 2; + int i = layers()->getSelectedItemIndex() - kLayersComboboxExtraInitialItems; return i < 0 ? -1 : i; } diff --git a/src/app/ui/layer_frame_comboboxes.cpp b/src/app/ui/layer_frame_comboboxes.cpp index 4740ccf6d..ff5568fa3 100644 --- a/src/app/ui/layer_frame_comboboxes.cpp +++ b/src/app/ui/layer_frame_comboboxes.cpp @@ -67,12 +67,16 @@ void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const if (defLayer == kSelectedLayers) layers->setSelectedItemIndex(i); + assert(layers->getItemCount() == kLayersComboboxExtraInitialItems); + static_assert(kLayersComboboxExtraInitialItems == 2, + "Update kLayersComboboxExtraInitialItems value to match the number of initial items in layers combobox"); + doc::LayerList layersList = sprite->allLayers(); for (auto it=layersList.rbegin(), end=layersList.rend(); it!=end; ++it) { doc::Layer* layer = *it; i = layers->addItem(new LayerListItem(layer)); if (defLayer == layer->name() && defLayerIndex == -1 || - defLayer == layer->name() && defLayerIndex == i-2) + defLayer == layer->name() && defLayerIndex == i-kLayersComboboxExtraInitialItems) layers->setSelectedItemIndex(i); } } diff --git a/src/app/ui/layer_frame_comboboxes.h b/src/app/ui/layer_frame_comboboxes.h index 365d4a0e1..2f4744705 100644 --- a/src/app/ui/layer_frame_comboboxes.h +++ b/src/app/ui/layer_frame_comboboxes.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2019-2022 Igara Studio S.A. // Copyright (C) 2016-2018 David Capello // // This program is distributed under the terms of @@ -35,6 +35,8 @@ namespace app { extern const char* kSelectedLayers; extern const char* kSelectedFrames; + constexpr const int kLayersComboboxExtraInitialItems = 2; + class LayerListItem : public ui::ListItem { public: LayerListItem(doc::Layer* layer); From f925e225619eadcc97c0bed12b350cb31cf3d1bb Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 30 Aug 2022 17:35:39 -0300 Subject: [PATCH 3/4] Don't encourage the usage of layerIndex param in ExportSpriteSheetParams Until we don't have a standarized way to indicate layers by indexes. --- src/app/commands/cmd_export_sprite_sheet.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp index fe5c58ee4..c96380614 100644 --- a/src/app/commands/cmd_export_sprite_sheet.cpp +++ b/src/app/commands/cmd_export_sprite_sheet.cpp @@ -76,7 +76,12 @@ struct ExportSpriteSheetParams : public NewParams { Param mergeDuplicates { this, false, "mergeDuplicates" }; Param openGenerated { this, false, "openGenerated" }; Param layer { this, std::string(), "layer" }; - Param layerIndex { this, -1, "layerIndex" }; + // TODO The layerIndex parameter is for internal use only, layers + // are counted in the same order as they are displayed in the + // Timeline or in the Export Sprite Sheet combobox. But this + // index is different to the one specified in the .aseprite + // file spec (where layers are counted from bottom to top). + Param layerIndex { this, -1, "_layerIndex" }; Param tag { this, std::string(), "tag" }; Param splitLayers { this, false, "splitLayers" }; Param splitTags { this, false, "splitTags" }; From 826fc1a5fd08b468023f153cc14250bae9d46a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Capello?= Date: Mon, 5 Sep 2022 17:19:25 -0300 Subject: [PATCH 4/4] Remember layer index between export operations --- data/pref.xml | 2 ++ src/app/commands/cmd_export_sprite_sheet.cpp | 2 ++ src/app/ui/export_file_window.cpp | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/data/pref.xml b/data/pref.xml index b5cca015c..253b7be8a 100644 --- a/data/pref.xml +++ b/data/pref.xml @@ -485,6 +485,7 @@