BsUndoRedo.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include "BsUndoRedo.h"
  2. #include "BsEditorCommand.h"
  3. namespace BansheeEngine
  4. {
  5. const UINT32 UndoRedo::MAX_STACK_ELEMENTS = 1000;
  6. UndoRedo::UndoRedo()
  7. :mUndoStackPtr(0), mUndoNumElements(0),
  8. mRedoStackPtr(0), mRedoNumElements(0),
  9. mUndoStack(nullptr), mRedoStack(nullptr)
  10. {
  11. mUndoStack = bs_newN<EditorCommand*>(MAX_STACK_ELEMENTS);
  12. mRedoStack = bs_newN<EditorCommand*>(MAX_STACK_ELEMENTS);
  13. }
  14. UndoRedo::~UndoRedo()
  15. {
  16. clear();
  17. bs_deleteN(mUndoStack, MAX_STACK_ELEMENTS);
  18. bs_deleteN(mRedoStack, MAX_STACK_ELEMENTS);
  19. }
  20. void UndoRedo::undo()
  21. {
  22. if(mUndoNumElements == 0)
  23. return;
  24. EditorCommand* command = removeLastFromUndoStack();
  25. mRedoStackPtr = (mRedoStackPtr + 1) % MAX_STACK_ELEMENTS;
  26. mRedoStack[mRedoStackPtr] = command;
  27. mRedoNumElements = std::min(mRedoNumElements + 1, MAX_STACK_ELEMENTS);
  28. command->revert();
  29. }
  30. void UndoRedo::redo()
  31. {
  32. if(mRedoNumElements == 0)
  33. return;
  34. EditorCommand* command = mRedoStack[mRedoStackPtr];
  35. mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
  36. mRedoNumElements--;
  37. addToUndoStack(command);
  38. command->commit();
  39. }
  40. void UndoRedo::pushGroup(const String& name)
  41. {
  42. mGroups.push(GroupData());
  43. GroupData& newGroup = mGroups.top();
  44. newGroup.name = name;
  45. newGroup.numEntries = 0;
  46. clearRedoStack();
  47. }
  48. void UndoRedo::popGroup(const String& name)
  49. {
  50. if(mGroups.empty())
  51. BS_EXCEPT(InvalidStateException, "Attempting to pop an UndoRedo group that doesn't exist: " + name);
  52. GroupData& topGroup = mGroups.top();
  53. if(topGroup.name != name)
  54. BS_EXCEPT(InvalidStateException, "Attempting to pop invalid UndoRedo group. Got: " + name + ". Expected: " + topGroup.name);
  55. for(UINT32 i = 0; i < topGroup.numEntries; i++)
  56. {
  57. EditorCommand* command = mUndoStack[mUndoStackPtr];
  58. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  59. mUndoNumElements--;
  60. EditorCommand::destroy(command);
  61. }
  62. mGroups.pop();
  63. clearRedoStack();
  64. }
  65. void UndoRedo::registerCommand(EditorCommand* command)
  66. {
  67. addToUndoStack(command);
  68. clearRedoStack();
  69. }
  70. void UndoRedo::clear()
  71. {
  72. clearUndoStack();
  73. clearRedoStack();
  74. }
  75. EditorCommand* UndoRedo::removeLastFromUndoStack()
  76. {
  77. EditorCommand* command = mUndoStack[mUndoStackPtr];
  78. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  79. mUndoNumElements--;
  80. if(!mGroups.empty())
  81. {
  82. GroupData& topGroup = mGroups.top();
  83. if(topGroup.numEntries == 0)
  84. {
  85. BS_EXCEPT(InvalidStateException, "Removing an element from UndoRedo stack while in an " \
  86. "invalid UndoRedo group. Current group: " + topGroup.name);
  87. }
  88. topGroup.numEntries--;
  89. }
  90. return command;
  91. }
  92. void UndoRedo::addToUndoStack(EditorCommand* command)
  93. {
  94. mUndoStackPtr = (mUndoStackPtr + 1) % MAX_STACK_ELEMENTS;
  95. mUndoStack[mUndoStackPtr] = command;
  96. mUndoNumElements = std::min(mUndoNumElements + 1, MAX_STACK_ELEMENTS);
  97. if(!mGroups.empty())
  98. {
  99. GroupData& topGroup = mGroups.top();
  100. topGroup.numEntries = std::min(topGroup.numEntries + 1, MAX_STACK_ELEMENTS);
  101. }
  102. }
  103. void UndoRedo::clearUndoStack()
  104. {
  105. while(mUndoNumElements > 0)
  106. {
  107. EditorCommand* command = mUndoStack[mUndoStackPtr];
  108. mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
  109. mUndoNumElements--;
  110. EditorCommand::destroy(command);
  111. }
  112. while(!mGroups.empty())
  113. mGroups.pop();
  114. }
  115. void UndoRedo::clearRedoStack()
  116. {
  117. while(mRedoNumElements > 0)
  118. {
  119. EditorCommand* command = mRedoStack[mRedoStackPtr];
  120. mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
  121. mRedoNumElements--;
  122. EditorCommand::destroy(command);
  123. }
  124. }
  125. }