暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TimelineWindow_Navigator.cs 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Timeline;
  6. namespace UnityEditor.Timeline
  7. {
  8. partial class TimelineWindow
  9. {
  10. /// <summary>
  11. /// The public Breadcrumb navigation controller, accessible through TimelineEditorWindow
  12. /// </summary>
  13. public override TimelineNavigator navigator => new TimelineNavigator(this);
  14. /// <summary>
  15. /// Implementation of TimelineNavigator
  16. /// </summary>
  17. /// <remarks>
  18. /// Always use TimelineNavigator, not this class.
  19. ///
  20. /// The class acts as a handle on the TimelineWindow, and lets users navigate the breadcrumbs and dive into subtimelines
  21. /// </remarks>
  22. internal class TimelineNavigatorImpl
  23. {
  24. /// <summary>
  25. ///
  26. /// </summary>
  27. /// <param name="window"></param>
  28. public TimelineNavigatorImpl(IWindowStateProvider window)
  29. {
  30. if (window == null)
  31. throw new ArgumentNullException(nameof(window),
  32. "TimelineNavigator cannot be used with a null window");
  33. m_Window = window;
  34. }
  35. /// <summary>
  36. /// Creates a SequenceContext from the top of the breadcrumb stack
  37. /// </summary>
  38. /// <returns></returns>
  39. public SequenceContext GetCurrentContext()
  40. {
  41. return GetBreadcrumbs().LastOrDefault();
  42. }
  43. /// <summary>
  44. /// Creates a SequenceContext from the second to last breadcrumb in the list
  45. /// </summary>
  46. /// <returns>Valid context if there is a parent, Invalid context otherwise</returns>
  47. public SequenceContext GetParentContext()
  48. {
  49. //If the edit sequence is the master sequence, there is no parent context
  50. if (windowState.editSequence == windowState.masterSequence)
  51. return SequenceContext.Invalid;
  52. var contexts = GetBreadcrumbs();
  53. var length = contexts.Count();
  54. return contexts.ElementAtOrDefault(length - 2);
  55. }
  56. /// <summary>
  57. /// Creates a SequenceContext from the top of the breadcrumb stack
  58. /// </summary>
  59. /// <returns>Always returns a valid SequenceContext</returns>
  60. public SequenceContext GetRootContext()
  61. {
  62. return GetBreadcrumbs().FirstOrDefault();
  63. }
  64. /// <summary>
  65. /// Creates SequenceContexts for all the child Timelines
  66. /// </summary>
  67. /// <returns>Collection of SequenceContexts. Can be empty if there are no valid child contexts</returns>
  68. public IEnumerable<SequenceContext> GetChildContexts()
  69. {
  70. return windowState.GetSubSequences();
  71. }
  72. /// <summary>
  73. /// Creates SequenceContexts from the breadcrumb stack, from top to bottom
  74. /// </summary>
  75. /// <returns>Collection of SequenceContexts. Should never be empty</returns>
  76. public IEnumerable<SequenceContext> GetBreadcrumbs()
  77. {
  78. return CollectBreadcrumbContexts();
  79. }
  80. /// <summary>
  81. /// Changes the current Timeline shown in the TimelineWindow to a new SequenceContext (if different and valid)
  82. /// </summary>
  83. /// <remarks>
  84. /// Should only ever accept SequenceContexts that are in the breadcrumbs. SetTimeline is the proper
  85. /// method to use to switch root Timelines.
  86. /// </remarks>
  87. /// <param name="context">A valid SequenceContext. <paramref name="context"/> should always be found in the breadcrumbs</param>
  88. /// <exception cref="System.ArgumentException"> The context is not valid</exception>
  89. /// <exception cref="System.InvalidOperationException"> The context is not a valid navigation destination.</exception>
  90. public void NavigateTo(SequenceContext context)
  91. {
  92. if (!context.IsValid())
  93. throw new ArgumentException(
  94. $"Argument {nameof(context)} is not valid. Check validity with SequenceContext.IsValid.");
  95. //If the provided context is the current context
  96. if (windowState.editSequence.hostClip == context.clip &&
  97. windowState.editSequence.director == context.director &&
  98. windowState.editSequence.asset == context.director.playableAsset)
  99. {
  100. return; // Nothing to do
  101. }
  102. if (context.clip == null)
  103. {
  104. if (context.director != windowState.masterSequence.director)
  105. throw new InvalidOperationException($"{nameof(context)} is not a valid destination in this context. " +
  106. $"To change the root context, use TimelineEditorWindow.SetTimeline instead.");
  107. }
  108. var children = GetChildContexts().ToArray();
  109. var breadcrumbs = CollectBreadcrumbContexts().ToArray();
  110. if (!children.Contains(context) && !breadcrumbs.Contains(context))
  111. {
  112. throw new InvalidOperationException(
  113. "The provided SequenceContext is not a valid destination. " +
  114. "Use GetChildContexts or GetBreadcrumbs to acquire valid destination contexts.");
  115. }
  116. if (children.Contains(context))
  117. {
  118. windowState.SetCurrentSequence(context.director.playableAsset as TimelineAsset, context.director, context.clip);
  119. return;
  120. }
  121. var idx = Array.IndexOf(breadcrumbs, context);
  122. if (idx != -1)
  123. {
  124. windowState.PopSequencesUntilCount(idx + 1);
  125. }
  126. }
  127. private IWindowState windowState
  128. {
  129. get
  130. {
  131. if (m_Window == null || m_Window.windowState == null)
  132. throw new InvalidOperationException("The Window associated to this instance has been destroyed");
  133. return m_Window.windowState;
  134. }
  135. }
  136. private IEnumerable<SequenceContext> CollectBreadcrumbContexts()
  137. {
  138. return windowState.allSequences?.Select(s => new SequenceContext(s.director, s.hostClip));
  139. }
  140. private readonly IWindowStateProvider m_Window;
  141. }
  142. }
  143. }