mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-16 04:13:50 +00:00
[lua] Add access to user data properties in Sprite object (aseprite/api#88)
This is a basic implementation where we can only access basic properties (not maps or vectors yet).
This commit is contained in:
parent
c7864c9fac
commit
76a398b162
@ -191,6 +191,7 @@ if(ENABLE_SCRIPTING)
|
||||
script/plugin_class.cpp
|
||||
script/point_class.cpp
|
||||
script/preferences_object.cpp
|
||||
script/properties_class.cpp
|
||||
script/range_class.cpp
|
||||
script/rectangle_class.cpp
|
||||
script/security.cpp
|
||||
|
@ -176,6 +176,7 @@ void register_palette_class(lua_State* L);
|
||||
void register_palettes_class(lua_State* L);
|
||||
void register_plugin_class(lua_State* L);
|
||||
void register_point_class(lua_State* L);
|
||||
void register_properties_class(lua_State* L);
|
||||
void register_range_class(lua_State* L);
|
||||
void register_rect_class(lua_State* L);
|
||||
void register_selection_class(lua_State* L);
|
||||
@ -454,6 +455,7 @@ Engine::Engine()
|
||||
register_palettes_class(L);
|
||||
register_plugin_class(L);
|
||||
register_point_class(L);
|
||||
register_properties_class(L);
|
||||
register_range_class(L);
|
||||
register_rect_class(L);
|
||||
register_selection_class(L);
|
||||
|
@ -150,6 +150,7 @@ namespace app {
|
||||
void push_layers(lua_State* L, const doc::ObjectIds& layers);
|
||||
void push_palette(lua_State* L, doc::Palette* palette);
|
||||
void push_plugin(lua_State* L, Extension* ext);
|
||||
void push_properties(lua_State* L, doc::WithUserData* userData);
|
||||
void push_sprite_cel(lua_State* L, doc::Cel* cel);
|
||||
void push_sprite_events(lua_State* L, doc::Sprite* sprite);
|
||||
void push_sprite_frame(lua_State* L, doc::Sprite* sprite, doc::frame_t frame);
|
||||
@ -166,7 +167,6 @@ namespace app {
|
||||
void push_tileset_image(lua_State* L, doc::Tileset* tileset, doc::Image* image);
|
||||
void push_tilesets(lua_State* L, doc::Tilesets* tilesets);
|
||||
void push_tool(lua_State* L, app::tools::Tool* tool);
|
||||
void push_userdata(lua_State* L, doc::WithUserData* userData);
|
||||
void push_version(lua_State* L, const base::Version& ver);
|
||||
|
||||
gfx::Point convert_args_into_point(lua_State* L, int index);
|
||||
|
128
src/app/script/properties_class.cpp
Normal file
128
src/app/script/properties_class.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 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/docobj.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/script/values.h"
|
||||
#include "doc/with_user_data.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Properties {
|
||||
doc::ObjectId id = 0;
|
||||
Properties(doc::ObjectId id) : id(id) { }
|
||||
};
|
||||
|
||||
int Properties_index(lua_State* L)
|
||||
{
|
||||
auto propObj = get_obj<Properties>(L, 1);
|
||||
const char* field = lua_tostring(L, 2);
|
||||
if (!field)
|
||||
return luaL_error(L, "field in 'properties.field' must be a string");
|
||||
|
||||
auto obj = static_cast<doc::WithUserData*>(get_object(propObj->id));
|
||||
if (!obj)
|
||||
return luaL_error(L, "the object with these properties was destroyed");
|
||||
|
||||
auto& properties = obj->userData().properties();
|
||||
auto it = properties.find(field);
|
||||
if (it != properties.end()) {
|
||||
push_value_to_lua(L, (*it).second);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Properties_newindex(lua_State* L)
|
||||
{
|
||||
auto propObj = get_obj<Properties>(L, 1);
|
||||
const char* field = lua_tostring(L, 2);
|
||||
if (!field)
|
||||
return luaL_error(L, "field in 'properties.field' must be a string");
|
||||
|
||||
auto obj = static_cast<doc::WithUserData*>(get_object(propObj->id));
|
||||
if (!obj)
|
||||
return luaL_error(L, "the object with these properties was destroyed");
|
||||
|
||||
auto& properties = obj->userData().properties();
|
||||
|
||||
// TODO add undo information
|
||||
switch (lua_type(L, 3)) {
|
||||
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
default: {
|
||||
// Just erase the property
|
||||
auto it = properties.find(field);
|
||||
if (it != properties.end())
|
||||
properties.erase(it);
|
||||
break;
|
||||
}
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
properties[field] = (lua_toboolean(L, 3) ? true: false);
|
||||
break;
|
||||
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, 3))
|
||||
properties[field] = lua_tointeger(L, 3);
|
||||
else {
|
||||
properties[field] = doc::UserData::Fixed{
|
||||
fixmath::ftofix(lua_tonumber(L, 3))
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
properties[field] = lua_tostring(L, 3);
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
// TODO convert a full table into properties recursively
|
||||
break;
|
||||
|
||||
case LUA_TUSERDATA:
|
||||
// TODO convert table-like objects (Size, Point, Rectangle, etc.)
|
||||
break;
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg Properties_methods[] = {
|
||||
{ "__index", Properties_index },
|
||||
{ "__newindex", Properties_newindex },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
DEF_MTNAME(Properties);
|
||||
|
||||
void register_properties_class(lua_State* L)
|
||||
{
|
||||
REG_CLASS(L, Properties);
|
||||
}
|
||||
|
||||
void push_properties(lua_State* L, doc::WithUserData* userData)
|
||||
{
|
||||
push_obj<Properties>(L, userData->id());
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
@ -882,6 +882,7 @@ const Property Sprite_properties[] = {
|
||||
{ "gridBounds", Sprite_get_gridBounds, Sprite_set_gridBounds },
|
||||
{ "color", UserData_get_color<Sprite>, UserData_set_color<Sprite> },
|
||||
{ "data", UserData_get_text<Sprite>, UserData_set_text<Sprite> },
|
||||
{ "properties", UserData_get_properties<Sprite>, nullptr },
|
||||
{ "pixelRatio", Sprite_get_pixelRatio, Sprite_set_pixelRatio },
|
||||
{ "events", Sprite_get_events, nullptr },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
|
@ -51,6 +51,13 @@ int UserData_get_color(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int UserData_get_properties(lua_State* L) {
|
||||
auto obj = get_docobj<T>(L, 1);
|
||||
push_properties(L, get_WithUserData<T>(obj));
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int UserData_set_text(lua_State* L) {
|
||||
auto obj = get_docobj<T>(L, 1);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "doc/remap.h"
|
||||
|
||||
#include <any>
|
||||
#include <variant>
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
@ -39,9 +40,21 @@ bool get_value_from_lua(lua_State* L, int index) {
|
||||
// int
|
||||
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const int& value) {
|
||||
lua_pushinteger(L, value);
|
||||
}
|
||||
void push_value_to_lua(lua_State* L, const int8_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const int16_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const int32_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const int64_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const uint8_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const uint16_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const uint32_t& value) { lua_pushinteger(L, value); }
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const uint64_t& value) { lua_pushinteger(L, value); }
|
||||
|
||||
template<>
|
||||
int get_value_from_lua(lua_State* L, int index) {
|
||||
@ -61,6 +74,14 @@ double get_value_from_lua(lua_State* L, int index) {
|
||||
return lua_tonumber(L, index);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// fixed
|
||||
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const doc::UserData::Fixed& value) {
|
||||
lua_pushnumber(L, fixmath::fixtof(value.value));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// std::string
|
||||
|
||||
@ -193,10 +214,12 @@ app::tools::InkType get_value_from_lua(lua_State* L, int index) {
|
||||
// ----------------------------------------------------------------------
|
||||
// doc::tile_t
|
||||
|
||||
#if 0 // doc::tile_t matches uint32_t, and we have the uint32_t version already defined
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const doc::tile_t& value) {
|
||||
lua_pushinteger(L, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<>
|
||||
doc::tile_t get_value_from_lua(lua_State* L, int index) {
|
||||
@ -251,5 +274,23 @@ FOR_ENUM(filters::HueSaturationFilter::Mode)
|
||||
FOR_ENUM(filters::TiledMode)
|
||||
FOR_ENUM(render::OnionskinPosition)
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UserData::Properties / VariantStruct
|
||||
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const doc::UserData::Properties& value) {
|
||||
// TODO convert a Properties map into a Lua table
|
||||
}
|
||||
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const doc::UserData::Vector& value) {
|
||||
// TODO convert a Vector into a Lua table
|
||||
}
|
||||
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const doc::UserData::Variant& value) {
|
||||
std::visit([L](auto&& v){ push_value_to_lua(L, v); }, value);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
24
tests/scripts/userdata.lua
Normal file
24
tests/scripts/userdata.lua
Normal file
@ -0,0 +1,24 @@
|
||||
-- Copyright (C) 2022 Igara Studio S.A.
|
||||
--
|
||||
-- This file is released under the terms of the MIT license.
|
||||
-- Read LICENSE.txt for more information.
|
||||
|
||||
do
|
||||
local spr = Sprite(1, 1)
|
||||
|
||||
spr.properties.a = true
|
||||
spr.properties.b = 1
|
||||
spr.properties.c = "hi"
|
||||
spr.properties.d = 2.3
|
||||
assert(spr.properties.a == true)
|
||||
assert(spr.properties.b == 1)
|
||||
assert(spr.properties.c == "hi")
|
||||
-- TODO we don't have too much precision saving fixed points in properties
|
||||
assert(math.abs(spr.properties.d - 2.3) < 0.00001)
|
||||
|
||||
spr.properties.a = false
|
||||
assert(spr.properties.a == false)
|
||||
|
||||
spr.properties.b = nil
|
||||
assert(spr.properties.b == nil)
|
||||
end
|
Loading…
Reference in New Issue
Block a user