TrackViewSequence.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438
  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 "EditorDefs.h"
  9. #include "Entity/EditorEntityHelpers.h"
  10. #include "TrackViewSequence.h"
  11. // Qt
  12. #include <QMessageBox>
  13. // AzCore
  14. #include <AzCore/std/algorithm.h>
  15. #include <AzCore/std/containers/set.h>
  16. #include <AzCore/std/sort.h>
  17. // AzToolsFramework
  18. #include <AzToolsFramework/API/ComponentEntityObjectBus.h>
  19. // CryCommon
  20. #include <CryCommon/Maestro/Types/AnimValueType.h>
  21. #include <CryCommon/Maestro/Types/AnimNodeType.h>
  22. #include <CryCommon/Maestro/Bus/EditorSequenceComponentBus.h>
  23. #include <CryCommon/MathConversion.h>
  24. // Editor
  25. #include "AnimationContext.h"
  26. #include "Clipboard.h"
  27. #include "TrackViewSequenceManager.h"
  28. #include "TrackViewNodeFactories.h"
  29. CTrackViewSequence::CTrackViewSequence(IAnimSequence* pSequence)
  30. : CTrackViewAnimNode(pSequence, nullptr, nullptr)
  31. , m_pAnimSequence(pSequence)
  32. {
  33. AZ_Assert(m_pAnimSequence, "Expected valid m_pAnimSequence");
  34. }
  35. CTrackViewSequence::CTrackViewSequence(AZStd::intrusive_ptr<IAnimSequence>& sequence)
  36. : CTrackViewAnimNode(sequence.get(), nullptr, nullptr)
  37. , m_pAnimSequence(sequence)
  38. {
  39. }
  40. CTrackViewSequence::~CTrackViewSequence()
  41. {
  42. GetIEditor()->GetSequenceManager()->RemoveListener(this);
  43. GetIEditor()->GetUndoManager()->RemoveListener(this); // For safety. Should be done by OnRemoveSequence callback
  44. // For safety, disconnect to any buses we may have been listening on for record mode
  45. if (m_pAnimSequence)
  46. {
  47. // disconnect from all EBuses for notification of changes for all AZ::Entities in our sequence
  48. for (int i = m_pAnimSequence->GetNodeCount(); --i >= 0;)
  49. {
  50. IAnimNode* animNode = m_pAnimSequence->GetNode(i);
  51. if (animNode->GetType() == AnimNodeType::AzEntity)
  52. {
  53. Maestro::EditorSequenceComponentRequestBus::Event(m_pAnimSequence->GetSequenceEntityId(), &Maestro::EditorSequenceComponentRequestBus::Events::RemoveEntityToAnimate, animNode->GetAzEntityId());
  54. ConnectToBusesForRecording(animNode->GetAzEntityId(), false);
  55. }
  56. }
  57. }
  58. }
  59. void CTrackViewSequence::Load()
  60. {
  61. m_childNodes.clear();
  62. const int nodeCount = m_pAnimSequence->GetNodeCount();
  63. for (int i = 0; i < nodeCount; ++i)
  64. {
  65. IAnimNode* node = m_pAnimSequence->GetNode(i);
  66. // Only add top level nodes to sequence
  67. if (!node->GetParent())
  68. {
  69. CTrackViewAnimNodeFactory animNodeFactory;
  70. CTrackViewAnimNode* pNewTVAnimNode = animNodeFactory.BuildAnimNode(m_pAnimSequence.get(), node, this);
  71. m_childNodes.push_back(AZStd::unique_ptr<CTrackViewNode>(pNewTVAnimNode));
  72. }
  73. }
  74. SortNodes();
  75. }
  76. void CTrackViewSequence::BindToEditorObjects()
  77. {
  78. m_bBoundToEditorObjects = true;
  79. CTrackViewAnimNode::BindToEditorObjects();
  80. }
  81. void CTrackViewSequence::UnBindFromEditorObjects()
  82. {
  83. m_bBoundToEditorObjects = false;
  84. CTrackViewAnimNode::UnBindFromEditorObjects();
  85. }
  86. bool CTrackViewSequence::IsBoundToEditorObjects() const
  87. {
  88. return m_bBoundToEditorObjects;
  89. }
  90. CTrackViewKeyHandle CTrackViewSequence::FindSingleSelectedKey()
  91. {
  92. CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
  93. if (!pSequence)
  94. {
  95. return CTrackViewKeyHandle();
  96. }
  97. CTrackViewKeyBundle selectedKeys = pSequence->GetSelectedKeys();
  98. if (selectedKeys.GetKeyCount() != 1)
  99. {
  100. return CTrackViewKeyHandle();
  101. }
  102. return selectedKeys.GetKey(0);
  103. }
  104. void CTrackViewSequence::OnEntityComponentPropertyChanged(AZ::ComponentId changedComponentId)
  105. {
  106. // find the component node for this changeComponentId if it exists
  107. for (int i = m_pAnimSequence->GetNodeCount(); --i >= 0;)
  108. {
  109. IAnimNode* animNode = m_pAnimSequence->GetNode(i);
  110. if (animNode && animNode->GetComponentId() == changedComponentId)
  111. {
  112. // we have a component animNode for this changedComponentId. Process the component change
  113. RecordTrackChangesForNode(static_cast<CTrackViewAnimNode*>(animNode->GetNodeOwner()));
  114. }
  115. }
  116. }
  117. CTrackViewTrack* CTrackViewSequence::FindTrackById(unsigned int trackId)
  118. {
  119. CTrackViewTrack* result = nullptr;
  120. CTrackViewTrackBundle allTracks = GetAllTracks();
  121. int allTracksCount = allTracks.GetCount();
  122. for (int trackIndex = 0; trackIndex < allTracksCount; trackIndex++)
  123. {
  124. CTrackViewTrack* track = allTracks.GetTrack(trackIndex);
  125. AZ_Assert(track, "Expected valid track.");
  126. if (track->GetId() == trackId)
  127. {
  128. result = track;
  129. break;
  130. }
  131. }
  132. return result;
  133. }
  134. AZStd::vector<bool> CTrackViewSequence::SaveKeyStates() const
  135. {
  136. // const hack because GetAllKeys();
  137. CTrackViewSequence* nonConstSequence = const_cast<CTrackViewSequence*>(this);
  138. CTrackViewKeyBundle keys = nonConstSequence->GetAllKeys();
  139. const unsigned int numkeys = keys.GetKeyCount();
  140. AZStd::vector<bool> selectionState;
  141. selectionState.reserve(numkeys);
  142. for (unsigned int i = 0; i < numkeys; ++i)
  143. {
  144. const CTrackViewKeyHandle& keyHandle = keys.GetKey(i);
  145. selectionState.push_back(keyHandle.IsSelected());
  146. }
  147. return selectionState;
  148. }
  149. void CTrackViewSequence::RestoreKeyStates(const AZStd::vector<bool>& keyStates)
  150. {
  151. CTrackViewKeyBundle keys = GetAllKeys();
  152. const unsigned int numkeys = keys.GetKeyCount();
  153. if (keyStates.size() >= numkeys)
  154. {
  155. CTrackViewSequenceNotificationContext context(this);
  156. for (unsigned int i = 0; i < numkeys; ++i)
  157. {
  158. CTrackViewKeyHandle keyHandle = keys.GetKey(i);
  159. keyHandle.Select(keyStates[i]);
  160. }
  161. }
  162. }
  163. void CTrackViewSequence::ConnectToBusesForRecording(const AZ::EntityId& entityId, bool enableConnection)
  164. {
  165. // we connect to PropertyEditorEntityChangeNotificationBus for all other changes
  166. if (enableConnection)
  167. {
  168. AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler::BusConnect(entityId);
  169. }
  170. else
  171. {
  172. AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler::BusDisconnect(entityId);
  173. }
  174. }
  175. int CTrackViewSequence::RecordTrackChangesForNode(CTrackViewAnimNode* componentNode)
  176. {
  177. int retNumKeysSet = 0;
  178. if (componentNode)
  179. {
  180. retNumKeysSet = componentNode->SetKeysForChangedTrackValues(GetIEditor()->GetAnimation()->GetTime());
  181. if (retNumKeysSet)
  182. {
  183. OnKeysChanged(); // change notification for updating TrackView UI
  184. }
  185. }
  186. return retNumKeysSet;
  187. }
  188. void CTrackViewSequence::SetRecording(bool enableRecording)
  189. {
  190. if (m_pAnimSequence)
  191. {
  192. // connect (or disconnect) to EBuses for notification of changes for all AZ::Entities in our sequence
  193. for (int i = m_pAnimSequence->GetNodeCount(); --i >= 0;)
  194. {
  195. IAnimNode* animNode = m_pAnimSequence->GetNode(i);
  196. if (animNode->GetType() == AnimNodeType::AzEntity)
  197. {
  198. ConnectToBusesForRecording(animNode->GetAzEntityId(), enableRecording);
  199. }
  200. }
  201. }
  202. }
  203. bool CTrackViewSequence::IsAncestorOf(CTrackViewSequence* pSequence) const
  204. {
  205. return m_pAnimSequence->IsAncestorOf(pSequence->m_pAnimSequence.get());
  206. }
  207. void CTrackViewSequence::BeginCutScene(const bool bResetFx) const
  208. {
  209. IMovieSystem* movieSystem = AZ::Interface<IMovieSystem>::Get();
  210. IMovieUser* pMovieUser = movieSystem ? movieSystem->GetUser() : nullptr;
  211. if (pMovieUser)
  212. {
  213. pMovieUser->BeginCutScene(m_pAnimSequence.get(), m_pAnimSequence->GetCutSceneFlags(false), bResetFx);
  214. }
  215. }
  216. void CTrackViewSequence::EndCutScene() const
  217. {
  218. IMovieSystem* movieSystem = AZ::Interface<IMovieSystem>::Get();
  219. IMovieUser* pMovieUser = movieSystem ? movieSystem->GetUser() : nullptr;
  220. if (pMovieUser)
  221. {
  222. pMovieUser->EndCutScene(m_pAnimSequence.get(), m_pAnimSequence->GetCutSceneFlags(true));
  223. }
  224. }
  225. void CTrackViewSequence::Render(const SAnimContext& animContext)
  226. {
  227. for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
  228. {
  229. CTrackViewNode* pChildNode = (*iter).get();
  230. if (pChildNode->GetNodeType() == eTVNT_AnimNode)
  231. {
  232. CTrackViewAnimNode* pChildAnimNode = (CTrackViewAnimNode*)pChildNode;
  233. pChildAnimNode->Render(animContext);
  234. }
  235. }
  236. m_pAnimSequence->Render();
  237. }
  238. void CTrackViewSequence::Animate(const SAnimContext& animContext)
  239. {
  240. if (!m_pAnimSequence->IsActivated())
  241. {
  242. return;
  243. }
  244. m_time = animContext.time;
  245. m_pAnimSequence->Animate(animContext);
  246. CTrackViewSequenceNoNotificationContext context(this);
  247. for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
  248. {
  249. CTrackViewNode* pChildNode = (*iter).get();
  250. if (pChildNode->GetNodeType() == eTVNT_AnimNode)
  251. {
  252. CTrackViewAnimNode* pChildAnimNode = (CTrackViewAnimNode*)pChildNode;
  253. pChildAnimNode->Animate(animContext);
  254. }
  255. }
  256. }
  257. void CTrackViewSequence::AddListener(ITrackViewSequenceListener* pListener)
  258. {
  259. stl::push_back_unique(m_sequenceListeners, pListener);
  260. }
  261. void CTrackViewSequence::RemoveListener(ITrackViewSequenceListener* pListener)
  262. {
  263. stl::find_and_erase(m_sequenceListeners, pListener);
  264. }
  265. void CTrackViewSequence::OnNodeSelectionChanged()
  266. {
  267. if (m_bNoNotifications)
  268. {
  269. return;
  270. }
  271. if (m_bQueueNotifications)
  272. {
  273. m_bNodeSelectionChanged = true;
  274. }
  275. else
  276. {
  277. CTrackViewSequenceNoNotificationContext context(this);
  278. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  279. {
  280. (*iter)->OnNodeSelectionChanged(this);
  281. }
  282. }
  283. }
  284. void CTrackViewSequence::ForceAnimation()
  285. {
  286. if (m_bNoNotifications)
  287. {
  288. return;
  289. }
  290. if (m_bQueueNotifications)
  291. {
  292. m_bForceAnimation = true;
  293. }
  294. else
  295. {
  296. if (IsActive())
  297. {
  298. GetIEditor()->GetAnimation()->ForceAnimation();
  299. }
  300. }
  301. }
  302. void CTrackViewSequence::OnKeySelectionChanged()
  303. {
  304. if (m_bNoNotifications)
  305. {
  306. return;
  307. }
  308. if (m_bQueueNotifications)
  309. {
  310. m_bKeySelectionChanged = true;
  311. }
  312. else
  313. {
  314. CTrackViewSequenceNoNotificationContext context(this);
  315. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  316. {
  317. (*iter)->OnKeySelectionChanged(this);
  318. }
  319. }
  320. }
  321. void CTrackViewSequence::OnKeysChanged()
  322. {
  323. if (m_bNoNotifications)
  324. {
  325. return;
  326. }
  327. if (m_bQueueNotifications)
  328. {
  329. m_bKeysChanged = true;
  330. }
  331. else
  332. {
  333. CTrackViewSequenceNoNotificationContext context(this);
  334. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  335. {
  336. (*iter)->OnKeysChanged(this);
  337. }
  338. if (IsActive())
  339. {
  340. GetIEditor()->GetAnimation()->ForceAnimation();
  341. }
  342. }
  343. }
  344. void CTrackViewSequence::OnKeyAdded(CTrackViewKeyHandle& addedKeyHandle)
  345. {
  346. if (m_bNoNotifications)
  347. {
  348. return;
  349. }
  350. CTrackViewSequenceNoNotificationContext context(this);
  351. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  352. {
  353. (*iter)->OnKeyAdded(addedKeyHandle);
  354. }
  355. }
  356. void CTrackViewSequence::OnNodeChanged(CTrackViewNode* node, ITrackViewSequenceListener::ENodeChangeType type)
  357. {
  358. if (node && node->GetNodeType() == eTVNT_AnimNode)
  359. {
  360. // Deselect the node before deleting to give listeners a chance to update things like UI state.
  361. if (type == ITrackViewSequenceListener::eNodeChangeType_Removed)
  362. {
  363. CTrackViewSequenceNotificationContext context(this);
  364. // Make sure to deselect any keys
  365. CTrackViewKeyBundle keys = node->GetAllKeys();
  366. for (unsigned int key = 0; key < keys.GetKeyCount(); key++)
  367. {
  368. CTrackViewKeyHandle keyHandle = keys.GetKey(key);
  369. if (keyHandle.IsSelected())
  370. {
  371. keyHandle.Select(false);
  372. m_bKeySelectionChanged = true;
  373. }
  374. }
  375. // Cancel notification if nothing changed.
  376. if (!m_bKeySelectionChanged)
  377. {
  378. context.Cancel();
  379. }
  380. // deselect the node
  381. if (node->IsSelected())
  382. {
  383. node->SetSelected(false);
  384. }
  385. }
  386. CTrackViewAnimNode* pAnimNode = static_cast<CTrackViewAnimNode*>(node);
  387. if (pAnimNode->IsActive())
  388. {
  389. switch (type)
  390. {
  391. case ITrackViewSequenceListener::eNodeChangeType_Added:
  392. {
  393. ForceAnimation();
  394. // if we're in record mode and this is an AzEntity node, add the node to the buses we listen to for notification of changes
  395. if (pAnimNode->GetType() == AnimNodeType::AzEntity && GetIEditor()->GetAnimation()->IsRecordMode())
  396. {
  397. ConnectToBusesForRecording(pAnimNode->GetAzEntityId(), true);
  398. }
  399. }
  400. break;
  401. case ITrackViewSequenceListener::eNodeChangeType_Removed:
  402. {
  403. ForceAnimation();
  404. // if we're in record mode and this is an AzEntity node, remove the node to the buses we listen to for notification of changes
  405. if (pAnimNode->GetType() == AnimNodeType::AzEntity && GetIEditor()->GetAnimation()->IsRecordMode())
  406. {
  407. ConnectToBusesForRecording(pAnimNode->GetAzEntityId(), false);
  408. }
  409. }
  410. break;
  411. }
  412. }
  413. switch (type)
  414. {
  415. case ITrackViewSequenceListener::eNodeChangeType_Enabled:
  416. // Fall through
  417. case ITrackViewSequenceListener::eNodeChangeType_Hidden:
  418. // Fall through
  419. case ITrackViewSequenceListener::eNodeChangeType_SetAsActiveDirector:
  420. // Fall through
  421. case ITrackViewSequenceListener::eNodeChangeType_NodeOwnerChanged:
  422. ForceAnimation();
  423. break;
  424. }
  425. }
  426. // Mark Layer with Sequence Object as dirty for non-internal or non-UI changes
  427. if (type != ITrackViewSequenceListener::eNodeChangeType_NodeOwnerChanged &&
  428. type != ITrackViewSequenceListener::eNodeChangeType_Selected &&
  429. type != ITrackViewSequenceListener::eNodeChangeType_Deselected &&
  430. type != ITrackViewSequenceListener::eNodeChangeType_Collapsed &&
  431. type != ITrackViewSequenceListener::eNodeChangeType_Expanded)
  432. {
  433. MarkAsModified();
  434. }
  435. if (m_bNoNotifications)
  436. {
  437. return;
  438. }
  439. CTrackViewSequenceNoNotificationContext context(this);
  440. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  441. {
  442. (*iter)->OnNodeChanged(node, type);
  443. }
  444. }
  445. void CTrackViewSequence::OnNodeRenamed(CTrackViewNode* node, const char* pOldName)
  446. {
  447. // Marks Layer with Sequence Object as dirty
  448. MarkAsModified();
  449. if (m_bNoNotifications)
  450. {
  451. return;
  452. }
  453. CTrackViewSequenceNoNotificationContext context(this);
  454. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  455. {
  456. (*iter)->OnNodeRenamed(node, pOldName);
  457. }
  458. }
  459. void CTrackViewSequence::OnSequenceSettingsChanged()
  460. {
  461. MarkAsModified();
  462. if (m_bNoNotifications)
  463. {
  464. return;
  465. }
  466. CTrackViewSequenceNoNotificationContext context(this);
  467. for (auto iter = m_sequenceListeners.begin(); iter != m_sequenceListeners.end(); ++iter)
  468. {
  469. (*iter)->OnSequenceSettingsChanged(this);
  470. }
  471. }
  472. void CTrackViewSequence::MarkAsModified()
  473. {
  474. if (m_pAnimSequence)
  475. {
  476. Maestro::EditorSequenceComponentRequestBus::Event(
  477. m_pAnimSequence->GetSequenceEntityId(), &Maestro::EditorSequenceComponentRequestBus::Events::MarkEntityAsDirty);
  478. }
  479. }
  480. void CTrackViewSequence::QueueNotifications()
  481. {
  482. m_bQueueNotifications = true;
  483. ++m_selectionRecursionLevel;
  484. }
  485. void CTrackViewSequence::DequeueNotifications()
  486. {
  487. AZ_Assert(m_selectionRecursionLevel > 0, "QueueNotifications should be called before DequeueNotifications()");
  488. --m_selectionRecursionLevel;
  489. if (m_selectionRecursionLevel == 0)
  490. {
  491. m_bQueueNotifications = false;
  492. }
  493. }
  494. void CTrackViewSequence::SubmitPendingNotifications(bool force)
  495. {
  496. if (force)
  497. {
  498. m_selectionRecursionLevel = 1;
  499. }
  500. AZ_Assert(m_selectionRecursionLevel > 0, "Dangling SubmitPendingNotifications()");
  501. if (m_selectionRecursionLevel > 0)
  502. {
  503. --m_selectionRecursionLevel;
  504. }
  505. if (m_selectionRecursionLevel == 0)
  506. {
  507. m_bQueueNotifications = false;
  508. if (m_bNodeSelectionChanged)
  509. {
  510. OnNodeSelectionChanged();
  511. }
  512. if (m_bKeysChanged)
  513. {
  514. OnKeysChanged();
  515. }
  516. if (m_bKeySelectionChanged)
  517. {
  518. OnKeySelectionChanged();
  519. }
  520. if (m_bForceAnimation)
  521. {
  522. ForceAnimation();
  523. }
  524. m_bForceAnimation = false;
  525. m_bKeysChanged = false;
  526. m_bNodeSelectionChanged = false;
  527. m_bKeySelectionChanged = false;
  528. }
  529. }
  530. void CTrackViewSequence::OnSequenceRemoved(CTrackViewSequence* removedSequence)
  531. {
  532. if (removedSequence == this)
  533. {
  534. // submit any queued notifications before removing
  535. if (m_bQueueNotifications)
  536. {
  537. SubmitPendingNotifications(true);
  538. }
  539. // remove ourselves as listeners from the undo manager
  540. GetIEditor()->GetUndoManager()->RemoveListener(this);
  541. }
  542. }
  543. void CTrackViewSequence::OnSequenceAdded(CTrackViewSequence* addedSequence)
  544. {
  545. if (addedSequence == this)
  546. {
  547. GetIEditor()->GetUndoManager()->AddListener(this);
  548. }
  549. }
  550. void CTrackViewSequence::DeleteSelectedNodes()
  551. {
  552. if (IsSelected())
  553. {
  554. GetIEditor()->GetSequenceManager()->DeleteSequence(this);
  555. return;
  556. }
  557. // Don't notify in the above IsSelected() case,
  558. // because 'this' will become deleted and invalid.
  559. CTrackViewSequenceNotificationContext context(this);
  560. CTrackViewAnimNodeBundle selectedNodes = GetSelectedAnimNodes();
  561. const unsigned int numSelectedNodes = selectedNodes.GetCount();
  562. // Call RemoveEntityToAnimate on any nodes that are able to be removed right here. If we wait to do it inside
  563. // of RemoveSubNode() it will fail because the EditorSequenceComponentRequestBus will be disconnected
  564. // by the Deactivate / Activate of the sequence entity.
  565. if (nullptr != m_pAnimSequence)
  566. {
  567. AZ::EntityId sequenceEntityId = m_pAnimSequence->GetSequenceEntityId();
  568. if (sequenceEntityId.IsValid())
  569. {
  570. for (unsigned int i = 0; i < numSelectedNodes; ++i)
  571. {
  572. AZ::EntityId removedNodeId = selectedNodes.GetNode(i)->GetAzEntityId();
  573. if (removedNodeId.IsValid())
  574. {
  575. Maestro::EditorSequenceComponentRequestBus::Event(
  576. m_pAnimSequence->GetSequenceEntityId(), &Maestro::EditorSequenceComponentRequestBus::Events::RemoveEntityToAnimate,
  577. removedNodeId);
  578. }
  579. }
  580. }
  581. }
  582. // Deactivate the sequence entity while we are potentially removing things from it.
  583. // We need to allow the full removal operation (node and children) to complete before
  584. // OnActivate happens on the Sequence again. If we don't deactivate the sequence entity
  585. // OnActivate will get called by the entity system as components are removed.
  586. // In some cases this will erroneously cause some components to be added
  587. // back to the sequence that were just deleted.
  588. bool sequenceEntityWasActive = false;
  589. AZ::Entity* sequenceEntity = nullptr;
  590. if (GetSequenceComponentEntityId().IsValid())
  591. {
  592. AZ::ComponentApplicationBus::BroadcastResult(sequenceEntity, &AZ::ComponentApplicationBus::Events::FindEntity, GetSequenceComponentEntityId());
  593. if (sequenceEntity != nullptr)
  594. {
  595. if (sequenceEntity->GetState() == AZ::Entity::State::Active)
  596. {
  597. sequenceEntityWasActive = true;
  598. sequenceEntity->Deactivate();
  599. }
  600. }
  601. }
  602. CTrackViewTrackBundle selectedTracks = GetSelectedTracks();
  603. const unsigned int numSelectedTracks = selectedTracks.GetCount();
  604. for (int i = numSelectedTracks - 1; i >= 0; i--)
  605. {
  606. CTrackViewTrack* pTrack = selectedTracks.GetTrack(i);
  607. // Ignore sub tracks
  608. if (!pTrack->IsSubTrack())
  609. {
  610. pTrack->GetAnimNode()->RemoveTrack(pTrack);
  611. }
  612. }
  613. // GetSelectedAnimNodes() will add parent nodes first and then children to the selected
  614. // node bundle list. So iterating backwards here causes child nodes to be deleted first,
  615. // and then parents. If parent nodes get deleted first, node->GetParentNode() will return
  616. // a bad pointer if it happens to be one of the nodes that was deleted.
  617. for (int i = numSelectedNodes - 1; i >= 0; i--)
  618. {
  619. CTrackViewAnimNode* node = selectedNodes.GetNode(i);
  620. CTrackViewAnimNode* pParentNode = static_cast<CTrackViewAnimNode*>(node->GetParentNode());
  621. pParentNode->RemoveSubNode(node);
  622. }
  623. if (sequenceEntityWasActive && sequenceEntity != nullptr)
  624. {
  625. sequenceEntity->Activate();
  626. }
  627. }
  628. void CTrackViewSequence::SelectSelectedNodesInViewport()
  629. {
  630. AZ_Assert(CUndo::IsRecording(), "Undo is not recording");
  631. CTrackViewAnimNodeBundle selectedNodes = GetSelectedAnimNodes();
  632. const unsigned int numSelectedNodes = selectedNodes.GetCount();
  633. AZStd::vector<AZ::EntityId> entitiesToBeSelected;
  634. for (unsigned int i = 0; i < numSelectedNodes; ++i)
  635. {
  636. CTrackViewAnimNode* node = selectedNodes.GetNode(i);
  637. ETrackViewNodeType nodeType = node->GetNodeType();
  638. if (nodeType == eTVNT_Sequence)
  639. {
  640. CTrackViewSequence* seqNode = static_cast<CTrackViewSequence*>(node);
  641. entitiesToBeSelected.push_back(seqNode->GetSequenceComponentEntityId());
  642. }
  643. else
  644. {
  645. // TrackView AnimNode
  646. entitiesToBeSelected.push_back(node->GetAzEntityId());
  647. }
  648. }
  649. // remove duplicate entities
  650. AZStd::sort(entitiesToBeSelected.begin(), entitiesToBeSelected.end());
  651. entitiesToBeSelected.erase(
  652. AZStd::unique(entitiesToBeSelected.begin(), entitiesToBeSelected.end()), entitiesToBeSelected.end());
  653. AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
  654. &AzToolsFramework::ToolsApplicationRequests::SetSelectedEntities, entitiesToBeSelected);
  655. }
  656. bool CTrackViewSequence::SetName(const char* name)
  657. {
  658. // Check if there is already a sequence with that name
  659. const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
  660. if (pSequenceManager->GetSequenceByName(name))
  661. {
  662. return false;
  663. }
  664. AZStd::string oldName = GetName();
  665. if (name != oldName)
  666. {
  667. m_pAnimSequence->SetName(name);
  668. MarkAsModified();
  669. AzToolsFramework::ScopedUndoBatch undoBatch("Rename Sequence");
  670. GetSequence()->OnNodeRenamed(this, oldName.c_str());
  671. undoBatch.MarkEntityDirty(m_pAnimSequence->GetSequenceEntityId());
  672. }
  673. return true;
  674. }
  675. void CTrackViewSequence::DeleteSelectedKeys()
  676. {
  677. CTrackViewSequenceNotificationContext context(this);
  678. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  679. for (int k = (int)selectedKeys.GetKeyCount() - 1; k >= 0; --k)
  680. {
  681. CTrackViewKeyHandle skey = selectedKeys.GetKey(k);
  682. skey.Delete();
  683. }
  684. // The selected keys are deleted, so notify the selection was just changed.
  685. OnKeySelectionChanged();
  686. }
  687. void CTrackViewSequence::CopyKeysToClipboard(const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks)
  688. {
  689. XmlNodeRef copyNode = XmlHelpers::CreateXmlNode("CopyKeysNode");
  690. CopyKeysToClipboard(copyNode, bOnlySelectedKeys, bOnlyFromSelectedTracks);
  691. CClipboard clip(nullptr);
  692. clip.Put(copyNode, "Track view keys");
  693. }
  694. void CTrackViewSequence::CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks)
  695. {
  696. for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
  697. {
  698. CTrackViewNode* pChildNode = (*iter).get();
  699. pChildNode->CopyKeysToClipboard(xmlNode, bOnlySelectedKeys, bOnlyFromSelectedTracks);
  700. }
  701. }
  702. void CTrackViewSequence::PasteKeysFromClipboard(CTrackViewAnimNode* pTargetNode, CTrackViewTrack* pTargetTrack, const float timeOffset)
  703. {
  704. AZ_Assert(CUndo::IsRecording(), "Undo is not recording");
  705. CClipboard clipboard(nullptr);
  706. XmlNodeRef clipboardContent = clipboard.Get();
  707. if (clipboardContent)
  708. {
  709. AZStd::vector<TMatchedTrackLocation> matchedLocations = GetMatchedPasteLocations(clipboardContent, pTargetNode, pTargetTrack);
  710. for (auto iter = matchedLocations.begin(); iter != matchedLocations.end(); ++iter)
  711. {
  712. const TMatchedTrackLocation& location = *iter;
  713. CTrackViewTrack* pTrack = location.first;
  714. const XmlNodeRef& trackNode = location.second;
  715. pTrack->PasteKeys(trackNode, timeOffset);
  716. }
  717. OnKeysChanged();
  718. }
  719. }
  720. AZStd::vector<CTrackViewSequence::TMatchedTrackLocation>
  721. CTrackViewSequence::GetMatchedPasteLocations(XmlNodeRef clipboardContent, CTrackViewAnimNode* pTargetNode, CTrackViewTrack* pTargetTrack)
  722. {
  723. AZStd::vector<TMatchedTrackLocation> matchedLocations;
  724. bool bPastingSingleNode = false;
  725. XmlNodeRef singleNode;
  726. bool bPastingSingleTrack = false;
  727. XmlNodeRef singleTrack;
  728. // Check if the XML tree only contains one node and if so if that node only contains one track
  729. for (XmlNodeRef currentNode = clipboardContent; currentNode->getChildCount() > 0; currentNode = currentNode->getChild(0))
  730. {
  731. bool bAllChildsAreTracks = true;
  732. const unsigned int numChilds = currentNode->getChildCount();
  733. for (unsigned int i = 0; i < numChilds; ++i)
  734. {
  735. XmlNodeRef childNode = currentNode->getChild(i);
  736. if (strcmp(currentNode->getChild(0)->getTag(), "Track") != 0)
  737. {
  738. bAllChildsAreTracks = false;
  739. break;
  740. }
  741. }
  742. if (bAllChildsAreTracks)
  743. {
  744. bPastingSingleNode = true;
  745. singleNode = currentNode;
  746. if (currentNode->getChildCount() == 1)
  747. {
  748. bPastingSingleTrack = true;
  749. singleTrack = currentNode->getChild(0);
  750. }
  751. }
  752. else if (currentNode->getChildCount() != 1)
  753. {
  754. break;
  755. }
  756. }
  757. if (bPastingSingleTrack && pTargetNode && pTargetTrack)
  758. {
  759. // We have a target node & track, so try to match the value type
  760. int valueType = 0;
  761. if (singleTrack->getAttr("valueType", valueType))
  762. {
  763. if (pTargetTrack->GetValueType() == static_cast<AnimValueType>(valueType))
  764. {
  765. matchedLocations.push_back(TMatchedTrackLocation(pTargetTrack, singleTrack));
  766. return matchedLocations;
  767. }
  768. }
  769. }
  770. if (bPastingSingleNode && pTargetNode)
  771. {
  772. // Set of tracks that were already matched
  773. AZStd::vector<CTrackViewTrack*> matchedTracks;
  774. // We have a single node to paste and have been given a target node
  775. // so try to match the tracks by param type
  776. const unsigned int numTracks = singleNode->getChildCount();
  777. for (unsigned int i = 0; i < numTracks; ++i)
  778. {
  779. XmlNodeRef trackNode = singleNode->getChild(i);
  780. // Try to match the track
  781. auto matchingTracks = GetMatchingTracks(pTargetNode, trackNode);
  782. for (auto iter = matchingTracks.begin(); iter != matchingTracks.end(); ++iter)
  783. {
  784. CTrackViewTrack* pMatchedTrack = *iter;
  785. // Pick the first track that was matched *and* was not already matched
  786. if (!AZStd::find(matchedTracks.begin(), matchedTracks.end(), pMatchedTrack))
  787. {
  788. stl::push_back_unique(matchedTracks, pMatchedTrack);
  789. matchedLocations.push_back(TMatchedTrackLocation(pMatchedTrack, trackNode));
  790. break;
  791. }
  792. }
  793. }
  794. // Return if matching succeeded
  795. if (matchedLocations.size() > 0)
  796. {
  797. return matchedLocations;
  798. }
  799. }
  800. if (!bPastingSingleNode)
  801. {
  802. // Ok, we're pasting keys from multiple nodes, haven't been given any target
  803. // or matching the targets failed. Ignore given target pointers and start
  804. // a recursive match at the sequence root.
  805. GetMatchedPasteLocationsRec(matchedLocations, this, clipboardContent);
  806. }
  807. return matchedLocations;
  808. }
  809. AZStd::deque<CTrackViewTrack*> CTrackViewSequence::GetMatchingTracks(CTrackViewAnimNode* pAnimNode, XmlNodeRef trackNode)
  810. {
  811. AZStd::deque<CTrackViewTrack*> matchingTracks;
  812. const AZStd::string trackName = trackNode->getAttr("name");
  813. CAnimParamType animParamType;
  814. animParamType.LoadFromXml(trackNode);
  815. int valueType;
  816. if (!trackNode->getAttr("valueType", valueType))
  817. {
  818. return matchingTracks;
  819. }
  820. CTrackViewTrackBundle tracks = pAnimNode->GetTracksByParam(animParamType);
  821. const unsigned int trackCount = tracks.GetCount();
  822. if (trackCount > 0)
  823. {
  824. // Search for a track with the given name and value type
  825. for (unsigned int i = 0; i < trackCount; ++i)
  826. {
  827. CTrackViewTrack* pTrack = tracks.GetTrack(i);
  828. if (pTrack->GetValueType() == static_cast<AnimValueType>(valueType))
  829. {
  830. if (pTrack->GetName() == trackName)
  831. {
  832. matchingTracks.push_back(pTrack);
  833. }
  834. }
  835. }
  836. // Then with lower precedence add the tracks that only match the value
  837. for (unsigned int i = 0; i < trackCount; ++i)
  838. {
  839. CTrackViewTrack* pTrack = tracks.GetTrack(i);
  840. if (pTrack->GetValueType() == static_cast<AnimValueType>(valueType))
  841. {
  842. stl::push_back_unique(matchingTracks, pTrack);
  843. }
  844. }
  845. }
  846. return matchingTracks;
  847. }
  848. void CTrackViewSequence::GetMatchedPasteLocationsRec(AZStd::vector<TMatchedTrackLocation>& locations, CTrackViewNode* pCurrentNode, XmlNodeRef clipboardNode)
  849. {
  850. if (pCurrentNode->GetNodeType() == eTVNT_Sequence)
  851. {
  852. if (strcmp(clipboardNode->getTag(), "CopyKeysNode") != 0)
  853. {
  854. return;
  855. }
  856. }
  857. const unsigned int numChildNodes = clipboardNode->getChildCount();
  858. for (unsigned int nodeIndex = 0; nodeIndex < numChildNodes; ++nodeIndex)
  859. {
  860. XmlNodeRef xmlChildNode = clipboardNode->getChild(nodeIndex);
  861. const AZStd::string tagName = xmlChildNode->getTag();
  862. if (tagName == "Node")
  863. {
  864. const AZStd::string nodeName = xmlChildNode->getAttr("name");
  865. int nodeType = static_cast<int>(AnimNodeType::Invalid);
  866. xmlChildNode->getAttr("type", nodeType);
  867. const unsigned int childCount = pCurrentNode->GetChildCount();
  868. for (unsigned int i = 0; i < childCount; ++i)
  869. {
  870. CTrackViewNode* pChildNode = pCurrentNode->GetChild(i);
  871. if (pChildNode->GetNodeType() == eTVNT_AnimNode)
  872. {
  873. CTrackViewAnimNode* pAnimNode = static_cast<CTrackViewAnimNode*>(pChildNode);
  874. if (pAnimNode->GetName() == nodeName && pAnimNode->GetType() == static_cast<AnimNodeType>(nodeType))
  875. {
  876. GetMatchedPasteLocationsRec(locations, pChildNode, xmlChildNode);
  877. }
  878. }
  879. }
  880. }
  881. else if (tagName == "Track")
  882. {
  883. const AZStd::string trackName = xmlChildNode->getAttr("name");
  884. CAnimParamType trackParamType;
  885. trackParamType.Serialize(xmlChildNode, true);
  886. int trackParamValue = static_cast<int>(AnimValueType::Unknown);
  887. xmlChildNode->getAttr("valueType", trackParamValue);
  888. const unsigned int childCount = pCurrentNode->GetChildCount();
  889. for (unsigned int i = 0; i < childCount; ++i)
  890. {
  891. CTrackViewNode* node = pCurrentNode->GetChild(i);
  892. if (node->GetNodeType() == eTVNT_Track)
  893. {
  894. CTrackViewTrack* pTrack = static_cast<CTrackViewTrack*>(node);
  895. if (pTrack->GetName() == trackName && pTrack->GetParameterType() == trackParamType)
  896. {
  897. locations.push_back(TMatchedTrackLocation(pTrack, xmlChildNode));
  898. }
  899. }
  900. }
  901. }
  902. }
  903. }
  904. void CTrackViewSequence::AdjustKeysToTimeRange(Range newTimeRange)
  905. {
  906. // Set new time range
  907. Range oldTimeRange = GetTimeRange();
  908. float offset = newTimeRange.start - oldTimeRange.start;
  909. // Calculate scale ratio.
  910. float scale = newTimeRange.Length() / oldTimeRange.Length();
  911. SetTimeRange(newTimeRange);
  912. CTrackViewKeyBundle keyBundle = GetAllKeys();
  913. const unsigned int numKeys = keyBundle.GetKeyCount();
  914. // Do not notify listeners until all the times are set, otherwise the
  915. // keys will be sorted and the indices inside the CTrackViewKeyHandle
  916. // will become invalid.
  917. bool notifyListeners = false;
  918. for (unsigned int i = 0; i < numKeys; ++i)
  919. {
  920. CTrackViewKeyHandle keyHandle = keyBundle.GetKey(i);
  921. float scaled = (keyHandle.GetTime() - oldTimeRange.start) * scale;
  922. keyHandle.SetTime(offset + scaled + oldTimeRange.start, notifyListeners);
  923. }
  924. // notifyListeners was disabled in the above SetTime() calls so
  925. // notify all the keys changes now.
  926. OnKeysChanged();
  927. MarkAsModified();
  928. }
  929. void CTrackViewSequence::SetTimeRange(Range timeRange)
  930. {
  931. m_pAnimSequence->SetTimeRange(timeRange);
  932. OnSequenceSettingsChanged();
  933. }
  934. Range CTrackViewSequence::GetTimeRange() const
  935. {
  936. return m_pAnimSequence->GetTimeRange();
  937. }
  938. void CTrackViewSequence::SetFlags(IAnimSequence::EAnimSequenceFlags flags)
  939. {
  940. m_pAnimSequence->SetFlags(flags);
  941. OnSequenceSettingsChanged();
  942. }
  943. IAnimSequence::EAnimSequenceFlags CTrackViewSequence::GetFlags() const
  944. {
  945. return (IAnimSequence::EAnimSequenceFlags)m_pAnimSequence->GetFlags();
  946. }
  947. void CTrackViewSequence::DeselectAllKeys()
  948. {
  949. CTrackViewSequenceNotificationContext context(this);
  950. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  951. for (unsigned int i = 0; i < selectedKeys.GetKeyCount(); ++i)
  952. {
  953. CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(i);
  954. keyHandle.Select(false);
  955. }
  956. }
  957. void CTrackViewSequence::OffsetSelectedKeys(const float timeOffset)
  958. {
  959. AZ_Assert(CUndo::IsRecording(), "Undo is not recording");
  960. CTrackViewSequenceNotificationContext context(this);
  961. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  962. // Set notifyListeners to false and wait until all keys
  963. // have been updated, otherwise the indexes in CTrackViewKeyHandle
  964. // may become invalid after sorted with a new time.
  965. bool notifyListeners = false;
  966. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  967. {
  968. CTrackViewKeyHandle skey = selectedKeys.GetKey(k);
  969. skey.Offset(timeOffset, notifyListeners);
  970. }
  971. if (selectedKeys.GetKeyCount() > 0)
  972. {
  973. OnKeysChanged();
  974. }
  975. }
  976. float CTrackViewSequence::ClipTimeOffsetForOffsetting(const float timeOffset)
  977. {
  978. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  979. float newTimeOffset = timeOffset;
  980. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  981. {
  982. CTrackViewKeyHandle skey = selectedKeys.GetKey(k);
  983. const float keyTime = skey.GetTime();
  984. float newKeyTime = keyTime + timeOffset;
  985. Range extendedTimeRange(0.0f, GetTimeRange().end);
  986. extendedTimeRange.ClipValue(newKeyTime);
  987. float offset = newKeyTime - keyTime;
  988. if (fabs(offset) < fabs(newTimeOffset))
  989. {
  990. newTimeOffset = offset;
  991. }
  992. }
  993. return newTimeOffset;
  994. }
  995. float CTrackViewSequence::ClipTimeOffsetForScaling(float timeOffset)
  996. {
  997. if (timeOffset <= 0)
  998. {
  999. return timeOffset;
  1000. }
  1001. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  1002. float newTimeOffset = timeOffset;
  1003. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  1004. {
  1005. CTrackViewKeyHandle skey = selectedKeys.GetKey(k);
  1006. float keyTime = skey.GetTime();
  1007. float newKeyTime = keyTime * timeOffset;
  1008. GetTimeRange().ClipValue(newKeyTime);
  1009. float offset = newKeyTime / keyTime;
  1010. if (offset < newTimeOffset)
  1011. {
  1012. newTimeOffset = offset;
  1013. }
  1014. }
  1015. return newTimeOffset;
  1016. }
  1017. void CTrackViewSequence::ScaleSelectedKeys(const float timeOffset)
  1018. {
  1019. AZ_Assert(CUndo::IsRecording(), "Undo is not recording");
  1020. CTrackViewSequenceNotificationContext context(this);
  1021. if (timeOffset <= 0)
  1022. {
  1023. return;
  1024. }
  1025. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  1026. const CTrackViewTrack* pTrack = nullptr;
  1027. for (int k = 0; k < (int)selectedKeys.GetKeyCount(); ++k)
  1028. {
  1029. CTrackViewKeyHandle skey = selectedKeys.GetKey(k);
  1030. if (pTrack != skey.GetTrack())
  1031. {
  1032. pTrack = skey.GetTrack();
  1033. }
  1034. float keyt = skey.GetTime() * timeOffset;
  1035. skey.SetTime(keyt);
  1036. }
  1037. }
  1038. float CTrackViewSequence::ClipTimeOffsetForSliding(const float timeOffset)
  1039. {
  1040. CTrackViewKeyBundle keys = GetSelectedKeys();
  1041. AZStd::set<CTrackViewTrack*> tracks;
  1042. AZStd::set<CTrackViewTrack*>::const_iterator pTrackIter;
  1043. Range timeRange = GetTimeRange();
  1044. // Get the first key in the timeline among selected and
  1045. // also gather tracks.
  1046. float time0 = timeRange.end;
  1047. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  1048. {
  1049. CTrackViewKeyHandle skey = keys.GetKey(k);
  1050. tracks.insert(skey.GetTrack());
  1051. float keyTime = skey.GetTime();
  1052. if (keyTime < time0)
  1053. {
  1054. time0 = keyTime;
  1055. }
  1056. }
  1057. // If 'bAll' is true, slide all tracks.
  1058. // (Otherwise, slide only selected tracks.)
  1059. bool bAll = Qt::AltModifier & QApplication::queryKeyboardModifiers();
  1060. if (bAll)
  1061. {
  1062. keys = GetKeysInTimeRange(time0, timeRange.end);
  1063. // Gather tracks again.
  1064. tracks.clear();
  1065. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  1066. {
  1067. CTrackViewKeyHandle skey = keys.GetKey(k);
  1068. tracks.insert(skey.GetTrack());
  1069. }
  1070. }
  1071. float newTimeOffset = timeOffset;
  1072. for (pTrackIter = tracks.begin(); pTrackIter != tracks.end(); ++pTrackIter)
  1073. {
  1074. CTrackViewTrack* pTrack = *pTrackIter;
  1075. for (unsigned int i = 0; i < pTrack->GetKeyCount(); ++i)
  1076. {
  1077. const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(i);
  1078. const float keyTime = keyHandle.GetTime();
  1079. if (keyTime >= time0)
  1080. {
  1081. float newKeyTime = keyTime + timeOffset;
  1082. timeRange.ClipValue(newKeyTime);
  1083. float offset = newKeyTime - keyTime;
  1084. if (fabs(offset) < fabs(newTimeOffset))
  1085. {
  1086. newTimeOffset = offset;
  1087. }
  1088. }
  1089. }
  1090. }
  1091. return newTimeOffset;
  1092. }
  1093. void CTrackViewSequence::SlideKeys(float timeOffset)
  1094. {
  1095. AZ_Assert(CUndo::IsRecording(), "Undo is not recording");
  1096. CTrackViewSequenceNotificationContext context(this);
  1097. CTrackViewKeyBundle keys = GetSelectedKeys();
  1098. AZStd::set<CTrackViewTrack*> tracks;
  1099. AZStd::set<CTrackViewTrack*>::const_iterator pTrackIter;
  1100. Range timeRange = GetTimeRange();
  1101. // Get the first key in the timeline among selected and
  1102. // also gather tracks.
  1103. float time0 = timeRange.end;
  1104. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  1105. {
  1106. CTrackViewKeyHandle skey = keys.GetKey(k);
  1107. tracks.insert(skey.GetTrack());
  1108. float keyTime = skey.GetTime();
  1109. if (keyTime < time0)
  1110. {
  1111. time0 = keyTime;
  1112. }
  1113. }
  1114. // If 'bAll' is true, slide all tracks.
  1115. // (Otherwise, slide only selected tracks.)
  1116. bool bAll = Qt::AltModifier & QApplication::queryKeyboardModifiers();
  1117. if (bAll)
  1118. {
  1119. keys = GetKeysInTimeRange(time0, timeRange.end);
  1120. // Gather tracks again.
  1121. tracks.clear();
  1122. for (int k = 0; k < (int)keys.GetKeyCount(); ++k)
  1123. {
  1124. CTrackViewKeyHandle skey = keys.GetKey(k);
  1125. tracks.insert(skey.GetTrack());
  1126. }
  1127. }
  1128. for (pTrackIter = tracks.begin(); pTrackIter != tracks.end(); ++pTrackIter)
  1129. {
  1130. CTrackViewTrack* pTrack = *pTrackIter;
  1131. pTrack->SlideKeys(time0, timeOffset);
  1132. }
  1133. }
  1134. void CTrackViewSequence::CloneSelectedKeys()
  1135. {
  1136. AZ_Assert(CUndo::IsRecording(), "Undo is not recording");
  1137. CTrackViewSequenceNotificationContext context(this);
  1138. CTrackViewKeyBundle selectedKeys = GetSelectedKeys();
  1139. const CTrackViewTrack* pTrack = nullptr;
  1140. // In case of multiple cloning, indices cannot be used as a solid pointer to the original.
  1141. // So use the time of keys as an identifier, instead.
  1142. AZStd::vector<float> selectedKeyTimes;
  1143. for (size_t k = 0; k < selectedKeys.GetKeyCount(); ++k)
  1144. {
  1145. CTrackViewKeyHandle skey = selectedKeys.GetKey(static_cast<unsigned int>(k));
  1146. if (pTrack != skey.GetTrack())
  1147. {
  1148. pTrack = skey.GetTrack();
  1149. }
  1150. selectedKeyTimes.push_back(skey.GetTime());
  1151. }
  1152. // Now, do the actual cloning.
  1153. for (size_t k = 0; k < selectedKeyTimes.size(); ++k)
  1154. {
  1155. CTrackViewKeyHandle skey = selectedKeys.GetKey(static_cast<unsigned int>(k));
  1156. skey = skey.GetTrack()->GetKeyByTime(selectedKeyTimes[k]);
  1157. AZ_Assert(skey.IsValid(), "Key is not valid");
  1158. if (!skey.IsValid())
  1159. {
  1160. continue;
  1161. }
  1162. CTrackViewKeyHandle newKey = skey.Clone();
  1163. // Select new key.
  1164. newKey.Select(true);
  1165. // Deselect cloned key.
  1166. skey.Select(false);
  1167. }
  1168. }
  1169. void CTrackViewSequence::BeginUndoTransaction()
  1170. {
  1171. QueueNotifications();
  1172. }
  1173. void CTrackViewSequence::EndUndoTransaction()
  1174. {
  1175. // if the sequence was added during a redo, it will add itself as an UndoManagerListener in the process and we'll
  1176. // get an EndUndoTransaction without a corresponding BeginUndoTransaction() call - only SubmitPendingNotifications()
  1177. // if we're queued
  1178. if (m_bQueueNotifications)
  1179. {
  1180. SubmitPendingNotifications();
  1181. }
  1182. }
  1183. void CTrackViewSequence::BeginRestoreTransaction()
  1184. {
  1185. QueueNotifications();
  1186. }
  1187. void CTrackViewSequence::EndRestoreTransaction()
  1188. {
  1189. // if the sequence was added during a restore, it will add itself as an UndoManagerListener in the process and we'll
  1190. // get an EndUndoTransaction without a corresponding BeginUndoTransaction() call - only SubmitPendingNotifications()
  1191. // if we're queued
  1192. if (m_bQueueNotifications)
  1193. {
  1194. SubmitPendingNotifications();
  1195. }
  1196. }
  1197. bool CTrackViewSequence::IsActiveSequence() const
  1198. {
  1199. return GetIEditor()->GetAnimation()->GetSequence() == this;
  1200. }
  1201. const float CTrackViewSequence::GetTime() const
  1202. {
  1203. return m_time;
  1204. }
  1205. CTrackViewSequence* CTrackViewSequence::LookUpSequenceByEntityId(const AZ::EntityId& sequenceId)
  1206. {
  1207. CTrackViewSequence* sequence = nullptr;
  1208. IEditor* editor = nullptr;
  1209. AzToolsFramework::EditorRequests::Bus::BroadcastResult(editor, &AzToolsFramework::EditorRequests::Bus::Events::GetEditor);
  1210. if (editor)
  1211. {
  1212. ITrackViewSequenceManager* sequenceManager = editor->GetSequenceManager();
  1213. if (sequenceManager)
  1214. {
  1215. sequence = sequenceManager->GetSequenceByEntityId(sequenceId);
  1216. }
  1217. }
  1218. return sequence;
  1219. }