Add possibility to move tiles w/drag and drop + remap tiles

This commit is contained in:
David Capello 2019-11-16 12:09:33 -03:00
parent 8db5b3fb4e
commit e792d4e078
27 changed files with 773 additions and 91 deletions

View File

@ -226,6 +226,11 @@ generate and stack new tiles automatically
END
remap_palette = Remap Palette
remap_palette_tooltip = Matches old indexes with new indexes
remap_tiles = Remap Tiles
remap_tiles_tooltip = Matches old tiles with new tiles
clear_tiles = Clear Tiles
resize_tiles = Resize Tiles
drag_and_drop_tiles = Drag And Drop Tiles
[commands]
About = About
@ -276,6 +281,7 @@ Copy = Copy
CopyCel = Copy Cel
CopyColors = Copy Colors
CopyMerged = Copy Merged
CopyTiles = Copy Tiles
CropSprite = Crop Sprite
Cut = Cut
DeselectMask = Deselect Mask
@ -357,6 +363,7 @@ MoveColors = Move Colors
MoveMask = Move {0} {1}
MoveMask_Boundaries = Selection Boundaries
MoveMask_Content = Selection Content
MoveTiles = Move Tiles
NewBrush = New Brush
NewFile = New File
NewFile_FromClipboard = New File from Clipboard

View File

