[lua] Add Tileset:tile(tileIndex) API to get tile image/data/properties (fix #3653)

This should replace the old Tileset:getTile(tileIndex) which returns
only the image.
This commit is contained in:
David Capello 2023-01-06 19:50:04 -03:00
parent 6534d37b40
commit 81b2507bb6
16 changed files with 696 additions and 34 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 <cstdio>
@ -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);

View File

@ -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 <cstring>
@ -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::WithUserData*>(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<doc::UserData*>(
&static_cast<doc::Tileset*>(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<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& 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<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& 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<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)));
if (propObj->ti != doc::notile) {
tx(new cmd::SetTileDataProperty(static_cast<doc::Tileset*>(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<doc::Tileset*>(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<Properties>(L, propObj->id, extID);
push_new<Properties>(L, *propObj, 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& properties = propObj->properties(L);
auto& it = *get_obj<PropertiesIterator>(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<Properties>(L, userData->id(), extID);
push_new<Properties>(L, wud, extID);
}
void push_tile_properties(lua_State* L,
const doc::Tileset* ts,
doc::tile_index ti,
const std::string& extID)
{
push_new<Properties>(L, ts, ti, extID);
}
} // namespace script

View File

@ -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<Tile>(L, 1);
auto ts = doc::get<Tileset>(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<Tile>(L, 1);
auto ts = doc::get<Tileset>(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<Tile>(L, 1);
auto ts = doc::get<Tileset>(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<app::Color>(L, appColor);
return 1;
}
int Tile_get_properties(lua_State* L)
{
auto tile = get_obj<Tile>(L, 1);
auto ts = doc::get<Tileset>(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<Tile>(L, 1);
auto ts = doc::get<Tileset>(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<Tile>(L, 1);
auto ts = doc::get<Tileset>(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<Tile>(L, 1);
auto ts = doc::get<Tileset>(tile->id);
if (!ts)
return 0;
auto newProperties = get_value_from_lua<doc::UserData::Properties>(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<Tile>(L, ts, ti);
}
} // namespace script
} // namespace app

View File

@ -48,6 +48,17 @@ int Tileset_getTile(lua_State* L)
return 1;
}
int Tileset_tile(lua_State* L)
{
auto tileset = get_docobj<Tileset>(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<Tileset>(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 }
};

View File

@ -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,

View File

@ -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<ImageRef> Tiles;
typedef std::vector<UserData> 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<UserData&>(m_datas[ti]);
else
return UserData();
return kNoUserData;
}
void setTileData(const tile_index ti,
const UserData& userData);

View File

@ -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

View File

@ -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