From 80c61ca926a7c29ccefcb92b93a03490bffe3edb Mon Sep 17 00:00:00 2001 From: David Capello Date: Wed, 12 Apr 2017 12:35:13 -0300 Subject: [PATCH] Export slice data in .aseprite-data file (#721) --- src/app/CMakeLists.txt | 1 + src/app/file/file.cpp | 207 ++---------------- src/app/file/file.h | 2 - src/app/file/file_data.cpp | 425 +++++++++++++++++++++++++++++++++++++ src/app/file/file_data.h | 26 +++ 5 files changed, 465 insertions(+), 196 deletions(-) create mode 100644 src/app/file/file_data.cpp create mode 100644 src/app/file/file_data.h diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 1dc385275e..26237fa58f 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -364,6 +364,7 @@ add_library(app-lib document_undo.cpp extra_cel.cpp file/file.cpp + file/file_data.cpp file/file_format.cpp file/file_formats_manager.cpp file/palette_file.cpp diff --git a/src/app/file/file.cpp b/src/app/file/file.cpp index 0013ff7d4c..0d8edb3181 100644 --- a/src/app/file/file.cpp +++ b/src/app/file/file.cpp @@ -13,6 +13,7 @@ #include "app/console.h" #include "app/context.h" #include "app/document.h" +#include "app/file/file_data.h" #include "app/file/file_format.h" #include "app/file/file_formats_manager.h" #include "app/file/format_options.h" @@ -20,9 +21,7 @@ #include "app/filename_formatter.h" #include "app/modules/gui.h" #include "app/modules/palettes.h" -#include "app/pref/preferences.h" #include "app/ui/status_bar.h" -#include "app/xml_document.h" #include "base/fs.h" #include "base/mutex.h" #include "base/scoped_lock.h" @@ -43,45 +42,6 @@ namespace app { using namespace base; -namespace { - -void updateXmlPartFromSliceKey(const doc::SliceKey* key, TiXmlElement* xmlPart) -{ - xmlPart->SetAttribute("x", key->bounds().x); - xmlPart->SetAttribute("y", key->bounds().y); - if (!key->hasCenter()) { - xmlPart->SetAttribute("w", key->bounds().w); - xmlPart->SetAttribute("h", key->bounds().h); - if (xmlPart->Attribute("w1")) xmlPart->RemoveAttribute("w1"); - if (xmlPart->Attribute("w2")) xmlPart->RemoveAttribute("w2"); - if (xmlPart->Attribute("w3")) xmlPart->RemoveAttribute("w3"); - if (xmlPart->Attribute("h1")) xmlPart->RemoveAttribute("h1"); - if (xmlPart->Attribute("h2")) xmlPart->RemoveAttribute("h2"); - if (xmlPart->Attribute("h3")) xmlPart->RemoveAttribute("h3"); - } - else { - xmlPart->SetAttribute("w1", key->center().x); - xmlPart->SetAttribute("w2", key->center().w); - xmlPart->SetAttribute("w3", key->bounds().w - key->center().x2()); - xmlPart->SetAttribute("h1", key->center().y); - xmlPart->SetAttribute("h2", key->center().h); - xmlPart->SetAttribute("h3", key->bounds().h - key->center().y2()); - if (xmlPart->Attribute("w")) xmlPart->RemoveAttribute("w"); - if (xmlPart->Attribute("h")) xmlPart->RemoveAttribute("h"); - } - - if (key->hasPivot()) { - xmlPart->SetAttribute("focusx", key->pivot().x); - xmlPart->SetAttribute("focusy", key->pivot().y); - } - else { - if (xmlPart->Attribute("focusx")) xmlPart->RemoveAttribute("focusx"); - if (xmlPart->Attribute("focusy")) xmlPart->RemoveAttribute("focusy"); - } -} - -} // anonymous namespace - std::string get_readable_extensions() { std::string buf; @@ -723,7 +683,12 @@ void FileOp::operate(IFileOpProgress* progress) if (m_document && m_document->sprite() && !m_dataFilename.empty()) { - loadData(); + try { + load_aseprite_data_file(m_dataFilename, m_document); + } + catch (const std::exception& ex) { + setError("Error loading data file: %s\n", ex.what()); + } } } // Save ////////////////////////////////////////////////////////////////////// @@ -805,7 +770,12 @@ void FileOp::operate(IFileOpProgress* progress) m_document->sprite() && !hasError() && !m_dataFilename.empty()) { - saveData(); + try { + save_aseprite_data_file(m_dataFilename, m_document); + } + catch (const std::exception& ex) { + setError("Error loading data file: %s\n", ex.what()); + } } #else setError( @@ -1091,155 +1061,4 @@ void FileOp::prepareForSequence() m_formatOptions.reset(); } -void FileOp::loadData() -{ - try { - XmlDocumentRef xmlDoc = open_xml(m_dataFilename); - TiXmlHandle handle(xmlDoc.get()); - - TiXmlElement* xmlSlices = handle - .FirstChild("sprite") - .FirstChild("slices").ToElement(); - - // Update theme.xml file - if (xmlSlices && - xmlSlices->Attribute("theme")) { - std::string themeFileName = xmlSlices->Attribute("theme"); - - // Open theme XML file - XmlDocumentRef xmlThemeDoc = open_xml( - base::join_path(base::get_file_path(m_dataFilename), themeFileName)); - TiXmlHandle themeHandle(xmlThemeDoc.get()); - for (TiXmlElement* xmlPart = themeHandle - .FirstChild("theme") - .FirstChild("parts") - .FirstChild("part").ToElement(); - xmlPart; - xmlPart=xmlPart->NextSiblingElement()) { - const char* partId = xmlPart->Attribute("id"); - if (!partId) - continue; - - auto slice = new doc::Slice(); - slice->setName(partId); - - // Default slice color - auto color = Preferences::instance().slices.defaultColor(); - slice->userData().setColor( - doc::rgba(color.getRed(), - color.getGreen(), - color.getBlue(), - color.getAlpha())); - - doc::SliceKey key; - - int x = strtol(xmlPart->Attribute("x"), NULL, 10); - int y = strtol(xmlPart->Attribute("y"), NULL, 10); - - if (xmlPart->Attribute("w1")) { - int w1 = xmlPart->Attribute("w1") ? strtol(xmlPart->Attribute("w1"), NULL, 10): 0; - int w2 = xmlPart->Attribute("w2") ? strtol(xmlPart->Attribute("w2"), NULL, 10): 0; - int w3 = xmlPart->Attribute("w3") ? strtol(xmlPart->Attribute("w3"), NULL, 10): 0; - int h1 = xmlPart->Attribute("h1") ? strtol(xmlPart->Attribute("h1"), NULL, 10): 0; - int h2 = xmlPart->Attribute("h2") ? strtol(xmlPart->Attribute("h2"), NULL, 10): 0; - int h3 = xmlPart->Attribute("h3") ? strtol(xmlPart->Attribute("h3"), NULL, 10): 0; - - key.setBounds(gfx::Rect(x, y, w1+w2+w3, h1+h2+h3)); - key.setCenter(gfx::Rect(w1, h1, w2, h2)); - } - else if (xmlPart->Attribute("w")) { - int w = xmlPart->Attribute("w") ? strtol(xmlPart->Attribute("w"), NULL, 10): 0; - int h = xmlPart->Attribute("h") ? strtol(xmlPart->Attribute("h"), NULL, 10): 0; - key.setBounds(gfx::Rect(x, y, w, h)); - } - - if (xmlPart->Attribute("focusx")) { - int x = xmlPart->Attribute("focusx") ? strtol(xmlPart->Attribute("focusx"), NULL, 10): 0; - int y = xmlPart->Attribute("focusy") ? strtol(xmlPart->Attribute("focusy"), NULL, 10): 0; - key.setPivot(gfx::Point(x, y)); - } - - slice->insert(0, key); - m_document->sprite()->slices().add(slice); - } - } - } - catch (const std::exception& ex) { - setError("Error loading data file: %s\n", ex.what()); - } -} - -void FileOp::saveData() -{ - try { - XmlDocumentRef xmlDoc = open_xml(m_dataFilename); - TiXmlHandle handle(xmlDoc.get()); - - TiXmlElement* xmlSlices = handle - .FirstChild("sprite") - .FirstChild("slices").ToElement(); - - if (xmlSlices && - xmlSlices->Attribute("theme")) { - // Open theme XML file - std::string themeFileName = base::join_path( - base::get_file_path(m_dataFilename), xmlSlices->Attribute("theme")); - XmlDocumentRef xmlThemeDoc = open_xml(themeFileName); - - TiXmlHandle themeHandle(xmlThemeDoc.get()); - TiXmlElement* xmlNext = nullptr; - std::set existent; - - TiXmlElement* xmlParts = - themeHandle - .FirstChild("theme") - .FirstChild("parts").ToElement(); - - for (TiXmlElement* xmlPart=(TiXmlElement*)xmlParts->FirstChild("part"); - xmlPart; - xmlPart=xmlNext) { - xmlNext = xmlPart->NextSiblingElement(); - - const char* partId = xmlPart->Attribute("id"); - if (!partId) - continue; - - bool found = false; - for (auto slice : m_document->sprite()->slices()) { - const SliceKey* key; - if ((slice->name() == partId) && - (key = slice->getByFrame(0))) { - existent.insert(slice->name()); - updateXmlPartFromSliceKey(key, xmlPart); - found = true; - break; - } - } - - // Delete this element (as the slice was removed) - if (!found) - xmlPart->Parent()->RemoveChild(xmlPart); - } - - for (auto slice : m_document->sprite()->slices()) { - const SliceKey* key; - if (existent.find(slice->name()) == existent.end() && - (key = slice->getByFrame(0))) { - - TiXmlElement xmlPart("part"); - xmlPart.SetAttribute("id", slice->name().c_str()); - updateXmlPartFromSliceKey(key, &xmlPart); - - xmlParts->InsertAfterChild(xmlParts->LastChild(), xmlPart); - } - } - - save_xml(xmlThemeDoc, themeFileName); - } - } - catch (const std::exception& ex) { - setError("Error loading data file: %s\n", ex.what()); - } -} - } // namespace app diff --git a/src/app/file/file.h b/src/app/file/file.h index 25545fcc3c..3a50eec8aa 100644 --- a/src/app/file/file.h +++ b/src/app/file/file.h @@ -212,8 +212,6 @@ namespace app { } m_seq; void prepareForSequence(); - void loadData(); - void saveData(); }; // Available extensions for each load/save operation. diff --git a/src/app/file/file_data.cpp b/src/app/file/file_data.cpp new file mode 100644 index 0000000000..43ed386ac6 --- /dev/null +++ b/src/app/file/file_data.cpp @@ -0,0 +1,425 @@ +// Aseprite +// Copyright (C) 2001-2017 David Capello +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app/file/file_data.h" + +#include "app/pref/preferences.h" +#include "app/xml_document.h" +#include "base/convert_to.h" +#include "base/fs.h" +#include "doc/color.h" +#include "doc/document.h" +#include "doc/slice.h" + +#include +#include + +namespace app { + +using namespace base; + +namespace { + +std::string color_to_hex(doc::color_t color) +{ + char buf[256]; + if (doc::rgba_geta(color) == 255) { + std::sprintf(buf, "#%02x%02x%02x", + doc::rgba_getr(color), + doc::rgba_getg(color), + doc::rgba_getb(color)); + } + else { + std::sprintf(buf, "#%02x%02x%02x%02x", + doc::rgba_getr(color), + doc::rgba_getg(color), + doc::rgba_getb(color), + doc::rgba_geta(color)); + } + return buf; +} + +doc::color_t color_from_hex(const char* str) +{ + if (*str == '#') + ++str; + + if (std::strlen(str) == 3) { // #fff + uint32_t value = std::strtol(str, nullptr, 16); + int r = ((value & 0xf00) >> 8); + int g = ((value & 0xf0) >> 4); + int b = (value & 0xf); + return gfx::rgba( + r | (r << 4), + g | (g << 4), + b | (b << 4)); + } + else if (std::strlen(str) == 6) { // #ffffff + uint32_t value = std::strtol(str, nullptr, 16); + return gfx::rgba( + (value & 0xff0000) >> 16, + (value & 0xff00) >> 8, + (value & 0xff)); + } + else if (std::strlen(str) == 8) { // #ffffffff + uint32_t value = std::strtol(str, nullptr, 16); + return gfx::rgba( + (value & 0xff000000) >> 24, + (value & 0xff0000) >> 16, + (value & 0xff00) >> 8, + (value & 0xff)); + } + else + return gfx::rgba(0, 0, 0, 255); +} + +template +void update_xml_collection(Container& container, + TiXmlElement* xmlParent, + const char* childElemName, + const char* idAttrName, + ChildNameGetterFunc childNameGetter, + UpdateXmlChildFunc updateXmlChild) +{ + if (!xmlParent) + return; + + TiXmlElement* xmlNext = nullptr; + std::set existent; + + // Update existent children + for (TiXmlElement* xmlChild=(xmlParent->FirstChild(childElemName) ? + xmlParent->FirstChild(childElemName)->ToElement(): nullptr); + xmlChild; + xmlChild=xmlNext) { + xmlNext = xmlChild->NextSiblingElement(); + + const char* xmlChildName = xmlChild->Attribute(idAttrName); + if (!xmlChildName) + continue; + + bool found = false; + for (auto child : container) { + std::string thisChildName = childNameGetter(child); + if (thisChildName == xmlChildName) { + existent.insert(thisChildName); + updateXmlChild(child, xmlChild); + found = true; + break; + } + } + + // Delete this element (as the child was removed from the + // original container) + if (!found) + xmlParent->RemoveChild(xmlChild); + } + + // Add new children + for (auto child : container) { + std::string thisChildName = childNameGetter(child); + if (existent.find(thisChildName) == existent.end()) { + TiXmlElement xmlChild(childElemName); + xmlChild.SetAttribute(idAttrName, thisChildName.c_str()); + updateXmlChild(child, &xmlChild); + + xmlParent->InsertEndChild(xmlChild); + } + } +} + +void update_xml_part_from_slice_key(const doc::SliceKey* key, TiXmlElement* xmlPart) +{ + xmlPart->SetAttribute("x", key->bounds().x); + xmlPart->SetAttribute("y", key->bounds().y); + if (!key->hasCenter()) { + xmlPart->SetAttribute("w", key->bounds().w); + xmlPart->SetAttribute("h", key->bounds().h); + if (xmlPart->Attribute("w1")) xmlPart->RemoveAttribute("w1"); + if (xmlPart->Attribute("w2")) xmlPart->RemoveAttribute("w2"); + if (xmlPart->Attribute("w3")) xmlPart->RemoveAttribute("w3"); + if (xmlPart->Attribute("h1")) xmlPart->RemoveAttribute("h1"); + if (xmlPart->Attribute("h2")) xmlPart->RemoveAttribute("h2"); + if (xmlPart->Attribute("h3")) xmlPart->RemoveAttribute("h3"); + } + else { + xmlPart->SetAttribute("w1", key->center().x); + xmlPart->SetAttribute("w2", key->center().w); + xmlPart->SetAttribute("w3", key->bounds().w - key->center().x2()); + xmlPart->SetAttribute("h1", key->center().y); + xmlPart->SetAttribute("h2", key->center().h); + xmlPart->SetAttribute("h3", key->bounds().h - key->center().y2()); + if (xmlPart->Attribute("w")) xmlPart->RemoveAttribute("w"); + if (xmlPart->Attribute("h")) xmlPart->RemoveAttribute("h"); + } + + if (key->hasPivot()) { + xmlPart->SetAttribute("focusx", key->pivot().x); + xmlPart->SetAttribute("focusy", key->pivot().y); + } + else { + if (xmlPart->Attribute("focusx")) xmlPart->RemoveAttribute("focusx"); + if (xmlPart->Attribute("focusy")) xmlPart->RemoveAttribute("focusy"); + } +} + +void update_xml_slice(const doc::Slice* slice, TiXmlElement* xmlSlice) +{ + if (!slice->userData().text().empty()) + xmlSlice->SetAttribute("text", slice->userData().text().c_str()); + else if (xmlSlice->Attribute("text")) + xmlSlice->RemoveAttribute("text"); + xmlSlice->SetAttribute("color", color_to_hex(slice->userData().color()).c_str()); + + // Update elements + update_xml_collection( + *slice, + xmlSlice, "key", "frame", + [](const Keyframes::Key& key) -> std::string { + return base::convert_to(key.frame()); + }, + [](const Keyframes::Key& key, TiXmlElement* xmlKey) { + SliceKey* sliceKey = key.value(); + + xmlKey->SetAttribute("x", sliceKey->bounds().x); + xmlKey->SetAttribute("y", sliceKey->bounds().y); + xmlKey->SetAttribute("w", sliceKey->bounds().w); + xmlKey->SetAttribute("h", sliceKey->bounds().h); + + if (sliceKey->hasCenter()) { + xmlKey->SetAttribute("cx", sliceKey->center().x); + xmlKey->SetAttribute("cy", sliceKey->center().y); + xmlKey->SetAttribute("cw", sliceKey->center().w); + xmlKey->SetAttribute("ch", sliceKey->center().h); + } + else { + if (xmlKey->Attribute("cx")) xmlKey->RemoveAttribute("cx"); + if (xmlKey->Attribute("cy")) xmlKey->RemoveAttribute("cy"); + if (xmlKey->Attribute("cw")) xmlKey->RemoveAttribute("cw"); + if (xmlKey->Attribute("ch")) xmlKey->RemoveAttribute("ch"); + } + + if (sliceKey->hasPivot()) { + xmlKey->SetAttribute("px", sliceKey->pivot().x); + xmlKey->SetAttribute("py", sliceKey->pivot().y); + } + else { + if (xmlKey->Attribute("px")) xmlKey->RemoveAttribute("px"); + if (xmlKey->Attribute("py")) xmlKey->RemoveAttribute("py"); + } + }); +} + +} // anonymous namespace + +void load_aseprite_data_file(const std::string& dataFilename, doc::Document* doc) +{ + XmlDocumentRef xmlDoc = open_xml(dataFilename); + TiXmlHandle handle(xmlDoc.get()); + + TiXmlElement* xmlSlices = handle + .FirstChild("sprite") + .FirstChild("slices").ToElement(); + + // Load slices/parts from theme.xml file + if (xmlSlices && + xmlSlices->Attribute("theme")) { + std::string themeFileName = xmlSlices->Attribute("theme"); + + // Open theme XML file + XmlDocumentRef xmlThemeDoc = open_xml( + base::join_path(base::get_file_path(dataFilename), themeFileName)); + TiXmlHandle themeHandle(xmlThemeDoc.get()); + for (TiXmlElement* xmlPart = themeHandle + .FirstChild("theme") + .FirstChild("parts") + .FirstChild("part").ToElement(); + xmlPart; + xmlPart=xmlPart->NextSiblingElement()) { + const char* partId = xmlPart->Attribute("id"); + if (!partId) + continue; + + auto slice = new doc::Slice(); + slice->setName(partId); + + // Default slice color + auto color = Preferences::instance().slices.defaultColor(); + slice->userData().setColor( + doc::rgba(color.getRed(), + color.getGreen(), + color.getBlue(), + color.getAlpha())); + + doc::SliceKey key; + + int x = strtol(xmlPart->Attribute("x"), NULL, 10); + int y = strtol(xmlPart->Attribute("y"), NULL, 10); + + if (xmlPart->Attribute("w1")) { + int w1 = xmlPart->Attribute("w1") ? strtol(xmlPart->Attribute("w1"), NULL, 10): 0; + int w2 = xmlPart->Attribute("w2") ? strtol(xmlPart->Attribute("w2"), NULL, 10): 0; + int w3 = xmlPart->Attribute("w3") ? strtol(xmlPart->Attribute("w3"), NULL, 10): 0; + int h1 = xmlPart->Attribute("h1") ? strtol(xmlPart->Attribute("h1"), NULL, 10): 0; + int h2 = xmlPart->Attribute("h2") ? strtol(xmlPart->Attribute("h2"), NULL, 10): 0; + int h3 = xmlPart->Attribute("h3") ? strtol(xmlPart->Attribute("h3"), NULL, 10): 0; + + key.setBounds(gfx::Rect(x, y, w1+w2+w3, h1+h2+h3)); + key.setCenter(gfx::Rect(w1, h1, w2, h2)); + } + else if (xmlPart->Attribute("w")) { + int w = xmlPart->Attribute("w") ? strtol(xmlPart->Attribute("w"), NULL, 10): 0; + int h = xmlPart->Attribute("h") ? strtol(xmlPart->Attribute("h"), NULL, 10): 0; + key.setBounds(gfx::Rect(x, y, w, h)); + } + + if (xmlPart->Attribute("focusx")) { + int x = xmlPart->Attribute("focusx") ? strtol(xmlPart->Attribute("focusx"), NULL, 10): 0; + int y = xmlPart->Attribute("focusy") ? strtol(xmlPart->Attribute("focusy"), NULL, 10): 0; + key.setPivot(gfx::Point(x, y)); + } + + slice->insert(0, key); + doc->sprite()->slices().add(slice); + } + } + // Load slices from elements + else if (xmlSlices) { + for (TiXmlElement* xmlSlice=(xmlSlices->FirstChild("slice") ? + xmlSlices->FirstChild("slice")->ToElement(): nullptr); + xmlSlice; + xmlSlice=xmlSlice->NextSiblingElement()) { + const char* sliceId = xmlSlice->Attribute("id"); + if (!sliceId) + continue; + + // If the document already contains a slice with this name, use the one from the document + if (doc->sprite()->slices().getByName(sliceId)) + continue; + + auto slice = new doc::Slice(); + slice->setName(sliceId); + + // Slice text + if (xmlSlice->Attribute("text")) + slice->userData().setText(xmlSlice->Attribute("text")); + + // Slice color + doc::color_t color; + if (xmlSlice->Attribute("color")) { + color = color_from_hex(xmlSlice->Attribute("color")); + } + else { + app::Color appColor = Preferences::instance().slices.defaultColor(); + color = doc::rgba(appColor.getRed(), + appColor.getGreen(), + appColor.getBlue(), + appColor.getAlpha()); + } + slice->userData().setColor(color); + + for (TiXmlElement* xmlKey=(xmlSlice->FirstChild("key") ? + xmlSlice->FirstChild("key")->ToElement(): nullptr); + xmlKey; + xmlKey=xmlKey->NextSiblingElement()) { + if (!xmlKey->Attribute("frame")) + continue; + + doc::SliceKey key; + doc::frame_t frame = std::strtol(xmlKey->Attribute("frame"), nullptr, 10); + + int x = std::strtol(xmlKey->Attribute("x"), nullptr, 10); + int y = std::strtol(xmlKey->Attribute("y"), nullptr, 10); + int w = std::strtol(xmlKey->Attribute("w"), nullptr, 10); + int h = std::strtol(xmlKey->Attribute("h"), nullptr, 10); + key.setBounds(gfx::Rect(x, y, w, h)); + + if (xmlKey->Attribute("cx")) { + int cx = std::strtol(xmlKey->Attribute("cx"), nullptr, 10); + int cy = std::strtol(xmlKey->Attribute("cy"), nullptr, 10); + int cw = std::strtol(xmlKey->Attribute("cw"), nullptr, 10); + int ch = std::strtol(xmlKey->Attribute("ch"), nullptr, 10); + key.setCenter(gfx::Rect(cx, cy, cw, ch)); + } + + if (xmlKey->Attribute("px")) { + int px = std::strtol(xmlKey->Attribute("px"), nullptr, 10); + int py = std::strtol(xmlKey->Attribute("py"), nullptr, 10); + key.setPivot(gfx::Point(px, py)); + } + + slice->insert(frame, key); + } + + doc->sprite()->slices().add(slice); + } + } +} + +#ifdef ENABLE_SAVE +void save_aseprite_data_file(const std::string& dataFilename, const doc::Document* doc) +{ + XmlDocumentRef xmlDoc = open_xml(dataFilename); + TiXmlHandle handle(xmlDoc.get()); + + TiXmlElement* xmlSlices = handle + .FirstChild("sprite") + .FirstChild("slices").ToElement(); + + // Update theme.xml file + if (xmlSlices && + xmlSlices->Attribute("theme")) { + // Open theme XML file + std::string themeFileName = base::join_path( + base::get_file_path(dataFilename), xmlSlices->Attribute("theme")); + XmlDocumentRef xmlThemeDoc = open_xml(themeFileName); + + TiXmlHandle themeHandle(xmlThemeDoc.get()); + TiXmlElement* xmlParts = + themeHandle + .FirstChild("theme") + .FirstChild("parts").ToElement(); + + update_xml_collection( + doc->sprite()->slices(), + xmlParts, "part", "id", + [](const Slice* slice) -> std::string { + if (slice->getByFrame(0)) + return slice->name(); + else + return std::string(); + }, + [](Slice* slice, TiXmlElement* xmlSlice) { + ASSERT(slice->getByFrame(0)); + update_xml_part_from_slice_key(slice->getByFrame(0), xmlSlice); + }); + + // Save theme.xml file + save_xml(xmlThemeDoc, themeFileName); + } + // without "theme" attribute + else if (xmlSlices) { + update_xml_collection( + doc->sprite()->slices(), + xmlSlices, "slice", "id", + [](const Slice* slice) -> std::string { + return slice->name(); + }, + update_xml_slice); + + // Save .aseprite-data file + save_xml(xmlDoc, dataFilename); + } +} +#endif + +} // namespace app diff --git a/src/app/file/file_data.h b/src/app/file/file_data.h new file mode 100644 index 0000000000..110d5dc66c --- /dev/null +++ b/src/app/file/file_data.h @@ -0,0 +1,26 @@ +// Aseprite +// Copyright (C) 2017 David Capello +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifndef APP_FILE_FILE_DATA_H_INCLUDED +#define APP_FILE_FILE_DATA_H_INCLUDED +#pragma once + +#include + +namespace doc { + class Document; +} + +namespace app { + +void load_aseprite_data_file(const std::string& dataFilename, doc::Document* doc); +#ifdef ENABLE_SAVE +void save_aseprite_data_file(const std::string& dataFilename, const doc::Document* doc); +#endif + +} // namespace app + +#endif