This is an automated email from the git hooks/post-receive script. thansen pushed a commit to branch master in repository aseprite.
commit ce962f4999e4b52dace5a4d263c96c2fbbf17e45 Author: David Capello <[email protected]> Date: Thu Nov 6 21:04:32 2014 -0300 Add more command line options to export or convert sprites Added --save-as, --scale, --split-layers, and --import-layer command line options. --- src/app/app.cpp | 190 +++++++++++++++++++++++++---------- src/app/app_menus.cpp | 5 +- src/app/app_options.cpp | 59 +++++------ src/app/app_options.h | 52 +++++----- src/app/commands/cmd_save_file.cpp | 2 +- src/app/commands/cmd_save_file.h | 4 + src/app/commands/cmd_sprite_size.cpp | 161 ++++++++++++++++------------- src/app/commands/cmd_sprite_size.h | 72 +++++++++++++ src/app/document_exporter.cpp | 95 +++++++++++------- src/app/document_exporter.h | 20 +++- src/app/job.cpp | 47 +++++---- src/app/job.h | 2 +- src/app/modules/gui.cpp | 3 +- src/app/ui_context.cpp | 15 ++- src/base/program_options.cpp | 4 +- src/doc/documents.h | 1 + 16 files changed, 483 insertions(+), 249 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 009a7f3..bfc9a8f 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 David Capello * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,8 @@ #include "app/app_options.h" #include "app/check_update.h" #include "app/color_utils.h" +#include "app/commands/cmd_save_file.h" +#include "app/commands/cmd_sprite_size.h" #include "app/commands/commands.h" #include "app/commands/params.h" #include "app/console.h" @@ -133,14 +135,9 @@ void App::initialize(int argc, const char* argv[]) m_isShell = options.startShell(); m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0); - if (options.hasExporterParams()) { + if (options.hasExporterParams()) m_exporter.reset(new DocumentExporter); - m_exporter->setDataFilename(options.data()); - m_exporter->setTextureFilename(options.sheet()); - m_exporter->setScale(options.scale()); - } - // Register well-known image file types. FileFormatsManager::instance()->registerAllFormats(); @@ -181,14 +178,14 @@ void App::initialize(int argc, const char* argv[]) set_current_palette(NULL, true); // Initialize GUI interface - UIContext* context = UIContext::instance(); + UIContext* ctx = UIContext::instance(); if (isGui()) { PRINTF("GUI mode\n"); // Setup the GUI cursor and redraw screen ui::set_use_native_cursors( - context->settings()->experimental()->useNativeCursor()); + ctx->settings()->experimental()->useNativeCursor()); jmouse_set_cursor(kArrowCursor); @@ -214,30 +211,111 @@ void App::initialize(int argc, const char* argv[]) PRINTF("Processing options...\n"); // Open file specified in the command line - { + if (!options.values().empty()) { Console console; - for (const auto& value : options.values()) { - if (value.option() != NULL) // File names aren't associated to any option - continue; + bool splitLayers = false; + std::string importLayer; - const std::string& filename = value.value(); - - // Load the sprite - Document* document = load_document(context, filename.c_str()); - if (!document) { - if (!isGui()) - console.printf("Error loading file \"%s\"\n", filename.c_str()); + for (const auto& value : options.values()) { + const AppOptions::Option* opt = value.option(); + + // Special options/commands + if (opt) { + // --data <file.json> + if (opt == &options.data()) { + if (m_exporter) + m_exporter->setDataFilename(value.value()); + } + // --sheet <file.png> + else if (opt == &options.sheet()) { + if (m_exporter) + m_exporter->setTextureFilename(value.value()); + } + // --split-layers + else if (opt == &options.splitLayers()) { + splitLayers = true; + } + // --import-layer <layer-name> + else if (opt == &options.importLayer()) { + importLayer = value.value(); + } + // --save-as <filename> + else if (opt == &options.saveAs()) { + Document* doc = NULL; + if (!ctx->documents().empty()) + doc = dynamic_cast<Document*>(ctx->documents().lastAdded()); + + if (!doc) { + console.printf("A document is needed before --save-as argument\n"); + } + else { + ctx->setActiveDocument(doc); + + Command* command = CommandsModule::instance()->getCommandByName(CommandId::SaveFileCopyAs); + static_cast<SaveFileBaseCommand*>(command)->setFilename(value.value()); + ctx->executeCommand(command); + } + } + // --scale <factor> + else if (opt == &options.scale()) { + Command* command = CommandsModule::instance()->getCommandByName(CommandId::SpriteSize); + double scale = strtod(value.value().c_str(), NULL); + static_cast<SpriteSizeCommand*>(command)->setScale(scale, scale); + + // Scale all sprites + for (auto doc : ctx->documents()) { + ctx->setActiveDocument(doc); + ctx->executeCommand(command); + } + } } + // File names aren't associated to any option else { - // Add the given file in the argument as a "recent file" only - // if we are running in GUI mode. If the program is executed - // in batch mode this is not desirable. - if (isGui()) - getRecentFiles()->addRecentFile(filename.c_str()); - - // Add the document to the exporter. - if (m_exporter != NULL) - m_exporter->addDocument(document); + const std::string& filename = value.value(); + + // Load the sprite + Document* doc = load_document(ctx, filename.c_str()); + if (!doc) { + if (!isGui()) + console.printf("Error loading file \"%s\"\n", filename.c_str()); + } + else { + // Add the given file in the argument as a "recent file" only + // if we are running in GUI mode. If the program is executed + // in batch mode this is not desirable. + if (isGui()) + getRecentFiles()->addRecentFile(filename.c_str()); + + if (m_exporter != NULL) { + if (!importLayer.empty()) { + std::vector<Layer*> layers; + Layer* foundLayer = NULL; + doc->sprite()->getLayersList(layers); + for (Layer* layer : layers) { + if (layer->name() == importLayer) { + foundLayer = layer; + break; + } + } + if (foundLayer) + m_exporter->addDocument(doc, foundLayer); + } + else if (splitLayers) { + std::vector<Layer*> layers; + doc->sprite()->getLayersList(layers); + for (auto layer : layers) + m_exporter->addDocument(doc, layer); + } + else + m_exporter->addDocument(doc); + } + } + + if (!importLayer.empty()) + importLayer.clear(); + + if (splitLayers) + splitLayers = false; } } } @@ -272,32 +350,10 @@ void App::run() // Run the GUI main message loop gui_run(); - - // Destroy all documents in the UIContext. - const doc::Documents& docs = m_modules->m_ui_context.documents(); - while (!docs.empty()) { - doc::Document* doc = docs.back(); - - // First we close the document. In this way we receive recent - // notifications related to the document as an app::Document. If - // we delete the document directly, we destroy the app::Document - // too early, and then doc::~Document() call - // DocumentsObserver::onRemoveDocument(). In this way, observers - // could think that they have a fully created app::Document when - // in reality it's a doc::Document (in the middle of a - // destruction process). - // - // TODO: This problem is because we're extending doc::Document, - // in the future, we should remove app::Document. - doc->close(); - delete doc; - } - - // Destroy the window. - m_mainWindow.reset(NULL); } + // Start shell to execute scripts. - else if (m_isShell) { + if (m_isShell) { m_systemConsole.prepareShell(); if (m_modules->m_scriptingEngine.supportEval()) { @@ -308,6 +364,31 @@ void App::run() std::cerr << "Your version of " PACKAGE " wasn't compiled with shell support.\n"; } } + + // Destroy all documents in the UIContext. + const doc::Documents& docs = m_modules->m_ui_context.documents(); + while (!docs.empty()) { + doc::Document* doc = docs.back(); + + // First we close the document. In this way we receive recent + // notifications related to the document as an app::Document. If + // we delete the document directly, we destroy the app::Document + // too early, and then doc::~Document() call + // DocumentsObserver::onRemoveDocument(). In this way, observers + // could think that they have a fully created app::Document when + // in reality it's a doc::Document (in the middle of a + // destruction process). + // + // TODO: This problem is because we're extending doc::Document, + // in the future, we should remove app::Document. + doc->close(); + delete doc; + } + + if (isGui()) { + // Destroy the window. + m_mainWindow.reset(NULL); + } } // Finishes the Aseprite application. @@ -410,7 +491,8 @@ void app_refresh_screen() void app_rebuild_documents_tabs() { - App::instance()->getMainWindow()->getTabsBar()->updateTabsText(); + if (App::instance()->isGui()) + App::instance()->getMainWindow()->getTabsBar()->updateTabsText(); } PixelFormat app_get_current_pixel_format() diff --git a/src/app/app_menus.cpp b/src/app/app_menus.cpp index 66cd5ef..6e1f32c 100644 --- a/src/app/app_menus.cpp +++ b/src/app/app_menus.cpp @@ -287,9 +287,10 @@ void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Widget* child = *it; if (child->getType() == kMenuItemWidget) { - ASSERT(dynamic_cast<AppMenuItem*>(child) != NULL); + AppMenuItem* menuitem = dynamic_cast<AppMenuItem*>(child); + if (!menuitem) + continue; - AppMenuItem* menuitem = static_cast<AppMenuItem*>(child); Command* mi_command = menuitem->getCommand(); Params* mi_params = menuitem->getParams(); diff --git a/src/app/app_options.cpp b/src/app/app_options.cpp index fb4e744..4f47f71 100644 --- a/src/app/app_options.cpp +++ b/src/app/app_options.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 David Capello * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,49 +35,37 @@ AppOptions::AppOptions(int argc, const char* argv[]) : m_exeName(base::get_file_name(argv[0])) , m_startUI(true) , m_startShell(false) - , m_verbose(false) - , m_scale(1.0) + , m_verboseEnabled(false) + , m_palette(m_po.add("palette").requiresValue("<filename>").description("Use a specific palette by default")) + , m_shell(m_po.add("shell").description("Start an interactive console to execute scripts")) + , m_batch(m_po.add("batch").description("Do not start the UI")) + , m_saveAs(m_po.add("save-as").requiresValue("<filename>").description("Save the last give document with other name/format")) + , m_scale(m_po.add("scale").requiresValue("<factor>").description("Scale all opened documents at the moment")) + , m_data(m_po.add("data").requiresValue("<filename.json>").description("File to store the sprite sheet metadata")) + , m_sheet(m_po.add("sheet").requiresValue("<filename.png>").description("Image file to save the texture")) + , m_splitLayers(m_po.add("split-layers").description("Import each layer of the next given sprite as\n a separated image in the sheet")) + , m_importLayer(m_po.add("import-layer").requiresValue("<name>").description("Import just one layer of the next given sprite")) + , m_verbose(m_po.add("verbose").description("Explain what is being done (in stderr or log file)")) + , m_help(m_po.add("help").mnemonic('?').description("Display this help and exits")) + , m_version(m_po.add("version").description("Output version information and exit")) { - Option& palette = m_po.add("palette").requiresValue("<filename>").description("Use a specific palette by default"); - Option& shell = m_po.add("shell").description("Start an interactive console to execute scripts"); - Option& batch = m_po.add("batch").description("Do not start the UI"); - // Option& dataFormat = m_po.add("format").requiresValue("<name>").description("Select the format for the sprite sheet data"); - Option& data = m_po.add("data").requiresValue("<filename>").description("File to store the sprite sheet metadata (.json file)"); - //Option& textureFormat = m_po.add("texture-format").requiresValue("<name>").description("Output texture format."); - Option& sheet = m_po.add("sheet").requiresValue("<filename>").description("Image file to save the texture (.png)"); - //Option& scale = m_po.add("scale").requiresValue("<float>").description(""); - //Option& scaleMode = m_po.add("scale-mode").requiresValue("<mode>").description("Export the first given document to a JSON object"); - //Option& splitLayers = m_po.add("split-layers").description("Specifies that each layer of the given file should be saved as a different image in the sheet."); - //Option& rotsprite = m_po.add("rotsprite").requiresValue("<angle1,angle2,...>").description("Specifies different angles to export the given image."); - //Option& merge = m_po.add("merge").requiresValue("<datafiles>").description("Merge several sprite sheets in one."); - Option& verbose = m_po.add("verbose").description("Explain what is being done (in stderr or a log file)"); - Option& help = m_po.add("help").mnemonic('?').description("Display this help and exits"); - Option& version = m_po.add("version").description("Output version information and exit"); - try { m_po.parse(argc, argv); - m_verbose = m_po.enabled(verbose); - m_paletteFileName = m_po.value_of(palette); - m_startShell = m_po.enabled(shell); - // m_dataFormat = m_po.value_of(dataFormat); - m_data = m_po.value_of(data); - // m_textureFormat = m_po.value_of(textureFormat); - m_sheet = m_po.value_of(sheet); - // if (scale.enabled()) - // m_scale = std::strtod(m_po.value_of(scale).c_str(), NULL); - // m_scaleMode = m_po.value_of(scaleMode); + m_verboseEnabled = m_po.enabled(m_verbose); + m_paletteFileName = m_po.value_of(m_palette); + m_startShell = m_po.enabled(m_shell); - if (m_po.enabled(help)) { + if (m_po.enabled(m_help)) { showHelp(); m_startUI = false; } - else if (m_po.enabled(version)) { + else if (m_po.enabled(m_version)) { showVersion(); m_startUI = false; } - if (m_po.enabled(shell) || m_po.enabled(batch)) { + if (m_po.enabled(m_shell) || m_po.enabled(m_batch)) { m_startUI = false; } } @@ -88,6 +76,13 @@ AppOptions::AppOptions(int argc, const char* argv[]) } } +bool AppOptions::hasExporterParams() const +{ + return + m_po.enabled(m_data) || + m_po.enabled(m_sheet); +} + void AppOptions::showHelp() { std::cout diff --git a/src/app/app_options.h b/src/app/app_options.h index 045869f..dc7523a 100644 --- a/src/app/app_options.h +++ b/src/app/app_options.h @@ -30,33 +30,31 @@ namespace app { class AppOptions { public: + typedef base::ProgramOptions PO; + typedef PO::Option Option; + typedef PO::ValueList ValueList; + AppOptions(int argc, const char* argv[]); bool startUI() const { return m_startUI; } bool startShell() const { return m_startShell; } - bool verbose() const { return m_verbose; } + bool verbose() const { return m_verboseEnabled; } const std::string& paletteFileName() const { return m_paletteFileName; } - const base::ProgramOptions::ValueList& values() const { + const ValueList& values() const { return m_po.values(); } // Export options - const std::string& dataFormat() const { return m_dataFormat; } - const std::string& data() const { return m_data; } - const std::string& textureFormat() const { return m_textureFormat; } - const std::string& sheet() const { return m_sheet; } - const double scale() const { return m_scale; } - const std::string& scaleMode() const { return m_scaleMode; } - - bool hasExporterParams() { - return - !m_dataFormat.empty() || - !m_data.empty() || - !m_textureFormat.empty() || - !m_sheet.empty(); - } + const Option& saveAs() const { return m_saveAs; } + const Option& scale() const { return m_scale; } + const Option& data() const { return m_data; } + const Option& sheet() const { return m_sheet; } + const Option& splitLayers() const { return m_splitLayers; } + const Option& importLayer() const { return m_importLayer; } + + bool hasExporterParams() const; private: void showHelp(); @@ -66,15 +64,23 @@ private: base::ProgramOptions m_po; bool m_startUI; bool m_startShell; - bool m_verbose; + bool m_verboseEnabled; std::string m_paletteFileName; - std::string m_dataFormat; - std::string m_data; - std::string m_textureFormat; - std::string m_sheet; - double m_scale; - std::string m_scaleMode; + Option& m_palette; + Option& m_shell; + Option& m_batch; + Option& m_saveAs; + Option& m_scale; + Option& m_data; + Option& m_sheet; + Option& m_splitLayers; + Option& m_importLayer; + + Option& m_verbose; + Option& m_help; + Option& m_version; + }; } // namespace app diff --git a/src/app/commands/cmd_save_file.cpp b/src/app/commands/cmd_save_file.cpp index 7d8320e..0defd78 100644 --- a/src/app/commands/cmd_save_file.cpp +++ b/src/app/commands/cmd_save_file.cpp @@ -100,7 +100,7 @@ static void save_document_in_background(Context* context, Document* document, bo else if (fop_is_stop(fop)) { document->impossibleToBackToSavedState(); } - else { + else if (context->isUiAvailable()) { App::instance()->getRecentFiles()->addRecentFile(document->filename().c_str()); if (mark_as_saved) document->markAsSaved(); diff --git a/src/app/commands/cmd_save_file.h b/src/app/commands/cmd_save_file.h index 8affee5..f400979 100644 --- a/src/app/commands/cmd_save_file.h +++ b/src/app/commands/cmd_save_file.h @@ -35,6 +35,10 @@ namespace app { return m_selectedFilename; } + void setFilename(const std::string& fn) { + m_filename = fn; + } + protected: void onLoadParams(Params* params) override; bool onEnabled(Context* context) override; diff --git a/src/app/commands/cmd_sprite_size.cpp b/src/app/commands/cmd_sprite_size.cpp index ab642e6..99cee9f 100644 --- a/src/app/commands/cmd_sprite_size.cpp +++ b/src/app/commands/cmd_sprite_size.cpp @@ -20,7 +20,9 @@ #include "config.h" #endif +#include "app/commands/cmd_sprite_size.h" #include "app/commands/command.h" +#include "app/commands/params.h" #include "app/context_access.h" #include "app/document_api.h" #include "app/find_widget.h" @@ -159,34 +161,48 @@ protected: }; -class SpriteSizeCommand : public Command { -public: - SpriteSizeCommand(); - Command* clone() const override { return new SpriteSizeCommand(*this); } - -protected: - bool onEnabled(Context* context); - void onExecute(Context* context); - -private: - void onLockRatioClick(); - void onWidthPxChange(); - void onHeightPxChange(); - void onWidthPercChange(); - void onHeightPercChange(); - - CheckBox* m_lockRatio; - Entry* m_widthPx; - Entry* m_heightPx; - Entry* m_widthPerc; - Entry* m_heightPerc; -}; - SpriteSizeCommand::SpriteSizeCommand() : Command("SpriteSize", "Sprite Size", CmdRecordableFlag) { + m_width = 0; + m_height = 0; + m_scaleX = 1.0; + m_scaleY = 1.0; + m_resizeMethod = raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR; +} + +Command* SpriteSizeCommand::clone() const +{ + return new SpriteSizeCommand(*this); +} + +void SpriteSizeCommand::onLoadParams(Params* params) +{ + std::string width = params->get("width"); + if (!width.empty()) { + m_width = std::strtol(width.c_str(), NULL, 10); + } + else + m_width = 0; + + std::string height = params->get("height"); + if (!height.empty()) { + m_height = std::strtol(height.c_str(), NULL, 10); + } + else + m_height = 0; + + std::string resize_method = params->get("resize-method"); + if (!resize_method.empty()) { + if (resize_method == "bilinear") + m_resizeMethod = raster::algorithm::RESIZE_METHOD_BILINEAR; + else + m_resizeMethod = raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR; + } + else + m_resizeMethod = raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR; } bool SpriteSizeCommand::onEnabled(Context* context) @@ -197,58 +213,63 @@ bool SpriteSizeCommand::onEnabled(Context* context) void SpriteSizeCommand::onExecute(Context* context) { - const ContextReader reader(UIContext::instance()); // TODO use the context in sprite size command + const ContextReader reader(context); const Sprite* sprite(reader.sprite()); - - // load the window widget - base::UniquePtr<Window> window(app::load_widget<Window>("sprite_size.xml", "sprite_size")); - m_widthPx = app::find_widget<Entry>(window, "width_px"); - m_heightPx = app::find_widget<Entry>(window, "height_px"); - m_widthPerc = app::find_widget<Entry>(window, "width_perc"); - m_heightPerc = app::find_widget<Entry>(window, "height_perc"); - m_lockRatio = app::find_widget<CheckBox>(window, "lock_ratio"); - ComboBox* method = app::find_widget<ComboBox>(window, "method"); - Widget* ok = app::find_widget<Widget>(window, "ok"); - - m_widthPx->setTextf("%d", sprite->width()); - m_heightPx->setTextf("%d", sprite->height()); - - m_lockRatio->Click.connect(Bind<void>(&SpriteSizeCommand::onLockRatioClick, this)); - m_widthPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPxChange, this)); - m_heightPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPxChange, this)); - m_widthPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPercChange, this)); - m_heightPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPercChange, this)); - - method->addItem("Nearest-neighbor"); - method->addItem("Bilinear"); - method->setSelectedItemIndex(get_config_int("SpriteSize", "Method", - raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR)); - - window->remapWindow(); - window->centerWindow(); - - load_window_pos(window, "SpriteSize"); - window->setVisible(true); - window->openWindowInForeground(); - save_window_pos(window, "SpriteSize"); - - if (window->getKiller() == ok) { - int new_width = m_widthPx->getTextInt(); - int new_height = m_heightPx->getTextInt(); - ResizeMethod resize_method = - (ResizeMethod)method->getSelectedItemIndex(); + int new_width = (m_width ? m_width: sprite->width()*m_scaleX); + int new_height = (m_height ? m_height: sprite->height()*m_scaleY); + ResizeMethod resize_method = m_resizeMethod; + + if (context->isUiAvailable()) { + // load the window widget + base::UniquePtr<Window> window(app::load_widget<Window>("sprite_size.xml", "sprite_size")); + m_widthPx = app::find_widget<Entry>(window, "width_px"); + m_heightPx = app::find_widget<Entry>(window, "height_px"); + m_widthPerc = app::find_widget<Entry>(window, "width_perc"); + m_heightPerc = app::find_widget<Entry>(window, "height_perc"); + m_lockRatio = app::find_widget<CheckBox>(window, "lock_ratio"); + ComboBox* method = app::find_widget<ComboBox>(window, "method"); + Widget* ok = app::find_widget<Widget>(window, "ok"); + + m_widthPx->setTextf("%d", new_width); + m_heightPx->setTextf("%d", new_height); + + m_lockRatio->Click.connect(Bind<void>(&SpriteSizeCommand::onLockRatioClick, this)); + m_widthPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPxChange, this)); + m_heightPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPxChange, this)); + m_widthPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPercChange, this)); + m_heightPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPercChange, this)); + + method->addItem("Nearest-neighbor"); + method->addItem("Bilinear"); + method->setSelectedItemIndex(get_config_int("SpriteSize", "Method", + raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR)); + + window->remapWindow(); + window->centerWindow(); + + load_window_pos(window, "SpriteSize"); + window->setVisible(true); + window->openWindowInForeground(); + save_window_pos(window, "SpriteSize"); + + if (window->getKiller() != ok) + return; + + new_width = m_widthPx->getTextInt(); + new_height = m_heightPx->getTextInt(); + resize_method = (ResizeMethod)method->getSelectedItemIndex(); set_config_int("SpriteSize", "Method", resize_method); + } - { - SpriteSizeJob job(reader, new_width, new_height, resize_method); - job.startJob(); - job.waitJob(); - } - - ContextWriter writer(reader); - update_screen_for_document(writer.document()); + { + SpriteSizeJob job(reader, new_width, new_height, resize_method); + job.startJob(); + job.waitJob(); } + + ContextWriter writer(reader); + update_screen_for_document(writer.document()); } void SpriteSizeCommand::onLockRatioClick() diff --git a/src/app/commands/cmd_sprite_size.h b/src/app/commands/cmd_sprite_size.h new file mode 100644 index 0000000..11887c6 --- /dev/null +++ b/src/app/commands/cmd_sprite_size.h @@ -0,0 +1,72 @@ +/* Aseprite + * Copyright (C) 2001-2014 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef APP_COMMANDS_CMD_SPRITE_SIZE_H_INCLUDED +#define APP_COMMANDS_CMD_SPRITE_SIZE_H_INCLUDED +#pragma once + +#include "app/commands/command.h" +#include "raster/algorithm/resize_image.h" + +#include <string> + +namespace ui { + class CheckBox; + class Entry; +} + +namespace app { + + class SpriteSizeCommand : public Command { + public: + SpriteSizeCommand(); + Command* clone() const override; + + void setScale(double x, double y) { + m_scaleX = x; + m_scaleY = y; + } + + protected: + virtual void onLoadParams(Params* params) override; + virtual bool onEnabled(Context* context) override; + virtual void onExecute(Context* context) override; + + private: + void onLockRatioClick(); + void onWidthPxChange(); + void onHeightPxChange(); + void onWidthPercChange(); + void onHeightPercChange(); + + ui::CheckBox* m_lockRatio; + ui::Entry* m_widthPx; + ui::Entry* m_heightPx; + ui::Entry* m_widthPerc; + ui::Entry* m_heightPerc; + + int m_width; + int m_height; + double m_scaleX; + double m_scaleY; + raster::algorithm::ResizeMethod m_resizeMethod; + }; + +} // namespace app + +#endif diff --git a/src/app/document_exporter.cpp b/src/app/document_exporter.cpp index e5c4626..0034748 100644 --- a/src/app/document_exporter.cpp +++ b/src/app/document_exporter.cpp @@ -35,6 +35,7 @@ #include "raster/image.h" #include "raster/layer.h" #include "raster/palette.h" +#include "raster/primitives.h" #include "raster/sprite.h" #include "raster/stock.h" @@ -48,16 +49,18 @@ namespace app { class DocumentExporter::Sample { public: - Sample(Document* document, Sprite* sprite, + Sample(Document* document, Sprite* sprite, Layer* layer, FrameNumber frame, const std::string& filename) : m_document(document), m_sprite(sprite), + m_layer(layer), m_frame(frame), m_filename(filename) { } Document* document() const { return m_document; } Sprite* sprite() const { return m_sprite; } + Layer* layer() const { return m_layer; } FrameNumber frame() const { return m_frame; } std::string filename() const { return m_filename; } const gfx::Size& originalSize() const { return m_originalSize; } @@ -78,6 +81,7 @@ public: private: Document* m_document; Sprite* m_sprite; + Layer* m_layer; FrameNumber m_frame; std::string m_filename; gfx::Size m_originalSize; @@ -117,27 +121,29 @@ class DocumentExporter::SimpleLayoutSamples : public: void layoutSamples(Samples& samples) override { const Sprite* oldSprite = NULL; + const Layer* oldLayer = NULL; gfx::Point framePt(0, 0); - for (Samples::iterator it=samples.begin(), end=samples.end(); - it != end; ++it) { - const Sprite* sprite = it->sprite(); + for (auto& sample : samples) { + const Sprite* sprite = sample.sprite(); + const Layer* layer = sample.layer(); gfx::Size size(sprite->width(), sprite->height()); - it->setOriginalSize(size); - it->setTrimmedBounds(gfx::Rect(gfx::Point(0, 0), size)); - it->setInTextureBounds(gfx::Rect(framePt, size)); - - // All frames of each sprite in one row. - if (oldSprite != NULL && oldSprite != it->sprite()) { + // New sprite or layer, go to next row. + if (oldSprite && (oldSprite != sprite || oldLayer != layer)) { framePt.x = 0; framePt.y += size.h; } - else { - framePt.x += size.w; - } - oldSprite = it->sprite(); + sample.setOriginalSize(size); + sample.setTrimmedBounds(gfx::Rect(gfx::Point(0, 0), size)); + sample.setInTextureBounds(gfx::Rect(framePt, size)); + + // Next frame position. + framePt.x += size.w; + + oldSprite = sprite; + oldLayer = layer; } } }; @@ -174,7 +180,8 @@ void DocumentExporter::exportSheet() createEmptyTexture(samples)); Sprite* texture = textureDocument->sprite(); - Image* textureImage = static_cast<LayerImage*>(texture->folder()->getFirstLayer()) + Image* textureImage = static_cast<LayerImage*>( + texture->folder()->getFirstLayer()) ->getCel(FrameNumber(0))->image(); renderTexture(samples, textureImage); @@ -193,15 +200,14 @@ void DocumentExporter::captureSamples(Samples& samples) { std::vector<char> buf(32); - for (std::vector<Document*>::iterator - it = m_documents.begin(), - end = m_documents.end(); it != end; ++it) { - Document* document = *it; - Sprite* sprite = document->sprite(); - + for (auto& item : m_documents) { + Document* doc = item.doc; + Sprite* sprite = doc->sprite(); + Layer* layer = item.layer; + for (FrameNumber frame=FrameNumber(0); frame<sprite->totalFrames(); ++frame) { - std::string filename = document->filename(); + std::string filename = doc->filename(); if (sprite->totalFrames() > FrameNumber(1)) { int frameNumWidth = @@ -212,11 +218,16 @@ void DocumentExporter::captureSamples(Samples& samples) std::string path = base::get_file_path(filename); std::string title = base::get_file_title(filename); + if (layer) { + title += "-"; + title += layer->name(); + } + std::string ext = base::get_file_extension(filename); filename = base::join_path(path, title + &buf[0] + "." + ext); } - samples.addSample(Sample(document, sprite, frame, filename)); + samples.addSample(Sample(doc, sprite, layer, frame, filename)); } } } @@ -268,21 +279,26 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage { textureImage->clear(0); - for (Samples::const_iterator - it = samples.begin(), - end = samples.end(); it != end; ++it) { + for (const auto& sample : samples) { // Make the sprite compatible with the texture so the render() // works correctly. - if (it->sprite()->pixelFormat() != textureImage->pixelFormat()) { - DocumentApi docApi(it->document(), NULL); // DocumentApi without undo - docApi.setPixelFormat(it->sprite(), textureImage->pixelFormat(), + if (sample.sprite()->pixelFormat() != textureImage->pixelFormat()) { + DocumentApi docApi(sample.document(), NULL); // DocumentApi without undo + docApi.setPixelFormat( + sample.sprite(), + textureImage->pixelFormat(), DITHERING_NONE); } - it->sprite()->render(textureImage, - it->inTextureBounds().x - it->trimmedBounds().x, - it->inTextureBounds().y - it->trimmedBounds().y, - it->frame()); + int x = sample.inTextureBounds().x - sample.trimmedBounds().x; + int y = sample.inTextureBounds().y - sample.trimmedBounds().y; + + if (sample.layer()) { + layer_render(sample.layer(), textureImage, x, y, sample.frame()); + } + else { + sample.sprite()->render(textureImage, x, y, sample.frame()); + } } } @@ -292,18 +308,19 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os, for (Samples::const_iterator it = samples.begin(), end = samples.end(); it != end; ) { - gfx::Size srcSize = it->originalSize(); - gfx::Rect spriteSourceBounds = it->trimmedBounds(); - gfx::Rect frameBounds = it->inTextureBounds(); + const Sample& sample = *it; + gfx::Size srcSize = sample.originalSize(); + gfx::Rect spriteSourceBounds = sample.trimmedBounds(); + gfx::Rect frameBounds = sample.inTextureBounds(); - os << " \"" << it->filename() << "\": {\n" + os << " \"" << sample.filename() << "\": {\n" << " \"frame\": { " << "\"x\": " << frameBounds.x << ", " << "\"y\": " << frameBounds.y << ", " << "\"w\": " << frameBounds.w << ", " << "\"h\": " << frameBounds.h << " },\n" << " \"rotated\": false,\n" - << " \"trimmed\": " << (it->trimmed() ? "true": "false") << ",\n" + << " \"trimmed\": " << (sample.trimmed() ? "true": "false") << ",\n" << " \"spriteSourceSize\": { " << "\"x\": " << spriteSourceBounds.x << ", " << "\"y\": " << spriteSourceBounds.y << ", " @@ -312,7 +329,7 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os, << " \"sourceSize\": { " << "\"w\": " << srcSize.w << ", " << "\"h\": " << srcSize.h << " },\n" - << " \"duration\": " << it->sprite()->getFrameDuration(it->frame()) << "\n" + << " \"duration\": " << sample.sprite()->getFrameDuration(sample.frame()) << "\n" << " }"; if (++it != samples.end()) diff --git a/src/app/document_exporter.h b/src/app/document_exporter.h index 434478c..df7e097 100644 --- a/src/app/document_exporter.h +++ b/src/app/document_exporter.h @@ -29,6 +29,7 @@ namespace raster { class Image; + class Layer; } namespace app { @@ -53,7 +54,8 @@ namespace app { DocumentExporter() : m_dataFormat(DefaultDataFormat), m_textureFormat(DefaultTextureFormat), - m_scaleMode(DefaultScaleMode) { + m_scaleMode(DefaultScaleMode), + m_scale(1.0) { } void setDataFormat(DataFormat format) { @@ -80,8 +82,8 @@ namespace app { m_scaleMode = mode; } - void addDocument(Document* document) { - m_documents.push_back(document); + void addDocument(Document* document, raster::Layer* layer = NULL) { + m_documents.push_back(Item(document, layer)); } void exportSheet(); @@ -97,13 +99,23 @@ namespace app { void renderTexture(const Samples& samples, raster::Image* textureImage); void createDataFile(const Samples& samples, std::ostream& os, raster::Image* textureImage); + class Item { + public: + Document* doc; + raster::Layer* layer; + Item(Document* doc, raster::Layer* layer) + : doc(doc), layer(layer) { + } + }; + typedef std::vector<Item> Items; + DataFormat m_dataFormat; std::string m_dataFilename; TextureFormat m_textureFormat; std::string m_textureFilename; double m_scale; ScaleMode m_scaleMode; - std::vector<Document*> m_documents; + Items m_documents; DISABLE_COPYING(DocumentExporter); }; diff --git a/src/app/job.cpp b/src/app/job.cpp index 1ea0472..51640c7 100644 --- a/src/app/job.cpp +++ b/src/app/job.cpp @@ -22,6 +22,7 @@ #include "app/job.h" +#include "app/app.h" #include "app/ui/status_bar.h" #include "base/mutex.h" #include "base/scoped_lock.h" @@ -34,7 +35,7 @@ static const int kMonitoringPeriod = 100; namespace app { -Job::Job(const char* job_name) +Job::Job(const char* jobName) { m_mutex = NULL; m_thread = NULL; @@ -44,24 +45,29 @@ Job::Job(const char* job_name) m_canceled_flag = false; m_mutex = new base::mutex(); - m_progress = StatusBar::instance()->addProgress(); - m_alert_window = ui::Alert::create("%s<<Working...||&Cancel", job_name); - m_timer.reset(new ui::Timer(kMonitoringPeriod, m_alert_window)); - m_timer->Tick.connect(&Job::onMonitoringTick, this); - m_timer->start(); + if (App::instance()->isGui()) { + m_progress = StatusBar::instance()->addProgress(); + m_alert_window = ui::Alert::create("%s<<Working...||&Cancel", jobName); + + m_timer.reset(new ui::Timer(kMonitoringPeriod, m_alert_window)); + m_timer->Tick.connect(&Job::onMonitoringTick, this); + m_timer->start(); + } } Job::~Job() { - ASSERT(!m_timer->isRunning()); - ASSERT(m_thread == NULL); + if (App::instance()->isGui()) { + ASSERT(!m_timer->isRunning()); + ASSERT(m_thread == NULL); - if (m_alert_window != NULL) - m_alert_window->closeWindow(NULL); + if (m_alert_window != NULL) + m_alert_window->closeWindow(NULL); - if (m_progress) - delete m_progress; + if (m_progress) + delete m_progress; + } if (m_mutex) delete m_mutex; @@ -70,19 +76,22 @@ Job::~Job() void Job::startJob() { m_thread = new base::thread(&Job::thread_proc, this); - m_alert_window->openWindowInForeground(); - // The job was canceled by the user? - { - base::scoped_lock hold(*m_mutex); - if (!m_done_flag) - m_canceled_flag = true; + if (m_alert_window) { + m_alert_window->openWindowInForeground(); + + // The job was canceled by the user? + { + base::scoped_lock hold(*m_mutex); + if (!m_done_flag) + m_canceled_flag = true; + } } } void Job::waitJob() { - if (m_timer->isRunning()) + if (m_timer && m_timer->isRunning()) m_timer->stop(); if (m_thread) { diff --git a/src/app/job.h b/src/app/job.h index 61fac80..a1067dc 100644 --- a/src/app/job.h +++ b/src/app/job.h @@ -34,7 +34,7 @@ namespace app { class Job { public: - Job(const char* job_name); + Job(const char* jobName); virtual ~Job(); // Starts the job calling onJob() event in another thread and diff --git a/src/app/modules/gui.cpp b/src/app/modules/gui.cpp index d307d07..f6617f9 100644 --- a/src/app/modules/gui.cpp +++ b/src/app/modules/gui.cpp @@ -228,7 +228,8 @@ void update_screen_for_document(Document* document) // Well, change to the default palette. if (set_current_palette(NULL, false)) { // If the palette changes, refresh the whole screen. - Manager::getDefault()->invalidate(); + if (Manager::getDefault()) + Manager::getDefault()->invalidate(); } } // With a document. diff --git a/src/app/ui_context.cpp b/src/app/ui_context.cpp index ba6cf86..13c46cd 100644 --- a/src/app/ui_context.cpp +++ b/src/app/ui_context.cpp @@ -22,6 +22,7 @@ #include "app/app.h" #include "app/document.h" +#include "app/document_location.h" #include "app/modules/editors.h" #include "app/settings/ui_settings_impl.h" #include "app/ui/color_bar.h" @@ -167,6 +168,10 @@ void UIContext::onRemoveDocument(doc::Document* doc) { Context::onRemoveDocument(doc); + // We don't destroy views in batch mode. + if (!isUiAvailable()) + return; + Workspace* workspace = App::instance()->getMainWindow()->getWorkspace(); DocumentViews docViews; @@ -190,8 +195,16 @@ void UIContext::onRemoveDocument(doc::Document* doc) void UIContext::onGetActiveLocation(DocumentLocation* location) const { DocumentView* view = activeView(); - if (view) + if (view) { view->getDocumentLocation(location); + } + // Default/dummy location (maybe for batch/command line mode) + else if (Document* doc = activeDocument()) { + location->document(doc); + location->sprite(doc->sprite()); + location->layer(doc->sprite()->indexToLayer(LayerIndex(0))); + location->frame(FrameNumber(0)); + } } } // namespace app diff --git a/src/base/program_options.cpp b/src/base/program_options.cpp index 1ef589a..addc4d7 100644 --- a/src/base/program_options.cpp +++ b/src/base/program_options.cpp @@ -192,8 +192,8 @@ std::ostream& operator<<(std::ostream& os, const base::ProgramOptions& po) it=po.options().begin(), end=po.options().end(); it != end; ++it) { const base::ProgramOptions::Option* option = *it; size_t optionWidth = - std::min<int>(26, 6+option->name().size()+1+ - (option->doesRequireValue() ? option->getValueName().size()+1: 0)); + 6+option->name().size()+1+ + (option->doesRequireValue() ? option->getValueName().size()+1: 0); if (maxOptionWidth < optionWidth) maxOptionWidth = optionWidth; diff --git a/src/doc/documents.h b/src/doc/documents.h index 248f8cd..f589dd7 100644 --- a/src/doc/documents.h +++ b/src/doc/documents.h @@ -35,6 +35,7 @@ namespace doc { Document* front() const { return m_docs.front(); } Document* back() const { return m_docs.back(); } + Document* lastAdded() const { return front(); } int size() const { return m_docs.size(); } bool empty() const { return m_docs.empty(); } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git _______________________________________________ Pkg-games-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-games-commits

