From 4335f0c728e14a2fc8f7b25e989a422116034b81 Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 7 Jan 2019 16:42:55 -0300 Subject: [PATCH] Add CommandWithNewParams to load command parameters from Lua tables directly With these new classes (Param/NewParams/CommandWithNewParams(Base)) we can load parameters for commands from a Lua table directly without converting to a string. So instead of Lua value -> string -> C++ param type We can do Lua value -> C++ param type directly. --- src/app/CMakeLists.txt | 5 +- src/app/commands/cmd_export_sprite_sheet.cpp | 52 +++---- src/app/commands/commands_list.h | 4 +- src/app/commands/new_params.cpp | 62 ++++++++ src/app/commands/new_params.h | 145 +++++++++++++++++++ src/app/script/app_command_object.cpp | 25 ++-- 6 files changed, 249 insertions(+), 44 deletions(-) create mode 100644 src/app/commands/new_params.cpp create mode 100644 src/app/commands/new_params.h diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index c02686d06..86feff69b 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -194,7 +194,6 @@ if(ENABLE_UI) commands/cmd_add_color.cpp commands/cmd_advanced_mode.cpp commands/cmd_cancel.cpp - commands/cmd_canvas_size.cpp commands/cmd_cel_properties.cpp commands/cmd_change_brush.cpp commands/cmd_change_color.cpp @@ -213,7 +212,6 @@ if(ENABLE_UI) commands/cmd_duplicate_sprite.cpp commands/cmd_duplicate_view.cpp commands/cmd_exit.cpp - commands/cmd_export_sprite_sheet.cpp commands/cmd_eyedropper.cpp commands/cmd_fill_and_stroke.cpp commands/cmd_fit_screen.cpp @@ -506,9 +504,11 @@ add_library(app-lib color_spaces.cpp color_utils.cpp commands/cmd_background_from_layer.cpp + commands/cmd_canvas_size.cpp commands/cmd_cel_opacity.cpp commands/cmd_change_pixel_format.cpp commands/cmd_crop.cpp + commands/cmd_export_sprite_sheet.cpp commands/cmd_flatten_layers.cpp commands/cmd_layer_from_background.cpp commands/cmd_load_palette.cpp @@ -523,6 +523,7 @@ add_library(app-lib commands/command.cpp commands/commands.cpp commands/move_thing.cpp + commands/new_params.cpp commands/quick_command.cpp console.cpp context.cpp diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp index 4b6a6f0e3..3da00f4ea 100644 --- a/src/app/commands/cmd_export_sprite_sheet.cpp +++ b/src/app/commands/cmd_export_sprite_sheet.cpp @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -9,7 +10,7 @@ #endif #include "app/app.h" -#include "app/commands/command.h" +#include "app/commands/new_params.h" #include "app/context.h" #include "app/context_access.h" #include "app/doc.h" @@ -581,43 +582,26 @@ private: bool m_dataFilenameAskOverwrite; }; -class ExportSpriteSheetCommand : public Command { +struct ExportSpriteSheetParams : public NewParams { + Param ui { this, true, "ui" }; + Param askOverwrite { this, true, { "askOverwrite", "ask-overwrite" } }; +}; + +class ExportSpriteSheetCommand : public CommandWithNewParams { public: ExportSpriteSheetCommand(); Command* clone() const override { return new ExportSpriteSheetCommand(*this); } - void setUseUI(bool useUI) { m_useUI = useUI; } - protected: - void onLoadParams(const Params& params) override; bool onEnabled(Context* context) override; void onExecute(Context* context) override; - -private: - bool m_useUI; - bool m_askOverwrite; }; ExportSpriteSheetCommand::ExportSpriteSheetCommand() - : Command(CommandId::ExportSpriteSheet(), CmdRecordableFlag) - , m_useUI(true) - , m_askOverwrite(true) + : CommandWithNewParams(CommandId::ExportSpriteSheet(), CmdRecordableFlag) { } -void ExportSpriteSheetCommand::onLoadParams(const Params& params) -{ - if (params.has_param("ui")) - m_useUI = params.get_as("ui"); - else - m_useUI = true; - - if (params.has_param("ask-overwrite")) - m_askOverwrite = params.get_as("ask-overwrite"); - else - m_askOverwrite = true; -} - bool ExportSpriteSheetCommand::onEnabled(Context* context) { return context->checkFlags(ContextFlags::ActiveDocumentIsWritable); @@ -629,9 +613,10 @@ void ExportSpriteSheetCommand::onExecute(Context* context) Doc* document = site.document(); Sprite* sprite = site.sprite(); DocumentPreferences& docPref(Preferences::instance().document(document)); - bool askOverwrite = m_askOverwrite; - if (m_useUI && context->isUIAvailable()) { +#ifdef ENABLE_UI + bool askOverwrite = params().askOverwrite(); + if (params().ui() && context->isUIAvailable()) { ExportSpriteSheetWindow window(site, docPref); window.openWindowInForeground(); if (!window.ok()) @@ -670,6 +655,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context) askOverwrite = false; // Already asked in the ExportSpriteSheetWindow } +#endif // ENABLE_UI app::SpriteSheetType type = docPref.spriteSheet.type(); int columns = docPref.spriteSheet.columns(); @@ -693,11 +679,13 @@ void ExportSpriteSheetCommand::onExecute(Context* context) const bool listFrameTags = docPref.spriteSheet.listFrameTags(); const bool listSlices = docPref.spriteSheet.listSlices(); +#ifdef ENABLE_UI if (context->isUIAvailable() && askOverwrite) { if (!ask_overwrite(true, filename, true, dataFilename)) return; // Do not overwrite } +#endif SelectedFrames selFrames; FrameTag* frameTag = @@ -781,9 +769,13 @@ void ExportSpriteSheetCommand::onExecute(Context* context) if (!newDocument) return; - StatusBar* statusbar = StatusBar::instance(); - if (statusbar) - statusbar->showTip(1000, "Sprite Sheet Generated"); +#ifdef ENABLE_UI + if (context->isUIAvailable()) { + StatusBar* statusbar = StatusBar::instance(); + if (statusbar) + statusbar->showTip(1000, "Sprite Sheet Generated"); + } +#endif // Copy background and grid preferences { diff --git a/src/app/commands/commands_list.h b/src/app/commands/commands_list.h index 82c01c20f..fdcced10c 100644 --- a/src/app/commands/commands_list.h +++ b/src/app/commands/commands_list.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -11,6 +11,7 @@ FOR_EACH_COMMAND(CanvasSize) FOR_EACH_COMMAND(CelOpacity) FOR_EACH_COMMAND(ChangePixelFormat) FOR_EACH_COMMAND(CropSprite) +FOR_EACH_COMMAND(ExportSpriteSheet) FOR_EACH_COMMAND(FlattenLayers) FOR_EACH_COMMAND(LayerFromBackground) FOR_EACH_COMMAND(LoadPalette) @@ -54,7 +55,6 @@ FOR_EACH_COMMAND(DuplicateLayer) FOR_EACH_COMMAND(DuplicateSprite) FOR_EACH_COMMAND(DuplicateView) FOR_EACH_COMMAND(Exit) -FOR_EACH_COMMAND(ExportSpriteSheet) FOR_EACH_COMMAND(Eyedropper) FOR_EACH_COMMAND(Fill) FOR_EACH_COMMAND(FitScreen) diff --git a/src/app/commands/new_params.cpp b/src/app/commands/new_params.cpp new file mode 100644 index 000000000..59f559c9c --- /dev/null +++ b/src/app/commands/new_params.cpp @@ -0,0 +1,62 @@ +// Aseprite +// Copyright (C) 2019 Igara Studio S.A. +// +// 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/commands/new_params.h" + +#include "app/script/luacpp.h" + +namespace app { + +template<> +void Param::fromString(const std::string& value) +{ + m_value = (value == "1" || value == "true"); +} + +#ifdef ENABLE_SCRIPTING + +template<> +void Param::fromLua(lua_State* L, int index) +{ + m_value = lua_toboolean(L, index); +} + +void CommandWithNewParamsBase::onLoadParams(const Params& params) +{ + if (m_skipLoadParams) { + m_skipLoadParams = false; + return; + } + onResetValues(); + for (const auto& pair : params) { + if (ParamBase* p = onGetParam(pair.first)) + p->fromString(pair.second); + } +} + +void CommandWithNewParamsBase::loadParamsFromLuaTable(lua_State* L, int index) +{ + onResetValues(); + if (lua_istable(L, index)) { + lua_pushnil(L); + while (lua_next(L, index) != 0) { + if (const char* k = lua_tostring(L, -2)) { + if (ParamBase* p = onGetParam(k)) + p->fromLua(L, -1); + } + lua_pop(L, 1); // Pop the value, leave the key + } + } + m_skipLoadParams = true; +} + +#endif + +} // namespace app diff --git a/src/app/commands/new_params.h b/src/app/commands/new_params.h new file mode 100644 index 000000000..3615a9983 --- /dev/null +++ b/src/app/commands/new_params.h @@ -0,0 +1,145 @@ +// Aseprite +// Copyright (C) 2019 Igara Studio S.A. +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifndef APP_COMMANDS_NEW_PARAMS_H +#define APP_COMMANDS_NEW_PARAMS_H + +#include "app/commands/command.h" +#include "app/commands/params.h" + +#include +#include +#include + +#ifdef ENABLE_SCRIPTING +extern "C" struct lua_State; +#endif + +namespace app { + + class ParamBase { + public: + virtual ~ParamBase() { } + virtual void resetValue() = 0; + virtual void fromString(const std::string& value) = 0; +#ifdef ENABLE_SCRIPTING + virtual void fromLua(lua_State* L, int index) = 0; +#endif + }; + + class NewParams { + public: + void addParam(const char* id, ParamBase* param) { + m_params[id] = param; + } + + void resetValues() { + for (auto& pair : m_params) + pair.second->resetValue(); + } + + ParamBase* getParam(const std::string& id) { + auto it = m_params.find(id); + if (it != m_params.end()) + return it->second; + else + return nullptr; + } + + private: + std::map m_params; + }; + + template + class Param : public ParamBase { + public: + Param(NewParams* params, + const T& defaultValue, + const char* id) + : m_defaultValue(defaultValue) + , m_value(defaultValue) { + if (id) + params->addParam(id, this); + } + + Param(NewParams* params, + const T& defaultValue, + const std::initializer_list ids) + : Param(params, defaultValue, nullptr) { + for (const auto& id : ids) + params->addParam(id, this); + } + + void resetValue() override { + m_value = m_defaultValue; + } + + void fromString(const std::string& value) override; +#ifdef ENABLE_SCRIPTING + void fromLua(lua_State* L, int index) override; +#endif + + const T& operator()() const { + return m_value; + } + + void operator()(const T& value) { + m_value = value; + } + + private: + T m_defaultValue; + T m_value; + }; + + class CommandWithNewParamsBase : public Command { + public: + template + CommandWithNewParamsBase(Args&&...args) + : Command(std::forward(args)...) { } + +#ifdef ENABLE_SCRIPTING + void loadParamsFromLuaTable(lua_State* L, int index); +#endif + + protected: + void onLoadParams(const Params& params) override; + + virtual void onResetValues() = 0; + virtual ParamBase* onGetParam(const std::string& k) = 0; + + private: +#ifdef ENABLE_SCRIPTING + bool m_skipLoadParams = false; +#endif + }; + + template + class CommandWithNewParams : public CommandWithNewParamsBase { + public: + template + CommandWithNewParams(Args&&...args) + : CommandWithNewParamsBase(std::forward(args)...) { } + + T& params() { + return m_params; + } + + private: + void onResetValues() override { + m_params.resetValues(); + } + + ParamBase* onGetParam(const std::string& k) override { + return m_params.getParam(k); + } + + T m_params; + }; + +} // namespace app + +#endif diff --git a/src/app/script/app_command_object.cpp b/src/app/script/app_command_object.cpp index 3e6828e8e..0d65a9b53 100644 --- a/src/app/script/app_command_object.cpp +++ b/src/app/script/app_command_object.cpp @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2018 David Capello // // This program is distributed under the terms of @@ -11,6 +12,7 @@ #include "app/app.h" #include "app/commands/command.h" #include "app/commands/commands.h" +#include "app/commands/new_params.h" #include "app/commands/params.h" #include "app/context.h" #include "app/script/luacpp.h" @@ -31,18 +33,21 @@ int Command_call(lua_State* L) auto command = get_ptr(L, 1); Params params; - if (lua_istable(L, 2)) { - lua_pushnil(L); - while (lua_next(L, 2) != 0) { - const char* k = lua_tostring(L, -2); - if (k) { - const char* v = luaL_tolstring(L, -1, nullptr); - if (v) { - params.set(k, v); + if (auto commandLua = dynamic_cast(command)) { + commandLua->loadParamsFromLuaTable(L, 2); + } + else { + if (lua_istable(L, 2)) { + lua_pushnil(L); + while (lua_next(L, 2) != 0) { + if (const char* k = lua_tostring(L, -2)) { + const char* v = luaL_tolstring(L, -1, nullptr); + if (v) + params.set(k, v); + lua_pop(L, 1); // pop the value generated by luaL_tolstring() } - lua_pop(L, 1); + lua_pop(L, 1); // pop the value lua_next(), leave the key in the stack } - lua_pop(L, 1); } }