mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-16 05:42:32 +00:00
Implement Undo limit (fix #1127)
This commit is contained in:
parent
363341ad34
commit
f0c11ef567
@ -141,6 +141,21 @@ private:
|
|||||||
actions()->selectChild(item);
|
actions()->selectChild(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onDeleteUndoState(DocumentUndo* history,
|
||||||
|
undo::UndoState* state) override {
|
||||||
|
for (auto child : actions()->children()) {
|
||||||
|
Item* item = static_cast<Item*>(child);
|
||||||
|
if (item->state() == state) {
|
||||||
|
actions()->removeChild(item);
|
||||||
|
item->deferDelete();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actions()->layout();
|
||||||
|
view()->updateView();
|
||||||
|
}
|
||||||
|
|
||||||
void onAfterUndo(DocumentUndo* history) override {
|
void onAfterUndo(DocumentUndo* history) override {
|
||||||
selectState(history->currentState());
|
selectState(history->currentState());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -15,6 +15,7 @@
|
|||||||
#include "app/cmd_transaction.h"
|
#include "app/cmd_transaction.h"
|
||||||
#include "app/document_undo_observer.h"
|
#include "app/document_undo_observer.h"
|
||||||
#include "app/pref/preferences.h"
|
#include "app/pref/preferences.h"
|
||||||
|
#include "base/mem_utils.h"
|
||||||
#include "doc/context.h"
|
#include "doc/context.h"
|
||||||
#include "undo/undo_history.h"
|
#include "undo/undo_history.h"
|
||||||
#include "undo/undo_state.h"
|
#include "undo/undo_state.h"
|
||||||
@ -22,10 +23,14 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#define UNDO_TRACE(...)
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
DocumentUndo::DocumentUndo()
|
DocumentUndo::DocumentUndo()
|
||||||
: m_ctx(NULL)
|
: m_undoHistory(this)
|
||||||
|
, m_ctx(nullptr)
|
||||||
|
, m_totalUndoSize(0)
|
||||||
, m_savedCounter(0)
|
, m_savedCounter(0)
|
||||||
, m_savedStateIsLost(false)
|
, m_savedStateIsLost(false)
|
||||||
{
|
{
|
||||||
@ -39,6 +44,10 @@ void DocumentUndo::setContext(doc::Context* ctx)
|
|||||||
void DocumentUndo::add(CmdTransaction* cmd)
|
void DocumentUndo::add(CmdTransaction* cmd)
|
||||||
{
|
{
|
||||||
ASSERT(cmd);
|
ASSERT(cmd);
|
||||||
|
UNDO_TRACE("UNDO: Add state <%s> of %s to %s\n",
|
||||||
|
cmd->label().c_str(),
|
||||||
|
base::get_pretty_memory_size(cmd->memSize()).c_str(),
|
||||||
|
base::get_pretty_memory_size(m_totalUndoSize).c_str());
|
||||||
|
|
||||||
// A linear undo history is the default behavior
|
// A linear undo history is the default behavior
|
||||||
if (!App::instance() ||
|
if (!App::instance() ||
|
||||||
@ -47,7 +56,33 @@ void DocumentUndo::add(CmdTransaction* cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_undoHistory.add(cmd);
|
m_undoHistory.add(cmd);
|
||||||
|
m_totalUndoSize += cmd->memSize();
|
||||||
|
|
||||||
notify_observers(&DocumentUndoObserver::onAddUndoState, this);
|
notify_observers(&DocumentUndoObserver::onAddUndoState, this);
|
||||||
|
|
||||||
|
if (App::instance()) {
|
||||||
|
const size_t undoLimitSize =
|
||||||
|
int(App::instance()->preferences().undo.sizeLimit())
|
||||||
|
* 1024 * 1024;
|
||||||
|
|
||||||
|
// If undo limit is 0, it means "no limit", so we ignore the
|
||||||
|
// complete logic to discard undo states.
|
||||||
|
if (undoLimitSize > 0 &&
|
||||||
|
m_totalUndoSize > undoLimitSize) {
|
||||||
|
UNDO_TRACE("UNDO: Reducing undo history from %s to %s\n",
|
||||||
|
base::get_pretty_memory_size(m_totalUndoSize).c_str(),
|
||||||
|
base::get_pretty_memory_size(undoLimitSize).c_str());
|
||||||
|
|
||||||
|
while (m_undoHistory.firstState() &&
|
||||||
|
m_totalUndoSize > undoLimitSize) {
|
||||||
|
if (!m_undoHistory.deleteFirstState())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNDO_TRACE("UNDO: New undo size %s\n",
|
||||||
|
base::get_pretty_memory_size(m_totalUndoSize).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DocumentUndo::canUndo() const
|
bool DocumentUndo::canUndo() const
|
||||||
@ -160,4 +195,17 @@ const undo::UndoState* DocumentUndo::nextRedo() const
|
|||||||
return m_undoHistory.firstState();
|
return m_undoHistory.firstState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentUndo::onDeleteUndoState(undo::UndoState* state)
|
||||||
|
{
|
||||||
|
Cmd* cmd = static_cast<Cmd*>(state->cmd());
|
||||||
|
|
||||||
|
UNDO_TRACE("UNDO: Deleting undo state <%s> of %s from %s\n",
|
||||||
|
cmd->label().c_str(),
|
||||||
|
base::get_pretty_memory_size(cmd->memSize()).c_str(),
|
||||||
|
base::get_pretty_memory_size(m_totalUndoSize).c_str());
|
||||||
|
|
||||||
|
m_totalUndoSize -= cmd->memSize();
|
||||||
|
notify_observers(&DocumentUndoObserver::onDeleteUndoState, this, state);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -27,7 +27,8 @@ namespace app {
|
|||||||
class CmdTransaction;
|
class CmdTransaction;
|
||||||
class DocumentUndoObserver;
|
class DocumentUndoObserver;
|
||||||
|
|
||||||
class DocumentUndo : public obs::observable<DocumentUndoObserver> {
|
class DocumentUndo : public obs::observable<DocumentUndoObserver>,
|
||||||
|
public undo::UndoHistoryDelegate {
|
||||||
public:
|
public:
|
||||||
DocumentUndo();
|
DocumentUndo();
|
||||||
|
|
||||||
@ -65,8 +66,12 @@ namespace app {
|
|||||||
const undo::UndoState* nextUndo() const;
|
const undo::UndoState* nextUndo() const;
|
||||||
const undo::UndoState* nextRedo() const;
|
const undo::UndoState* nextRedo() const;
|
||||||
|
|
||||||
|
// undo::UndoHistoryDelegate impl
|
||||||
|
void onDeleteUndoState(undo::UndoState* state) override;
|
||||||
|
|
||||||
undo::UndoHistory m_undoHistory;
|
undo::UndoHistory m_undoHistory;
|
||||||
doc::Context* m_ctx;
|
doc::Context* m_ctx;
|
||||||
|
size_t m_totalUndoSize;
|
||||||
|
|
||||||
// This counter is equal to 0 if we are in the "saved state", i.e.
|
// This counter is equal to 0 if we are in the "saved state", i.e.
|
||||||
// the document on memory is equal to the document on disk. This
|
// the document on memory is equal to the document on disk. This
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2015 David Capello
|
// Copyright (C) 2015-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -20,6 +20,8 @@ class DocumentUndo;
|
|||||||
public:
|
public:
|
||||||
virtual ~DocumentUndoObserver() { }
|
virtual ~DocumentUndoObserver() { }
|
||||||
virtual void onAddUndoState(DocumentUndo* history) = 0;
|
virtual void onAddUndoState(DocumentUndo* history) = 0;
|
||||||
|
virtual void onDeleteUndoState(DocumentUndo* history,
|
||||||
|
undo::UndoState* state) = 0;
|
||||||
virtual void onAfterUndo(DocumentUndo* history) = 0;
|
virtual void onAfterUndo(DocumentUndo* history) = 0;
|
||||||
virtual void onAfterRedo(DocumentUndo* history) = 0;
|
virtual void onAfterRedo(DocumentUndo* history) = 0;
|
||||||
virtual void onClearRedo(DocumentUndo* history) = 0;
|
virtual void onClearRedo(DocumentUndo* history) = 0;
|
||||||
|
@ -1769,8 +1769,10 @@ void Timeline::drawHeaderFrame(ui::Graphics* g, frame_t frame)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Draw the header for the layers.
|
// Draw the header for the layers.
|
||||||
std::string text = base::convert_to<std::string, int>(
|
const int n = (docPref().timeline.firstFrame()+frame);
|
||||||
(docPref().timeline.firstFrame()+frame) % 100);
|
std::string text = base::convert_to<std::string, int>(n % 100);
|
||||||
|
if (n >= 100 && (n % 100) < 10)
|
||||||
|
text.insert(0, 1, '0');
|
||||||
|
|
||||||
drawPart(g, bounds, &text,
|
drawPart(g, bounds, &text,
|
||||||
skinTheme()->styles.timelineHeaderFrame(),
|
skinTheme()->styles.timelineHeaderFrame(),
|
||||||
|
2
src/undo
2
src/undo
@ -1 +1 @@
|
|||||||
Subproject commit f39b188e29d0f9adaa49c8705c0f492939d967a9
|
Subproject commit f17044afa2632bb2f3c21509bd064cbfa891e653
|
Loading…
x
Reference in New Issue
Block a user