UiAnimViewSequence.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  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 "UiEditorAnimationBus.h"
  9. #include "UiAnimViewSequence.h"
  10. #include "UiAnimViewSequenceManager.h"
  11. #include "UiAnimViewAnimNode.h"
  12. #include "UiAnimViewUndo.h"
  13. #include "UiAnimViewTrack.h"
  14. #include "UiAnimViewNodeFactories.h"
  15. #include "UiAnimViewSequence.h"
  16. #include "AnimationContext.h"
  17. #include "Clipboard.h"
  18. #include "UiEditorAnimationBus.h"
  19. #include <Util/EditorUtils.h>
  20. #include <QApplication>
  21. //////////////////////////////////////////////////////////////////////////
  22. CUiAnimViewSequence::CUiAnimViewSequence(IUiAnimSequence* pSequence)
  23. : CUiAnimViewAnimNode(pSequence, nullptr, nullptr)
  24. , m_pAnimSequence(pSequence)
  25. , m_bBoundToEditorObjects(false)
  26. , m_selectionRecursionLevel(0)
  27. , m_bQueueNotifications(false)
  28. , m_bKeySelectionChanged(false)
  29. , m_bKeysChanged(false)
  30. , m_bForceUiAnimation(false)
  31. , m_bNodeSelectionChanged(false)
  32. , m_time(0.0f)
  33. , m_bNoNotifications(false)
  34. {
  35. assert(m_pAnimSequence);
  36. SetExpanded(true);
  37. }
  38. //////////////////////////////////////////////////////////////////////////
  39. CUiAnimViewSequence::~CUiAnimViewSequence()
  40. {
  41. // For safety. Should be done by sequence manager
  42. UiAnimUndoManager::Get()->RemoveListener(this);
  43. }
  44. //////////////////////////////////////////////////////////////////////////
  45. void CUiAnimViewSequence::Load()
  46. {
  47. const int nodeCount = m_pAnimSequence->GetNodeCount();
  48. for (int i = 0; i < nodeCount; ++i)
  49. {
  50. IUiAnimNode* pNode = m_pAnimSequence->GetNode(i);
  51. // Only add top level nodes to sequence
  52. if (!pNode->GetParent())
  53. {
  54. CUiAnimViewAnimNodeFactory animNodeFactory;
  55. CUiAnimViewAnimNode* pNewTVAnimNode = animNodeFactory.BuildAnimNode(m_pAnimSequence.get(), pNode, this);
  56. m_childNodes.push_back(std::unique_ptr<CUiAnimViewNode>(pNewTVAnimNode));
  57. }
  58. }
  59. SortNodes();
  60. }
  61. //////////////////////////////////////////////////////////////////////////
  62. void CUiAnimViewSequence::BindToEditorObjects()
  63. {
  64. m_bBoundToEditorObjects = true;
  65. CUiAnimViewAnimNode::BindToEditorObjects();
  66. }
  67. //////////////////////////////////////////////////////////////////////////
  68. void CUiAnimViewSequence::UnBindFromEditorObjects()
  69. {
  70. m_bBoundToEditorObjects = false;
  71. CUiAnimViewAnimNode::UnBindFromEditorObjects();
  72. }
  73. //////////////////////////////////////////////////////////////////////////
  74. bool CUiAnimViewSequence::IsBoundToEditorObjects() const
  75. {
  76. return m_bBoundToEditorObjects;
  77. }
  78. //////////////////////////////////////////////////////////////////////////
  79. CUiAnimViewKeyHandle CUiAnimViewSequence::FindSingleSelectedKey()
  80. {
  81. CUiAnimViewSequence* pSequence = nullptr;
  82. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  83. if (!pSequence)
  84. {
  85. return CUiAnimViewKeyHandle();
  86. }
  87. CUiAnimViewKeyBundle selectedKeys = pSequence->GetSelectedKeys();
  88. if (selectedKeys.GetKeyCount() != 1)
  89. {
  90. return CUiAnimViewKeyHandle();
  91. }
  92. return selectedKeys.GetKey(0);
  93. }
  94. //////////////////////////////////////////////////////////////////////////
  95. bool CUiAnimViewSequence::IsAncestorOf(CUiAnimViewSequence* pSequence) const
  96. {
  97. return m_pAnimSequence->IsAncestorOf(pSequence->m_pAnimSequence.get());
  98. }
  99. //////////////////////////////////////////////////////////////////////////
  100. void CUiAnimViewSequence::BeginCutScene([[maybe_unused]] const bool bResetFx) const
  101. {
  102. }
  103. //////////////////////////////////////////////////////////////////////////
  104. void CUiAnimViewSequence::EndCutScene() const
  105. {
  106. }
  107. //////////////////////////////////////////////////////////////////////////
  108. void CUiAnimViewSequence::Render(const SUiAnimContext& animContext)
  109. {
  110. for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
  111. {
  112. CUiAnimViewNode* pChildNode = (*iter).get();
  113. if (pChildNode->GetNodeType() == eUiAVNT_AnimNode)
  114. {
  115. CUiAnimViewAnimNode* pChildAnimNode = (CUiAnimViewAnimNode*)pChildNode;
  116. pChildAnimNode->Render(animContext);
  117. }
  118. }
  119. m_pAnimSequence->Render();
  120. }
  121. //////////////////////////////////////////////////////////////////////////
  122. void CUiAnimViewSequence::Animate(const SUiAnimContext& animContext)
  123. {
  124. if (!m_pAnimSequence->IsActivated())
  125. {
  126. return;
  127. }
  128. m_time = animContext.time;
  129. m_pAnimSequence->Animate(animContext);
  130. CUiAnimViewSequenceNoNotificationContext context(this);
  131. for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
  132. {
  133. CUiAnimViewNode* pChildNode = (*iter).get();
  134. if (pChildNode->GetNodeType() == eUiAVNT_AnimNode)
  135. {
  136. CUiAnimViewAnimNode* pChildAnimNode = (CUiAnimViewAnimNode*)pChildNode;
  137. pChildAnimNode->Animate(animContext);
  138. }
  139. }
  140. }
  141. //////////////////////////////////////////////////////////////////////////
  142. void CUiAnimViewSequence::AddListener(IUiAnimViewSequenceListener* pListener)
  143. {
  144. stl::push_back_unique(m_sequenceListeners, pListener);
  145. }
  146. //////////////////////////////////////////////////////////////////////////
  147. void CUiAnimViewSequence::RemoveListener(IUiAnimViewSequenceListener* pListener)
  148. {
  149. stl::find_and_erase(m_sequenceListeners, pListener);
  150. }
  151. //////////////////////////////////////////////////////////////////////////
  152. void CUiAnimViewSequence::OnNodeSelectionChanged()
  153. {
  154. if (m_bNoNotifications)
  155. {
  156. return;
  157. }
  158. if (m_bQueueNotifications)
  159. {
  160. m_bNodeSelectionChanged = true;
  161. }
  162. else
  163. {
  164. CUiAnimViewSequenceNoNotificationContext context(this);
  165. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  166. {
  167. (*iter)->OnNodeSelectionChanged(this);
  168. }
  169. }
  170. }
  171. //////////////////////////////////////////////////////////////////////////
  172. void CUiAnimViewSequence::ForceAnimation()
  173. {
  174. if (m_bNoNotifications)
  175. {
  176. return;
  177. }
  178. if (m_bQueueNotifications)
  179. {
  180. m_bForceUiAnimation = true;
  181. }
  182. else
  183. {
  184. if (IsActive())
  185. {
  186. CUiAnimationContext* pAnimationContext = nullptr;
  187. UiEditorAnimationBus::BroadcastResult(pAnimationContext, &UiEditorAnimationBus::Events::GetAnimationContext);
  188. pAnimationContext->ForceAnimation();
  189. }
  190. }
  191. }
  192. //////////////////////////////////////////////////////////////////////////
  193. void CUiAnimViewSequence::OnKeySelectionChanged()
  194. {
  195. if (m_bNoNotifications)
  196. {
  197. return;
  198. }
  199. if (m_bQueueNotifications)
  200. {
  201. m_bKeySelectionChanged = true;
  202. }
  203. else
  204. {
  205. CUiAnimViewSequenceNoNotificationContext context(this);
  206. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  207. {
  208. (*iter)->OnKeySelectionChanged(this);
  209. }
  210. }
  211. }
  212. //////////////////////////////////////////////////////////////////////////
  213. void CUiAnimViewSequence::OnKeysChanged()
  214. {
  215. if (m_bNoNotifications)
  216. {
  217. return;
  218. }
  219. if (m_bQueueNotifications)
  220. {
  221. m_bKeysChanged = true;
  222. }
  223. else
  224. {
  225. CUiAnimViewSequenceNoNotificationContext context(this);
  226. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  227. {
  228. (*iter)->OnKeysChanged(this);
  229. }
  230. if (IsActive())
  231. {
  232. CUiAnimationContext* pAnimationContext = nullptr;
  233. UiEditorAnimationBus::BroadcastResult(pAnimationContext, &UiEditorAnimationBus::Events::GetAnimationContext);
  234. pAnimationContext->ForceAnimation();
  235. }
  236. }
  237. }
  238. //////////////////////////////////////////////////////////////////////////
  239. void CUiAnimViewSequence::OnNodeChanged(CUiAnimViewNode* pNode, IUiAnimViewSequenceListener::ENodeChangeType type)
  240. {
  241. if (m_bNoNotifications)
  242. {
  243. return;
  244. }
  245. CUiAnimViewSequenceNoNotificationContext context(this);
  246. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  247. {
  248. (*iter)->OnNodeChanged(pNode, type);
  249. }
  250. }
  251. //////////////////////////////////////////////////////////////////////////
  252. void CUiAnimViewSequence::OnNodeRenamed(CUiAnimViewNode* pNode, const char* pOldName)
  253. {
  254. if (m_bNoNotifications)
  255. {
  256. return;
  257. }
  258. CUiAnimViewSequenceNoNotificationContext context(this);
  259. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  260. {
  261. (*iter)->OnNodeRenamed(pNode, pOldName);
  262. }
  263. }
  264. //////////////////////////////////////////////////////////////////////////
  265. void CUiAnimViewSequence::OnSequenceSettingsChanged()
  266. {
  267. if (m_bNoNotifications)
  268. {
  269. return;
  270. }
  271. CUiAnimViewSequenceNoNotificationContext context(this);
  272. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  273. {
  274. (*iter)->OnSequenceSettingsChanged(this);
  275. }
  276. }
  277. //////////////////////////////////////////////////////////////////////////
  278. void CUiAnimViewSequence::QueueNotifications()
  279. {
  280. m_bQueueNotifications = true;
  281. ++m_selectionRecursionLevel;
  282. }
  283. //////////////////////////////////////////////////////////////////////////
  284. void CUiAnimViewSequence::SubmitPendingNotifcations()
  285. {
  286. assert(m_selectionRecursionLevel > 0);
  287. if (m_selectionRecursionLevel > 0)
  288. {
  289. --m_selectionRecursionLevel;
  290. }
  291. if (m_selectionRecursionLevel == 0)
  292. {
  293. m_bQueueNotifications = false;
  294. if (m_bNodeSelectionChanged)
  295. {
  296. OnNodeSelectionChanged();
  297. }
  298. if (m_bKeysChanged)
  299. {
  300. OnKeysChanged();
  301. }
  302. if (m_bKeySelectionChanged)
  303. {
  304. OnKeySelectionChanged();
  305. }
  306. if (m_bForceUiAnimation)
  307. {
  308. ForceAnimation();
  309. }
  310. m_bForceUiAnimation = false;
  311. m_bKeysChanged = false;
  312. m_bNodeSelectionChanged = false;
  313. m_bKeySelectionChanged = false;
  314. }
  315. }
  316. //////////////////////////////////////////////////////////////////////////
  317. void CUiAnimViewSequence::DeleteSelectedNodes()
  318. {
  319. assert(UiAnimUndo::IsRecording());
  320. CUiAnimViewSequenceNotificationContext context(this);
  321. if (IsSelected())
  322. {
  323. CUiAnimViewSequenceManager::GetSequenceManager()->DeleteSequence(this);
  324. return;
  325. }
  326. CUiAnimViewAnimNodeBundle selectedNodes = GetSelectedAnimNodes();
  327. CUiAnimViewTrackBundle selectedTracks = GetSelectedTracks();
  328. for (unsigned int i = 0; i < selectedTracks.GetCount(); ++i)
  329. {
  330. CUiAnimViewTrack* pTrack = selectedTracks.GetTrack(i);
  331. // Ignore sub tracks
  332. if (!pTrack->IsSubTrack())
  333. {
  334. pTrack->GetAnimNode()->RemoveTrack(pTrack);
  335. }
  336. }
  337. for (unsigned int i = 0; i < selectedNodes.GetCount(); ++i)
  338. {
  339. CUiAnimViewAnimNode* pNode = selectedNodes.GetNode(i);
  340. CUiAnimViewAnimNode* pParentNode = static_cast<CUiAnimViewAnimNode*>(pNode->GetParentNode());
  341. pParentNode->RemoveSubNode(pNode);
  342. }
  343. }
  344. //////////////////////////////////////////////////////////////////////////
  345. bool CUiAnimViewSequence::SetName(const char* pName)
  346. {
  347. // Check if there is already a sequence with that name
  348. const CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
  349. if (pSequenceManager->GetSequenceByName(pName))
  350. {
  351. return false;
  352. }
  353. AZStd::string oldName = GetName();
  354. m_pAnimSequence->SetName(pName);
  355. if (UiAnimUndo::IsRecording())
  356. {
  357. UiAnimUndo::Record(new CUndoAnimNodeRename(this, oldName));
  358. }
  359. GetSequence()->OnNodeRenamed(this, oldName.c_str());
  360. return true;
  361. }
  362. //////////////////////////////////////////////////////////////////////////
  363. void CUiAnimViewSequence::DeleteSelectedKeys()
  364. {
  365. assert(UiAnimUndo::IsRecording());
  366. StoreUndoForTracksWithSelectedKeys();
  367. CUiAnimViewSequenceNotificationContext context(this);
  368. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  369. for (int k = (int)selectedKeys.GetKeyCount() - 1; k >= 0; --k)
  370. {
  371. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(k);
  372. skey.Delete();
  373. }
  374. // The selected keys are deleted, so notify the selection was just changed.
  375. OnKeySelectionChanged();
  376. }
  377. //////////////////////////////////////////////////////////////////////////
  378. void CUiAnimViewSequence::StoreUndoForTracksWithSelectedKeys()
  379. {
  380. assert(UiAnimUndo::IsRecording());
  381. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  382. // Construct the set of tracks that have selected keys
  383. std::set<CUiAnimViewTrack*> tracks;
  384. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  385. {
  386. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(k);
  387. tracks.insert(skey.GetTrack());
  388. }
  389. // Store one key selection undo before...
  390. UiAnimUndo::Record(new CUndoAnimKeySelection(this));
  391. // For each of those tracks store an undo object
  392. for (auto iter = tracks.begin(); iter != tracks.end(); ++iter)
  393. {
  394. UiAnimUndo::Record(new CUndoTrackObject(*iter, false));
  395. }
  396. // ... and one after key changes
  397. UiAnimUndo::Record(new CUndoAnimKeySelection(this));
  398. }
  399. //////////////////////////////////////////////////////////////////////////
  400. void CUiAnimViewSequence::CopyKeysToClipboard(const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks)
  401. {
  402. XmlNodeRef copyNode = XmlHelpers::CreateXmlNode("CopyKeysNode");
  403. CopyKeysToClipboard(copyNode, bOnlySelectedKeys, bOnlyFromSelectedTracks);
  404. CClipboard clip(nullptr);
  405. clip.Put(copyNode, "Track view keys");
  406. }
  407. //////////////////////////////////////////////////////////////////////////
  408. void CUiAnimViewSequence::CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks)
  409. {
  410. for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
  411. {
  412. CUiAnimViewNode* pChildNode = (*iter).get();
  413. pChildNode->CopyKeysToClipboard(xmlNode, bOnlySelectedKeys, bOnlyFromSelectedTracks);
  414. }
  415. }
  416. //////////////////////////////////////////////////////////////////////////
  417. void CUiAnimViewSequence::PasteKeysFromClipboard(CUiAnimViewAnimNode* pTargetNode, CUiAnimViewTrack* pTargetTrack, const float timeOffset)
  418. {
  419. assert(UiAnimUndo::IsRecording());
  420. CClipboard clipboard(nullptr);
  421. XmlNodeRef clipboardContent = clipboard.Get();
  422. if (clipboardContent)
  423. {
  424. std::vector<TMatchedTrackLocation> matchedLocations = GetMatchedPasteLocations(clipboardContent, pTargetNode, pTargetTrack);
  425. for (auto iter = matchedLocations.begin(); iter != matchedLocations.end(); ++iter)
  426. {
  427. const TMatchedTrackLocation& location = *iter;
  428. CUiAnimViewTrack* pTrack = location.first;
  429. const XmlNodeRef& trackNode = location.second;
  430. pTrack->PasteKeys(trackNode, timeOffset);
  431. }
  432. OnKeysChanged();
  433. }
  434. }
  435. //////////////////////////////////////////////////////////////////////////
  436. std::vector<CUiAnimViewSequence::TMatchedTrackLocation>
  437. CUiAnimViewSequence::GetMatchedPasteLocations(XmlNodeRef clipboardContent, CUiAnimViewAnimNode* pTargetNode, CUiAnimViewTrack* pTargetTrack)
  438. {
  439. std::vector<TMatchedTrackLocation> matchedLocations;
  440. bool bPastingSingleNode = false;
  441. XmlNodeRef singleNode;
  442. bool bPastingSingleTrack = false;
  443. XmlNodeRef singleTrack;
  444. // Check if the XML tree only contains one node and if so if that node only contains one track
  445. for (XmlNodeRef currentNode = clipboardContent; currentNode->getChildCount() > 0; currentNode = currentNode->getChild(0))
  446. {
  447. bool bAllChildsAreTracks = true;
  448. const unsigned int numChilds = currentNode->getChildCount();
  449. for (unsigned int i = 0; i < numChilds; ++i)
  450. {
  451. XmlNodeRef childNode = currentNode->getChild(i);
  452. if (strcmp(currentNode->getChild(0)->getTag(), "Track") != 0)
  453. {
  454. bAllChildsAreTracks = false;
  455. break;
  456. }
  457. }
  458. if (bAllChildsAreTracks)
  459. {
  460. bPastingSingleNode = true;
  461. singleNode = currentNode;
  462. if (currentNode->getChildCount() == 1)
  463. {
  464. bPastingSingleTrack = true;
  465. singleTrack = currentNode->getChild(0);
  466. }
  467. }
  468. else if (currentNode->getChildCount() != 1)
  469. {
  470. break;
  471. }
  472. }
  473. if (bPastingSingleTrack && pTargetNode && pTargetTrack)
  474. {
  475. // We have a target node & track, so try to match the value type
  476. unsigned int valueType = 0;
  477. if (singleTrack->getAttr("valueType", valueType))
  478. {
  479. if (pTargetTrack->GetValueType() == valueType)
  480. {
  481. matchedLocations.push_back(TMatchedTrackLocation(pTargetTrack, singleTrack));
  482. return matchedLocations;
  483. }
  484. }
  485. }
  486. if (bPastingSingleNode && pTargetNode)
  487. {
  488. // Set of tracks that were already matched
  489. std::vector<CUiAnimViewTrack*> matchedTracks;
  490. // We have a single node to paste and have been given a target node
  491. // so try to match the tracks by param type
  492. const unsigned int numTracks = singleNode->getChildCount();
  493. for (unsigned int i = 0; i < numTracks; ++i)
  494. {
  495. XmlNodeRef trackNode = singleNode->getChild(i);
  496. // Try to match the track
  497. auto matchingTracks = GetMatchingTracks(pTargetNode, trackNode);
  498. for (auto iter = matchingTracks.begin(); iter != matchingTracks.end(); ++iter)
  499. {
  500. CUiAnimViewTrack* pMatchedTrack = *iter;
  501. // Pick the first track that was matched *and* was not already matched
  502. if (!stl::find(matchedTracks, pMatchedTrack))
  503. {
  504. stl::push_back_unique(matchedTracks, pMatchedTrack);
  505. matchedLocations.push_back(TMatchedTrackLocation(pMatchedTrack, trackNode));
  506. break;
  507. }
  508. }
  509. }
  510. // Return if matching succeeded
  511. if (matchedLocations.size() > 0)
  512. {
  513. return matchedLocations;
  514. }
  515. }
  516. if (!bPastingSingleNode)
  517. {
  518. // Ok, we're pasting keys from multiple nodes, haven't been given any target
  519. // or matching the targets failed. Ignore given target pointers and start
  520. // a recursive match at the sequence root.
  521. GetMatchedPasteLocationsRec(matchedLocations, this, clipboardContent);
  522. }
  523. return matchedLocations;
  524. }
  525. //////////////////////////////////////////////////////////////////////////
  526. std::deque<CUiAnimViewTrack*> CUiAnimViewSequence::GetMatchingTracks(CUiAnimViewAnimNode* pAnimNode, XmlNodeRef trackNode)
  527. {
  528. std::deque<CUiAnimViewTrack*> matchingTracks;
  529. const AZStd::string trackName = trackNode->getAttr("name");
  530. IUiAnimationSystem* animationSystem = nullptr;
  531. UiEditorAnimationBus::BroadcastResult(animationSystem, &UiEditorAnimationBus::Events::GetAnimationSystem);
  532. CUiAnimParamType animParamType;
  533. animParamType.Serialize(animationSystem, trackNode, true);
  534. unsigned int valueType;
  535. if (!trackNode->getAttr("valueType", valueType))
  536. {
  537. return matchingTracks;
  538. }
  539. CUiAnimViewTrackBundle tracks = pAnimNode->GetTracksByParam(animParamType);
  540. const unsigned int trackCount = tracks.GetCount();
  541. if (trackCount > 0)
  542. {
  543. // Search for a track with the given name and value type
  544. for (unsigned int i = 0; i < trackCount; ++i)
  545. {
  546. CUiAnimViewTrack* pTrack = tracks.GetTrack(i);
  547. if (pTrack->GetValueType() == valueType)
  548. {
  549. if (pTrack->GetName() == trackName)
  550. {
  551. matchingTracks.push_back(pTrack);
  552. }
  553. }
  554. }
  555. // Then with lower precedence add the tracks that only match the value
  556. for (unsigned int i = 0; i < trackCount; ++i)
  557. {
  558. CUiAnimViewTrack* pTrack = tracks.GetTrack(i);
  559. if (pTrack->GetValueType() == valueType)
  560. {
  561. stl::push_back_unique(matchingTracks, pTrack);
  562. }
  563. }
  564. }
  565. return matchingTracks;
  566. }
  567. //////////////////////////////////////////////////////////////////////////
  568. void CUiAnimViewSequence::GetMatchedPasteLocationsRec(std::vector<TMatchedTrackLocation>& locations, CUiAnimViewNode* pCurrentNode, XmlNodeRef clipboardNode)
  569. {
  570. if (pCurrentNode->GetNodeType() == eUiAVNT_Sequence)
  571. {
  572. if (strcmp(clipboardNode->getTag(), "CopyKeysNode") != 0)
  573. {
  574. return;
  575. }
  576. }
  577. const unsigned int numChildNodes = clipboardNode->getChildCount();
  578. for (unsigned int nodeIndex = 0; nodeIndex < numChildNodes; ++nodeIndex)
  579. {
  580. XmlNodeRef xmlChildNode = clipboardNode->getChild(nodeIndex);
  581. const AZStd::string tagName = xmlChildNode->getTag();
  582. if (tagName == "Node")
  583. {
  584. const AZStd::string nodeName = xmlChildNode->getAttr("name");
  585. int nodeType = eUiAnimNodeType_Invalid;
  586. xmlChildNode->getAttr("type", nodeType);
  587. const unsigned int childCount = pCurrentNode->GetChildCount();
  588. for (unsigned int i = 0; i < childCount; ++i)
  589. {
  590. CUiAnimViewNode* pChildNode = pCurrentNode->GetChild(i);
  591. if (pChildNode->GetNodeType() == eUiAVNT_AnimNode)
  592. {
  593. CUiAnimViewAnimNode* pAnimNode = static_cast<CUiAnimViewAnimNode*>(pChildNode);
  594. if (pAnimNode->GetName() == nodeName && pAnimNode->GetType() == nodeType)
  595. {
  596. GetMatchedPasteLocationsRec(locations, pChildNode, xmlChildNode);
  597. }
  598. }
  599. }
  600. }
  601. else if (tagName == "Track")
  602. {
  603. const AZStd::string trackName = xmlChildNode->getAttr("name");
  604. IUiAnimationSystem* animationSystem = nullptr;
  605. UiEditorAnimationBus::BroadcastResult(animationSystem, &UiEditorAnimationBus::Events::GetAnimationSystem);
  606. CUiAnimParamType trackParamType;
  607. trackParamType.Serialize(animationSystem, xmlChildNode, true);
  608. int trackParamValue = eUiAnimValue_Unknown;
  609. xmlChildNode->getAttr("valueType", trackParamValue);
  610. const unsigned int childCount = pCurrentNode->GetChildCount();
  611. for (unsigned int i = 0; i < childCount; ++i)
  612. {
  613. CUiAnimViewNode* pNode = pCurrentNode->GetChild(i);
  614. if (pNode->GetNodeType() == eUiAVNT_Track)
  615. {
  616. CUiAnimViewTrack* pTrack = static_cast<CUiAnimViewTrack*>(pNode);
  617. if (pTrack->GetName() == trackName && pTrack->GetParameterType() == trackParamType)
  618. {
  619. locations.push_back(TMatchedTrackLocation(pTrack, xmlChildNode));
  620. }
  621. }
  622. }
  623. }
  624. }
  625. }
  626. //////////////////////////////////////////////////////////////////////////
  627. void CUiAnimViewSequence::AdjustKeysToTimeRange(Range newTimeRange)
  628. {
  629. assert (UiAnimUndo::IsRecording());
  630. // Store one key selection undo before...
  631. UiAnimUndo::Record(new CUndoAnimKeySelection(this));
  632. // Store key undo for each track
  633. CUiAnimViewTrackBundle tracks = GetAllTracks();
  634. const unsigned int numTracks = tracks.GetCount();
  635. for (unsigned int i = 0; i < numTracks; ++i)
  636. {
  637. CUiAnimViewTrack* pTrack = tracks.GetTrack(i);
  638. UiAnimUndo::Record(new CUndoTrackObject(pTrack, false));
  639. }
  640. // ... and one after key changes
  641. UiAnimUndo::Record(new CUndoAnimKeySelection(this));
  642. // Set new time range
  643. Range oldTimeRange = GetTimeRange();
  644. float offset = newTimeRange.start - oldTimeRange.start;
  645. // Calculate scale ratio.
  646. float scale = newTimeRange.Length() / oldTimeRange.Length();
  647. SetTimeRange(newTimeRange);
  648. CUiAnimViewKeyBundle keyBundle = GetAllKeys();
  649. const unsigned int numKeys = keyBundle.GetKeyCount();
  650. for (unsigned int i = 0; i < numKeys; ++i)
  651. {
  652. CUiAnimViewKeyHandle keyHandle = keyBundle.GetKey(i);
  653. keyHandle.SetTime(offset + keyHandle.GetTime() * scale);
  654. }
  655. }
  656. //////////////////////////////////////////////////////////////////////////
  657. void CUiAnimViewSequence::SetTimeRange(Range timeRange)
  658. {
  659. if (UiAnimUndo::IsRecording())
  660. {
  661. // Store old sequence settings
  662. UiAnimUndo::Record(new CUndoSequenceSettings(this));
  663. }
  664. m_pAnimSequence->SetTimeRange(timeRange);
  665. OnSequenceSettingsChanged();
  666. }
  667. //////////////////////////////////////////////////////////////////////////
  668. Range CUiAnimViewSequence::GetTimeRange() const
  669. {
  670. return m_pAnimSequence->GetTimeRange();
  671. }
  672. //////////////////////////////////////////////////////////////////////////
  673. void CUiAnimViewSequence::SetFlags(IUiAnimSequence::EUiAnimSequenceFlags flags)
  674. {
  675. if (UiAnimUndo::IsRecording())
  676. {
  677. // Store old sequence settings
  678. UiAnimUndo::Record(new CUndoSequenceSettings(this));
  679. }
  680. m_pAnimSequence->SetFlags(flags);
  681. OnSequenceSettingsChanged();
  682. }
  683. //////////////////////////////////////////////////////////////////////////
  684. IUiAnimSequence::EUiAnimSequenceFlags CUiAnimViewSequence::GetFlags() const
  685. {
  686. return (IUiAnimSequence::EUiAnimSequenceFlags)m_pAnimSequence->GetFlags();
  687. }
  688. //////////////////////////////////////////////////////////////////////////
  689. void CUiAnimViewSequence::DeselectAllKeys()
  690. {
  691. assert(UiAnimUndo::IsRecording());
  692. CUiAnimViewSequenceNotificationContext context(this);
  693. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  694. for (unsigned int i = 0; i < selectedKeys.GetKeyCount(); ++i)
  695. {
  696. CUiAnimViewKeyHandle keyHandle = selectedKeys.GetKey(i);
  697. keyHandle.Select(false);
  698. }
  699. }
  700. //////////////////////////////////////////////////////////////////////////
  701. void CUiAnimViewSequence::OffsetSelectedKeys(const float timeOffset)
  702. {
  703. assert(UiAnimUndo::IsRecording());
  704. CUiAnimViewSequenceNotificationContext context(this);
  705. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  706. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  707. {
  708. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(k);
  709. skey.Offset(timeOffset);
  710. }
  711. }
  712. //////////////////////////////////////////////////////////////////////////
  713. float CUiAnimViewSequence::ClipTimeOffsetForOffsetting(const float timeOffset)
  714. {
  715. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  716. float newTimeOffset = timeOffset;
  717. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  718. {
  719. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(k);
  720. const float keyTime = skey.GetTime();
  721. float newKeyTime = keyTime + timeOffset;
  722. Range extendedTimeRange(0.0f, GetTimeRange().end);
  723. extendedTimeRange.ClipValue(newKeyTime);
  724. float offset = newKeyTime - keyTime;
  725. if (fabs(offset) < fabs(newTimeOffset))
  726. {
  727. newTimeOffset = offset;
  728. }
  729. }
  730. return newTimeOffset;
  731. }
  732. //////////////////////////////////////////////////////////////////////////
  733. float CUiAnimViewSequence::ClipTimeOffsetForScaling(float timeOffset)
  734. {
  735. if (timeOffset <= 0)
  736. {
  737. return timeOffset;
  738. }
  739. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  740. float newTimeOffset = timeOffset;
  741. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  742. {
  743. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(k);
  744. float keyTime = skey.GetTime();
  745. float newKeyTime = keyTime * timeOffset;
  746. GetTimeRange().ClipValue(newKeyTime);
  747. float offset = newKeyTime / keyTime;
  748. if (offset < newTimeOffset)
  749. {
  750. newTimeOffset = offset;
  751. }
  752. }
  753. return newTimeOffset;
  754. }
  755. //////////////////////////////////////////////////////////////////////////
  756. void CUiAnimViewSequence::ScaleSelectedKeys(const float timeOffset)
  757. {
  758. assert(UiAnimUndo::IsRecording());
  759. CUiAnimViewSequenceNotificationContext context(this);
  760. if (timeOffset <= 0)
  761. {
  762. return;
  763. }
  764. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  765. const CUiAnimViewTrack* pTrack = nullptr;
  766. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  767. {
  768. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(k);
  769. if (pTrack != skey.GetTrack())
  770. {
  771. pTrack = skey.GetTrack();
  772. }
  773. float keyt = skey.GetTime() * timeOffset;
  774. skey.SetTime(keyt);
  775. }
  776. }
  777. //////////////////////////////////////////////////////////////////////////
  778. float CUiAnimViewSequence::ClipTimeOffsetForSliding(const float timeOffset)
  779. {
  780. CUiAnimViewKeyBundle keys = GetSelectedKeys();
  781. std::set<CUiAnimViewTrack*> tracks;
  782. std::set<CUiAnimViewTrack*>::const_iterator pTrackIter;
  783. Range timeRange = GetTimeRange();
  784. // Get the first key in the timeline among selected and
  785. // also gather tracks.
  786. float time0 = timeRange.end;
  787. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  788. {
  789. CUiAnimViewKeyHandle skey = keys.GetKey(k);
  790. tracks.insert(skey.GetTrack());
  791. float keyTime = skey.GetTime();
  792. if (keyTime < time0)
  793. {
  794. time0 = keyTime;
  795. }
  796. }
  797. // If 'bAll' is true, slide all tracks.
  798. // (Otherwise, slide only selected tracks.)
  799. bool bAll = Qt::AltModifier & QApplication::queryKeyboardModifiers();
  800. if (bAll)
  801. {
  802. keys = GetKeysInTimeRange(time0, timeRange.end);
  803. // Gather tracks again.
  804. tracks.clear();
  805. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  806. {
  807. CUiAnimViewKeyHandle skey = keys.GetKey(k);
  808. tracks.insert(skey.GetTrack());
  809. }
  810. }
  811. float newTimeOffset = timeOffset;
  812. for (pTrackIter = tracks.begin(); pTrackIter != tracks.end(); ++pTrackIter)
  813. {
  814. CUiAnimViewTrack* pTrack = *pTrackIter;
  815. for (unsigned int i = 0; i < pTrack->GetKeyCount(); ++i)
  816. {
  817. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(i);
  818. const float keyTime = keyHandle.GetTime();
  819. if (keyTime >= time0)
  820. {
  821. float newKeyTime = keyTime + timeOffset;
  822. timeRange.ClipValue(newKeyTime);
  823. float offset = newKeyTime - keyTime;
  824. if (fabs(offset) < fabs(newTimeOffset))
  825. {
  826. newTimeOffset = offset;
  827. }
  828. }
  829. }
  830. }
  831. return newTimeOffset;
  832. }
  833. //////////////////////////////////////////////////////////////////////////
  834. void CUiAnimViewSequence::SlideKeys(float timeOffset)
  835. {
  836. assert(UiAnimUndo::IsRecording());
  837. CUiAnimViewSequenceNotificationContext context(this);
  838. CUiAnimViewKeyBundle keys = GetSelectedKeys();
  839. std::set<CUiAnimViewTrack*> tracks;
  840. std::set<CUiAnimViewTrack*>::const_iterator pTrackIter;
  841. Range timeRange = GetTimeRange();
  842. // Get the first key in the timeline among selected and
  843. // also gather tracks.
  844. float time0 = timeRange.end;
  845. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  846. {
  847. CUiAnimViewKeyHandle skey = keys.GetKey(k);
  848. tracks.insert(skey.GetTrack());
  849. float keyTime = skey.GetTime();
  850. if (keyTime < time0)
  851. {
  852. time0 = keyTime;
  853. }
  854. }
  855. // If 'bAll' is true, slide all tracks.
  856. // (Otherwise, slide only selected tracks.)
  857. bool bAll = Qt::AltModifier & QApplication::queryKeyboardModifiers();
  858. if (bAll)
  859. {
  860. keys = GetKeysInTimeRange(time0, timeRange.end);
  861. // Gather tracks again.
  862. tracks.clear();
  863. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  864. {
  865. CUiAnimViewKeyHandle skey = keys.GetKey(k);
  866. tracks.insert(skey.GetTrack());
  867. }
  868. }
  869. for (pTrackIter = tracks.begin(); pTrackIter != tracks.end(); ++pTrackIter)
  870. {
  871. CUiAnimViewTrack* pTrack = *pTrackIter;
  872. pTrack->SlideKeys(time0, timeOffset);
  873. }
  874. }
  875. //////////////////////////////////////////////////////////////////////////
  876. void CUiAnimViewSequence::CloneSelectedKeys()
  877. {
  878. assert(UiAnimUndo::IsRecording());
  879. CUiAnimViewSequenceNotificationContext context(this);
  880. CUiAnimViewKeyBundle selectedKeys = GetSelectedKeys();
  881. const CUiAnimViewTrack* pTrack = nullptr;
  882. // In case of multiple cloning, indices cannot be used as a solid pointer to the original.
  883. // So use the time of keys as an identifier, instead.
  884. std::vector<float> selectedKeyTimes;
  885. for (size_t k = 0; k < selectedKeys.GetKeyCount(); ++k)
  886. {
  887. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(static_cast<unsigned int>(k));
  888. if (pTrack != skey.GetTrack())
  889. {
  890. pTrack = skey.GetTrack();
  891. }
  892. selectedKeyTimes.push_back(skey.GetTime());
  893. }
  894. // Now, do the actual cloning.
  895. for (size_t k = 0; k < selectedKeyTimes.size(); ++k)
  896. {
  897. CUiAnimViewKeyHandle skey = selectedKeys.GetKey(static_cast<unsigned int>(k));
  898. skey = skey.GetTrack()->GetKeyByTime(selectedKeyTimes[k]);
  899. assert(skey.IsValid());
  900. if (!skey.IsValid())
  901. {
  902. continue;
  903. }
  904. CUiAnimViewKeyHandle newKey = skey.Clone();
  905. // Select new key.
  906. newKey.Select(true);
  907. // Deselect cloned key.
  908. skey.Select(false);
  909. }
  910. }
  911. //////////////////////////////////////////////////////////////////////////
  912. void CUiAnimViewSequence::BeginUndoTransaction()
  913. {
  914. QueueNotifications();
  915. }
  916. //////////////////////////////////////////////////////////////////////////
  917. void CUiAnimViewSequence::EndUndoTransaction()
  918. {
  919. SubmitPendingNotifcations();
  920. }
  921. //////////////////////////////////////////////////////////////////////////
  922. void CUiAnimViewSequence::BeginRestoreTransaction()
  923. {
  924. QueueNotifications();
  925. }
  926. //////////////////////////////////////////////////////////////////////////
  927. void CUiAnimViewSequence::EndRestoreTransaction()
  928. {
  929. SubmitPendingNotifcations();
  930. }
  931. //////////////////////////////////////////////////////////////////////////
  932. bool CUiAnimViewSequence::IsActiveSequence() const
  933. {
  934. CUiAnimViewSequence* pSequence = nullptr;
  935. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  936. return pSequence == this;
  937. }
  938. //////////////////////////////////////////////////////////////////////////
  939. const float CUiAnimViewSequence::GetTime() const
  940. {
  941. return m_time;
  942. }