| 
									
										
										
										
											2015-02-12 23:16:25 +08:00
										 |  |  | // Aseprite
 | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  | // Copyright (C) 2022-2023  Igara Studio S.A.
 | 
					
						
							| 
									
										
										
										
											2018-06-09 01:40:02 +08:00
										 |  |  | // Copyright (C) 2001-2018  David Capello
 | 
					
						
							| 
									
										
										
										
											2015-02-12 23:16:25 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-08-27 04:02:58 +08:00
										 |  |  | // This program is distributed under the terms of
 | 
					
						
							|  |  |  | // the End-User License Agreement for Aseprite.
 | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #ifdef HAVE_CONFIG_H
 | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | #include "config.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | #include "app/doc_undo.h"
 | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  | #include "app/app.h"
 | 
					
						
							|  |  |  | #include "app/cmd.h"
 | 
					
						
							|  |  |  | #include "app/cmd_transaction.h"
 | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  | #include "app/console.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:47:42 +08:00
										 |  |  | #include "app/context.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | #include "app/doc_undo_observer.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  | #include "app/pref/preferences.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | #include "base/mem_utils.h"
 | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  | #include "base/scoped_value.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  | #include "undo/undo_history.h"
 | 
					
						
							|  |  |  | #include "undo/undo_state.h"
 | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <cassert>
 | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | #include <stdexcept>
 | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | #define UNDO_TRACE(...)
 | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  | #define STATE_CMD(state) (static_cast<CmdTransaction*>(state->cmd()))
 | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | namespace app { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | DocUndo::DocUndo() | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  |   : m_undoHistory(this) | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::setContext(Context* ctx) | 
					
						
							| 
									
										
										
										
											2014-07-31 11:19:58 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   m_ctx = ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::add(CmdTransaction* cmd) | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   ASSERT(cmd); | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (m_undoing) { | 
					
						
							| 
									
										
										
										
											2023-03-08 07:41:15 +08:00
										 |  |  |     delete cmd; | 
					
						
							|  |  |  |     throw CannotModifyWhenUndoingException(); | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  |   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()); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // A linear undo history is the default behavior
 | 
					
						
							|  |  |  |   if (!App::instance() || | 
					
						
							|  |  |  |       !App::instance()->preferences().undo.allowNonlinearHistory()) { | 
					
						
							| 
									
										
										
										
											2015-10-20 22:27:05 +08:00
										 |  |  |     clearRedo(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   m_undoHistory.add(cmd); | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  |   m_totalUndoSize += cmd->memSize(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onAddUndoState, this); | 
					
						
							|  |  |  |   notify_observers(&DocUndoObserver::onTotalUndoSizeChange, this); | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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()); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | bool DocUndo::canUndo() const | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   return m_undoHistory.canUndo(); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | bool DocUndo::canRedo() const | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   return m_undoHistory.canRedo(); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::undo() | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  |   ASSERT(!m_undoing); | 
					
						
							| 
									
										
										
										
											2023-04-15 00:43:36 +08:00
										 |  |  |   base::ScopedValue undoing(m_undoing, true); | 
					
						
							| 
									
										
										
										
											2022-09-29 21:57:40 +08:00
										 |  |  |   const size_t oldSize = m_totalUndoSize; | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-09-29 22:04:05 +08:00
										 |  |  |     const undo::UndoState* state = nextUndo(); | 
					
						
							|  |  |  |     ASSERT(state); | 
					
						
							| 
									
										
										
										
											2022-09-29 21:57:40 +08:00
										 |  |  |     const Cmd* cmd = STATE_CMD(state); | 
					
						
							|  |  |  |     m_totalUndoSize -= cmd->memSize(); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     m_undoHistory.undo(); | 
					
						
							| 
									
										
										
										
											2022-09-29 21:57:40 +08:00
										 |  |  |     m_totalUndoSize += cmd->memSize(); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-29 21:57:40 +08:00
										 |  |  |   // This notification could execute a script that modifies the sprite
 | 
					
						
							|  |  |  |   // again (e.g. a script that is listening the "change" event, check
 | 
					
						
							|  |  |  |   // the SpriteEvents class). If the sprite is modified, the "cmd" is
 | 
					
						
							|  |  |  |   // not valid anymore.
 | 
					
						
							|  |  |  |   notify_observers(&DocUndoObserver::onCurrentUndoStateChange, this); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   if (m_totalUndoSize != oldSize) | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |     notify_observers(&DocUndoObserver::onTotalUndoSizeChange, this); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::redo() | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-09 18:43:33 +08:00
										 |  |  |   ASSERT(!m_undoing); | 
					
						
							| 
									
										
										
										
											2023-04-15 00:43:36 +08:00
										 |  |  |   base::ScopedValue undoing(m_undoing, true); | 
					
						
							| 
									
										
										
										
											2022-09-29 22:04:05 +08:00
										 |  |  |   const size_t oldSize = m_totalUndoSize; | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-09-29 22:04:05 +08:00
										 |  |  |     const undo::UndoState* state = nextRedo(); | 
					
						
							|  |  |  |     ASSERT(state); | 
					
						
							|  |  |  |     const Cmd* cmd = STATE_CMD(state); | 
					
						
							|  |  |  |     m_totalUndoSize -= cmd->memSize(); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     m_undoHistory.redo(); | 
					
						
							| 
									
										
										
										
											2022-09-29 22:04:05 +08:00
										 |  |  |     m_totalUndoSize += cmd->memSize(); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-29 22:04:05 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onCurrentUndoStateChange, this); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   if (m_totalUndoSize != oldSize) | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |     notify_observers(&DocUndoObserver::onTotalUndoSizeChange, this); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::clearRedo() | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-05-24 03:19:06 +08:00
										 |  |  |   // Do nothing
 | 
					
						
							|  |  |  |   if (currentState() == lastState()) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-20 22:27:05 +08:00
										 |  |  |   m_undoHistory.clearRedo(); | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onClearRedo, this); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 20:53:41 +08:00
										 |  |  | bool DocUndo::isInSavedStateOrSimilar() const | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-11-02 20:53:41 +08:00
										 |  |  |   if (m_savedStateIsLost) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Here we try to find if we can reach the saved state from the
 | 
					
						
							|  |  |  |   // currentState() undoing or redoing and the sprite is exactly the
 | 
					
						
							|  |  |  |   // same as the saved state, e.g. this can happen if the undo states
 | 
					
						
							|  |  |  |   // don't modify the sprite (like actions that change the current
 | 
					
						
							|  |  |  |   // selection/mask boundaries).
 | 
					
						
							|  |  |  |   bool savedStateWithUndoes = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto state = currentState(); | 
					
						
							|  |  |  |   while (state) { | 
					
						
							|  |  |  |     if (m_savedState == state) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (STATE_CMD(state)->doesChangeSavedState()) { | 
					
						
							|  |  |  |       savedStateWithUndoes = false; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     state = state->prev(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If we reached the end of the undo history (e.g. because all undo
 | 
					
						
							|  |  |  |   // states do not modify the sprite), the only way to be in the saved
 | 
					
						
							|  |  |  |   // state is if the initial point of history is the saved state too
 | 
					
						
							|  |  |  |   // i.e. when m_savedState is nullptr (and m_savedStateIsLost is
 | 
					
						
							|  |  |  |   // false).
 | 
					
						
							|  |  |  |   if (savedStateWithUndoes && m_savedState == nullptr) | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Now we try with redoes.
 | 
					
						
							|  |  |  |   state = (currentState() ? currentState()->next(): firstState()); | 
					
						
							|  |  |  |   while (state) { | 
					
						
							|  |  |  |     if (STATE_CMD(state)->doesChangeSavedState()) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (m_savedState == state) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     state = state->next(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::markSavedState() | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-11-02 05:57:19 +08:00
										 |  |  |   m_savedState = currentState(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   m_savedStateIsLost = false; | 
					
						
							| 
									
										
										
										
											2022-11-02 05:57:19 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onNewSavedState, this); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::impossibleToBackToSavedState() | 
					
						
							| 
									
										
										
										
											2014-05-03 04:04:55 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-11-02 05:57:19 +08:00
										 |  |  |   // Now there is no state related to the disk state.
 | 
					
						
							|  |  |  |   m_savedState = nullptr; | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   m_savedStateIsLost = true; | 
					
						
							| 
									
										
										
										
											2022-11-02 05:57:19 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onNewSavedState, this); | 
					
						
							| 
									
										
										
										
											2014-05-03 04:04:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | std::string DocUndo::nextUndoLabel() const | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  |   const undo::UndoState* state = nextUndo(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   if (state) | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     return STATE_CMD(state)->label(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   else | 
					
						
							|  |  |  |     return ""; | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | std::string DocUndo::nextRedoLabel() const | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  |   const undo::UndoState* state = nextRedo(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   if (state) | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     return STATE_CMD(state)->label(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   else | 
					
						
							|  |  |  |     return ""; | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | SpritePosition DocUndo::nextUndoSpritePosition() const | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  |   const undo::UndoState* state = nextUndo(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   if (state) | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     return STATE_CMD(state)->spritePositionBeforeExecute(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   else | 
					
						
							|  |  |  |     return SpritePosition(); | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | SpritePosition DocUndo::nextRedoSpritePosition() const | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  |   const undo::UndoState* state = nextRedo(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   if (state) | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     return STATE_CMD(state)->spritePositionAfterExecute(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   else | 
					
						
							|  |  |  |     return SpritePosition(); | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 21:07:21 +08:00
										 |  |  | std::istream* DocUndo::nextUndoDocRange() const | 
					
						
							| 
									
										
										
										
											2018-06-09 01:40:02 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   const undo::UndoState* state = nextUndo(); | 
					
						
							|  |  |  |   if (state) | 
					
						
							|  |  |  |     return STATE_CMD(state)->documentRangeBeforeExecute(); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 21:07:21 +08:00
										 |  |  | std::istream* DocUndo::nextRedoDocRange() const | 
					
						
							| 
									
										
										
										
											2018-06-09 01:40:02 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   const undo::UndoState* state = nextRedo(); | 
					
						
							|  |  |  |   if (state) | 
					
						
							|  |  |  |     return STATE_CMD(state)->documentRangeAfterExecute(); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | Cmd* DocUndo::lastExecutedCmd() const | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  |   const undo::UndoState* state = m_undoHistory.currentState(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   if (state) | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |     return STATE_CMD(state); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   else | 
					
						
							|  |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::moveToState(const undo::UndoState* state) | 
					
						
							| 
									
										
										
										
											2015-10-20 22:27:05 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-17 04:10:17 +08:00
										 |  |  |   ASSERT(!m_undoing); | 
					
						
							| 
									
										
										
										
											2023-04-15 00:43:36 +08:00
										 |  |  |   base::ScopedValue undoing(m_undoing, true); | 
					
						
							| 
									
										
										
										
											2023-03-17 04:10:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-20 22:27:05 +08:00
										 |  |  |   m_undoHistory.moveTo(state); | 
					
						
							| 
									
										
										
										
											2022-09-29 22:04:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // After onCurrentUndoStateChange don't use the "state" argument, it
 | 
					
						
							|  |  |  |   // might be deleted because some script might have modified the
 | 
					
						
							|  |  |  |   // sprite on its "change" event.
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onCurrentUndoStateChange, this); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Recalculate the total undo size
 | 
					
						
							|  |  |  |   size_t oldSize = m_totalUndoSize; | 
					
						
							|  |  |  |   m_totalUndoSize = 0; | 
					
						
							|  |  |  |   const undo::UndoState* s = m_undoHistory.firstState(); | 
					
						
							|  |  |  |   while (s) { | 
					
						
							|  |  |  |     m_totalUndoSize += STATE_CMD(s)->memSize(); | 
					
						
							|  |  |  |     s = s->next(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (m_totalUndoSize != oldSize) | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |     notify_observers(&DocUndoObserver::onTotalUndoSizeChange, this); | 
					
						
							| 
									
										
										
										
											2015-10-20 22:27:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | const undo::UndoState* DocUndo::nextUndo() const | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   return m_undoHistory.currentState(); | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | const undo::UndoState* DocUndo::nextRedo() const | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-01-19 09:16:29 +08:00
										 |  |  |   const undo::UndoState* state = m_undoHistory.currentState(); | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |   if (state) | 
					
						
							|  |  |  |     return state->next(); | 
					
						
							| 
									
										
										
										
											2012-07-11 05:26:08 +08:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2015-01-19 09:05:33 +08:00
										 |  |  |     return m_undoHistory.firstState(); | 
					
						
							| 
									
										
										
										
											2012-07-08 12:25:26 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  | void DocUndo::onDeleteUndoState(undo::UndoState* state) | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-22 22:11:31 +08:00
										 |  |  |   ASSERT(state); | 
					
						
							| 
									
										
										
										
											2017-10-27 08:42:25 +08:00
										 |  |  |   Cmd* cmd = STATE_CMD(state); | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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(); | 
					
						
							| 
									
										
										
										
											2018-07-07 13:55:27 +08:00
										 |  |  |   notify_observers(&DocUndoObserver::onDeleteUndoState, this, state); | 
					
						
							| 
									
										
										
										
											2022-11-02 05:57:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Mark this document as impossible to match the version on disk
 | 
					
						
							|  |  |  |   // because we're just going to delete the saved state.
 | 
					
						
							|  |  |  |   if (m_savedState == state) | 
					
						
							|  |  |  |     impossibleToBackToSavedState(); | 
					
						
							| 
									
										
										
										
											2017-10-26 04:25:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | } // namespace app
 |