@ -447,7 +447,8 @@ add_library(app-lib
cmd/move_layer.cpp
cmd/patch_cel.cpp
cmd/remap_colors.cpp
cmd/remap_tiles.cpp
cmd/remap_tilemaps.cpp
cmd/remap_tileset.cpp
cmd/remove_cel.cpp
cmd/remove_frame.cpp
cmd/remove_layer.cpp
@ -539,6 +540,7 @@ add_library(app-lib
commands/filters/filter_worker.cpp
commands/move_colors_command.cpp
commands/move_thing.cpp
commands/move_tiles_command.cpp
commands/new_params.cpp
commands/quick_command.cpp
console.cpp

View File

@ -65,6 +65,7 @@ void ActiveSiteHandler::getActiveSiteForDoc(Doc* doc, Site* site)
site->layer(doc::get<doc::Layer>(data.layer));
site->frame(data.frame);
site->selectedColors(data.selectedColors);
site->selectedTiles(data.selectedTiles);
}
void ActiveSiteHandler::setActiveLayerInDoc(Doc* doc, doc::Layer* layer)
@ -85,6 +86,12 @@ void ActiveSiteHandler::setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks
data.selectedColors = picks;
}
void ActiveSiteHandler::setSelectedTilesInDoc(Doc* doc, const doc::PalettePicks& picks)
{
Data& data = getData(doc);
data.selectedTiles = picks;
}
void ActiveSiteHandler::onAddLayer(DocEvent& ev)
{
Data& data = getData(ev.document());

View File

@ -39,6 +39,7 @@ namespace app {
void setActiveLayerInDoc(Doc* doc, doc::Layer* layer);
void setActiveFrameInDoc(Doc* doc, doc::frame_t frame);
void setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks& picks);
void setSelectedTilesInDoc(Doc* doc, const doc::PalettePicks& picks);
private:
// DocObserver impl
@ -52,6 +53,7 @@ namespace app {
doc::ObjectId layer;
doc::frame_t frame;
doc::PalettePicks selectedColors;
doc::PalettePicks selectedTiles;
};
Data& getData(Doc* doc);

View File

@ -8,7 +8,7 @@
#include "config.h"
#endif
#include "app/cmd/remap_tiles.h"
#include "app/cmd/remap_tilemaps.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
@ -24,14 +24,14 @@ namespace cmd {
using namespace doc;
RemapTiles::RemapTiles(Tileset* tileset,
const Remap& remap)
RemapTilemaps::RemapTilemaps(Tileset* tileset,
const Remap& remap)
: WithTileset(tileset)
, m_remap(remap)
{
}
void RemapTiles::onExecute()
void RemapTilemaps::onExecute()
{
Tileset* tileset = this->tileset();
Sprite* spr = tileset->sprite();
@ -39,7 +39,7 @@ void RemapTiles::onExecute()
incrementVersions(tileset);
}
void RemapTiles::onUndo()
void RemapTilemaps::onUndo()
{
Tileset* tileset = this->tileset();
Sprite* spr = tileset->sprite();
@ -47,7 +47,7 @@ void RemapTiles::onUndo()
incrementVersions(tileset);
}
void RemapTiles::incrementVersions(Tileset* tileset)
void RemapTilemaps::incrementVersions(Tileset* tileset)
{
Sprite* spr = tileset->sprite();
for (const Cel* cel : spr->uniqueCels()) {

View File

@ -4,8 +4,8 @@
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_CMD_REMAP_TILES_H_INCLUDED
#define APP_CMD_REMAP_TILES_H_INCLUDED
#ifndef APP_CMD_REMAP_TILEMAPS_H_INCLUDED
#define APP_CMD_REMAP_TILEMAPS_H_INCLUDED
#pragma once
#include "app/cmd.h"
@ -16,11 +16,11 @@ namespace app {
namespace cmd {
using namespace doc;
class RemapTiles : public Cmd
, public WithTileset {
class RemapTilemaps : public Cmd
, public WithTileset {
public:
RemapTiles(Tileset* tileset,
const Remap& remap);
RemapTilemaps(Tileset* tileset,
const Remap& remap);
protected:
void onExecute() override;

View File

@ -0,0 +1,54 @@
// Aseprite
// Copyright (C) 2019 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/remap_tileset.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/layer_tilemap.h"
#include "doc/remap.h"
#include "doc/sprite.h"
#include "doc/tileset.h"
namespace app {
namespace cmd {
using namespace doc;
RemapTileset::RemapTileset(Tileset* tileset,
const Remap& remap)
: WithTileset(tileset)
, m_remap(remap)
{
}
void RemapTileset::onExecute()
{
Tileset* tileset = this->tileset();
applyRemap(tileset, m_remap);
}
void RemapTileset::onUndo()
{
Tileset* tileset = this->tileset();
applyRemap(tileset, m_remap.invert());
}
void RemapTileset::applyRemap(Tileset* tileset, const Remap& remap)
{
tileset->remap(remap);
tileset->incrementVersion();
tileset->sprite()->incrementVersion();
}
} // namespace cmd
} // namespace app

View File

@ -0,0 +1,41 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_CMD_REMAP_TILESET_H_INCLUDED
#define APP_CMD_REMAP_TILESET_H_INCLUDED
#pragma once
#include "app/cmd.h"
#include "app/cmd/with_tileset.h"
#include "doc/remap.h"
namespace app {
namespace cmd {
using namespace doc;
class RemapTileset : public Cmd
, public WithTileset {
public:
RemapTileset(Tileset* tileset,
const Remap& remap);
protected:
void onExecute() override;
void onUndo() override;
size_t onMemSize() const override {
return sizeof(*this) + m_remap.getMemSize();
}
private:
void applyRemap(Tileset* tileset, const Remap& remap);
Remap m_remap;
};
} // namespace cmd
} // namespace app
#endif

View File

@ -16,6 +16,7 @@ FOR_EACH_COMMAND(ColorCurve)
FOR_EACH_COMMAND(ColorQuantization)
FOR_EACH_COMMAND(ConvolutionMatrix)
FOR_EACH_COMMAND(CopyColors)
FOR_EACH_COMMAND(CopyTiles)
FOR_EACH_COMMAND(CropSprite)
FOR_EACH_COMMAND(Despeckle)
FOR_EACH_COMMAND(ExportSpriteSheet)
@ -26,6 +27,7 @@ FOR_EACH_COMMAND(LayerFromBackground)
FOR_EACH_COMMAND(LoadPalette)
FOR_EACH_COMMAND(MergeDownLayer)
FOR_EACH_COMMAND(MoveColors)
FOR_EACH_COMMAND(MoveTiles)
FOR_EACH_COMMAND(NewFile)
FOR_EACH_COMMAND(NewFrame)
FOR_EACH_COMMAND(NewLayer)

View File

@ -0,0 +1,85 @@
// Aseprite
// Copyright (c) 2019 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/app.h"
#include "app/commands/new_params.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/tx.h"
#include "app/util/cel_ops.h"
#include "doc/layer.h"
#include "doc/layer_tilemap.h"
#include "doc/remap.h"
#include "doc/tileset.h"
namespace app {
using namespace ui;
struct MoveTilesParams : public NewParams {
Param<int> before { this, 0, "before" };
};
class MoveTilesCommand : public CommandWithNewParams<MoveTilesParams> {
public:
MoveTilesCommand(const bool copy)
: CommandWithNewParams<MoveTilesParams>(CommandId::MoveTiles(),
CmdRecordableFlag)
, m_copy(copy) { }
protected:
bool onEnabled(Context* ctx) override {
return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable |
ContextFlags::HasActiveLayer |
ContextFlags::ActiveLayerIsTilemap);
}
void onExecute(Context* ctx) override {
ContextWriter writer(ctx);
doc::Layer* layer = writer.layer();
if (!layer || !layer->isTilemap())
return;
doc::Tileset* tileset = static_cast<LayerTilemap*>(layer)->tileset();
ASSERT(tileset);
if (!tileset)
return;
PalettePicks picks = writer.site()->selectedTiles();
if (picks.picks() == 0)
return;
Tx tx(writer.context(), onGetFriendlyName(), ModifyDocument);
const int beforeIndex = params().before();
int currentEntry = picks.firstPick();
if (m_copy)
copy_tiles_in_tileset(tx, tileset, picks, currentEntry, beforeIndex);
else
move_tiles_in_tileset(tx, tileset, picks, currentEntry, beforeIndex);
tx.commit();
}
private:
bool m_copy;
};
Command* CommandFactory::createMoveTilesCommand()
{
return new MoveTilesCommand(false);
}
Command* CommandFactory::createCopyTilesCommand()
{
return new MoveTilesCommand(true);
}
} // namespace app

View File

@ -99,6 +99,11 @@ void Context::setSelectedColors(const doc::PalettePicks& picks)
onSetSelectedColors(picks);
}
void Context::setSelectedTiles(const doc::PalettePicks& picks)
{
onSetSelectedTiles(picks);
}
bool Context::hasModifiedDocuments() const
{
for (auto doc : documents())
@ -241,6 +246,12 @@ void Context::onSetSelectedColors(const doc::PalettePicks& picks)
activeSiteHandler()->setSelectedColorsInDoc(m_lastSelectedDoc, picks);
}
void Context::onSetSelectedTiles(const doc::PalettePicks& picks)
{
if (m_lastSelectedDoc)
activeSiteHandler()->setSelectedTilesInDoc(m_lastSelectedDoc, picks);
}
ActiveSiteHandler* Context::activeSiteHandler() const
{
if (!m_activeSiteHandler)

View File

@ -89,6 +89,7 @@ namespace app {
void setActiveLayer(doc::Layer* layer);
void setActiveFrame(doc::frame_t frame);
void setSelectedColors(const doc::PalettePicks& picks);
void setSelectedTiles(const doc::PalettePicks& picks);
bool hasModifiedDocuments() const;
void notifyActiveSiteChanged();
@ -112,6 +113,7 @@ namespace app {
virtual void onSetActiveLayer(doc::Layer* layer);
virtual void onSetActiveFrame(const doc::frame_t frame);
virtual void onSetSelectedColors(const doc::PalettePicks& picks);
virtual void onSetSelectedTiles(const doc::PalettePicks& picks);
virtual void onCloseDocument(Doc* doc);
Doc* lastSelectedDoc() { return m_lastSelectedDoc; }

View File

@ -116,6 +116,9 @@ void ContextFlags::updateFlagsFromSite(const Site& site)
if (site.selectedColors().picks() > 0)
m_flags |= HasSelectedColors;
if (site.selectedTiles().picks() > 0)
m_flags |= HasSelectedTiles;
}
} // namespace app

View File

@ -35,6 +35,7 @@ namespace app {
ActiveLayerIsReference = 1 << 13,
ActiveLayerIsTilemap = 1 << 14,
HasSelectedColors = 1 << 15,
HasSelectedTiles = 1 << 16,
};
ContextFlags();

View File

@ -20,6 +20,7 @@
#include "doc/layer.h"
#include "doc/object_ids.h"
#include "doc/sprite.h"
#include "doc/tile.h"
#include <algorithm>
#include <set>
@ -37,6 +38,7 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs
std::vector<frame_t> frames;
std::set<ObjectId> cels;
std::vector<color_t> colors;
std::vector<tile_index> tiles;
RangeObj(Site& site) {
const DocRange& docRange = site.range();
@ -67,6 +69,9 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs
if (site.selectedColors().picks() > 0)
colors = site.selectedColors().toVectorOfIndexes();
if (site.selectedTiles().picks() > 0)
tiles = site.selectedTiles().toVectorOfIndexes();
}
RangeObj(const RangeObj&) = delete;
RangeObj& operator=(const RangeObj&) = delete;
@ -85,6 +90,9 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs
bool containsColor(const color_t color) const {
return (std::find(colors.begin(), colors.end(), color) != colors.end());
}
bool containsTile(const tile_t tile) const {
return (std::find(tiles.begin(), tiles.end(), tile) != tiles.end());
}
};
int Range_gc(lua_State* L)
@ -128,11 +136,19 @@ int Range_contains(lua_State* L)
int Range_containsColor(lua_State* L)
{
auto obj = get_obj<RangeObj>(L, 1);
color_t color = lua_tointeger(L, 2);
const color_t color = lua_tointeger(L, 2);
lua_pushboolean(L, obj->containsColor(color));
return 1;
}
int Range_containsTile(lua_State* L)
{
auto obj = get_obj<RangeObj>(L, 1);
const tile_index tile = lua_tointeger(L, 2);
lua_pushboolean(L, obj->containsTile(tile));
return 1;
}
int Range_get_isEmpty(lua_State* L)
{
auto obj = get_obj<RangeObj>(L, 1);
@ -212,6 +228,18 @@ int Range_get_colors(lua_State* L)
return 1;
}
int Range_get_tiles(lua_State* L)
{
auto obj = get_obj<RangeObj>(L, 1);
lua_newtable(L);
int j = 1;
for (tile_index i : obj->tiles) {
lua_pushinteger(L, i);
lua_rawseti(L, -2, j++);
}
return 1;
}
int Range_set_colors(lua_State* L)
{
app::Context* ctx = App::instance()->context();
@ -230,10 +258,29 @@ int Range_set_colors(lua_State* L)
return 0;
}
int Range_set_tiles(lua_State* L)
{
app::Context* ctx = App::instance()->context();
doc::PalettePicks picks;
if (lua_istable(L, 2)) {
lua_pushnil(L);
while (lua_next(L, 2) != 0) {
int i = lua_tointeger(L, -1);
if (i >= picks.size())
picks.resize(i+1);
picks[i] = true;
lua_pop(L, 1);
}
}
ctx->setSelectedTiles(picks);
return 0;
}
const luaL_Reg Range_methods[] = {
{ "__gc", Range_gc },
{ "contains", Range_contains },
{ "containsColor", Range_containsColor },
{ "containsTile", Range_containsTile },
{ nullptr, nullptr }
};
@ -247,6 +294,7 @@ const Property Range_properties[] = {
{ "images", Range_get_images, nullptr },
{ "editableImages", Range_get_editableImages, nullptr },
{ "colors", Range_get_colors, Range_set_colors },
{ "tiles", Range_get_tiles, Range_set_tiles },
{ nullptr, nullptr, nullptr }
};

View File

@ -91,6 +91,13 @@ namespace app {
m_selectedColors = colors;
}
// Selected tiles selected in the ColorBar
const doc::PalettePicks& selectedTiles() const { return m_selectedTiles; }
doc::PalettePicks& selectedTiles() { return m_selectedTiles; }
void selectedTiles(const doc::PalettePicks& tiles) {
m_selectedTiles = tiles;
}
const doc::SelectedObjects& selectedSlices() const { return m_selectedSlices; }
doc::SelectedObjects& selectedSlices() { return m_selectedSlices; }
void selectedSlices(const doc::SelectedObjects& set) {
@ -116,6 +123,7 @@ namespace app {
doc::frame_t m_frame;
DocRange m_range;
doc::PalettePicks m_selectedColors;
doc::PalettePicks m_selectedTiles;
doc::SelectedObjects m_selectedSlices;
TilesetMode m_tilesetMode;
};

View File

@ -5,7 +5,7 @@
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#define COLOR_BAR_TRACE(...)
#define COLOR_BAR_TRACE(...) // TRACE
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -16,6 +16,8 @@
#include "app/app.h"
#include "app/app_menus.h"
#include "app/cmd/remap_colors.h"
#include "app/cmd/remap_tilemaps.h"
#include "app/cmd/remap_tileset.h"
#include "app/cmd/remove_tile.h"
#include "app/cmd/replace_image.h"
#include "app/cmd/set_palette.h"
@ -50,6 +52,7 @@
#include "app/ui/timeline/timeline.h"
#include "app/ui_context.h"
#include "app/ui_context.h"
#include "app/util/cel_ops.h"
#include "app/util/clipboard.h"
#include "base/bind.h"
#include "base/scoped_value.h"
@ -64,6 +67,7 @@
#include "doc/rgbmap.h"
#include "doc/sort_palette.h"
#include "doc/sprite.h"
#include "doc/tileset_hash_table.h"
#include "os/surface.h"
#include "ui/alert.h"
#include "ui/graphics.h"
@ -146,7 +150,8 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
, m_splitter(Splitter::ByPercentage, VERTICAL)
, m_paletteView(true, PaletteView::FgBgColors, this, 16)
, m_tilesView(true, PaletteView::FgBgTiles, this, 16)
, m_remapButton("Remap")
, m_remapPalButton(Strings::color_bar_remap_palette())
, m_remapTilesButton(Strings::color_bar_remap_tiles())
, m_selector(ColorSelector::NONE)
, m_tintShadeTone(nullptr)
, m_spectrum(nullptr)
@ -199,11 +204,13 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
m_scrollableTilesView.setExpansive(true);
m_scrollableTilesView.setVisible(false);
m_remapButton.setVisible(false);
m_remapPalButton.setVisible(false);
m_remapTilesButton.setVisible(false);
m_palettePlaceholder.addChild(&m_scrollablePalView);
m_palettePlaceholder.addChild(&m_scrollableTilesView);
m_palettePlaceholder.addChild(&m_remapButton);
m_palettePlaceholder.addChild(&m_remapPalButton);
m_palettePlaceholder.addChild(&m_remapTilesButton);
m_splitter.setId("palette_spectrum_splitter");
m_splitter.setPosition(80);
m_splitter.setExpansive(true);
@ -249,7 +256,8 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
m_fgColor.setExpansive(true);
m_bgColor.setExpansive(true);
m_remapButton.Click.connect(base::Bind<void>(&ColorBar::onRemapButtonClick, this));
m_remapPalButton.Click.connect(base::Bind<void>(&ColorBar::onRemapPalButtonClick, this));
m_remapTilesButton.Click.connect(base::Bind<void>(&ColorBar::onRemapTilesButtonClick, this));
m_fgColor.Change.connect(&ColorBar::onFgColorButtonChange, this);
m_fgColor.BeforeChange.connect(&ColorBar::onFgColorButtonBeforeChange, this);
m_bgColor.Change.connect(&ColorBar::onBgColorButtonChange, this);
@ -328,7 +336,8 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
m_fgConn = Preferences::instance().colorBar.fgColor.AfterChange.connect(base::Bind<void>(&ColorBar::onFgColorChangeFromPreferences, this));
m_bgConn = Preferences::instance().colorBar.bgColor.AfterChange.connect(base::Bind<void>(&ColorBar::onBgColorChangeFromPreferences, this));
m_sepConn = Preferences::instance().colorBar.entriesSeparator.AfterChange.connect(base::Bind<void>(&ColorBar::invalidate, this));
m_paletteView.FocusOrClick.connect(&ColorBar::onFocusPaletteView, this);
m_paletteView.FocusOrClick.connect(&ColorBar::onFocusPaletteOrTilesView, this);
m_tilesView.FocusOrClick.connect(&ColorBar::onFocusPaletteOrTilesView, this);
m_appPalChangeConn = App::instance()->PaletteChange.connect(&ColorBar::onAppPaletteChange, this);
KeyboardShortcuts::instance()->UserChange.connect(
base::Bind<void>(&ColorBar::setupTooltips, this, tooltipManager));
@ -542,7 +551,8 @@ void ColorBar::onActiveSiteChange(const Site& site)
if (m_lastDocument)
m_lastDocument->add_observer(this);
hideRemap();
hideRemapPal();
hideRemapTiles();
}
bool isTilemap = false;
@ -599,7 +609,7 @@ void ColorBar::onAppPaletteChange()
updateWarningIcon(m_bgColor.getColor(), m_bgWarningIcon);
}
void ColorBar::onFocusPaletteView(ui::Message* msg)
void ColorBar::onFocusPaletteOrTilesView(ui::Message* msg)
{
App::instance()->inputChain().prioritize(this, msg);
}
@ -608,8 +618,9 @@ void ColorBar::onBeforeExecuteCommand(CommandExecutionEvent& ev)
{
if (ev.command()->id() == CommandId::SetPalette() ||
ev.command()->id() == CommandId::LoadPalette() ||
ev.command()->id() == CommandId::ColorQuantization())
showRemap();
ev.command()->id() == CommandId::ColorQuantization()) {
showRemapPal();
}
}
void ColorBar::onAfterExecuteCommand(CommandExecutionEvent& ev)
@ -619,12 +630,19 @@ void ColorBar::onAfterExecuteCommand(CommandExecutionEvent& ev)
invalidate();
// If the sprite isn't Indexed anymore (e.g. because we've just
// undone a "RGB -> Indexed" conversion), we hide the "Remap"
// button.
// undone a "RGB -> Indexed" conversion), we hide the "Remap
// Palette" button.
Site site = UIContext::instance()->activeSite();
if (site.sprite() &&
site.sprite()->pixelFormat() != IMAGE_INDEXED) {
hideRemap();
hideRemapPal();
}
// If the layer isn't a tilemap anymore, we hide the "Remap Tiles"
// button.
if (site.layer() &&
!site.layer()->isTilemap()) {
hideRemapTiles();
}
}
@ -670,7 +688,7 @@ void ColorBar::onTilesetModeButtonClick()
setTilesetMode(static_cast<TilesetMode>(item));
}
void ColorBar::onRemapButtonClick()
void ColorBar::onRemapPalButtonClick()
{
ASSERT(m_oldPalette);
@ -741,7 +759,59 @@ void ColorBar::onRemapButtonClick()
tx.commit();
}
update_screen_for_document(writer.document());
hideRemap();
hideRemapPal();
}
catch (base::Exception& e) {
Console::showException(e);
}
}
void ColorBar::onRemapTilesButtonClick()
{
COLOR_BAR_TRACE("remapTiles\n");
try {
ContextWriter writer(UIContext::instance(), 500);
Sprite* sprite = writer.sprite();
if (!sprite)
return;
auto tileset = m_tilesView.tileset();
doc::TilesetHashTable hash;
{
doc::tile_index i = 0;
for (const auto& image : *tileset) {
ASSERT(image);
hash[image] = i++;
}
}
// Remap all tiles in the same order as in newTileset
Remap remap(tileset->size());
for (tile_index ti=0; ti<remap.size(); ++ti) {
auto img = m_oldTileset->get(ti);
if (img && hash.find(img) != hash.end()) {
auto destTi = hash[img];
COLOR_BAR_TRACE(" - Remap tile %d -> %d\n", ti, destTi);
remap.map(ti, destTi);
}
else {
remap.map(ti, ti);
}
}
// Nothing to remap
if (remap.isIdentity()) {
COLOR_BAR_TRACE(" - Nothing to remap\n");
return;
}
Tx tx(writer.context(), Strings::color_bar_remap_tiles(), ModifyDocument);
tx(new cmd::RemapTilemaps(tileset, remap));
tx.commit();
hideRemapTiles();
// TODO this should be automatic in last ~Tx() destruction
manager()->invalidate();
}
catch (base::Exception& e) {
Console::showException(e);
@ -752,10 +822,6 @@ void ColorBar::onPaletteViewIndexChange(int index, ui::MouseButtons buttons)
{
COLOR_BAR_TRACE("ColorBar::onPaletteViewIndexChange(%d)\n", index);
// TODO select tiles to stamp
if (inTilesMode())
return;
base::ScopedValue<bool> lock(m_fromPalView, true, m_fromPalView);
app::Color color = app::Color::fromIndex(index);
@ -784,10 +850,10 @@ void ColorBar::onPaletteViewModification(const Palette* newPalette,
void ColorBar::setPalette(const doc::Palette* newPalette, const std::string& actionText)
{
showRemap();
showRemapPal();
try {
ContextWriter writer(UIContext::instance());
ContextWriter writer(UIContext::instance(), 500);
Sprite* sprite = writer.sprite();
frame_t frame = writer.frame();
if (sprite &&
@ -884,7 +950,7 @@ app::Color ColorBar::onPaletteViewGetBackgroundIndex()
return getBgColor();
}
void ColorBar::onPaletteViewClearTiles(const doc::PalettePicks& picks)
void ColorBar::onTilesViewClearTiles(const doc::PalettePicks& picks)
{
try {
ContextWriter writer(UIContext::instance(), 500);
@ -894,9 +960,13 @@ void ColorBar::onPaletteViewClearTiles(const doc::PalettePicks& picks)
auto tileset = m_tilesView.tileset();
Tx tx(writer.context(), "Clear Tiles", ModifyDocument);
for (auto ti : picks)
tx(new cmd::RemoveTile(tileset, ti));
for (doc::tile_index ti=0; ti<picks.size(); ++ti) {
if (picks[ti])
tx(new cmd::RemoveTile(tileset, ti));
}
tx.commit();
update_screen_for_document(writer.document());
}
}
catch (base::Exception& e) {
@ -904,6 +974,78 @@ void ColorBar::onPaletteViewClearTiles(const doc::PalettePicks& picks)
}
}
void ColorBar::onTilesViewResize(const int newSize)
{
auto tileset = m_tilesView.tileset();
if (!tileset || tileset->size() == newSize)
return;
try {
ContextWriter writer(UIContext::instance(), 500);
Sprite* sprite = writer.sprite();
ASSERT(writer.layer()->isTilemap());
if (sprite) {
auto tileset = m_tilesView.tileset();
Tx tx(writer.context(), Strings::color_bar_resize_tiles(), ModifyDocument);
if (tileset->size() < newSize) {
for (doc::tile_index ti=tileset->size(); ti<newSize; ++ti) {
ImageRef img = tileset->makeEmptyTile();
tx(new cmd::AddTile(tileset, img));
}
}
else {
for (doc::tile_index ti=tileset->size()-1;
ti!=(doc::tile_index)newSize-1; --ti) {
tx(new cmd::RemoveTile(tileset, ti));
}
}
tx.commit();
// TODO this should be automatic (when tileset is changed after a transaction)
m_scrollableTilesView.updateView();
update_screen_for_document(writer.document());
}
}
catch (base::Exception& e) {
Console::showException(e);
}
}
void ColorBar::onTilesViewDragAndDrop(doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
const int beforeIndex,
const bool isCopy)
{
COLOR_BAR_TRACE("ColorBar::onTilesViewDragAndDrop() -> beforeIndex=%d\n",
beforeIndex);
showRemapTiles();
try {
ContextWriter writer(UIContext::instance(), 500);
Tx tx(writer.context(), Strings::color_bar_drag_and_drop_tiles(), ModifyDocument);
if (isCopy)
copy_tiles_in_tileset(tx, tileset, picks, currentEntry, beforeIndex);
else
move_tiles_in_tileset(tx, tileset, picks, currentEntry, beforeIndex);
tx.commit();
m_scrollableTilesView.updateView();
update_screen_for_document(writer.document());
}
catch (base::Exception& e) {
Console::showException(e);
}
}
void ColorBar::onTilesViewIndexChange(int index, ui::MouseButtons buttons)
{
// TODO show tools to stamp/draw/pick tiles
}
void ColorBar::onFgColorChangeFromPreferences()
{
COLOR_BAR_TRACE("ColorBar::onFgColorChangeFromPreferences() -> %s\n",
@ -1132,26 +1274,51 @@ void ColorBar::setAscending(bool ascending)
m_ascending = ascending;
}
void ColorBar::showRemap()
void ColorBar::showRemapPal()
{
Site site = UIContext::instance()->activeSite();
if (site.sprite() &&
site.sprite()->pixelFormat() == IMAGE_INDEXED) {
if (!m_oldPalette) {
m_oldPalette.reset(new Palette(*get_current_palette()));
m_remapButton.setVisible(true);
m_remapPalButton.setVisible(true);
layout();
}
}
}
void ColorBar::hideRemap()
void ColorBar::showRemapTiles()
{
Site site = UIContext::instance()->activeSite();
if (site.layer() &&
site.layer()->isTilemap()) {
if (!m_oldTileset) {
m_oldTileset.reset(
Tileset::MakeCopyCopyingImages(
static_cast<LayerTilemap*>(site.layer())->tileset()));
m_remapTilesButton.setVisible(true);
layout();
}
}
}
void ColorBar::hideRemapPal()
{
if (!m_oldPalette)
return;
m_oldPalette.reset();
m_remapButton.setVisible(false);
m_remapPalButton.setVisible(false);
layout();
}
void ColorBar::hideRemapTiles()
{
if (!m_oldTileset)
return;
m_oldTileset.reset();
m_remapTilesButton.setVisible(false);
layout();
}
@ -1162,34 +1329,46 @@ void ColorBar::onNewInputPriority(InputChainElement* element,
msg && (msg->ctrlPressed() || msg->shiftPressed()))
return;
if (element != this)
m_paletteView.deselect();
if (element != this) {
if (m_tilesMode)
m_tilesView.deselect();
else
m_paletteView.deselect();
}
}
bool ColorBar::onCanCut(Context* ctx)
{
return (m_paletteView.getSelectedEntriesCount() > 0);
if (m_tilesMode)
return (m_tilesView.getSelectedEntriesCount() > 0);
else
return (m_paletteView.getSelectedEntriesCount() > 0);
}
bool ColorBar::onCanCopy(Context* ctx)
{
return (m_paletteView.getSelectedEntriesCount() > 0);
return onCanCut(ctx);
}
bool ColorBar::onCanPaste(Context* ctx)
{
return (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries);
if (m_tilesMode)
return (clipboard::get_current_format() == clipboard::ClipboardTiles);
else
return (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries);
}
bool ColorBar::onCanClear(Context* ctx)
{
return (m_paletteView.getSelectedEntriesCount() > 0);
return onCanCut(ctx);
}
bool ColorBar::onCut(Context* ctx)
{
if (m_tilesMode)
if (m_tilesMode) {
m_tilesView.cutToClipboard();
showRemapTiles();
}
else
m_paletteView.cutToClipboard();
return true;
@ -1206,8 +1385,10 @@ bool ColorBar::onCopy(Context* ctx)
bool ColorBar::onPaste(Context* ctx)
{
if (m_tilesMode)
if (m_tilesMode) {
m_tilesView.pasteFromClipboard();
showRemapTiles();
}
else
m_paletteView.pasteFromClipboard();
return true;
@ -1215,8 +1396,10 @@ bool ColorBar::onPaste(Context* ctx)
bool ColorBar::onClear(Context* ctx)
{
if (m_tilesMode)
if (m_tilesMode) {
m_tilesView.clearSelection();
showRemapTiles();
}
else
m_paletteView.clearSelection();
return true;
@ -1416,7 +1599,8 @@ void ColorBar::setupTooltips(TooltipManager* tooltipManager)
tooltipManager->addTooltipFor(m_buttons.getItem((int)PalButton::SORT), Strings::color_bar_sort_and_gradients(), BOTTOM);
tooltipManager->addTooltipFor(m_buttons.getItem((int)PalButton::PRESETS), Strings::color_bar_presets(), BOTTOM);
tooltipManager->addTooltipFor(m_buttons.getItem((int)PalButton::OPTIONS), Strings::color_bar_options(), BOTTOM);
tooltipManager->addTooltipFor(&m_remapButton, Strings::color_bar_remap_palette_tooltip(), BOTTOM);
tooltipManager->addTooltipFor(&m_remapPalButton, Strings::color_bar_remap_palette_tooltip(), BOTTOM);
tooltipManager->addTooltipFor(&m_remapTilesButton, Strings::color_bar_remap_tiles_tooltip(), BOTTOM);
tooltipManager->addTooltipFor(
m_tilesButton.getItem(0),

View File

@ -21,6 +21,7 @@
#include "doc/object_id.h"
#include "doc/pixel_format.h"
#include "doc/sort_palette.h"
#include "doc/tileset.h"
#include "obs/connection.h"
#include "obs/signal.h"
#include "ui/box.h"
@ -113,7 +114,7 @@ namespace app {
protected:
void onAppPaletteChange();
void onFocusPaletteView(ui::Message* msg);
void onFocusPaletteOrTilesView(ui::Message* msg);
void onBeforeExecuteCommand(CommandExecutionEvent& ev);
void onAfterExecuteCommand(CommandExecutionEvent& ev);
void onSwitchPalEditMode();
@ -121,7 +122,8 @@ namespace app {
void onTilesButtonClick();
void onTilesetModeButtonClick();
void onTilesetOptionsClick();
void onRemapButtonClick();
void onRemapPalButtonClick();
void onRemapTilesButtonClick();
void onPaletteIndexChange(PaletteIndexChangeEvent& ev);
void onFgColorChangeFromPreferences();
void onBgColorChangeFromPreferences();
@ -144,11 +146,20 @@ namespace app {
void onPaletteViewPasteColors(const Palette* fromPal, const doc::PalettePicks& from, const doc::PalettePicks& to) override;
app::Color onPaletteViewGetForegroundIndex() override;
app::Color onPaletteViewGetBackgroundIndex() override;
void onPaletteViewClearTiles(const doc::PalettePicks& picks) override;
void onTilesViewClearTiles(const doc::PalettePicks& picks) override;
void onTilesViewResize(const int newSize) override;
void onTilesViewDragAndDrop(doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
const int beforeIndex,
const bool isCopy) override;
void onTilesViewIndexChange(int index, ui::MouseButtons buttons) override;
private:
void showRemap();
void hideRemap();
void showRemapPal();
void showRemapTiles();
void hideRemapPal();
void hideRemapTiles();
void setPalette(const doc::Palette* newPalette, const std::string& actionText);
void setTransparentIndex(int index);
void updateWarningIcon(const app::Color& color, ui::Button* warningIcon);
@ -184,7 +195,8 @@ namespace app {
ScrollableView m_scrollableTilesView;
PaletteView m_paletteView;
PaletteView m_tilesView;
ui::Button m_remapButton;
ui::Button m_remapPalButton;
ui::Button m_remapTilesButton;
ColorSelector m_selector;
ColorTintShadeTone* m_tintShadeTone;
ColorSpectrum* m_spectrum;
@ -206,6 +218,7 @@ namespace app {
bool m_fromBgButton;
std::unique_ptr<doc::Palette> m_oldPalette;
std::unique_ptr<doc::Tileset> m_oldTileset;
Doc* m_lastDocument;
doc::ObjectId m_lastTilesetId;
bool m_ascending;

View File

@ -5,6 +5,8 @@
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#define PAL_TRACE(...) // TRACEARGS
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -52,6 +54,7 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <set>
namespace app {
@ -67,6 +70,15 @@ public:
virtual void activeSiteChange(const Site& site, doc::PalettePicks& picks) = 0;
virtual void clearSelection(PaletteView* paletteView,
doc::PalettePicks& picks) = 0;
virtual void selectIndex(PaletteView* paletteView,
int index, ui::MouseButtons buttons) = 0;
virtual void resizePalette(PaletteView* paletteView,
int newSize) = 0;
virtual void dropColors(PaletteView* paletteView,
doc::PalettePicks& picks,
int& currentEntry,
const int beforeIndex,
const bool isCopy) = 0;
virtual void showEntryInStatusBar(StatusBar* statusBar, int index) = 0;
virtual void showDragInfoInStatusBar(StatusBar* statusBar, bool copy, int destIndex, int newSize) = 0;
virtual void showResizeInfoInStatusBar(StatusBar* statusBar, int newSize) = 0;
@ -103,7 +115,39 @@ public:
newPalette.setEntry(remap[i], palette.getEntry(i));
}
paletteView->setNewPalette(&palette, &newPalette, PaletteViewModification::CLEAR);
paletteView->setNewPalette(&palette, &newPalette,
PaletteViewModification::CLEAR);
}
void selectIndex(PaletteView* paletteView,
int index, ui::MouseButtons buttons) override {
// Emit signal
if (paletteView->delegate())
paletteView->delegate()->onPaletteViewIndexChange(index, buttons);
}
void resizePalette(PaletteView* paletteView,
int newSize) override {
Palette newPalette(*paletteView->currentPalette());
newPalette.resize(newSize);
paletteView->setNewPalette(paletteView->currentPalette(),
&newPalette,
PaletteViewModification::RESIZE);
}
void dropColors(PaletteView* paletteView,
doc::PalettePicks& picks,
int& currentEntry,
const int beforeIndex,
const bool isCopy) override {
Palette palette(*paletteView->currentPalette());
Palette newPalette(palette);
move_or_copy_palette_colors(
palette,
newPalette,
picks,
currentEntry,
beforeIndex,
isCopy);
paletteView->setNewPalette(&palette, &newPalette,
PaletteViewModification::DRAGANDDROP);
}
void showEntryInStatusBar(StatusBar* statusBar, int index) override {
statusBar->showColor(
@ -175,7 +219,32 @@ public:
}
void clearSelection(PaletteView* paletteView,
doc::PalettePicks& picks) override {
paletteView->delegate()->onPaletteViewClearTiles(picks);
paletteView->delegate()->onTilesViewClearTiles(picks);
}
void selectIndex(PaletteView* paletteView,
int index, ui::MouseButtons buttons) override {
// Emit signal
if (paletteView->delegate())
paletteView->delegate()->onTilesViewIndexChange(index, buttons);
}
void resizePalette(PaletteView* paletteView,
int newSize) override {
paletteView->delegate()->onTilesViewResize(newSize);
}
void dropColors(PaletteView* paletteView,
doc::PalettePicks& picks,
int& currentEntry,
const int beforeIndex,
const bool isCopy) override {
PAL_TRACE("dropColors");
doc::Tileset* tileset = this->tileset();
ASSERT(tileset);
if (!tileset)
return;
paletteView->delegate()->onTilesViewDragAndDrop(
tileset, picks, currentEntry, beforeIndex, isCopy);
}
void showEntryInStatusBar(StatusBar* statusBar, int index) override {
statusBar->setStatusText(
@ -554,9 +623,7 @@ bool PaletteView::onProcessMessage(Message* msg)
}
}
// Emit signal
if (m_delegate)
m_delegate->onPaletteViewIndexChange(idx, buttons);
m_adapter->selectIndex(this, idx, buttons);
}
}
@ -590,11 +657,8 @@ bool PaletteView::onProcessMessage(Message* msg)
case State::RESIZING_PALETTE:
if (m_hot.part == Hit::COLOR ||
m_hot.part == Hit::POSSIBLE_COLOR) {
int newPalSize = MAX(1, m_hot.color);
Palette newPalette(*currentPalette());
newPalette.resize(newPalSize);
setNewPalette(currentPalette(), &newPalette,
PaletteViewModification::RESIZE);
int newSize = std::max(1, m_hot.color);
m_adapter->resizePalette(this, newSize);
}
break;
}
@ -988,17 +1052,11 @@ PaletteView::Hit PaletteView::hitTest(const gfx::Point& pos)
void PaletteView::dropColors(int beforeIndex)
{
Palette palette(*currentPalette());
Palette newPalette(palette);
move_or_copy_palette_colors(
palette,
newPalette,
m_selectedEntries,
m_currentEntry,
beforeIndex,
m_copy);
setNewPalette(&palette, &newPalette,
PaletteViewModification::DRAGANDDROP);
m_adapter->dropColors(this,
m_selectedEntries,
m_currentEntry,
beforeIndex,
m_copy);
}
void PaletteView::getEntryBoundsAndClip(int i, const PalettePicks& entries,

View File

@ -47,17 +47,26 @@ namespace app {
const doc::Palette* fromPal, const doc::PalettePicks& from, const doc::PalettePicks& to) { }
virtual app::Color onPaletteViewGetForegroundIndex() { return app::Color::fromMask(); }
virtual app::Color onPaletteViewGetBackgroundIndex() { return app::Color::fromMask(); }
virtual void onPaletteViewClearTiles(const doc::PalettePicks& tiles) { }
virtual void onTilesViewClearTiles(const doc::PalettePicks& tiles) { }
virtual void onTilesViewResize(const int newSize) { }
virtual void onTilesViewDragAndDrop(doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
const int beforeIndex,
const bool isCopy) { }
virtual void onTilesViewIndexChange(int index, ui::MouseButtons buttons) { }
};
class AbstractPaletteViewAdapter;
class PaletteViewAdapter;
class TilesetViewAdapter;
class PaletteView : public ui::Widget
, public MarchingAnts
, public IColorSource
, public ContextObserver {
friend class PaletteViewAdapter;
friend class TilesetViewAdapter;
public:
enum PaletteViewStyle {
SelectOneColor,

View File

@ -15,7 +15,8 @@
#include "app/cmd/clear_cel.h"
#include "app/cmd/clear_mask.h"
#include "app/cmd/copy_region.h"
#include "app/cmd/remap_tiles.h"
#include "app/cmd/remap_tilemaps.h"
#include "app/cmd/remap_tileset.h"
#include "app/cmd/remove_tile.h"
#include "app/cmd/replace_image.h"
#include "app/cmd/set_cel_position.h"
@ -46,7 +47,7 @@
#include <cmath>
#include <memory>
#define OPS_TRACE(...)
#define OPS_TRACE(...) // TRACE
namespace app {
@ -640,8 +641,46 @@ void remove_unused_tiles_from_tileset(
OPS_TRACE(" - remap tile[%d] -> %d\n", ti, remap[ti]);
}
#endif
cmds->executeAndAdd(new cmd::RemapTiles(tileset, remap));
cmds->executeAndAdd(new cmd::RemapTilemaps(tileset, remap));
}
}
void move_tiles_in_tileset(
CmdSequence* cmds,
doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
int beforeIndex)
{
OPS_TRACE("move_tiles_in_tileset\n");
int n = beforeIndex - tileset->size();
if (n > 0) {
picks.resize(picks.size()+n);
while (n-- > 0)
cmds->executeAndAdd(new cmd::AddTile(tileset, tileset->makeEmptyTile()));
}
Remap remap = create_remap_to_move_picks(picks, beforeIndex);
cmds->executeAndAdd(new cmd::RemapTileset(tileset, remap));
// New selection
auto oldPicks = picks;
for (int i=0; i<picks.size(); ++i)
picks[remap[i]] = oldPicks[i];
currentEntry = remap[currentEntry];
}
void copy_tiles_in_tileset(
CmdSequence* cmds,
doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
int beforeIndex)
{
OPS_TRACE("copy_tiles_in_tileset\n");
// TODO copy tiles
}
} // namespace app

View File

@ -23,6 +23,7 @@ namespace doc {
class Cel;
class Layer;
class LayerTilemap;
class PalettePicks;
class Sprite;
class Tileset;
}
@ -77,6 +78,20 @@ namespace app {
doc::Tileset* tileset,
std::vector<bool>& unusedTiles);
void move_tiles_in_tileset(
CmdSequence* cmds,
doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
int beforeIndex);
void copy_tiles_in_tileset(
CmdSequence* cmds,
doc::Tileset* tileset,
doc::PalettePicks& picks,
int& currentEntry,
int beforeIndex);
} // namespace app
#endif

View File

@ -99,6 +99,7 @@ namespace clipboard {
using namespace doc;
static std::shared_ptr<Palette> clipboard_palette;
static std::shared_ptr<Tileset> clipboard_tiles;
static PalettePicks clipboard_picks;
static ImageRef clipboard_image;
static std::shared_ptr<Mask> clipboard_mask;
@ -226,6 +227,8 @@ ClipboardFormat get_current_format()
return ClipboardDocRange;
else if (clipboard_palette && clipboard_picks.picks())
return ClipboardPaletteEntries;
else if (clipboard_tiles && clipboard_picks.picks())
return ClipboardTiles;
else
return ClipboardNone;
}

View File

@ -38,6 +38,7 @@ namespace app {
ClipboardImage,
ClipboardDocRange,
ClipboardPaletteEntries,
ClipboardTiles,
};
// TODO Horrible API: refactor it (maybe a merge with os::clipboard).

View File

@ -259,8 +259,8 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
bool same_width_columns = bool_attr_is_true(elem, "same_width_columns");
if (columns != NULL) {
widget = new Grid(strtol(columns, NULL, 10),
same_width_columns);
widget = new ui::Grid(strtol(columns, NULL, 10),
same_width_columns);
}
}
else if (elem_name == "label") {
@ -677,16 +677,16 @@ void WidgetLoader::fillWidgetWithXmlElementAttributesWithChildren(const TiXmlEle
int hspan = cell_hspan ? strtol(cell_hspan, NULL, 10): 1;
int vspan = cell_vspan ? strtol(cell_vspan, NULL, 10): 1;
int align = cell_align ? convert_align_value_to_flags(cell_align): 0;
Grid* grid = dynamic_cast<Grid*>(widget);
ASSERT(grid != NULL);
auto grid = dynamic_cast<ui::Grid*>(widget);
ASSERT(grid != nullptr);
grid->addChildInCell(child, hspan, vspan, align);
}
// Attach the child in the view
else if (widget->type() == kComboBoxWidget &&
child->type() == kListItemWidget) {
ComboBox* combo = dynamic_cast<ComboBox*>(widget);
ASSERT(combo != NULL);
auto combo = dynamic_cast<ComboBox*>(widget);
ASSERT(combo != nullptr);
combo->addItem(dynamic_cast<ListItem*>(child));
}

View File

@ -10,6 +10,11 @@
#include "doc/tileset.h"
#include "doc/remap.h"
#include "doc/sprite.h"
#include <memory>
namespace doc {
Tileset::Tileset(Sprite* sprite,
@ -20,6 +25,42 @@ Tileset::Tileset(Sprite* sprite,
, m_grid(grid)
, m_tiles(ntiles)
{
ASSERT(sprite);
for (tile_index ti=0; ti<ntiles; ++ti)
m_tiles[ti] = makeEmptyTile();
}
// static
Tileset* Tileset::MakeCopyWithSameImages(const Tileset* tileset)
{
std::unique_ptr<Tileset> copy(
new Tileset(tileset->sprite(),
tileset->grid(),
tileset->size()));
copy->setName(tileset->name());
for (tile_index ti=0; ti<copy->size(); ++ti) {
ImageRef image = tileset->get(ti);
ASSERT(image);
copy->set(ti, image);
}
return copy.release();
}
// static
Tileset* Tileset::MakeCopyCopyingImages(const Tileset* tileset)
{
std::unique_ptr<Tileset> copy(
new Tileset(tileset->sprite(),
tileset->grid(),
tileset->size()));
copy->setName(tileset->name());
for (tile_index ti=0; ti<copy->size(); ++ti) {
ImageRef image = tileset->get(ti);
ASSERT(image);
// TODO can we avoid making a copy of this image
copy->set(ti, ImageRef(Image::createCopy(image.get())));
}
return copy.release();
}
void Tileset::setOrigin(const gfx::Point& pt)
@ -31,15 +72,39 @@ int Tileset::getMemSize() const
{
int size = sizeof(Tileset) + m_name.size();
for (auto& img : const_cast<Tileset*>(this)->m_tiles) {
if (img)
size += img->getMemSize();
ASSERT(img);
size += img->getMemSize();
}
return size;
}
void Tileset::resize(const tile_index ntiles)
{
int oldSize = m_tiles.size();
m_tiles.resize(ntiles);
for (tile_index ti=oldSize; ti<ntiles; ++ti)
m_tiles[ti] = makeEmptyTile();
}
void Tileset::remap(const Remap& remap)
{
Tiles tmp = m_tiles;
for (tile_index ti=0; ti<size(); ++ti) {
TRACE("m_tiles[%d] = tmp[%d]\n", remap[ti], ti);
ASSERT(remap[ti] >= 0);
ASSERT(remap[ti] < m_tiles.size());
if (remap[ti] >= 0 &&
remap[ti] < m_tiles.size()) {
m_tiles[remap[ti]] = tmp[ti];
}
}
}
ImageRef Tileset::makeEmptyTile()
{
ImageSpec spec = m_sprite->spec();
spec.setSize(m_grid.tileSize());
return ImageRef(Image::create(spec));
}
void Tileset::setExternal(const std::string& filename,

View File

@ -18,17 +18,22 @@
namespace doc {
class Remap;
class Sprite;
class Tileset : public Object {
public:
typedef std::vector<ImageRef> Tiles;
typedef Tiles::iterator iterator;
typedef Tiles::const_iterator const_iterator;
Tileset(Sprite* sprite,
const Grid& grid,
const tileset_index ntiles);
static Tileset* MakeCopyWithSameImages(const Tileset* tileset);
static Tileset* MakeCopyCopyingImages(const Tileset* tileset);
Sprite* sprite() const { return m_sprite; }
const Grid& grid() const { return m_grid; }
void setOrigin(const gfx::Point& pt);
@ -40,8 +45,11 @@ namespace doc {
iterator begin() { return m_tiles.begin(); }
iterator end() { return m_tiles.end(); }
const_iterator begin() const { return m_tiles.begin(); }
const_iterator end() const { return m_tiles.end(); }
tile_index size() const { return tile_index(m_tiles.size()); }
void resize(const tile_index ntiles);
void remap(const Remap& remap);
ImageRef get(const tile_index ti) const {
if (ti < size())
@ -77,6 +85,20 @@ namespace doc {
const std::string& externalFilename() const { return m_external.filename; }
tileset_index externalTileset() const { return m_external.tileset; }
bool operator==(const Tileset& other) const {
// TODO compare the all grid members
return (m_grid.tileSize() == other.m_grid.tileSize() &&
m_tiles == other.m_tiles &&
m_name == other.m_name);
}
bool operator!=(const Tileset& other) const {
return !operator==(other);
}
// Returns a new empty tile with the tileset specs.
ImageRef makeEmptyTile();
private:
Sprite* m_sprite;
Grid m_grid;