mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-01 10:13:22 +00:00
Add nullptr_t to doc::UserData::Variant to fix bug when undoing an previously unexistent property
This commit is contained in:
parent
8f09728105
commit
d590d3f39a
@ -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
|
||||
|
@ -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<doc::WithUserData>(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<doc::WithUserData>(m_objId);
|
||||
obj->userData().properties(m_group)[m_field] = m_oldVariant;
|
||||
obj->incrementVersion();
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
@ -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
|
@ -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 {
|
||||
|
@ -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<doc::WithUserData>(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<doc::WithUserData>(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();
|
||||
}
|
||||
|
||||
|
@ -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<doc::UserData::Variant>(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<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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
@ -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<nullptr_t>(L, nullptr);
|
||||
break;
|
||||
case USER_DATA_PROPERTY_TYPE_BOOL:
|
||||
push_value_to_lua(L, *std::get_if<bool>(&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:
|
||||
|
@ -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;
|
||||
|
@ -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 <cstddef>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#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<Variant>;
|
||||
using Properties = std::map<std::string, Variant>;
|
||||
using PropertiesMaps = std::map<std::string, Properties>;
|
||||
using VariantBase = std::variant<bool,
|
||||
using VariantBase = std::variant<std::nullptr_t,
|
||||
bool,
|
||||
int8_t, uint8_t,
|
||||
int16_t, uint16_t,
|
||||
int32_t, uint32_t,
|
||||
@ -87,7 +90,7 @@ namespace doc {
|
||||
}
|
||||
|
||||
const uint16_t type() const {
|
||||
return index() + 1;
|
||||
return index();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -33,6 +33,12 @@ do
|
||||
spr.properties.b = nil
|
||||
assert(spr.properties.b == nil)
|
||||
assert(#spr.properties == 3)
|
||||
-- We set an unexistent property now, undo it, the property shouldn't exist
|
||||
spr.properties.b = 5
|
||||
assert(spr.properties.b == 5)
|
||||
assert(#spr.properties == 4)
|
||||
app.undo()
|
||||
assert(#spr.properties == 3)
|
||||
|
||||
spr.properties.v = { 10, 20, 30 }
|
||||
assert(#spr.properties.v == 3)
|
||||
|
Loading…
x
Reference in New Issue
Block a user