lua: Add app.preferences object

This commit is contained in:
David Capello 2019-04-24 21:14:20 -03:00
parent ad1a0af752
commit 0264964c4e
8 changed files with 385 additions and 0 deletions

View File

@ -345,6 +345,7 @@
<option id="filled_preview" type="bool" default="false" />
<option id="ink" type="app::tools::InkType" default="app::tools::InkType::DEFAULT" />
<option id="freehand_algorithm" type="app::tools::FreehandAlgorithm" default="app::tools::FreehandAlgorithm::DEFAULT" />
<!-- Update app::Preferences::resetToolPreferences() function if you add new sections here -->
<section id="brush">
<option id="type" type="BrushType" default="BrushType::CIRCLE" />
<option id="size" type="int" default="1" />

View File

@ -170,6 +170,7 @@ if(ENABLE_SCRIPTING)
script/palettes_class.cpp
script/pixel_color_object.cpp
script/point_class.cpp
script/preferences_object.cpp
script/range_class.cpp
script/rectangle_class.cpp
script/security.cpp
@ -183,6 +184,7 @@ if(ENABLE_SCRIPTING)
script/tag_class.cpp
script/tags_class.cpp
script/tool_class.cpp
script/values.cpp
script/version_class.cpp
shell.cpp
${scripting_files_ui})

View File

