mirror of https://github.com/aseprite/aseprite.git
Compare commits
3 Commits
7e65915c5a
...
1935e2f147
| Author | SHA1 | Date |
|---|---|---|
|
|
1935e2f147 | |
|
|
80fa065bd5 | |
|
|
27f19959bd |
|
|
@ -13,6 +13,8 @@
|
||||||
#include "app/console.h"
|
#include "app/console.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/context_observer.h"
|
#include "app/context_observer.h"
|
||||||
|
#include "app/doc.h"
|
||||||
|
#include "app/doc_undo.h"
|
||||||
#include "app/script/docobj.h"
|
#include "app/script/docobj.h"
|
||||||
#include "app/script/engine.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/script/luacpp.h"
|
#include "app/script/luacpp.h"
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@
|
||||||
#include "doc/tag.h"
|
#include "doc/tag.h"
|
||||||
#include "doc/tileset.h"
|
#include "doc/tileset.h"
|
||||||
#include "doc/tilesets.h"
|
#include "doc/tilesets.h"
|
||||||
|
#include "undo/undo_state.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
@ -1029,6 +1030,42 @@ int Sprite_set_useLayerUuids(lua_State* L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Sprite_get_undoHistory(lua_State* L)
|
||||||
|
{
|
||||||
|
const auto* sprite = get_docobj<Sprite>(L, 1);
|
||||||
|
const auto* doc = static_cast<Doc*>(sprite->document());
|
||||||
|
const auto* history = doc->undoHistory();
|
||||||
|
|
||||||
|
if (!history) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const undo::UndoState* currentState = history->currentState();
|
||||||
|
const undo::UndoState* s = history->firstState();
|
||||||
|
const bool canRedo = history->canRedo();
|
||||||
|
bool pastCurrent = !currentState && canRedo;
|
||||||
|
|
||||||
|
int undoSteps = 0;
|
||||||
|
int redoSteps = 0;
|
||||||
|
while (s) {
|
||||||
|
if (pastCurrent && canRedo)
|
||||||
|
redoSteps++;
|
||||||
|
else if (currentState || !canRedo)
|
||||||
|
undoSteps++;
|
||||||
|
|
||||||
|
if (s == currentState || !currentState)
|
||||||
|
pastCurrent = true;
|
||||||
|
|
||||||
|
s = s->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
setfield_integer(L, "undoSteps", undoSteps);
|
||||||
|
setfield_integer(L, "redoSteps", redoSteps);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg Sprite_methods[] = {
|
const luaL_Reg Sprite_methods[] = {
|
||||||
{ "__eq", Sprite_eq },
|
{ "__eq", Sprite_eq },
|
||||||
{ "resize", Sprite_resize },
|
{ "resize", Sprite_resize },
|
||||||
|
|
@ -1094,6 +1131,7 @@ const Property Sprite_properties[] = {
|
||||||
{ "events", Sprite_get_events, nullptr },
|
{ "events", Sprite_get_events, nullptr },
|
||||||
{ "tileManagementPlugin", Sprite_get_tileManagementPlugin, Sprite_set_tileManagementPlugin },
|
{ "tileManagementPlugin", Sprite_get_tileManagementPlugin, Sprite_set_tileManagementPlugin },
|
||||||
{ "useLayerUuids", Sprite_get_useLayerUuids, Sprite_set_useLayerUuids },
|
{ "useLayerUuids", Sprite_get_useLayerUuids, Sprite_set_useLayerUuids },
|
||||||
|
{ "undoHistory", Sprite_get_undoHistory, nullptr },
|
||||||
{ nullptr, nullptr, nullptr }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2748,7 +2748,10 @@ void Editor::setZoomAndCenterInMouse(const Zoom& zoom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::pasteImage(const Image* image, const Mask* mask, const gfx::Point* position)
|
void Editor::pasteImage(const Image* image,
|
||||||
|
const Mask* mask,
|
||||||
|
const gfx::Point* position,
|
||||||
|
const Tileset* srcTileset)
|
||||||
{
|
{
|
||||||
ASSERT(image);
|
ASSERT(image);
|
||||||
|
|
||||||
|
|
@ -2840,6 +2843,10 @@ void Editor::pasteImage(const Image* image, const Mask* mask, const gfx::Point*
|
||||||
PixelsMovementPtr pixelsMovement(
|
PixelsMovementPtr pixelsMovement(
|
||||||
new PixelsMovement(UIContext::instance(), site, image, &mask2, "Paste"));
|
new PixelsMovement(UIContext::instance(), site, image, &mask2, "Paste"));
|
||||||
|
|
||||||
|
// Adjust image when copying between tilemap layers
|
||||||
|
if (site.tilemapMode() == TilemapMode::Tiles && srcTileset != nullptr)
|
||||||
|
pixelsMovement->remapTilesForPaste(srcTileset);
|
||||||
|
|
||||||
setState(EditorStatePtr(new MovingPixelsState(this, NULL, pixelsMovement, NoHandle)));
|
setState(EditorStatePtr(new MovingPixelsState(this, NULL, pixelsMovement, NoHandle)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,8 @@ public:
|
||||||
|
|
||||||
void pasteImage(const Image* image,
|
void pasteImage(const Image* image,
|
||||||
const Mask* mask = nullptr,
|
const Mask* mask = nullptr,
|
||||||
const gfx::Point* position = nullptr);
|
const gfx::Point* position = nullptr,
|
||||||
|
const Tileset* srcTileset = nullptr);
|
||||||
|
|
||||||
void startSelectionTransformation(const gfx::Point& move, double angle);
|
void startSelectionTransformation(const gfx::Point& move, double angle);
|
||||||
void startFlipTransformation(doc::algorithm::FlipType flipType);
|
void startFlipTransformation(doc::algorithm::FlipType flipType);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "app/ui/editor/pixels_movement.h"
|
#include "app/ui/editor/pixels_movement.h"
|
||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
|
#include "app/cmd/add_tile.h"
|
||||||
#include "app/cmd/clear_mask.h"
|
#include "app/cmd/clear_mask.h"
|
||||||
#include "app/cmd/deselect_mask.h"
|
#include "app/cmd/deselect_mask.h"
|
||||||
#include "app/cmd/set_mask.h"
|
#include "app/cmd/set_mask.h"
|
||||||
|
|
@ -1356,6 +1357,39 @@ void PixelsMovement::drawTransformedTilemap(const Transformation& transformation
|
||||||
draw_row(dst->height() - 1, src->height() - 1, 1);
|
draw_row(dst->height() - 1, src->height() - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PixelsMovement::remapTilesForPaste(const Tileset* srcTileset)
|
||||||
|
{
|
||||||
|
// Check that tile size matches before doing anything
|
||||||
|
LayerTilemap* dstLayer = static_cast<LayerTilemap*>(m_site.layer());
|
||||||
|
Tileset* dstTileset = dstLayer->tileset();
|
||||||
|
const doc::Grid& srcGrid = srcTileset->grid();
|
||||||
|
const doc::Grid& dstGrid = dstTileset->grid();
|
||||||
|
if (srcGrid.tileSize() != dstGrid.tileSize())
|
||||||
|
throw base::Exception("Tile size does not match.");
|
||||||
|
|
||||||
|
// Map source to destination
|
||||||
|
tile_index dstSz = dstTileset->size();
|
||||||
|
for (int y = 0; y < m_originalImage->height(); ++y) {
|
||||||
|
for (int x = 0; x < m_originalImage->width(); ++x) {
|
||||||
|
// Blank tile can be skipped
|
||||||
|
const color_t srcTi = m_originalImage->getPixel(x, y);
|
||||||
|
if (!srcTi)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add tile to destination if missing
|
||||||
|
tile_index dstTi;
|
||||||
|
const ImageRef t = srcTileset->get(srcTi);
|
||||||
|
if (!dstTileset->findTileIndex(t, dstTi)) {
|
||||||
|
m_tx(new cmd::AddTile(dstTileset, t, srcTileset->getTileData(srcTi)));
|
||||||
|
dstTi = dstSz++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update tile index in image
|
||||||
|
m_originalImage->putPixel(x, y, dstTi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PixelsMovement::onPivotChange()
|
void PixelsMovement::onPivotChange()
|
||||||
{
|
{
|
||||||
set_pivot_from_preferences(m_currentData);
|
set_pivot_from_preferences(m_currentData);
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,9 @@ public:
|
||||||
const Transformation& getTransformation() const { return m_currentData; }
|
const Transformation& getTransformation() const { return m_currentData; }
|
||||||
void setTransformation(const Transformation& t);
|
void setTransformation(const Transformation& t);
|
||||||
|
|
||||||
|
// For copy/paste between tilemap layers
|
||||||
|
void remapTilesForPaste(const Tileset* srcTileset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setTransformationBase(const Transformation& t);
|
void setTransformationBase(const Transformation& t);
|
||||||
void adjustPivot();
|
void adjustPivot();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
|
#include "app/cmd/add_tileset.h"
|
||||||
#include "app/cmd/clear_mask.h"
|
#include "app/cmd/clear_mask.h"
|
||||||
#include "app/cmd/deselect_mask.h"
|
#include "app/cmd/deselect_mask.h"
|
||||||
#include "app/cmd/set_mask.h"
|
#include "app/cmd/set_mask.h"
|
||||||
|
|
@ -584,7 +585,10 @@ void Clipboard::paste(Context* ctx, const bool interactive, const gfx::Point* po
|
||||||
// TODO add post-command parameters (issue #2324)
|
// TODO add post-command parameters (issue #2324)
|
||||||
|
|
||||||
// Change to MovingTilemapState
|
// Change to MovingTilemapState
|
||||||
editor->pasteImage(m_data->tilemap.get(), m_data->mask.get(), position);
|
editor->pasteImage(m_data->tilemap.get(),
|
||||||
|
m_data->mask.get(),
|
||||||
|
position,
|
||||||
|
m_data->tileset.get());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO non-interactive version (for scripts)
|
// TODO non-interactive version (for scripts)
|
||||||
|
|
@ -763,7 +767,14 @@ void Clipboard::paste(Context* ctx, const bool interactive, const gfx::Point* po
|
||||||
afterThis = dstSpr->root()->lastLayer();
|
afterThis = dstSpr->root()->lastLayer();
|
||||||
|
|
||||||
Layer* newLayer = nullptr;
|
Layer* newLayer = nullptr;
|
||||||
if (srcLayer->isImage())
|
if (srcLayer->isTilemap()) {
|
||||||
|
Tileset* srcTileset = static_cast<LayerTilemap*>(srcLayer)->tileset();
|
||||||
|
Tileset* tilesetCopy = Tileset::MakeCopyCopyingImagesForSprite(srcTileset, dstSpr);
|
||||||
|
const tileset_index tsi = dstSpr->tilesets()->size();
|
||||||
|
tx(new cmd::AddTileset(dstSpr, tilesetCopy));
|
||||||
|
newLayer = new LayerTilemap(dstSpr, tsi);
|
||||||
|
}
|
||||||
|
else if (srcLayer->isImage())
|
||||||
newLayer = new LayerImage(dstSpr);
|
newLayer = new LayerImage(dstSpr);
|
||||||
else if (srcLayer->isGroup())
|
else if (srcLayer->isGroup())
|
||||||
newLayer = new LayerGroup(dstSpr);
|
newLayer = new LayerGroup(dstSpr);
|
||||||
|
|
|
||||||
|
|
@ -228,3 +228,69 @@ do
|
||||||
c = app.open(fn)
|
c = app.open(fn)
|
||||||
assert(c.tileManagementPlugin == nil)
|
assert(c.tileManagementPlugin == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Undo History
|
||||||
|
|
||||||
|
function test_undo_history()
|
||||||
|
local sprite = Sprite(1, 1)
|
||||||
|
|
||||||
|
assert(sprite.undoHistory.undoSteps == 0)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 0)
|
||||||
|
|
||||||
|
sprite:resize(10, 10)
|
||||||
|
|
||||||
|
assert(sprite.undoHistory.undoSteps == 1)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 0)
|
||||||
|
|
||||||
|
sprite:resize(10, 15)
|
||||||
|
|
||||||
|
assert(sprite.undoHistory.undoSteps == 2)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 0)
|
||||||
|
|
||||||
|
sprite:resize(10, 30)
|
||||||
|
|
||||||
|
assert(sprite.undoHistory.undoSteps == 3)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 0)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(sprite.undoHistory.undoSteps == 2)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 1)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(sprite.undoHistory.undoSteps == 1)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 2)
|
||||||
|
|
||||||
|
app.redo()
|
||||||
|
assert(sprite.undoHistory.undoSteps == 2)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 1)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
assert(sprite.undoHistory.undoSteps == 0)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 3)
|
||||||
|
|
||||||
|
sprite:resize(10, 30)
|
||||||
|
|
||||||
|
if (app.preferences.undo.allow_nonlinear_history) then
|
||||||
|
assert(sprite.undoHistory.undoSteps == 4)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 0)
|
||||||
|
else
|
||||||
|
assert(sprite.undoHistory.undoSteps == 1)
|
||||||
|
assert(sprite.undoHistory.redoSteps == 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local prevSetting = app.preferences.undo.allow_nonlinear_history
|
||||||
|
app.preferences.undo.allow_nonlinear_history = true
|
||||||
|
test_undo_history()
|
||||||
|
app.preferences.undo.allow_nonlinear_history = prevSetting
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local prevSetting = app.preferences.undo.allow_nonlinear_history
|
||||||
|
app.preferences.undo.allow_nonlinear_history = false
|
||||||
|
test_undo_history()
|
||||||
|
app.preferences.undo.allow_nonlinear_history = prevSetting
|
||||||
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue