UiAnimUndoManager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "UiAnimUndoManager.h"
  9. #include "UiAnimUndoObject.h"
  10. #include "Undo/IUndoManagerListener.h"
  11. #include <CryCommon/StlUtils.h>
  12. // UI Editor
  13. #include "EditorCommon.h"
  14. #include <QUndoCommand>
  15. UiAnimUndoManager* UiAnimUndoManager::s_instance = nullptr;
  16. //! UiAnimUndoStep is a collection of UiAnimUndoObjects instances that forms a single undo step.
  17. class UiAnimUndoStep
  18. : public QUndoCommand
  19. {
  20. public:
  21. UiAnimUndoStep()
  22. : m_hasDoneUndo(false) {};
  23. virtual ~UiAnimUndoStep() { ClearObjects(); }
  24. //! Set undo object name.
  25. void SetName(const AZStd::string& name) { m_name = name; };
  26. //! Get undo object name.
  27. const AZStd::string& GetName() { return m_name; };
  28. //! Add new undo object to undo step.
  29. void AddUndoObject(UiAnimUndoObject* o)
  30. {
  31. m_undoObjects.push_back(o);
  32. }
  33. void ClearObjects()
  34. {
  35. int i;
  36. // Release all undo objects.
  37. for (i = 0; i < m_undoObjects.size(); i++)
  38. {
  39. m_undoObjects[i]->Release();
  40. }
  41. m_undoObjects.clear();
  42. };
  43. virtual int GetSize() const
  44. {
  45. int size = 0;
  46. for (int i = 0; i < m_undoObjects.size(); i++)
  47. {
  48. size += m_undoObjects[i]->GetSize();
  49. }
  50. return size;
  51. }
  52. virtual bool IsEmpty() const { return m_undoObjects.empty(); };
  53. virtual void Undo(bool bUndo)
  54. {
  55. for (int i = aznumeric_cast<int>(m_undoObjects.size()) - 1; i >= 0; i--)
  56. {
  57. m_undoObjects[i]->Undo(bUndo);
  58. }
  59. }
  60. virtual void Redo()
  61. {
  62. for (int i = 0; i < m_undoObjects.size(); i++)
  63. {
  64. m_undoObjects[i]->Redo();
  65. }
  66. }
  67. // Add to Qt undo stack
  68. void Push(UndoStack* undoStack)
  69. {
  70. setText(m_name.c_str());
  71. undoStack->push(this);
  72. }
  73. private: // ------------------------------------------------------
  74. // these are called from the Qt undo system
  75. void undo() override
  76. {
  77. UiAnimUndoManager::Get()->UndoStep(this);
  78. m_hasDoneUndo = true;
  79. }
  80. void redo() override
  81. {
  82. // Qt automatically calls redo when a command is added to the Qt undo stack
  83. // We are emulating the CUndo behavior so we ingore that first redo
  84. if (m_hasDoneUndo)
  85. {
  86. UiAnimUndoManager::Get()->RedoStep(this);
  87. }
  88. }
  89. bool m_hasDoneUndo;
  90. friend class UiAnimUndoManager;
  91. AZStd::string m_name;
  92. // Undo objects registered for this step.
  93. std::vector<UiAnimUndoObject*> m_undoObjects;
  94. };
  95. //////////////////////////////////////////////////////////////////////////
  96. UiAnimUndoManager::UiAnimUndoManager()
  97. {
  98. m_bRecording = false;
  99. m_currentUndo = 0;
  100. m_suspendCount = 0;
  101. m_bUndoing = false;
  102. m_bRedoing = false;
  103. s_instance = this;
  104. }
  105. //////////////////////////////////////////////////////////////////////////
  106. UiAnimUndoManager::~UiAnimUndoManager()
  107. {
  108. m_bRecording = false;
  109. delete m_currentUndo;
  110. s_instance = nullptr;
  111. }
  112. //////////////////////////////////////////////////////////////////////////
  113. void UiAnimUndoManager::Begin()
  114. {
  115. //CryLog( "<Undo> Begin SuspendCount=%d",m_suspendCount );
  116. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  117. {
  118. return;
  119. }
  120. // assert( m_bRecording == false );
  121. if (m_bRecording)
  122. {
  123. //CLogFile::WriteLine( "<Undo> Begin (already recording)" );
  124. // Not cancel, just combine.
  125. return;
  126. }
  127. // Begin Creates a new undo object.
  128. m_currentUndo = new UiAnimUndoStep;
  129. m_bRecording = true;
  130. //CLogFile::WriteLine( "<Undo> Begin OK" );
  131. }
  132. //////////////////////////////////////////////////////////////////////////
  133. void UiAnimUndoManager::Restore(bool bUndo)
  134. {
  135. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  136. {
  137. return;
  138. }
  139. if (m_currentUndo)
  140. {
  141. BeginRestoreTransaction();
  142. Suspend();
  143. if (bUndo && m_currentUndo)
  144. {
  145. m_currentUndo->Undo(false); // Undo not by Undo command (no need to store Redo)
  146. }
  147. Resume();
  148. if (m_currentUndo)
  149. {
  150. m_currentUndo->ClearObjects();
  151. }
  152. EndRestoreTransaction();
  153. }
  154. //CryLog( "Restore Undo" );
  155. }
  156. //////////////////////////////////////////////////////////////////////////
  157. void UiAnimUndoManager::Accept(const AZStd::string& name)
  158. {
  159. //CryLog( "<Undo> Accept, Suspend Count=%d",m_suspendCount );
  160. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  161. {
  162. return;
  163. }
  164. if (!m_bRecording)
  165. {
  166. //CLogFile::WriteLine( "<Undo> Accept (Not recording)" );
  167. return;
  168. }
  169. if (!m_currentUndo->IsEmpty())
  170. {
  171. m_currentUndo->SetName(name);
  172. {
  173. // push this undo stap on the Ui Editor undo stack
  174. m_currentUndo->Push(m_uiUndoStack);
  175. }
  176. }
  177. else
  178. {
  179. // If no any object was recorded, Cancel undo operation.
  180. Cancel();
  181. }
  182. m_bRecording = false;
  183. m_currentUndo = 0;
  184. //CLogFile::WriteLine( "<Undo> Accept OK" );
  185. }
  186. //////////////////////////////////////////////////////////////////////////
  187. void UiAnimUndoManager::Cancel()
  188. {
  189. //CryLog( "<Undo> Cancel" );
  190. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  191. {
  192. return;
  193. }
  194. if (!m_bRecording)
  195. {
  196. return;
  197. }
  198. assert(m_currentUndo != 0);
  199. m_bRecording = false;
  200. if (!m_currentUndo->IsEmpty())
  201. {
  202. // Restore all objects to the state they was at Begin call and throws out all undo objects.
  203. Restore(true);
  204. }
  205. delete m_currentUndo;
  206. m_currentUndo = 0;
  207. //CLogFile::WriteLine( "<Undo> Cancel OK" );
  208. }
  209. //////////////////////////////////////////////////////////////////////////
  210. void UiAnimUndoManager::Redo()
  211. {
  212. // this is called when using the Redo menu/toolbar actions in the
  213. // UI Animation Editor. Just use the UI Editor redo
  214. m_uiUndoStack->redo();
  215. }
  216. //////////////////////////////////////////////////////////////////////////
  217. void UiAnimUndoManager::Undo()
  218. {
  219. // this is called when using the undo menu/toolbar actions in the
  220. // UI Animation Editor. Just use the UI Editor undo
  221. m_uiUndoStack->undo();
  222. }
  223. //////////////////////////////////////////////////////////////////////////
  224. void UiAnimUndoManager::RedoStep(UiAnimUndoStep* step)
  225. {
  226. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  227. {
  228. return;
  229. }
  230. if (m_bRecording)
  231. {
  232. // GetIEditor()->GetLogFile()->FormatLine("Cannot Redo while Recording");
  233. return;
  234. }
  235. m_bRedoing = true;
  236. BeginUndoTransaction();
  237. m_bRedoing = false;
  238. Suspend();
  239. m_bRedoing = true;
  240. step->Redo();
  241. m_bRedoing = false;
  242. Resume();
  243. // if (m_suspendCount == 0)
  244. // GetIEditor()->UpdateViews(eUpdateObjects);
  245. m_bRedoing = true;
  246. EndUndoTransaction();
  247. m_bRedoing = false;
  248. }
  249. //////////////////////////////////////////////////////////////////////////
  250. void UiAnimUndoManager::UndoStep(UiAnimUndoStep* step)
  251. {
  252. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  253. {
  254. return;
  255. }
  256. if (m_bRecording)
  257. {
  258. // GetIEditor()->GetLogFile()->FormatLine("Cannot Undo while Recording");
  259. return;
  260. }
  261. m_bUndoing = true;
  262. BeginUndoTransaction();
  263. m_bUndoing = false;
  264. Suspend();
  265. m_bUndoing = true;
  266. step->Undo(true);
  267. m_bUndoing = false;
  268. Resume();
  269. // Update viewports.
  270. // if (m_suspendCount == 0)
  271. // GetIEditor()->UpdateViews(eUpdateObjects);
  272. m_bUndoing = true;
  273. EndUndoTransaction();
  274. m_bUndoing = false;
  275. }
  276. //////////////////////////////////////////////////////////////////////////
  277. void UiAnimUndoManager::RecordUndo(UiAnimUndoObject* obj)
  278. {
  279. //CryLog( "<Undo> RecordUndo Name=%s",obj->GetDescription() );
  280. if (m_bUndoing || m_bRedoing) // If Undoing or redoing now, ignore this calls.
  281. {
  282. //CLogFile::WriteLine( "<Undo> RecordUndo (Undoing or Redoing)" );
  283. obj->Release();
  284. return;
  285. }
  286. if (m_bRecording && (m_suspendCount == 0))
  287. {
  288. assert(m_currentUndo != 0);
  289. m_currentUndo->AddUndoObject(obj);
  290. //CLogFile::FormatLine( "Undo Object Added: %s",obj->GetDescription() );
  291. }
  292. else
  293. {
  294. //CLogFile::WriteLine( "<Undo> RecordUndo (Not Recording)" );
  295. // Ignore this object.
  296. obj->Release();
  297. }
  298. }
  299. //////////////////////////////////////////////////////////////////////////
  300. void UiAnimUndoManager::Suspend()
  301. {
  302. m_suspendCount++;
  303. //CLogFile::FormatLine( "<Undo> Suspend %d",m_suspendCount );
  304. }
  305. //////////////////////////////////////////////////////////////////////////
  306. void UiAnimUndoManager::Resume()
  307. {
  308. assert(m_suspendCount >= 0);
  309. if (m_suspendCount > 0)
  310. {
  311. m_suspendCount--;
  312. }
  313. //CLogFile::FormatLine( "<Undo> Resume %d",m_suspendCount );
  314. }
  315. //////////////////////////////////////////////////////////////////////////
  316. void UiAnimUndoManager::Flush()
  317. {
  318. m_bRecording = false;
  319. delete m_currentUndo;
  320. m_currentUndo = 0;
  321. }
  322. void UiAnimUndoManager::AddListener(IUndoManagerListener* pListener)
  323. {
  324. stl::push_back_unique(m_listeners, pListener);
  325. }
  326. void UiAnimUndoManager::RemoveListener(IUndoManagerListener* pListener)
  327. {
  328. stl::find_and_erase(m_listeners, pListener);
  329. }
  330. void UiAnimUndoManager::BeginUndoTransaction()
  331. {
  332. for (auto iter = m_listeners.begin(); iter != m_listeners.end(); ++iter)
  333. {
  334. (*iter)->BeginUndoTransaction();
  335. }
  336. }
  337. void UiAnimUndoManager::EndUndoTransaction()
  338. {
  339. for (auto iter = m_listeners.begin(); iter != m_listeners.end(); ++iter)
  340. {
  341. (*iter)->EndUndoTransaction();
  342. }
  343. }
  344. void UiAnimUndoManager::BeginRestoreTransaction()
  345. {
  346. for (auto iter = m_listeners.begin(); iter != m_listeners.end(); ++iter)
  347. {
  348. (*iter)->BeginRestoreTransaction();
  349. }
  350. }
  351. void UiAnimUndoManager::EndRestoreTransaction()
  352. {
  353. for (auto iter = m_listeners.begin(); iter != m_listeners.end(); ++iter)
  354. {
  355. (*iter)->EndRestoreTransaction();
  356. }
  357. }
  358. bool UiAnimUndoManager::IsUndoRecording() const
  359. {
  360. return (m_bRecording) && m_suspendCount == 0;
  361. }
  362. bool UiAnimUndoManager::IsUndoSuspended() const
  363. {
  364. return m_suspendCount != 0;
  365. }
  366. void UiAnimUndoManager::SetActiveUndoStack(UndoStack* undoStack)
  367. {
  368. m_uiUndoStack = undoStack;
  369. }
  370. UndoStack* UiAnimUndoManager::GetActiveUndoStack() const
  371. {
  372. return m_uiUndoStack;
  373. }
  374. UiAnimUndoManager* UiAnimUndoManager::Get()
  375. {
  376. return s_instance;
  377. }