@ -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
@ -11,6 +12,10 @@
#include "obs/signal.h"
#include <string>
#ifdef ENABLE_SCRIPTING
#include "app/script/values.h"
#endif
namespace app {
class OptionBase;
@ -40,6 +45,12 @@ namespace app {
virtual ~OptionBase() { }
const char* section() const { return m_section->name(); }
const char* id() const { return m_id; }
#ifdef ENABLE_SCRIPTING
virtual void pushLua(lua_State* L) = 0;
virtual void fromLua(lua_State* L, int index) = 0;
#endif
protected:
Section* m_section;
const char* m_id;
@ -104,6 +115,15 @@ namespace app {
m_section->AfterChange();
}
#ifdef ENABLE_SCRIPTING
void pushLua(lua_State* L) override {
script::push_value_to_lua<T>(L, m_value);
}
void fromLua(lua_State* L, int index) override {
setValue(script::get_value_from_lua<T>(L, index));
}
#endif
obs::signal<void(const T&)> BeforeChange;
obs::signal<void(const T&)> AfterChange;

View File

@ -158,6 +158,12 @@ void Preferences::resetToolPreferences(tools::Tool* tool)
std::string section = std::string("tool.") + tool->getId();
del_config_section(section.c_str());
// TODO improve this, if we add new sections in pref.xml we have to
// update this manually :(
del_config_section((section + ".brush").c_str());
del_config_section((section + ".spray").c_str());
del_config_section((section + ".floodfill").c_str());
}
void Preferences::removeDocument(Doc* doc)

View File

@ -135,6 +135,7 @@ int unsupported(lua_State* L)
void register_app_object(lua_State* L);
void register_app_pixel_color_object(lua_State* L);
void register_app_command_object(lua_State* L);
void register_app_preferences_object(lua_State* L);
void register_brush_class(lua_State* L);
void register_cel_class(lua_State* L);
@ -231,6 +232,7 @@ Engine::Engine()
register_app_object(L);
register_app_pixel_color_object(L);
register_app_command_object(L);
register_app_preferences_object(L);
// Register constants
lua_newtable(L);

View File

@ -0,0 +1,152 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017-2018 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/app.h"
#include "app/doc.h"
#include "app/pref/option.h"
#include "app/pref/preferences.h"
#include "app/script/docobj.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "doc/sprite.h"
#include <cstring>
namespace app {
namespace script {
namespace {
struct AppPreferences { };
int Section_index(lua_State* L)
{
Section* section = get_ptr<Section>(L, 1);
const char* id = lua_tostring(L, 2);
if (!id)
return luaL_error(L, "optionName in 'app.preferences.%s.optionName' must be a string",
section->name());
OptionBase* option = section->option(id);
if (!option) {
Section* subSection = section->section(
(section->name() && *section->name() ? std::string(section->name()) + "." + id:
std::string(id)).c_str());
if (subSection) {
push_ptr(L, subSection);
return 1;
}
return luaL_error(L, "option '%s' in section '%s' doesn't exist", id, section->name());
}
option->pushLua(L);
return 1;
}
int Section_newindex(lua_State* L)
{
Section* section = get_ptr<Section>(L, 1);
const char* id = lua_tostring(L, 2);
if (!id)
return luaL_error(L, "optionName in 'app.preferences.%s.optionName' must be a string",
section->name());
OptionBase* option = section->option(id);
if (!option)
return luaL_error(L, "option '%s' in section '%s' doesn't exist",
id, section->name());
option->fromLua(L, 3);
return 0;
}
int ToolPref_function(lua_State* L)
{
auto tool = get_tool_from_arg(L, 1);
if (!tool)
return luaL_error(L, "tool preferences not found");
// If we don't have the UI available, we reset the tools
// preferences, so scripts that are executed in batch mode have a
// reproducible behavior.
if (!App::instance()->isGui())
Preferences::instance().resetToolPreferences(tool);
ToolPreferences& toolPref = Preferences::instance().tool(tool);
push_ptr(L, (Section*)&toolPref);
return 1;
}
int DocPref_function(lua_State* L)
{
auto sprite = get_docobj<Sprite>(L, 1);
DocumentPreferences& docPref =
Preferences::instance().document(
static_cast<const Doc*>(sprite->document()));
push_ptr(L, (Section*)&docPref);
return 1;
}
int AppPreferences_index(lua_State* L)
{
const char* id = lua_tostring(L, 2);
if (!id)
return luaL_error(L, "id in 'app.preferences.id' must be a string");
if (std::strcmp(id, "tool") == 0) {
lua_pushcfunction(L, ToolPref_function);
return 1;
}
else if (std::strcmp(id, "document") == 0) {
lua_pushcfunction(L, DocPref_function);
return 1;
}
Section* section = Preferences::instance().section(id);
if (!section)
return luaL_error(L, "section '%s' in preferences doesn't exist", id);
push_ptr(L, section);
return 1;
}
const luaL_Reg Section_methods[] = {
{ "__index", Section_index },
{ "__newindex", Section_newindex },
{ nullptr, nullptr }
};
const luaL_Reg AppPreferences_methods[] = {
{ "__index", AppPreferences_index },
{ nullptr, nullptr }
};
} // anonymous namespace
DEF_MTNAME(Section);
DEF_MTNAME(AppPreferences);
void register_app_preferences_object(lua_State* L)
{
REG_CLASS(L, Section);
REG_CLASS(L, AppPreferences);
lua_getglobal(L, "app");
lua_pushstring(L, "preferences");
push_new<AppPreferences>(L);
lua_rawset(L, -3);
lua_pop(L, 1);
}
} // namespace script
} // namespace app

173
src/app/script/values.cpp Normal file
View File

@ -0,0 +1,173 @@
// 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/script/values.h"
#include "app/pref/preferences.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
namespace app {
namespace script {
// TODO this is similar to app::Param<> specializations::fromLua() specializations
// ----------------------------------------------------------------------
// bool
template<>
void push_value_to_lua(lua_State* L, const bool& value) {
lua_pushboolean(L, value);
}
template<>
bool get_value_from_lua(lua_State* L, int index) {
return lua_toboolean(L, index);
}
// ----------------------------------------------------------------------
// int
template<>
void push_value_to_lua(lua_State* L, const int& value) {
lua_pushinteger(L, value);
}
template<>
int get_value_from_lua(lua_State* L, int index) {
return lua_tointeger(L, index);
}
// ----------------------------------------------------------------------
// double
template<>
void push_value_to_lua(lua_State* L, const double& value) {
lua_pushnumber(L, value);
}
template<>
double get_value_from_lua(lua_State* L, int index) {
return lua_tonumber(L, index);
}
// ----------------------------------------------------------------------
// std::string
template<>
void push_value_to_lua(lua_State* L, const std::string& value) {
lua_pushstring(L, value.c_str());
}
template<>
std::string get_value_from_lua(lua_State* L, int index) {
if (const char* v = lua_tostring(L, index))
return std::string(v);
else
return std::string();
}
// ----------------------------------------------------------------------
// Color
template<>
void push_value_to_lua(lua_State* L, const app::Color& value) {
push_obj(L, value);
}
template<>
app::Color get_value_from_lua(lua_State* L, int index) {
return convert_args_into_color(L, index);
}
// ----------------------------------------------------------------------
// Point
template<>
void push_value_to_lua(lua_State* L, const gfx::Point& value) {
push_obj(L, value);
}
template<>
gfx::Point get_value_from_lua(lua_State* L, int index) {
return convert_args_into_point(L, index);
}
// ----------------------------------------------------------------------
// Size
template<>
void push_value_to_lua(lua_State* L, const gfx::Size& value) {
push_obj(L, value);
}
template<>
gfx::Size get_value_from_lua(lua_State* L, int index) {
return convert_args_into_size(L, index);
}
// ----------------------------------------------------------------------
// Rect
template<>
void push_value_to_lua(lua_State* L, const gfx::Rect& value) {
push_obj(L, value);
}
template<>
gfx::Rect get_value_from_lua(lua_State* L, int index) {
return convert_args_into_rect(L, index);
}
// ----------------------------------------------------------------------
// enums
#define FOR_ENUM(T) \
template<> \
void push_value_to_lua(lua_State* L, const T& value) { \
lua_pushinteger(L, static_cast<int>(value)); \
} \
\
template<> \
T get_value_from_lua(lua_State* L, int index) { \
return static_cast<T>(lua_tointeger(L, index)); \
}
FOR_ENUM(app::CelsTarget)
FOR_ENUM(app::ColorBar::ColorSelector)
FOR_ENUM(app::DocExporter::DataFormat)
FOR_ENUM(app::SpriteSheetType)
FOR_ENUM(app::gen::BgType)
FOR_ENUM(app::gen::BrushPreview)
FOR_ENUM(app::gen::BrushType)
FOR_ENUM(app::gen::ColorProfileBehavior)
FOR_ENUM(app::gen::EyedropperChannel)
FOR_ENUM(app::gen::EyedropperSample)
FOR_ENUM(app::gen::FillReferTo)
FOR_ENUM(app::gen::HueSaturationMode)
FOR_ENUM(app::gen::OnionskinType)
FOR_ENUM(app::gen::PaintingCursorType)
FOR_ENUM(app::gen::PivotPosition)
FOR_ENUM(app::gen::RightClickMode)
FOR_ENUM(app::gen::SelectionMode)
FOR_ENUM(app::gen::StopAtGrid)
FOR_ENUM(app::gen::SymmetryMode)
FOR_ENUM(app::gen::TimelinePosition)
FOR_ENUM(app::tools::FreehandAlgorithm)
FOR_ENUM(app::tools::InkType)
FOR_ENUM(app::tools::RotationAlgorithm)
FOR_ENUM(doc::AniDir)
FOR_ENUM(doc::BrushPattern)
FOR_ENUM(doc::ColorMode)
FOR_ENUM(filters::TiledMode)
FOR_ENUM(render::OnionskinPosition)
} // namespace script
} // namespace app

29
src/app/script/values.h Normal file
View File

@ -0,0 +1,29 @@
// 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_SCRIPT_VALUES_H_INCLUDED
#define APP_SCRIPT_VALUES_H_INCLUDED
#pragma once
#ifdef ENABLE_SCRIPTING
extern "C" struct lua_State;
namespace app {
namespace script {
template<typename T>
T get_value_from_lua(lua_State* L, int index);
template<typename T>
void push_value_to_lua(lua_State* L, const T& value);
} // namespace script
} // namespace app
#endif // ENABLE_SCRIPTING
#endif