diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 9b8337877..fd67e26f0 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -206,6 +206,7 @@ if(ENABLE_SCRIPTING) script/sprites_class.cpp script/tag_class.cpp script/tags_class.cpp + script/tile_class.cpp script/tileset_class.cpp script/tilesets_class.cpp script/tool_class.cpp @@ -523,6 +524,9 @@ add_library(app-lib cmd/set_tag_name.cpp cmd/set_tag_range.cpp cmd/set_tag_repeat.cpp + cmd/set_tile_data.cpp + cmd/set_tile_data_properties.cpp + cmd/set_tile_data_property.cpp cmd/set_tileset_base_index.cpp cmd/set_tileset_name.cpp cmd/set_total_frames.cpp diff --git a/src/app/cmd/set_tile_data.cpp b/src/app/cmd/set_tile_data.cpp new file mode 100644 index 000000000..c8c413ea1 --- /dev/null +++ b/src/app/cmd/set_tile_data.cpp @@ -0,0 +1,43 @@ +// 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/set_tile_data.h" + +#include "doc/tileset.h" + +namespace app { +namespace cmd { + +SetTileData::SetTileData(doc::Tileset* ts, + doc::tile_index ti, + const doc::UserData& ud) + : WithTileset(ts) + , m_ti(ti) + , m_oldUserData(ts->getTileData(ti)) + , m_newUserData(ud) +{ +} + +void SetTileData::onExecute() +{ + auto ts = tileset(); + ts->setTileData(m_ti, m_newUserData); + ts->incrementVersion(); +} + +void SetTileData::onUndo() +{ + auto ts = tileset(); + ts->setTileData(m_ti, m_oldUserData); + ts->incrementVersion(); +} + +} // namespace cmd +} // namespace app diff --git a/src/app/cmd/set_tile_data.h b/src/app/cmd/set_tile_data.h new file mode 100644 index 000000000..685c059a2 --- /dev/null +++ b/src/app/cmd/set_tile_data.h @@ -0,0 +1,42 @@ +// 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_SET_TILE_DATA_H_INCLUDED +#define APP_CMD_SET_TILE_DATA_H_INCLUDED +#pragma once + +#include "app/cmd.h" +#include "app/cmd/with_tileset.h" +#include "doc/tile.h" +#include "doc/user_data.h" + +namespace app { +namespace cmd { + + class SetTileData : public Cmd, + public WithTileset { + public: + SetTileData(doc::Tileset* ts, + doc::tile_index ti, + const doc::UserData& ud); + + protected: + void onExecute() override; + void onUndo() override; + size_t onMemSize() const override { + return sizeof(*this); // TODO + properties size + } + + private: + doc::tile_index m_ti; + doc::UserData m_oldUserData; + doc::UserData m_newUserData; + }; + +} // namespace cmd +} // namespace app + +#endif diff --git a/src/app/cmd/set_tile_data_properties.cpp b/src/app/cmd/set_tile_data_properties.cpp new file mode 100644 index 000000000..7d735ac9b --- /dev/null +++ b/src/app/cmd/set_tile_data_properties.cpp @@ -0,0 +1,46 @@ +// 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/set_tile_data_properties.h" + +#include "doc/tileset.h" + +namespace app { +namespace cmd { + +SetTileDataProperties::SetTileDataProperties( + doc::Tileset* ts, + doc::tile_index ti, + const std::string& group, + doc::UserData::Properties&& newProperties) + : WithTileset(ts) + , m_ti(ti) + , m_group(group) + , m_oldProperties(ts->getTileData(ti).properties(group)) + , m_newProperties(std::move(newProperties)) +{ +} + +void SetTileDataProperties::onExecute() +{ + auto ts = tileset(); + ts->getTileData(m_ti).properties(m_group) = m_newProperties; + ts->incrementVersion(); +} + +void SetTileDataProperties::onUndo() +{ + auto ts = tileset(); + ts->getTileData(m_ti).properties(m_group) = m_oldProperties; + ts->incrementVersion(); +} + +} // namespace cmd +} // namespace app diff --git a/src/app/cmd/set_tile_data_properties.h b/src/app/cmd/set_tile_data_properties.h new file mode 100644 index 000000000..2a13ac046 --- /dev/null +++ b/src/app/cmd/set_tile_data_properties.h @@ -0,0 +1,45 @@ +// 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_SET_TILE_DATA_PROPERTIES_H_INCLUDED +#define APP_CMD_SET_TILE_DATA_PROPERTIES_H_INCLUDED +#pragma once + +#include "app/cmd.h" +#include "app/cmd/with_tileset.h" +#include "doc/tile.h" +#include "doc/user_data.h" + +namespace app { +namespace cmd { + + class SetTileDataProperties : public Cmd, + public WithTileset { + public: + SetTileDataProperties( + doc::Tileset* ts, + doc::tile_index ti, + const std::string& group, + doc::UserData::Properties&& newProperties); + + protected: + void onExecute() override; + void onUndo() override; + size_t onMemSize() const override { + return sizeof(*this); // TODO + properties size + } + + private: + doc::tile_index m_ti; + std::string m_group; + doc::UserData::Properties m_oldProperties; + doc::UserData::Properties m_newProperties; + }; + +} // namespace cmd +} // namespace app + +#endif diff --git a/src/app/cmd/set_tile_data_property.cpp b/src/app/cmd/set_tile_data_property.cpp new file mode 100644 index 000000000..b1b61e82c --- /dev/null +++ b/src/app/cmd/set_tile_data_property.cpp @@ -0,0 +1,68 @@ +// 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/set_tile_data_property.h" + +#include "doc/tileset.h" + +namespace app { +namespace cmd { + +SetTileDataProperty::SetTileDataProperty( + doc::Tileset* ts, + doc::tile_index ti, + const std::string& group, + const std::string& field, + doc::UserData::Variant&& newValue) + : WithTileset(ts) + , m_ti(ti) + , m_group(group) + , m_field(field) + , m_oldValue(ts->getTileData(m_ti).properties(m_group)[m_field]) + , m_newValue(std::move(newValue)) +{ +} + +void SetTileDataProperty::onExecute() +{ + auto ts = tileset(); + auto& properties = ts->getTileData(m_ti).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; + } + + ts->incrementVersion(); +} + +void SetTileDataProperty::onUndo() +{ + auto ts = tileset(); + auto& properties = ts->getTileData(m_ti).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; + } + + ts->incrementVersion(); +} + +} // namespace cmd +} // namespace app diff --git a/src/app/cmd/set_tile_data_property.h b/src/app/cmd/set_tile_data_property.h new file mode 100644 index 000000000..d8da04ee0 --- /dev/null +++ b/src/app/cmd/set_tile_data_property.h @@ -0,0 +1,47 @@ +// 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_SET_TILE_DATA_PROPERTY_H_INCLUDED +#define APP_CMD_SET_TILE_DATA_PROPERTY_H_INCLUDED +#pragma once + +#include "app/cmd.h" +#include "app/cmd/with_tileset.h" +#include "doc/tile.h" +#include "doc/user_data.h" + +namespace app { +namespace cmd { + + class SetTileDataProperty : public Cmd, + public WithTileset { + public: + SetTileDataProperty( + doc::Tileset* ts, + doc::tile_index ti, + const std::string& group, + const std::string& field, + doc::UserData::Variant&& newValue); + + protected: + void onExecute() override; + void onUndo() override; + size_t onMemSize() const override { + return sizeof(*this); // TODO + variant size + } + + private: + doc::tile_index m_ti; + std::string m_group; + std::string m_field; + doc::UserData::Variant m_oldValue; + doc::UserData::Variant m_newValue; + }; + +} // namespace cmd +} // namespace app + +#endif diff --git a/src/app/script/engine.cpp b/src/app/script/engine.cpp index 6703456d0..97f7417e9 100644 --- a/src/app/script/engine.cpp +++ b/src/app/script/engine.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2022 Igara Studio S.A. +// Copyright (C) 2018-2023 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -189,6 +189,7 @@ void register_sprites_class(lua_State* L); void register_tag_class(lua_State* L); void register_tags_class(lua_State* L); void register_theme_classes(lua_State* L); +void register_tile_class(lua_State* L); void register_tileset_class(lua_State* L); void register_tilesets_class(lua_State* L); void register_tool_class(lua_State* L); @@ -468,6 +469,7 @@ Engine::Engine() register_tag_class(L); register_tags_class(L); register_theme_classes(L); + register_tile_class(L); register_tileset_class(L); register_tilesets_class(L); register_tool_class(L); diff --git a/src/app/script/engine.h b/src/app/script/engine.h index adca790cb..9409e881d 100644 --- a/src/app/script/engine.h +++ b/src/app/script/engine.h @@ -20,6 +20,7 @@ #include "doc/frame.h" #include "doc/object_ids.h" #include "doc/pixel_format.h" +#include "doc/tile.h" #include "gfx/fwd.h" #include @@ -163,6 +164,8 @@ namespace app { void push_sprite_slices(lua_State* L, doc::Sprite* sprite); void push_sprite_tags(lua_State* L, doc::Sprite* sprite); void push_sprites(lua_State* L); + void push_tile(lua_State* L, const doc::Tileset* tileset, doc::tile_index ti); + void push_tile_properties(lua_State* L, const doc::Tileset* tileset, doc::tile_index ti, const std::string& extID); void push_tileset(lua_State* L, const doc::Tileset* tileset); void push_tileset_image(lua_State* L, doc::Tileset* tileset, doc::Image* image); void push_tilesets(lua_State* L, doc::Tilesets* tilesets); diff --git a/src/app/script/properties_class.cpp b/src/app/script/properties_class.cpp index 0a7a51fc3..c301b1171 100644 --- a/src/app/script/properties_class.cpp +++ b/src/app/script/properties_class.cpp @@ -8,6 +8,8 @@ #include "config.h" #endif +#include "app/cmd/set_tile_data_properties.h" +#include "app/cmd/set_tile_data_property.h" #include "app/cmd/set_user_data_properties.h" #include "app/cmd/set_user_data_property.h" #include "app/script/docobj.h" @@ -15,6 +17,7 @@ #include "app/script/luacpp.h" #include "app/script/values.h" #include "app/tx.h" +#include "doc/tileset.h" #include "doc/with_user_data.h" #include @@ -25,14 +28,58 @@ namespace script { namespace { struct Properties { + // WithUserData ID or tileset ID doc::ObjectId id = 0; + // If notile, it's the properties of a WithUserData, in other case, + // it's the user data of this specific tile. + doc::tile_index ti = doc::notile; std::string extID; - Properties(doc::ObjectId id, + Properties(const doc::WithUserData* wud, const std::string& extID) - : id(id) + : id(wud->id()) , extID(extID) { } + + Properties(const doc::Tileset* ts, + const doc::tile_index ti, + const std::string& extID) + : id(ts->id()) + , ti(ti) + , extID(extID) { + } + + Properties(const Properties& copy, + const std::string& extID) + : id(copy.id) + , ti(copy.ti) + , extID(extID) { + } + + doc::WithUserData* object(lua_State* L) { + auto obj = static_cast(doc::get_object(id)); + if (!obj) { + // luaL_error never returns + luaL_error(L, "the object with these properties was destroyed"); + } + return obj; + } + + doc::UserData::Properties& properties(lua_State* L, doc::WithUserData* obj = nullptr) { + if (!obj) + obj = object(L); + if (ti == doc::notile) { + return obj->userData().properties(extID); + } + else { + ASSERT(obj->type() == doc::ObjectType::Tileset); + return + const_cast( + &static_cast(obj)->getTileData(ti)) + ->properties(extID); + } + } + }; using PropertiesIterator = doc::UserData::Properties::iterator; @@ -40,11 +87,7 @@ using PropertiesIterator = doc::UserData::Properties::iterator; int Properties_len(lua_State* L) { auto propObj = get_obj(L, 1); - auto obj = static_cast(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& properties = propObj->properties(L); lua_pushinteger(L, properties.size()); return 1; } @@ -56,11 +99,7 @@ int Properties_index(lua_State* L) if (!field) return luaL_error(L, "field in 'properties.field' must be a string"); - auto obj = static_cast(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& properties = propObj->properties(L); auto it = properties.find(field); if (it != properties.end()) { push_value_to_lua(L, (*it).second); @@ -82,15 +121,22 @@ int Properties_newindex(lua_State* L) if (!obj) return luaL_error(L, "the object with these properties was destroyed"); - auto& properties = obj->userData().properties(propObj->extID); + auto& properties = propObj->properties(L, obj); 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))); + if (propObj->ti != doc::notile) { + tx(new cmd::SetTileDataProperty(static_cast(obj), + propObj->ti, propObj->extID, field, + std::move(newValue))); + } + else { + tx(new cmd::SetUserDataProperty(obj, propObj->extID, field, + std::move(newValue))); + } tx.commit(); } else { @@ -121,7 +167,13 @@ int Properties_call(lua_State* L) //if (obj->sprite()) { if (App::instance()->context()->activeDocument()) { Tx tx; - tx(new cmd::SetUserDataProperties(obj, extID, std::move(newProperties))); + if (propObj->ti != doc::notile) { + tx(new cmd::SetTileDataProperties(static_cast(obj), + propObj->ti, extID, std::move(newProperties))); + } + else { + tx(new cmd::SetUserDataProperties(obj, extID, std::move(newProperties))); + } tx.commit(); } else { @@ -130,18 +182,14 @@ int Properties_call(lua_State* L) } } - push_new(L, propObj->id, extID); + push_new(L, *propObj, extID); return 1; } int Properties_pairs_next(lua_State* L) { auto propObj = get_obj(L, 1); - auto obj = static_cast(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& properties = propObj->properties(L); auto& it = *get_obj(L, lua_upvalueindex(1)); if (it == properties.end()) return 0; @@ -158,7 +206,7 @@ int Properties_pairs(lua_State* L) if (!obj) return luaL_error(L, "the object with these properties was destroyed"); - auto& properties = obj->userData().properties(propObj->extID); + auto& properties = propObj->properties(L); push_obj(L, properties.begin()); lua_pushcclosure(L, Properties_pairs_next, 1); @@ -198,10 +246,18 @@ void register_properties_class(lua_State* L) } void push_properties(lua_State* L, - doc::WithUserData* userData, + doc::WithUserData* wud, const std::string& extID) { - push_new(L, userData->id(), extID); + push_new(L, wud, extID); +} + +void push_tile_properties(lua_State* L, + const doc::Tileset* ts, + doc::tile_index ti, + const std::string& extID) +{ + push_new(L, ts, ti, extID); } } // namespace script diff --git a/src/app/script/tile_class.cpp b/src/app/script/tile_class.cpp new file mode 100644 index 000000000..97f307500 --- /dev/null +++ b/src/app/script/tile_class.cpp @@ -0,0 +1,191 @@ +// 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/set_tile_data.h" +#include "app/cmd/set_tile_data_properties.h" +#include "app/script/docobj.h" +#include "app/script/engine.h" +#include "app/script/luacpp.h" +#include "app/script/userdata.h" +#include "doc/tileset.h" + +namespace app { +namespace script { + +using namespace doc; + +namespace { + +struct Tile { + ObjectId id; + tile_index ti; + Tile(const Tileset* ts, + const tile_index ti) + : id(ts->id()) + , ti(ti) { + } +}; + +int Tile_get_image(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + ImageRef image = ts->get(tile->ti); + if (image) + push_tileset_image(L, ts, image.get()); + else + lua_pushnil(L); + return 1; +} + +int Tile_get_data(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + auto& ud = ts->getTileData(tile->ti); + lua_pushstring(L, ud.text().c_str()); + return 1; +} + +int Tile_get_color(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + auto& ud = ts->getTileData(tile->ti); + doc::color_t docColor = ud.color(); + app::Color appColor = app::Color::fromRgb(doc::rgba_getr(docColor), + doc::rgba_getg(docColor), + doc::rgba_getb(docColor), + doc::rgba_geta(docColor)); + if (appColor.getAlpha() == 0) + appColor = app::Color::fromMask(); + push_obj(L, appColor); + return 1; +} + +int Tile_get_properties(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + push_tile_properties(L, ts, tile->ti, std::string()); + return 1; +} + +int Tile_set_data(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + const char* text = lua_tostring(L, 2); + if (!text) + text = ""; + + doc::UserData ud = ts->getTileData(tile->ti); + ud.setText(text); + + if (ts->sprite()) { // TODO use transaction in this sprite + Tx tx; + tx(new cmd::SetTileData(ts, tile->ti, ud)); + tx.commit(); + } + else { + ts->setTileData(tile->ti, ud); + } + return 0; +} + +int Tile_set_color(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + doc::color_t docColor = convert_args_into_pixel_color(L, 2, doc::IMAGE_RGB); + + doc::UserData ud = ts->getTileData(tile->ti); + ud.setColor(docColor); + + if (ts->sprite()) { // TODO use transaction in this sprite + Tx tx; + tx(new cmd::SetTileData(ts, tile->ti, ud)); + tx.commit(); + } + else { + ts->setTileData(tile->ti, ud); + } + return 0; +} + +int Tile_set_properties(lua_State* L) +{ + auto tile = get_obj(L, 1); + auto ts = doc::get(tile->id); + if (!ts) + return 0; + + auto newProperties = get_value_from_lua(L, 2); + if (ts->sprite()) { + Tx tx; + tx(new cmd::SetTileDataProperties(ts, tile->ti, + std::string(), + std::move(newProperties))); + tx.commit(); + } + else { + auto& properties = ts->getTileData(tile->ti).properties(); + properties = std::move(newProperties); + } + return 0; +} + +const luaL_Reg Tile_methods[] = { + { nullptr, nullptr } +}; + +const Property Tile_properties[] = { + { "image", Tile_get_image, nullptr }, // TODO Tile_set_image + { "data", Tile_get_data, Tile_set_data }, + { "color", Tile_get_color, Tile_set_color }, + { "properties", Tile_get_properties, Tile_set_properties }, + { nullptr, nullptr, nullptr } +}; + +} // anonymous namespace + +DEF_MTNAME(Tile); + +void register_tile_class(lua_State* L) +{ + REG_CLASS(L, Tile); + REG_CLASS_PROPERTIES(L, Tile); +} + +void push_tile(lua_State* L, const Tileset* ts, tile_index ti) +{ + push_new(L, ts, ti); +} + +} // namespace script +} // namespace app diff --git a/src/app/script/tileset_class.cpp b/src/app/script/tileset_class.cpp index a5a93278e..10c548de1 100644 --- a/src/app/script/tileset_class.cpp +++ b/src/app/script/tileset_class.cpp @@ -48,6 +48,17 @@ int Tileset_getTile(lua_State* L) return 1; } +int Tileset_tile(lua_State* L) +{ + auto tileset = get_docobj(L, 1); + tile_index ti = lua_tointeger(L, 2); + if (ti >= 0 && ti < tileset->size()) + push_tile(L, tileset, ti); + else + lua_pushnil(L); + return 1; +} + int Tileset_get_name(lua_State* L) { auto tileset = get_docobj(L, 1); @@ -89,8 +100,7 @@ const luaL_Reg Tileset_methods[] = { { "__eq", Tileset_eq }, { "__len", Tileset_len }, { "getTile", Tileset_getTile }, - // TODO - // { "setTile", Tileset_setTile }, + { "tile", Tileset_tile }, { nullptr, nullptr } }; diff --git a/src/doc/tileset.cpp b/src/doc/tileset.cpp index 747f87383..6c67c46b9 100644 --- a/src/doc/tileset.cpp +++ b/src/doc/tileset.cpp @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2019-2022 Igara Studio S.A. +// Copyright (c) 2019-2023 Igara Studio S.A. // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -20,6 +20,9 @@ namespace doc { +// static +UserData Tileset::kNoUserData; + Tileset::Tileset(Sprite* sprite, const Grid& grid, const tileset_index ntiles) @@ -131,7 +134,8 @@ void Tileset::remap(const Remap& remap) void Tileset::setTileData(const tile_index ti, const UserData& userData) { - m_datas[ti] = userData; + if (ti >= 0 && ti < size()) + m_datas[ti] = userData; } void Tileset::set(const tile_index ti, diff --git a/src/doc/tileset.h b/src/doc/tileset.h index 5e4f260df..7b1e464a2 100644 --- a/src/doc/tileset.h +++ b/src/doc/tileset.h @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2019-2022 Igara Studio S.A. +// Copyright (c) 2019-2023 Igara Studio S.A. // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -24,6 +24,7 @@ namespace doc { class Sprite; class Tileset : public WithUserData { + static UserData kNoUserData; public: typedef std::vector Tiles; typedef std::vector Datas; @@ -69,11 +70,11 @@ namespace doc { void set(const tile_index ti, const ImageRef& image); - UserData getTileData(const tile_index ti) const { + UserData& getTileData(const tile_index ti) const { if (ti >= 0 && ti < size()) - return m_datas[ti]; + return const_cast(m_datas[ti]); else - return UserData(); + return kNoUserData; } void setTileData(const tile_index ti, const UserData& userData); diff --git a/tests/scripts/tiledata.lua b/tests/scripts/tiledata.lua new file mode 100644 index 000000000..bdbdca72d --- /dev/null +++ b/tests/scripts/tiledata.lua @@ -0,0 +1,85 @@ +-- Copyright (C) 2023 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(4, 4, ColorMode.INDEXED) + spr.gridBounds = Rectangle(0, 0, 2, 2) + app.command.NewLayer{ tilemap=true } + local tilemap = spr.layers[2] + local tileset = tilemap.tileset + + app.useTool{ + tool='pencil', + color=1, + layer=tilemap, + tilesetMode=TilesetMode.STACK, + points={ Point(0, 0), Point(4, 3) }} + assert(#tileset == 3) + + -- Tileset properties + tileset.properties.kind = "terrain" + assert(tileset.properties.kind == "terrain") + assert(#tileset.properties == 1) + + -- Tiles user data + local tile1 = tileset:tile(1) + tile1.color = Color(255, 0, 0) + assert(tile1.color == Color(255, 0, 0)) + tile1.data = "solid" + assert(tile1.data == "solid") + tile1.data = nil + assert(tile1.data == "") + + tile1.properties.center = Point(2, 2) + tile1.properties("ext").pivot = Point(5, 5) + assert(tile1.properties.center == Point(2, 2)) + assert(tile1.properties("ext").pivot == Point(5, 5)) + assert(#tileset.properties == 1) -- Check that tileset properties are not set + + local tile2 = tileset:tile(2) + tile2.properties.center = Point(3, 2) + tile2.properties.extra = 32 + assert(tile2.properties.center == Point(3, 2)) + assert(tile2.properties.extra == 32) + assert(tile1.properties.center == Point(2, 2)) + assert(tile1.properties("ext").pivot == Point(5, 5)) + assert(#tileset.properties == 1) -- Check that tileset properties are not set + assert(#tile1.properties == 1) + assert(#tile1.properties("ext") == 1) + assert(#tile2.properties == 2) + app.undo() + assert(#tile2.properties == 1) + app.undo() + assert(#tile2.properties == 0) + app.redo() + app.redo() + assert(#tile2.properties == 2) + + -- Undoable Tile.color and Tile.data + assert(tile2.color == Color()) + tile2.color = Color(0, 0, 255) + assert(tile2.color == Color(0, 0, 255)) + app.undo() + assert(tile2.color == Color()) + + assert(tile2.data == "") + tile2.data = "B" + assert(tile2.data == "B") + app.undo() + assert(tile2.data == "") + + -- Set all properties at once + tile1.properties = { a=1, b=2.1 } + assert(#tile1.properties == 2) + assert(tile1.properties.a == 1) + assert(tile1.properties.b == 2.1) + + assert(#tile1.properties("ext") == 1) + tile1.properties("ext", { x=2, y=3 }) + assert(#tile1.properties("ext") == 2) + assert(tile1.properties("ext").x == 2) + assert(tile1.properties("ext").y == 3) + +end diff --git a/tests/scripts/tileset.lua b/tests/scripts/tileset.lua index 85aa4d061..e2761cd0d 100644 --- a/tests/scripts/tileset.lua +++ b/tests/scripts/tileset.lua @@ -26,6 +26,7 @@ do tileset.name = "Default Land" assert(tileset.name == "Default Land") + -- Tileset user data assert(tileset.data == "") tileset.data = "land" assert(tileset.data == "land") @@ -33,4 +34,18 @@ do assert(tileset.color == Color()) tileset.color = Color(255, 0, 0) assert(tileset.color == Color(255, 0, 0)) + + -- Create extra tile + app.useTool{ + tool='pencil', + color=1, + layer=tilemap, + tilesetMode=TilesetMode.STACK, + points={ Point(1, 1) }} + assert(#tileset == 3) + + -- Check that Tileset:getTile(ti) returns Tileset:tile(ti).image user data + for ti=0,2 do + assert(tileset:tile(ti).image.id == tileset:getTile(ti).id) + end end