TrackViewSequence.cpp 48 KB

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