undo.h 7.1 KB

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