Implement Undo limit (fix #1127)

This commit is contained in:
David Capello 2017-10-25 17:25:23 -03:00
parent 363341ad34
commit f0c11ef567
6 changed files with 80 additions and 8 deletions

View File

@ -141,6 +141,21 @@ private:
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 {
selectState(history->currentState());
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -15,6 +15,7 @@
#include "app/cmd_transaction.h"
#include "app/document_undo_observer.h"
#include "app/pref/preferences.h"
#include "base/mem_utils.h"
#include "doc/context.h"
#include "undo/undo_history.h"
#include "undo/undo_state.h"
@ -22,10 +23,14 @@
#include <cassert>
#include <stdexcept>
#define UNDO_TRACE(...)
namespace app {
DocumentUndo::DocumentUndo()
: m_ctx(NULL)
: m_undoHistory(this)
, m_ctx(nullptr)
, m_totalUndoSize(0)
, m_savedCounter(0)
, m_savedStateIsLost(false)
{
@ -39,6 +44,10 @@ void DocumentUndo::setContext(doc::Context* ctx)
void DocumentUndo::add(CmdTransaction* 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
if (!App::instance() ||
@ -47,7 +56,33 @@ void DocumentUndo::add(CmdTransaction* cmd)
}
m_undoHistory.add(cmd);
m_totalUndoSize += cmd->memSize();
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
@ -160,4 +195,17 @@ const undo::UndoState* DocumentUndo::nextRedo() const
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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -27,7 +27,8 @@ namespace app {
class CmdTransaction;
class DocumentUndoObserver;
class DocumentUndo : public obs::observable<DocumentUndoObserver> {
class DocumentUndo : public obs::observable<DocumentUndoObserver>,
public undo::UndoHistoryDelegate {
public:
DocumentUndo();
@ -65,8 +66,12 @@ namespace app {
const undo::UndoState* nextUndo() const;
const undo::UndoState* nextRedo() const;
// undo::UndoHistoryDelegate impl
void onDeleteUndoState(undo::UndoState* state) override;
undo::UndoHistory m_undoHistory;
doc::Context* m_ctx;
size_t m_totalUndoSize;
// 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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2015 David Capello
// Copyright (C) 2015-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -20,6 +20,8 @@ class DocumentUndo;
public:
virtual ~DocumentUndoObserver() { }
virtual void onAddUndoState(DocumentUndo* history) = 0;
virtual void onDeleteUndoState(DocumentUndo* history,
undo::UndoState* state) = 0;
virtual void onAfterUndo(DocumentUndo* history) = 0;
virtual void onAfterRedo(DocumentUndo* history) = 0;
virtual void onClearRedo(DocumentUndo* history) = 0;

View File

@ -1769,8 +1769,10 @@ void Timeline::drawHeaderFrame(ui::Graphics* g, frame_t frame)
return;
// Draw the header for the layers.
std::string text = base::convert_to<std::string, int>(
(docPref().timeline.firstFrame()+frame) % 100);
const int n = (docPref().timeline.firstFrame()+frame);
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,
skinTheme()->styles.timelineHeaderFrame(),

@ -1 +1 @@
Subproject commit f39b188e29d0f9adaa49c8705c0f492939d967a9
Subproject commit f17044afa2632bb2f3c21509bd064cbfa891e653