BsUndoRedo.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsUndoRedo.h"
  4. #include "BsEditorCommand.h"
  5. namespace BansheeEngine
  6. {
  7. const UINT32 UndoRedo::MAX_STACK_ELEMENTS = 1000;
  8. UndoRedo::UndoRedo()
  9. : mUndoStack(nullptr), mRedoStack(nullptr), mUndoStackPtr(0), mUndoNumElements(0), mRedoStackPtr(0)
  10. , mRedoNumElements(0), mNextCommandId(0)
  11. {
  12. mUndoStack = bs_newN<SPtr<EditorCommand>>(MAX_STACK_ELEMENTS);
  13. mRedoStack = bs_newN<SPtr<EditorCommand>>(MAX_STACK_ELEMENTS);
  14. }
  15. UndoRedo::~UndoRedo()
  16. {
  17. clear();
  18. bs_deleteN(mUndoStack, MAX_STACK_ELEMENTS);
  19. bs_deleteN(mRedoStack, MAX_STACK_ELEMENTS);
  20. }
  21. void UndoRedo::undo()
  22. {
  23. if(mUndoNumElements == 0)
  24. return;
  25. SPtr<EditorCommand> command = removeLastFromUndoStack();
  26. mRedoStackPtr = (mRedoStackPtr + 1) % MAX_STACK_ELEMENTS;
  27. mRedoStack[mRedoStackPtr] = command;
  28. mRedoNumElements = std::min(mRedoNumElements + 1, MAX_STACK_ELEMENTS);
  29. command->revert();
  30. }
  31. void UndoRedo::redo()
  32. {
  33. if(mRedoNumElements == 0)
  34. return;
  35. SPtr<EditorCommand> command = mRedoStack[mRedoStackPtr];
  36. mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
  37. mRedoNumElements--;
  38. addToUndoStack(command);
  39. command->commit();
  40. }
  41. void UndoRedo::pushGroup(const String& name)
  42. {
  43. mGroups.push(GroupData());
  44. GroupData& newGroup = mGroups.top();
  45. newGroup.name = name;
  46. newGroup.numEntries = 0;
  47. clearRedoStack();
  48. }
  49. void UndoRedo::popGroup(const String& name)
  50. {
  51. if(mGroups.empty())
  52. BS_EXCEPT(InvalidStateException, "Attempting to pop an UndoRedo group that doesn't exist: " + name);
  53. GroupData& topGroup = mGroups.top();
  54. if(topGroup.name != name)
  55. BS_EXCEPT(InvalidStateException, "Attempting to pop invalid UndoRedo group. Got: " + name + ". Expected: " + topGroup.name);
  56. for(UINT32 i = 0; i < topGroup.numEntries; i++)
  57. {
  58. mUndoStack[mUndoStackPtr] = SPtr<EditorCommand>();
  59. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  60. mUndoNumElements--;
  61. }
  62. mGroups.pop();
  63. clearRedoStack();
  64. }
  65. void UndoRedo::registerCommand(const SPtr<EditorCommand>& command)
  66. {
  67. command->mId = mNextCommandId++;
  68. addToUndoStack(command);
  69. clearRedoStack();
  70. }
  71. UINT32 UndoRedo::getTopCommandId() const
  72. {
  73. if (mUndoNumElements > 0)
  74. return mUndoStack[mUndoStackPtr]->mId;
  75. return 0;
  76. }
  77. void UndoRedo::popCommand(UINT32 id)
  78. {
  79. UINT32 undoPtr = mUndoStackPtr;
  80. for (UINT32 i = 0; i < mUndoNumElements; i++)
  81. {
  82. if (mUndoStack[undoPtr]->mId == id)
  83. {
  84. for (UINT32 j = mUndoNumElements - i; j < (mUndoNumElements - 1); j++)
  85. {
  86. UINT32 nextUndoPtr = (undoPtr + 1) % MAX_STACK_ELEMENTS;
  87. std::swap(mUndoStack[undoPtr], mUndoStack[nextUndoPtr]);
  88. undoPtr = nextUndoPtr;
  89. }
  90. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  91. mUndoNumElements--;
  92. break;
  93. }
  94. undoPtr = (undoPtr - 1) % MAX_STACK_ELEMENTS;
  95. }
  96. UINT32 redoPtr = mRedoStackPtr;
  97. for (UINT32 i = 0; i < mRedoNumElements; i++)
  98. {
  99. if (mRedoStack[redoPtr]->mId == id)
  100. {
  101. for (UINT32 j = mRedoNumElements - i; j < (mRedoNumElements - 1); j++)
  102. {
  103. UINT32 nextRedoPtr = (redoPtr + 1) % MAX_STACK_ELEMENTS;
  104. std::swap(mRedoStack[redoPtr], mRedoStack[nextRedoPtr]);
  105. redoPtr = nextRedoPtr;
  106. }
  107. mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
  108. mRedoNumElements--;
  109. break;
  110. }
  111. redoPtr = (redoPtr - 1) % MAX_STACK_ELEMENTS;
  112. }
  113. }
  114. void UndoRedo::clear()
  115. {
  116. clearUndoStack();
  117. clearRedoStack();
  118. }
  119. SPtr<EditorCommand> UndoRedo::removeLastFromUndoStack()
  120. {
  121. SPtr<EditorCommand> command = mUndoStack[mUndoStackPtr];
  122. mUndoStack[mUndoStackPtr] = SPtr<EditorCommand>();
  123. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  124. mUndoNumElements--;
  125. if(!mGroups.empty())
  126. {
  127. GroupData& topGroup = mGroups.top();
  128. if(topGroup.numEntries == 0)
  129. {
  130. BS_EXCEPT(InvalidStateException, "Removing an element from UndoRedo stack while in an " \
  131. "invalid UndoRedo group. Current group: " + topGroup.name);
  132. }
  133. topGroup.numEntries--;
  134. }
  135. return command;
  136. }
  137. void UndoRedo::addToUndoStack(const SPtr<EditorCommand>& command)
  138. {
  139. mUndoStackPtr = (mUndoStackPtr + 1) % MAX_STACK_ELEMENTS;
  140. mUndoStack[mUndoStackPtr] = command;
  141. mUndoNumElements = std::min(mUndoNumElements + 1, MAX_STACK_ELEMENTS);
  142. if(!mGroups.empty())
  143. {
  144. GroupData& topGroup = mGroups.top();
  145. topGroup.numEntries = std::min(topGroup.numEntries + 1, MAX_STACK_ELEMENTS);
  146. }
  147. }
  148. void UndoRedo::clearUndoStack()
  149. {
  150. while(mUndoNumElements > 0)
  151. {
  152. mUndoStack[mUndoStackPtr] = SPtr<EditorCommand>();
  153. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  154. mUndoNumElements--;
  155. }
  156. while(!mGroups.empty())
  157. mGroups.pop();
  158. }
  159. void UndoRedo::clearRedoStack()
  160. {
  161. while(mRedoNumElements > 0)
  162. {
  163. mRedoStack[mRedoStackPtr] = SPtr<EditorCommand>();
  164. mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
  165. mRedoNumElements--;
  166. }
  167. }
  168. }