diff --git a/data/pref.xml b/data/pref.xml
index 84053e6b2..61a157e35 100644
--- a/data/pref.xml
+++ b/data/pref.xml
@@ -529,6 +529,7 @@
+
diff --git a/data/strings/en.ini b/data/strings/en.ini
index 834c50109..1ab872be0 100644
--- a/data/strings/en.ini
+++ b/data/strings/en.ini
@@ -861,6 +861,12 @@ Each frame in the JSON data will contain a filename
how to build each frame. You can use special marks
like {layer}, {frame}, {tag}, {tagframe}, etc.
END
+data_tagname_format = Item Tagname:
+data_tagname_format_tooltip = <<
+
+
+
+
+
diff --git a/src/app/cli/app_options.cpp b/src/app/cli/app_options.cpp
index c3bf04a3d..1cf80f0d7 100644
--- a/src/app/cli/app_options.cpp
+++ b/src/app/cli/app_options.cpp
@@ -67,6 +67,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_crop(m_po.add("crop").requiresValue("x,y,width,height").description("Crop all the images to the given rectangle"))
, m_slice(m_po.add("slice").requiresValue("").description("Crop the sprite to the given slice area"))
, m_filenameFormat(m_po.add("filename-format").requiresValue("").description("Special format to generate filenames"))
+ , m_tagnameFormat(m_po.add("tagname-format").requiresValue("").description("Special format to generate tagnames"))
#ifdef ENABLE_SCRIPTING
, m_script(m_po.add("script").requiresValue("").description("Execute a specific script"))
, m_scriptParam(m_po.add("script-param").requiresValue("name=value").description("Parameter for a script executed from the\nCLI that you can access with app.params"))
diff --git a/src/app/cli/app_options.h b/src/app/cli/app_options.h
index d85e36974..bf487f2b3 100644
--- a/src/app/cli/app_options.h
+++ b/src/app/cli/app_options.h
@@ -83,6 +83,7 @@ public:
const Option& crop() const { return m_crop; }
const Option& slice() const { return m_slice; }
const Option& filenameFormat() const { return m_filenameFormat; }
+ const Option& tagnameFormat() const { return m_tagnameFormat; }
#ifdef ENABLE_SCRIPTING
const Option& script() const { return m_script; }
const Option& scriptParam() const { return m_scriptParam; }
@@ -152,6 +153,7 @@ private:
Option& m_crop;
Option& m_slice;
Option& m_filenameFormat;
+ Option& m_tagnameFormat;
#ifdef ENABLE_SCRIPTING
Option& m_script;
Option& m_scriptParam;
diff --git a/src/app/cli/cli_open_file.h b/src/app/cli/cli_open_file.h
index 4fec4591d..5e51f066b 100644
--- a/src/app/cli/cli_open_file.h
+++ b/src/app/cli/cli_open_file.h
@@ -24,6 +24,7 @@ namespace app {
Doc* document = nullptr;
std::string filename;
std::string filenameFormat;
+ std::string tagnameFormat;
std::string tag;
std::string slice;
std::vector includeLayers;
diff --git a/src/app/cli/cli_processor.cpp b/src/app/cli/cli_processor.cpp
index a8d067274..2e7c22802 100644
--- a/src/app/cli/cli_processor.cpp
+++ b/src/app/cli/cli_processor.cpp
@@ -390,6 +390,12 @@ int CliProcessor::process(Context* ctx)
if (m_exporter)
m_exporter->setFilenameFormat(cof.filenameFormat);
}
+ // --tagname-format
+ else if (opt == &m_options.tagnameFormat()) {
+ cof.tagnameFormat = value.value();
+ if (m_exporter)
+ m_exporter->setTagnameFormat(cof.tagnameFormat);
+ }
// --save-as
else if (opt == &m_options.saveAs()) {
if (lastDoc) {
diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp
index 28a491c68..3bb3d4ec9 100644
--- a/src/app/commands/cmd_export_sprite_sheet.cpp
+++ b/src/app/commands/cmd_export_sprite_sheet.cpp
@@ -158,6 +158,7 @@ Doc* generate_sprite_sheet_from_params(
const std::string dataFilename = params.dataFilename();
const SpriteSheetDataFormat dataFormat = params.dataFormat();
const std::string filenameFormat = params.filenameFormat();
+ const std::string tagnameFormat = params.tagnameFormat();
const std::string layerName = params.layer();
const int layerIndex = params.layerIndex();
const std::string tagName = params.tag();
@@ -235,6 +236,9 @@ Doc* generate_sprite_sheet_from_params(
if (!filenameFormat.empty())
exporter.setFilenameFormat(filenameFormat);
+ if (!tagnameFormat.empty())
+ exporter.setTagnameFormat(tagnameFormat);
+
exporter.setTextureWidth(width);
exporter.setTextureHeight(height);
exporter.setTextureColumns(columns);
@@ -308,6 +312,7 @@ public:
, m_genTimer(100, nullptr)
, m_executionID(0)
, m_filenameFormat(params.filenameFormat())
+ , m_tagnameFormat(params.tagnameFormat())
{
sectionTabs()->ItemChange.connect([this]{ onChangeSection(); });
expandSections()->Click.connect([this]{ onExpandSections(); });
@@ -414,6 +419,7 @@ public:
listSlices()->setSelected(params.listSlices());
updateDefaultDataFilenameFormat();
+ updateDefaultDataTagnameFormat();
updateDataFields();
std::string base = site.document()->filename();
@@ -457,6 +463,7 @@ public:
splitTags()->Click.connect([this]{ onSplitLayersOrFrames(); });
frames()->Change.connect([this]{ generatePreview(); });
dataFilenameFormat()->Change.connect([this]{ onDataFilenameFormatChange(); });
+ dataTagnameFormat()->Change.connect([this]{ onDataTagnameFormatChange(); });
openGenerated()->Click.connect([this]{ onOpenGeneratedChange(); });
preview()->Click.connect([this]{ generatePreview(); });
m_genTimer.Tick.connect([this]{ onGenTimerTick(); });
@@ -525,6 +532,7 @@ public:
params.dataFilename (dataFilenameValue());
params.dataFormat (dataFormatValue());
params.filenameFormat (filenameFormatValue());
+ params.tagnameFormat (tagnameFormatValue());
params.borderPadding (borderPaddingValue());
params.shapePadding (shapePaddingValue());
params.innerPadding (innerPaddingValue());
@@ -666,6 +674,14 @@ private:
return std::string();
}
+ std::string tagnameFormatValue() const {
+ if (!m_tagnameFormat.empty() &&
+ m_tagnameFormat != m_tagnameFormatDefault)
+ return m_tagnameFormat;
+ else
+ return std::string();
+ }
+
SpriteSheetDataFormat dataFormatValue() const {
if (dataEnabled()->isSelected())
return SpriteSheetDataFormat(dataFormat()->getSelectedItemIndex());
@@ -910,6 +926,7 @@ private:
void onSplitLayersOrFrames() {
updateDefaultDataFilenameFormat();
+ updateDefaultDataTagnameFormat();
generatePreview();
}
@@ -919,6 +936,12 @@ private:
updateDefaultDataFilenameFormat();
}
+ void onDataTagnameFormatChange() {
+ m_tagnameFormat = dataTagnameFormat()->text();
+ if (m_tagnameFormat.empty())
+ updateDefaultDataTagnameFormat();
+ }
+
void onOpenGeneratedChange() {
updateExportButton();
}
@@ -950,11 +973,16 @@ private:
}
}
+ void updateDefaultDataTagnameFormat() {
+ m_tagnameFormatDefault = "{tag}";
+ }
+
void updateDataFields() {
bool state = dataEnabled()->isSelected();
dataFilename()->setVisible(state);
dataMeta()->setVisible(state);
dataFilenameFormatPlaceholder()->setVisible(state);
+ dataTagnameFormatPlaceholder()->setVisible(state);
}
void onGenTimerTick() {
@@ -1142,6 +1170,8 @@ private:
int m_executionID;
std::string m_filenameFormat;
std::string m_filenameFormatDefault;
+ std::string m_tagnameFormat;
+ std::string m_tagnameFormatDefault;
};
class ExportSpriteSheetJob : public Job {
@@ -1235,6 +1265,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
if (!params.dataFilename.isSet()) params.dataFilename( defPref.spriteSheet.dataFilename());
if (!params.dataFormat.isSet()) params.dataFormat( defPref.spriteSheet.dataFormat());
if (!params.filenameFormat.isSet()) params.filenameFormat( defPref.spriteSheet.filenameFormat());
+ if (!params.tagnameFormat.isSet()) params.tagnameFormat( defPref.spriteSheet.tagnameFormat());
if (!params.borderPadding.isSet()) params.borderPadding( defPref.spriteSheet.borderPadding());
if (!params.shapePadding.isSet()) params.shapePadding( defPref.spriteSheet.shapePadding());
if (!params.innerPadding.isSet()) params.innerPadding( defPref.spriteSheet.innerPadding());
@@ -1283,6 +1314,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
docPref.spriteSheet.dataFilename (params.dataFilename());
docPref.spriteSheet.dataFormat (params.dataFormat());
docPref.spriteSheet.filenameFormat (params.filenameFormat());
+ docPref.spriteSheet.tagnameFormat (params.tagnameFormat());
docPref.spriteSheet.borderPadding (params.borderPadding());
docPref.spriteSheet.shapePadding (params.shapePadding());
docPref.spriteSheet.innerPadding (params.innerPadding());
diff --git a/src/app/commands/cmd_export_sprite_sheet.h b/src/app/commands/cmd_export_sprite_sheet.h
index f23ac2aee..7eb1f0f67 100644
--- a/src/app/commands/cmd_export_sprite_sheet.h
+++ b/src/app/commands/cmd_export_sprite_sheet.h
@@ -29,6 +29,7 @@ struct ExportSpriteSheetParams : public NewParams {
Param dataFilename { this, std::string(), "dataFilename" };
Param dataFormat { this, SpriteSheetDataFormat::Default, "dataFormat" };
Param filenameFormat { this, std::string(), "filenameFormat" };
+ Param tagnameFormat { this, std::string(), "tagnameFormat" };
Param borderPadding { this, 0, "borderPadding" };
Param shapePadding { this, 0, "shapePadding" };
Param innerPadding { this, 0, "innerPadding" };
diff --git a/src/app/doc_exporter.cpp b/src/app/doc_exporter.cpp
index 1da404385..34115ab09 100644
--- a/src/app/doc_exporter.cpp
+++ b/src/app/doc_exporter.cpp
@@ -604,6 +604,7 @@ void DocExporter::reset()
m_dataFilename.clear();
m_textureFilename.clear();
m_filenameFormat.clear();
+ m_tagnameFormat.clear();
m_textureWidth = 0;
m_textureHeight = 0;
m_textureColumns = 0;
@@ -1431,7 +1432,17 @@ void DocExporter::createDataFile(const Samples& samples,
else
os << ",";
- os << "\n { \"name\": \"" << escape_for_json(tag->name()) << "\","
+ std::string format = m_tagnameFormat;
+ if (format.empty()) {
+ format = "{tag}";
+ }
+
+ FilenameInfo fnInfo;
+ fnInfo
+ .filename(doc->filename())
+ .innerTagName(tag->name());
+ std::string tagname = filename_formatter(format, fnInfo);
+ os << "\n { \"name\": \"" << escape_for_json(tagname) << "\","
<< " \"from\": " << (tag->fromFrame()) << ","
<< " \"to\": " << (tag->toFrame()) << ","
" \"direction\": \"" << escape_for_json(convert_anidir_to_string(tag->aniDir())) << "\"";
diff --git a/src/app/doc_exporter.h b/src/app/doc_exporter.h
index 2cc12f367..d238c9ca6 100644
--- a/src/app/doc_exporter.h
+++ b/src/app/doc_exporter.h
@@ -52,6 +52,7 @@ namespace app {
const std::string& textureFilename() { return m_textureFilename; }
SpriteSheetType spriteSheetType() { return m_sheetType; }
const std::string& filenameFormat() const { return m_filenameFormat; }
+ const std::string& tagnameFormat() const { return m_tagnameFormat; }
void setDataFormat(SpriteSheetDataFormat format) { m_dataFormat = format; }
void setDataFilename(const std::string& filename) { m_dataFilename = filename; }
@@ -71,6 +72,7 @@ namespace app {
void setTrimByGrid(bool trimByGrid) { m_trimByGrid = trimByGrid; }
void setExtrude(bool extrude) { m_extrude = extrude; }
void setFilenameFormat(const std::string& format) { m_filenameFormat = format; }
+ void setTagnameFormat(const std::string& format) { m_tagnameFormat = format; }
void setSplitLayers(bool splitLayers) { m_splitLayers = splitLayers; }
void setSplitTags(bool splitTags) { m_splitTags = splitTags; }
void setListTags(bool value) { m_listTags = value; }
@@ -160,6 +162,7 @@ namespace app {
std::string m_dataFilename;
std::string m_textureFilename;
std::string m_filenameFormat;
+ std::string m_tagnameFormat;
int m_textureWidth;
int m_textureHeight;
int m_textureColumns;