mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-10 12:44:53 +00:00
238 lines
6.2 KiB
C++
238 lines
6.2 KiB
C++
// Aseprite
|
|
// Copyright (C) 2022-2023 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/cmd/remove_user_data_property.h"
|
|
#include "app/cmd/set_user_data_properties.h"
|
|
#include "app/cmd/set_user_data_property.h"
|
|
#include "app/script/docobj.h"
|
|
#include "app/script/engine.h"
|
|
#include "app/script/luacpp.h"
|
|
#include "app/script/values.h"
|
|
#include "app/tx.h"
|
|
#include "doc/with_user_data.h"
|
|
|
|
#include <cstring>
|
|
|
|
namespace app {
|
|
namespace script {
|
|
|
|
namespace {
|
|
|
|
struct Properties {
|
|
doc::ObjectId id = 0;
|
|
std::string extID;
|
|
|
|
Properties(doc::ObjectId id,
|
|
const std::string& extID)
|
|
: id(id)
|
|
, extID(extID) {
|
|
}
|
|
};
|
|
|
|
using PropertiesIterator = doc::UserData::Properties::iterator;
|
|
|
|
int Properties_len(lua_State* L)
|
|
{
|
|
auto propObj = get_obj<Properties>(L, 1);
|
|
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(propObj->extID);
|
|
lua_pushinteger(L, properties.size());
|
|
return 1;
|
|
}
|
|
|
|
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(propObj->extID);
|
|
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(propObj->extID);
|
|
|
|
switch (lua_type(L, 3)) {
|
|
|
|
case LUA_TNONE:
|
|
case LUA_TNIL: {
|
|
// If we assign nil to a property, we just remove the property.
|
|
|
|
auto it = properties.find(field);
|
|
if (it != properties.end()) {
|
|
// TODO add Object::sprite() member function, and fix "Tx" object
|
|
// to use the sprite of this object instead of the activeDocument()
|
|
//if (obj->sprite()) {
|
|
if (App::instance()->context()->activeDocument()) {
|
|
Tx tx;
|
|
tx(new cmd::RemoveUserDataProperty(obj, propObj->extID, field));
|
|
tx.commit();
|
|
}
|
|
else {
|
|
properties.erase(it);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
auto newValue = get_value_from_lua<doc::UserData::Variant>(L, 3);
|
|
|
|
// TODO add Object::sprite() member function
|
|
//if (obj->sprite()) {
|
|
if (App::instance()->context()->activeDocument()) {
|
|
Tx tx;
|
|
tx(new cmd::SetUserDataProperty(obj, propObj->extID, field,
|
|
std::move(newValue)));
|
|
tx.commit();
|
|
}
|
|
else {
|
|
properties[field] = std::move(newValue);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Properties_call(lua_State* L)
|
|
{
|
|
auto propObj = get_obj<Properties>(L, 1);
|
|
const char* extID = lua_tostring(L, 2);
|
|
if (!extID)
|
|
return luaL_error(L, "extensionID in 'properties(\"extensionID\")' must be a string");
|
|
|
|
// Special syntax to change the full extension properties using:
|
|
//
|
|
// object.property("extension", { ...})
|
|
//
|
|
if (lua_istable(L, 3)) {
|
|
auto newProperties = get_value_from_lua<doc::UserData::Properties>(L, 3);
|
|
|
|
auto obj = static_cast<doc::WithUserData*>(get_object(propObj->id));
|
|
if (!obj)
|
|
return luaL_error(L, "the object with these properties was destroyed");
|
|
|
|
// TODO add Object::sprite() member function
|
|
//if (obj->sprite()) {
|
|
if (App::instance()->context()->activeDocument()) {
|
|
Tx tx;
|
|
tx(new cmd::SetUserDataProperties(obj, extID, std::move(newProperties)));
|
|
tx.commit();
|
|
}
|
|
else {
|
|
auto& properties = obj->userData().properties(extID);
|
|
properties = std::move(newProperties);
|
|
}
|
|
}
|
|
|
|
push_new<Properties>(L, propObj->id, extID);
|
|
return 1;
|
|
}
|
|
|
|
int Properties_pairs_next(lua_State* L)
|
|
{
|
|
auto propObj = get_obj<Properties>(L, 1);
|
|
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(propObj->extID);
|
|
auto& it = *get_obj<PropertiesIterator>(L, lua_upvalueindex(1));
|
|
if (it == properties.end())
|
|
return 0;
|
|
lua_pushstring(L, (*it).first.c_str());
|
|
push_value_to_lua(L, (*it).second);
|
|
++it;
|
|
return 2;
|
|
}
|
|
|
|
int Properties_pairs(lua_State* L)
|
|
{
|
|
auto propObj = get_obj<Properties>(L, 1);
|
|
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(propObj->extID);
|
|
|
|
push_obj(L, properties.begin());
|
|
lua_pushcclosure(L, Properties_pairs_next, 1);
|
|
lua_pushvalue(L, 1); // Copy the same propObj as the second return value
|
|
return 2;
|
|
}
|
|
|
|
int PropertiesIterator_gc(lua_State* L)
|
|
{
|
|
get_obj<PropertiesIterator>(L, 1)->~PropertiesIterator();
|
|
return 0;
|
|
}
|
|
|
|
const luaL_Reg Properties_methods[] = {
|
|
{ "__len", Properties_len },
|
|
{ "__call", Properties_call },
|
|
{ "__index", Properties_index },
|
|
{ "__newindex", Properties_newindex },
|
|
{ "__pairs", Properties_pairs },
|
|
{ nullptr, nullptr }
|
|
};
|
|
|
|
const luaL_Reg PropertiesIterator_methods[] = {
|
|
{ "__gc", PropertiesIterator_gc },
|
|
{ nullptr, nullptr }
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
DEF_MTNAME(Properties);
|
|
DEF_MTNAME(PropertiesIterator);
|
|
|
|
void register_properties_class(lua_State* L)
|
|
{
|
|
REG_CLASS(L, Properties);
|
|
REG_CLASS(L, PropertiesIterator);
|
|
}
|
|
|
|
void push_properties(lua_State* L,
|
|
doc::WithUserData* userData,
|
|
const std::string& extID)
|
|
{
|
|
push_new<Properties>(L, userData->id(), extID);
|
|
}
|
|
|
|
} // namespace script
|
|
} // namespace app
|