undo.h

Engine/source/util/undo.h

More...

Classes:

class

An undo action that is comprised of other undo actions.

class

Script Undo Action Creation.

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#ifndef _UNDO_H_
 25#define _UNDO_H_
 26
 27#ifndef _SIMOBJECT_H_
 28#include "console/simObject.h"
 29#endif
 30#ifndef _TVECTOR_H_
 31#include "core/util/tVector.h"
 32#endif
 33#ifndef _SIMBASE_H_
 34#include "console/simBase.h"
 35#endif
 36#ifndef _ENGINEAPI_H_
 37#include "console/engineAPI.h"
 38#endif
 39
 40class UndoManager;
 41
 42///
 43class UndoAction : public SimObject
 44{
 45   friend class UndoManager;
 46
 47protected:
 48   // The manager this was added to.
 49   UndoManager* mUndoManager;
 50
 51public:
 52
 53   /// A brief description of the action, for display in menus and the like.
 54   // not private because we're exposing it to the console.
 55   String mActionName;
 56
 57   // Required in all ConsoleObject subclasses.
 58   typedef SimObject Parent;
 59   DECLARE_CONOBJECT(UndoAction);
 60   static void initPersistFields();
 61   
 62   /// Create a new action, assigning it a name for display in menus et cetera.
 63   UndoAction(const UTF8 *actionName = " ");
 64   virtual ~UndoAction();
 65
 66   /// Implement these methods to perform your specific undo & redo tasks. 
 67   virtual void undo() { };
 68   virtual void redo() { };
 69   
 70   /// Adds the action to the undo stack of the default UndoManager, or the provided manager.
 71   void addToManager(UndoManager* theMan = NULL);
 72};
 73
 74/// An undo action that is comprised of other undo actions.
 75class CompoundUndoAction : public UndoAction
 76{
 77   friend class UndoManager;
 78
 79protected:
 80
 81   Vector< UndoAction*> mChildren;
 82
 83public:
 84
 85   typedef UndoAction Parent;
 86
 87   CompoundUndoAction( const UTF8 *actionName = " " );
 88   virtual ~CompoundUndoAction();
 89
 90   DECLARE_CONOBJECT(CompoundUndoAction);
 91
 92   virtual void addAction( UndoAction *action );
 93   virtual void undo();
 94   virtual void redo();
 95   
 96   virtual void onDeleteNotify( SimObject* object );
 97   
 98   U32 getNumChildren() const { return mChildren.size(); }
 99};
100
101///
102class UndoManager : public SimObject
103{
104private:
105   /// Default number of undo & redo levels.
106   const static U32 kDefaultNumLevels = 100;
107
108   /// The stacks of undo & redo actions. They will be capped at size mNumLevels.
109   Vector<UndoAction*> mUndoStack;
110   Vector<UndoAction*> mRedoStack;
111   
112   /// Stack for assembling compound actions.
113   Vector< CompoundUndoAction*> mCompoundStack;
114   
115   /// Deletes all the UndoActions in a stack, then clears it.
116   void clearStack(Vector<UndoAction*> &stack);
117   /// Clamps a Vector to mNumLevels entries.
118   void clampStack(Vector<UndoAction*> &stack);
119
120   /// Run the removal logic on the action.
121   void doRemove( UndoAction* action, bool noDelete );
122   
123public:
124   /// Number of undo & redo levels.
125   // not private because we're exposing it to the console.
126   U32 mNumLevels;
127
128   // Required in all ConsoleObject subclasses.
129   typedef SimObject Parent;
130   DECLARE_CONOBJECT(UndoManager);
131   static void initPersistFields();
132
133   /// Constructor. If levels = 0, we use the default number of undo levels.
134   UndoManager(U32 levels = kDefaultNumLevels);
135   /// Destructor. deletes and clears the undo & redo stacks.
136   ~UndoManager();
137   /// Accessor to the default undo manager singleton. Creates one if needed.
138   static UndoManager& getDefaultManager();
139   
140   /// Undo last action, and put it on the redo stack.
141   void undo();
142   /// Redo the last action, and put it on the undo stack.
143   void redo();
144   
145   /// Clears the undo and redo stacks.
146   void clearAll();
147
148   /// Returns the printable name of the top actions on the undo & redo stacks.
149   const char* getNextUndoName();
150   const char* getNextRedoName();
151
152   S32 getUndoCount();
153   S32 getRedoCount();
154
155   const char* getUndoName(S32 index);
156   const char* getRedoName(S32 index);
157
158   UndoAction* getUndoAction(S32 index);
159   UndoAction* getRedoAction(S32 index);
160
161   /// Add an action to the top of the undo stack, and clear the redo stack.
162   void addAction(UndoAction* action);
163   void removeAction(UndoAction* action, bool noDelete = false);
164   
165   /// @name Compound Actions
166   ///
167   /// The compound action stack allows to redirect undos to a CompoundUndoAction
168   /// and thus assemble multi-operation undos directly through the UndoManager.
169   /// When the bottom-most CompoundUndoAction is popped off the stack, the compound
170   /// will be moved onto the undo stack.
171   ///
172   /// @{
173   
174   /// Push a compound action called "name" onto the compound stack.  While the
175   /// compound stack is not empty, all undos that are queued on the undo manager will
176   /// go to the topmost compound instead of the undo stack.
177   CompoundUndoAction* pushCompound( const String& name );
178   
179   /// Pop the topmost compound off the compound stack and add it to the undo manager.
180   /// If the compound stack is still not empty, the compound will be added to the next
181   /// lower compound on the stack.  Otherwise it will be recorded as a regular undo.
182   void popCompound( bool discard = false );
183   
184   /// Return the current nesting depth of the compound stack.
185   U32 getCompoundStackDepth() const { return mCompoundStack.size(); }
186      
187   /// @}
188};
189
190
191/// Script Undo Action Creation
192/// 
193/// Undo actions can be created in script like this:
194/// 
195/// ...
196/// %undo = new UndoScriptAction() { class = SampleUndo; actionName = "Sample Undo"; };
197/// %undo.addToManager(UndoManager);
198/// ...
199/// 
200/// function SampleUndo::undo()
201/// {
202///    ...
203/// }
204/// 
205/// function SampleUndo::redo()
206/// {
207///    ...
208/// }
209/// 
210class UndoScriptAction : public UndoAction
211{
212public:
213   typedef UndoAction Parent;
214
215   UndoScriptAction() : UndoAction()
216   {
217   }
218
219   virtual void undo() { Con::executef(this, "undo"); };
220   virtual void redo() { Con::executef(this, "redo"); }
221
222   virtual bool onAdd()
223   {
224      // Let Parent Do Work.
225      if(!Parent::onAdd())
226         return false;
227
228
229      // Notify Script.
230      if(isMethod("onAdd"))
231         Con::executef(this, "onAdd");
232
233      // Return Success.
234      return true;
235   };
236
237   virtual void onRemove()
238   {
239      if (mUndoManager)
240         mUndoManager->removeAction((UndoAction*)this, true);
241
242      // notify script
243      if(isMethod("onRemove"))
244         Con::executef(this, "onRemove");
245
246      Parent::onRemove();
247   }
248
249   DECLARE_CONOBJECT(UndoScriptAction);
250};
251
252#endif // _UNDO_H_
253