mirror of https://github.com/aseprite/aseprite.git
Compare commits
8 Commits
6df09c554b
...
ffb5b0999b
Author | SHA1 | Date |
---|---|---|
|
ffb5b0999b | |
|
80fa065bd5 | |
|
de1ccb24dd | |
|
7d91c4b9d9 | |
|
6d89a6bc15 | |
|
d4e97b5a96 | |
|
205b18dc0f | |
|
c98a2056e5 |
2
laf
2
laf
|
@ -1 +1 @@
|
||||||
Subproject commit a2bb9ec7fb98354279a2c49870a4a47a67a8e86e
|
Subproject commit 8ec4b553f1618f7a4b47cdcf4cfc2663266111ac
|
|
@ -705,6 +705,7 @@ target_sources(app-lib PRIVATE
|
||||||
util/filetoks.cpp
|
util/filetoks.cpp
|
||||||
util/layer_boundaries.cpp
|
util/layer_boundaries.cpp
|
||||||
util/layer_utils.cpp
|
util/layer_utils.cpp
|
||||||
|
util/moving_utils.cpp
|
||||||
util/msk_file.cpp
|
util/msk_file.cpp
|
||||||
util/new_image_from_mask.cpp
|
util/new_image_from_mask.cpp
|
||||||
util/open_file_job.cpp
|
util/open_file_job.cpp
|
||||||
|
|
|
@ -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 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
|
@ -247,14 +247,10 @@ void MovingCelState::onCommitMouseMove(Editor* editor, const gfx::PointF& newCur
|
||||||
m_celOffset = newCursorPos - m_cursorStart;
|
m_celOffset = newCursorPos - m_cursorStart;
|
||||||
if (int(editor->getCustomizationDelegate()->getPressedKeyAction(
|
if (int(editor->getCustomizationDelegate()->getPressedKeyAction(
|
||||||
KeyContext::TranslatingSelection) &
|
KeyContext::TranslatingSelection) &
|
||||||
KeyAction::LockAxis)) {
|
KeyAction::LockAxis))
|
||||||
if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) {
|
app::lockAxis(m_lockedAxis, m_celOffset);
|
||||||
m_celOffset.x = 0;
|
else
|
||||||
}
|
m_lockedAxis = NONE;
|
||||||
else {
|
|
||||||
m_celOffset.y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_moved && intCelOffset() != gfx::Point(0, 0))
|
if (!m_moved && intCelOffset() != gfx::Point(0, 0))
|
||||||
m_moved = true;
|
m_moved = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2021-2022 Igara Studio S.A.
|
// Copyright (C) 2021-2025 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/ui/editor/delayed_mouse_move.h"
|
#include "app/ui/editor/delayed_mouse_move.h"
|
||||||
#include "app/ui/editor/handle_type.h"
|
#include "app/ui/editor/handle_type.h"
|
||||||
|
#include "app/util/moving_utils.h"
|
||||||
#include "doc/cel_list.h"
|
#include "doc/cel_list.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -80,6 +81,7 @@ private:
|
||||||
gfx::PointF m_celOffset;
|
gfx::PointF m_celOffset;
|
||||||
gfx::SizeF m_celMainSize;
|
gfx::SizeF m_celMainSize;
|
||||||
gfx::SizeF m_celScale;
|
gfx::SizeF m_celScale;
|
||||||
|
LockedAxis m_lockedAxis;
|
||||||
bool m_maskVisible;
|
bool m_maskVisible;
|
||||||
bool m_hasReference = false;
|
bool m_hasReference = false;
|
||||||
bool m_moved = false;
|
bool m_moved = false;
|
||||||
|
|
|
@ -376,6 +376,7 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
|
||||||
switch (m_handle) {
|
switch (m_handle) {
|
||||||
case MovePixelsHandle: {
|
case MovePixelsHandle: {
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
|
const bool isLockAxis = ((moveModifier & LockAxisMovement) == LockAxisMovement);
|
||||||
if (tilesModeOn) {
|
if (tilesModeOn) {
|
||||||
if (m_catchPos.x == 0 && m_catchPos.y == 0) {
|
if (m_catchPos.x == 0 && m_catchPos.y == 0) {
|
||||||
// Movement through keyboard:
|
// Movement through keyboard:
|
||||||
|
@ -393,7 +394,8 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
|
||||||
dy = point.y;
|
dy = point.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((moveModifier & FineControl) == 0) {
|
// FineControl is discarded if 'Locked Axis' is active
|
||||||
|
else if (isLockAxis || ((moveModifier & FineControl) == 0)) {
|
||||||
dx = (std::floor(pos.x) - std::floor(m_catchPos.x));
|
dx = (std::floor(pos.x) - std::floor(m_catchPos.x));
|
||||||
dy = (std::floor(pos.y) - std::floor(m_catchPos.y));
|
dy = (std::floor(pos.y) - std::floor(m_catchPos.y));
|
||||||
}
|
}
|
||||||
|
@ -402,12 +404,10 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
|
||||||
dy = (pos.y - m_catchPos.y);
|
dy = (pos.y - m_catchPos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((moveModifier & LockAxisMovement) == LockAxisMovement) {
|
if (isLockAxis)
|
||||||
if (std::abs(dx) < std::abs(dy))
|
lockAxis(m_lockedAxis, dx, dy);
|
||||||
dx = 0.0;
|
else
|
||||||
else
|
m_lockedAxis = LockedAxis::NONE;
|
||||||
dy = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bounds.offset(dx, dy);
|
bounds.offset(dx, dy);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
#include "app/transformation.h"
|
#include "app/transformation.h"
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
#include "app/ui/editor/handle_type.h"
|
#include "app/ui/editor/handle_type.h"
|
||||||
|
#include "app/util/moving_utils.h"
|
||||||
#include "doc/algorithm/flip_type.h"
|
#include "doc/algorithm/flip_type.h"
|
||||||
#include "doc/frame.h"
|
#include "doc/frame.h"
|
||||||
#include "doc/image_ref.h"
|
#include "doc/image_ref.h"
|
||||||
|
@ -190,6 +191,7 @@ private:
|
||||||
Transformation m_currentData;
|
Transformation m_currentData;
|
||||||
std::unique_ptr<Mask> m_initialMask, m_initialMask0;
|
std::unique_ptr<Mask> m_initialMask, m_initialMask0;
|
||||||
std::unique_ptr<Mask> m_currentMask;
|
std::unique_ptr<Mask> m_currentMask;
|
||||||
|
LockedAxis m_lockedAxis;
|
||||||
bool m_opaque;
|
bool m_opaque;
|
||||||
color_t m_maskColor;
|
color_t m_maskColor;
|
||||||
obs::scoped_connection m_pivotVisConn;
|
obs::scoped_connection m_pivotVisConn;
|
||||||
|
|
|
@ -443,12 +443,7 @@ bool WritingTextState::onSetCursor(Editor* editor, const gfx::Point& mouseScreen
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WritingTextState::onKeyDown(Editor*, KeyMessage*)
|
bool WritingTextState::onKeyDown(Editor*, KeyMessage* msg)
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WritingTextState::onKeyUp(Editor*, KeyMessage* msg)
|
|
||||||
{
|
{
|
||||||
// Cancel loop pressing Esc key
|
// Cancel loop pressing Esc key
|
||||||
if (msg->scancode() == ui::kKeyEsc) {
|
if (msg->scancode() == ui::kKeyEsc) {
|
||||||
|
@ -457,7 +452,17 @@ bool WritingTextState::onKeyUp(Editor*, KeyMessage* msg)
|
||||||
// Drop text pressing Enter key
|
// Drop text pressing Enter key
|
||||||
else if (msg->scancode() == ui::kKeyEnter) {
|
else if (msg->scancode() == ui::kKeyEnter) {
|
||||||
drop();
|
drop();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WritingTextState::onKeyUp(Editor*, KeyMessage* msg)
|
||||||
|
{
|
||||||
|
// Note: We cannot process kKeyEnter key here to drop the text as it
|
||||||
|
// could be received after the Enter key is pressed in the IME
|
||||||
|
// dialog to accept the composition (not to accept the text). So we
|
||||||
|
// process kKeyEnter in onKeyDown().
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2025 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#include "app/util/moving_utils.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
void lockAxis(LockedAxis& lockedAxis, gfx::PointF& delta)
|
||||||
|
{
|
||||||
|
double dx = delta.x;
|
||||||
|
double dy = delta.y;
|
||||||
|
lockAxis(lockedAxis, dx, dy);
|
||||||
|
delta.x = dx;
|
||||||
|
delta.y = dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lockAxis(LockedAxis& lockedAxis, double& dx, double& dy)
|
||||||
|
{
|
||||||
|
if (lockedAxis == LockedAxis::NONE) {
|
||||||
|
if (std::abs(dx) * 3 > std::abs(dy) * 7) {
|
||||||
|
lockedAxis = LockedAxis::Y;
|
||||||
|
dy = 0.0;
|
||||||
|
}
|
||||||
|
else if (std::abs(dy) * 3 > std::abs(dx) * 7) {
|
||||||
|
lockedAxis = LockedAxis::X;
|
||||||
|
dx = 0.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const bool sameSign = std::signbit(dx) == std::signbit(dy);
|
||||||
|
lockedAxis = sameSign ? LockedAxis::R_DIAG : LockedAxis::L_DIAG;
|
||||||
|
dy = sameSign ? dx : -dx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (lockedAxis) {
|
||||||
|
case LockedAxis::X: dx = 0.0; break;
|
||||||
|
case LockedAxis::Y: dy = 0.0; break;
|
||||||
|
case LockedAxis::R_DIAG: dy = dx; break;
|
||||||
|
case LockedAxis::L_DIAG: dy = -dx; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2025 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_UTIL_MOVING_UTILS_H_INCLUDED
|
||||||
|
#define APP_UTIL_MOVING_UTILS_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "gfx/point.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
enum LockedAxis {
|
||||||
|
NONE,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
R_DIAG,
|
||||||
|
L_DIAG,
|
||||||
|
};
|
||||||
|
|
||||||
|
void lockAxis(LockedAxis& lockedAxis, gfx::PointF& delta);
|
||||||
|
|
||||||
|
void lockAxis(LockedAxis& lockedAxis, double& dx, double& dy);
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif // APP_UTIL_MOVING_UTILS_H_INCLUDED
|
|
@ -128,6 +128,15 @@ int Entry::lastCaretPos() const
|
||||||
return int(m_boxes.size() - 1);
|
return int(m_boxes.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx::Point Entry::caretPosOnScreen() const
|
||||||
|
{
|
||||||
|
const gfx::Point caretPos = getCharBoxBounds(m_caret).point2();
|
||||||
|
const os::Window* nativeWindow = display()->nativeWindow();
|
||||||
|
const gfx::Point pos = nativeWindow->pointToScreen(caretPos + bounds().origin());
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
void Entry::setCaretPos(const int pos)
|
void Entry::setCaretPos(const int pos)
|
||||||
{
|
{
|
||||||
gfx::Size caretSize = theme()->getEntryCaretSize(this);
|
gfx::Size caretSize = theme()->getEntryCaretSize(this);
|
||||||
|
@ -160,6 +169,8 @@ void Entry::setCaretPos(const int pos)
|
||||||
startTimer();
|
startTimer();
|
||||||
m_state = true;
|
m_state = true;
|
||||||
|
|
||||||
|
os::System::instance()->setTextInput(true, caretPosOnScreen());
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +262,7 @@ gfx::Rect Entry::getEntryTextBounds() const
|
||||||
return onGetEntryTextBounds();
|
return onGetEntryTextBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect Entry::getCharBoxBounds(const int i)
|
gfx::Rect Entry::getCharBoxBounds(const int i) const
|
||||||
{
|
{
|
||||||
ASSERT(i >= 0 && i < int(m_boxes.size()));
|
ASSERT(i >= 0 && i < int(m_boxes.size()));
|
||||||
if (i >= 0 && i < int(m_boxes.size()))
|
if (i >= 0 && i < int(m_boxes.size()))
|
||||||
|
@ -288,8 +299,9 @@ bool Entry::onProcessMessage(Message* msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start processing dead keys
|
// Start processing dead keys
|
||||||
if (m_translate_dead_keys)
|
if (m_translate_dead_keys) {
|
||||||
os::System::instance()->setTextInput(true);
|
os::System::instance()->setTextInput(true, caretPosOnScreen());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kFocusLeaveMessage:
|
case kFocusLeaveMessage:
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
|
|
||||||
int caretPos() const { return m_caret; }
|
int caretPos() const { return m_caret; }
|
||||||
int lastCaretPos() const;
|
int lastCaretPos() const;
|
||||||
|
gfx::Point caretPosOnScreen() const;
|
||||||
|
|
||||||
void setCaretPos(int pos);
|
void setCaretPos(int pos);
|
||||||
void setCaretToEnd();
|
void setCaretToEnd();
|
||||||
|
@ -76,7 +77,7 @@ public:
|
||||||
obs::signal<void()> Change;
|
obs::signal<void()> Change;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
gfx::Rect getCharBoxBounds(int i);
|
gfx::Rect getCharBoxBounds(int i) const;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
bool onProcessMessage(Message* msg) override;
|
bool onProcessMessage(Message* msg) override;
|
||||||
|
|
|
@ -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