diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index ac22a9331..9b8337877 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -495,7 +495,6 @@ add_library(app-lib cmd/remove_tag.cpp cmd/remove_tile.cpp cmd/remove_tileset.cpp - cmd/remove_user_data_property.cpp cmd/replace_image.cpp cmd/replace_tileset.cpp cmd/reselect_mask.cpp diff --git a/src/app/cmd/remove_user_data_property.cpp b/src/app/cmd/remove_user_data_property.cpp deleted file mode 100644 index 835430c64..000000000 --- a/src/app/cmd/remove_user_data_property.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Aseprite -// Copyright (C) 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.h" -#include "app/cmd/with_document.h" -#include "doc/object_id.h" -#include "doc/user_data.h" -#include "doc/with_user_data.h" - -namespace app { -namespace cmd { - -RemoveUserDataProperty::RemoveUserDataProperty( - doc::WithUserData* obj, - const std::string& group, - const std::string& field) - : m_objId(obj->id()) - , m_group(group) - , m_field(field) - , m_oldVariant(obj->userData().properties(m_group)[m_field]) -{ -} - -void RemoveUserDataProperty::onExecute() -{ - auto obj = doc::get(m_objId); - auto& properties = obj->userData().properties(m_group); - auto it = properties.find(m_field); - ASSERT(it != properties.end()); - if (it != properties.end()) { - properties.erase(it); - obj->incrementVersion(); - } -} - -void RemoveUserDataProperty::onUndo() -{ - auto obj = doc::get(m_objId); - obj->userData().properties(m_group)[m_field] = m_oldVariant; - obj->incrementVersion(); -} - -} // namespace cmd -} // namespace app diff --git a/src/app/cmd/remove_user_data_property.h b/src/app/cmd/remove_user_data_property.h deleted file mode 100644 index 01fce682a..000000000 --- a/src/app/cmd/remove_user_data_property.h +++ /dev/null @@ -1,46 +0,0 @@ -// Aseprite -// Copyright (C) 2023 Igara Studio S.A. -// -// This program is distributed under the terms of -// the End-User License Agreement for Aseprite. - -#ifndef APP_CMD_REMOVE_USER_DATA_PROPERTY_H_INCLUDED -#define APP_CMD_REMOVE_USER_DATA_PROPERTY_H_INCLUDED -#pragma once - -#include "app/cmd.h" -#include "doc/object_id.h" -#include "doc/user_data.h" - -namespace doc { - class WithUserData; -} - -namespace app { -namespace cmd { - - class RemoveUserDataProperty : public Cmd { - public: - RemoveUserDataProperty( - doc::WithUserData* obj, - const std::string& group, - const std::string& field); - - protected: - void onExecute() override; - void onUndo() override; - size_t onMemSize() const override { - return sizeof(*this); // TODO + variants size - } - - private: - doc::ObjectId m_objId; - std::string m_group; - std::string m_field; - doc::UserData::Variant m_oldVariant; - }; - -} // namespace cmd -} // namespace app - -#endif diff --git a/src/app/cmd/set_user_data_properties.cpp b/src/app/cmd/set_user_data_properties.cpp index f36a7fd12..883933098 100644 --- a/src/app/cmd/set_user_data_properties.cpp +++ b/src/app/cmd/set_user_data_properties.cpp @@ -10,10 +10,6 @@ #include "app/cmd/set_user_data_properties.h" -#include "app/cmd.h" -#include "app/cmd/with_document.h" -#include "doc/object_id.h" -#include "doc/user_data.h" #include "doc/with_user_data.h" namespace app { diff --git a/src/app/cmd/set_user_data_property.cpp b/src/app/cmd/set_user_data_property.cpp index 36ffe4d87..cffc973d3 100644 --- a/src/app/cmd/set_user_data_property.cpp +++ b/src/app/cmd/set_user_data_property.cpp @@ -10,10 +10,6 @@ #include "app/cmd/set_user_data_property.h" -#include "app/cmd.h" -#include "app/cmd/with_document.h" -#include "doc/object_id.h" -#include "doc/user_data.h" #include "doc/with_user_data.h" namespace app { @@ -35,14 +31,34 @@ SetUserDataProperty::SetUserDataProperty( void SetUserDataProperty::onExecute() { auto obj = doc::get(m_objId); - obj->userData().properties(m_group)[m_field] = m_newValue; + auto& properties = obj->userData().properties(m_group); + + if (m_newValue.type() == USER_DATA_PROPERTY_TYPE_NULLPTR) { + auto it = properties.find(m_field); + if (it != properties.end()) + properties.erase(it); + } + else { + properties[m_field] = m_newValue; + } + obj->incrementVersion(); } void SetUserDataProperty::onUndo() { auto obj = doc::get(m_objId); - obj->userData().properties(m_group)[m_field] = m_oldValue; + auto& properties = obj->userData().properties(m_group); + + if (m_oldValue.type() == USER_DATA_PROPERTY_TYPE_NULLPTR) { + auto it = properties.find(m_field); + if (it != properties.end()) + properties.erase(it); + } + else { + properties[m_field] = m_oldValue; + } + obj->incrementVersion(); } diff --git a/src/app/script/properties_class.cpp b/src/app/script/properties_class.cpp index e164f5ff9..0a7a51fc3 100644 --- a/src/app/script/properties_class.cpp +++ b/src/app/script/properties_class.cpp @@ -8,7 +8,6 @@ #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" @@ -84,46 +83,18 @@ int Properties_newindex(lua_State* L) return luaL_error(L, "the object with these properties was destroyed"); auto& properties = obj->userData().properties(propObj->extID); + auto newValue = get_value_from_lua(L, 3); - 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(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; - } + // 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); } return 0; } diff --git a/src/app/script/values.cpp b/src/app/script/values.cpp index 01137b200..ec1e670b9 100644 --- a/src/app/script/values.cpp +++ b/src/app/script/values.cpp @@ -23,6 +23,15 @@ namespace script { // TODO this is similar to app::Param<> specializations::fromLua() specializations +// ---------------------------------------------------------------------- +// nullptr_t + +template<> +void push_value_to_lua(lua_State* L, const nullptr_t&) { + TRACEARGS("push_value_to_lua nullptr_t"); + lua_pushnil(L); +} + // ---------------------------------------------------------------------- // bool @@ -305,6 +314,9 @@ void push_value_to_lua(lua_State* L, const doc::UserData::Variant& value) { #if 1 // We are targetting macOS 10.9, so we don't have the std::visit() available switch (value.type()) { + case USER_DATA_PROPERTY_TYPE_NULLPTR: + push_value_to_lua(L, nullptr); + break; case USER_DATA_PROPERTY_TYPE_BOOL: push_value_to_lua(L, *std::get_if(&value)); break; @@ -374,7 +386,7 @@ doc::UserData::Variant get_value_from_lua(lua_State* L, int index) case LUA_TNONE: case LUA_TNIL: - // TODO should we add nullptr_t in Variant? + v = nullptr; break; case LUA_TBOOLEAN: diff --git a/src/dio/aseprite_decoder.cpp b/src/dio/aseprite_decoder.cpp index 9f2db0e7a..74ab096a9 100644 --- a/src/dio/aseprite_decoder.cpp +++ b/src/dio/aseprite_decoder.cpp @@ -1,5 +1,5 @@ // Aseprite Document IO Library -// Copyright (c) 2018-2022 Igara Studio S.A. +// Copyright (c) 2018-2023 Igara Studio S.A. // Copyright (c) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -1270,6 +1270,11 @@ void AsepriteDecoder::readPropertiesMaps(doc::UserData::PropertiesMaps& properti const doc::UserData::Variant AsepriteDecoder::readPropertyValue(uint16_t type) { switch (type) { + case USER_DATA_PROPERTY_TYPE_NULLPTR: { + // This shouldn't exist in a .aseprite file + ASSERT(false); + return nullptr; + } case USER_DATA_PROPERTY_TYPE_BOOL: { bool value = read8(); return value; diff --git a/src/doc/user_data.h b/src/doc/user_data.h index 379a5e94d..60666435c 100644 --- a/src/doc/user_data.h +++ b/src/doc/user_data.h @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2022 Igara Studio S.A. +// Copyright (c) 2022-2023 Igara Studio S.A. // Copyright (c) 2001-2015 David Capello // // This file is released under the terms of the MIT license. @@ -15,12 +15,14 @@ #include "gfx/size.h" #include "gfx/rect.h" +#include #include #include #include #include #include +#define USER_DATA_PROPERTY_TYPE_NULLPTR 0x0000 #define USER_DATA_PROPERTY_TYPE_BOOL 0x0001 #define USER_DATA_PROPERTY_TYPE_INT8 0x0002 #define USER_DATA_PROPERTY_TYPE_UINT8 0x0003 @@ -55,7 +57,8 @@ namespace doc { using Vector = std::vector; using Properties = std::map; using PropertiesMaps = std::map; - using VariantBase = std::variant