A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEditor.Timeline.Actions;
5using UnityEngine;
6using UnityEngine.Playables;
7using UnityEngine.Timeline;
8
9namespace UnityEditor.Timeline
10{
11 /// <summary>
12 /// Information currently being edited in the Timeline Editor Window.
13 /// </summary>
14 public static class TimelineEditor
15 {
16 /// <summary>
17 /// Returns a reference to the Timeline Window.
18 /// </summary>
19 /// <returns>A reference to the TimelineWindow and null if the window is not opened.</returns>
20 public static TimelineEditorWindow GetWindow()
21 {
22 return window;
23 }
24
25 /// <summary>
26 /// Returns a reference to the Timeline Window. If the window is not opened, it will be opened.
27 /// </summary>
28 /// <returns>A reference to the TimelineWindow.</returns>
29 public static TimelineEditorWindow GetOrCreateWindow()
30 {
31 if (window != null)
32 return window;
33
34 return EditorWindow.GetWindow<TimelineWindow>(false, null, false);
35 }
36
37 /// <summary>
38 /// The PlayableDirector associated with the timeline currently being shown in the Timeline window.
39 /// </summary>
40 public static PlayableDirector inspectedDirector => state?.editSequence.director;
41
42 /// <summary>
43 /// The PlayableDirector responsible for the playback of the timeline currently being shown in the Timeline window.
44 /// </summary>
45 public static PlayableDirector masterDirector => state?.masterSequence.director;
46
47 /// <summary>
48 /// The TimelineAsset currently being shown in the Timeline window.
49 /// </summary>
50 public static TimelineAsset inspectedAsset => state?.editSequence.asset;
51
52 /// <summary>
53 /// The TimelineAsset at the root of the hierarchy currently being shown in the Timeline window.
54 /// </summary>
55 public static TimelineAsset masterAsset => state?.masterSequence.asset;
56
57 /// <summary>
58 /// The PlayableDirector currently being shown in the Timeline Editor Window.
59 /// </summary>
60 [Obsolete("playableDirector is ambiguous. Please select either inspectedDirector or masterDirector instead.", false)]
61 public static PlayableDirector playableDirector
62 {
63 get { return inspectedDirector; }
64 }
65
66 /// <summary>
67 /// The TimelineAsset currently being shown in the Timeline Editor Window.
68 /// </summary>
69 [Obsolete("timelineAsset is ambiguous. Please select either inspectedAsset or masterAsset instead.", false)]
70 public static TimelineAsset timelineAsset
71 {
72 get { return inspectedAsset; }
73 }
74
75
76 /// <summary>
77 /// <para>
78 /// Refreshes the different components affected by the currently inspected
79 /// <see cref="UnityEngine.Timeline.TimelineAsset"/>, based on the <see cref="RefreshReason"/> provided.
80 /// </para>
81 /// <para>
82 /// For better performance, it is recommended that you invoke this method once, after you modify the
83 /// <see cref="UnityEngine.Timeline.TimelineAsset"/>. You should also combine reasons using the <c>|</c> operator.
84 /// </para>
85 /// </summary>
86 /// <remarks>
87 /// Note: This operation is not synchronous. It is performed during the next GUI loop.
88 /// </remarks>
89 /// <param name="reason">The reason why a refresh should be performed.</param>
90 public static void Refresh(RefreshReason reason)
91 {
92 if (state == null)
93 return;
94
95 if ((reason & RefreshReason.ContentsAddedOrRemoved) != 0)
96 {
97 state.Refresh();
98 }
99 else if ((reason & RefreshReason.ContentsModified) != 0)
100 {
101 state.rebuildGraph = true;
102 }
103 else if ((reason & RefreshReason.SceneNeedsUpdate) != 0)
104 {
105 state.Evaluate();
106 }
107
108 window.Repaint();
109 }
110
111 internal static TimelineWindow window => TimelineWindow.instance;
112 internal static WindowState state => window == null ? null : window.state;
113
114 internal static readonly Clipboard clipboard = new Clipboard();
115
116 /// <summary>
117 /// The list of clips selected in the TimelineEditor.
118 /// </summary>
119 public static TimelineClip[] selectedClips
120 {
121 get { return Selection.GetFiltered<EditorClip>(SelectionMode.Unfiltered).Select(e => e.clip).Where(x => x != null).ToArray(); }
122 set
123 {
124 if (value == null || value.Length == 0)
125 {
126 Selection.objects = null;
127 }
128 else
129 {
130 var objects = new List<UnityEngine.Object>();
131 foreach (var clip in value)
132 {
133 if (clip == null)
134 continue;
135
136 var editorClip = EditorClipFactory.GetEditorClip(clip);
137 if (editorClip != null)
138 objects.Add(editorClip);
139 }
140
141 Selection.objects = objects.ToArray();
142 }
143 }
144 }
145
146 /// <summary>
147 /// The clip selected in the TimelineEditor.
148 /// </summary>
149 /// <remarks>
150 /// If there are multiple clips selected, this property returns the first clip.
151 /// </remarks>
152 public static TimelineClip selectedClip
153 {
154 get
155 {
156 var editorClip = Selection.activeObject as EditorClip;
157 if (editorClip != null)
158 return editorClip.clip;
159 return null;
160 }
161 set
162 {
163 var editorClip = (value != null) ? EditorClipFactory.GetEditorClip(value) : null;
164 Selection.activeObject = editorClip;
165 }
166 }
167
168 /// <summary>
169 /// Local time (in seconds) of the inspected sequence.
170 /// </summary>
171 /// <exception cref="InvalidOperationException">Thrown if timeline window is not available.</exception>
172 internal static double inspectedSequenceTime
173 {
174 get => state?.editSequence.time ?? 0;
175 set
176 {
177 if (state == null)
178 throw new InvalidOperationException("Cannot set time. Timeline Window may not be available.");
179 state.editSequence.time = value;
180 }
181 }
182
183 /// <summary>
184 /// Global time (in seconds) of the master timeline.
185 /// Same as local time if not inspected a subtimeline.
186 /// </summary>
187 /// <exception cref="InvalidOperationException">Thrown if timeline window is not available.</exception>
188 internal static double masterSequenceTime
189 {
190 get => state?.editSequence.ToGlobalTime(state.editSequence.time) ?? 0;
191 set
192 {
193 if (state == null)
194 throw new InvalidOperationException("Cannot set time. Timeline Window may not be available.");
195 state.masterSequence.time = value;
196 }
197 }
198
199 /// <summary>
200 /// Visible time range (in seconds) in Editor.
201 /// x : min time
202 /// y : max time
203 /// </summary>
204 /// <exception cref="InvalidOperationException">Thrown if timeline window is not available.</exception>
205 internal static Vector2 visibleTimeRange
206 {
207 get => state?.timeAreaShownRange ?? TimelineAssetViewModel.TimeAreaDefaultRange;
208 set
209 {
210 if (state == null)
211 throw new InvalidOperationException("Cannot set visible time range. Timeline Window may not be available.");
212 state.timeAreaShownRange = value;
213 }
214 }
215
216 internal static ActionContext CurrentContext(Vector2? mousePos = null)
217 {
218 return new ActionContext
219 {
220 invocationTime = mousePos != null ? TimelineHelpers.GetCandidateTime(mousePos) : (double?)null,
221 clips = SelectionManager.SelectedClips(),
222 tracks = SelectionManager.SelectedTracks(),
223 markers = SelectionManager.SelectedMarkers(),
224 timeline = inspectedAsset,
225 director = inspectedDirector
226 };
227 }
228
229 /// <summary>
230 /// Converts time from the master timeline to the current inspected timeline.
231 /// </summary>
232 /// <param name="masterTime">Time in the referential of the main timeline</param>
233 /// <returns>Time in the referential of the sub-timeline that is currently show.
234 /// Returns <paramref name="masterTime"/> if there is no sub-timeline or if no timeline is shown.</returns>
235 public static double GetInspectedTimeFromMasterTime(double masterTime)
236 {
237 ISequenceState editSequence = state?.editSequence;
238 if (editSequence == null)
239 return masterTime;
240 return state.editSequence.ToLocalTime(masterTime);
241 }
242
243 /// <summary>
244 /// Converts time from the current inspected timeline to the master timeline.
245 /// </summary>
246 /// <param name="inspectedTime">Time in the referential of the sub-timeline</param>
247 /// <returns>Time in the referential of the main timeline.
248 /// Returns <paramref name="inspectedTime"/> if there if no timeline is shown.</returns>
249 public static double GetMasterTimeFromInspectedTime(double inspectedTime)
250 {
251 ISequenceState editSequence = state?.editSequence;
252 if (editSequence == null)
253 return inspectedTime;
254 return editSequence.ToGlobalTime(inspectedTime);
255 }
256
257 internal static void RefreshPreviewPlay()
258 {
259 if (state == null || !state.playing)
260 return;
261 state.Pause();
262 state.Play();
263 }
264 }
265
266 /// <summary>
267 /// <see cref="TimelineEditor.Refresh"/> uses these flags to determine what needs to be refreshed or updated.
268 /// </summary>
269 /// <remarks>
270 /// Use the <c>|</c> operator to combine flags.
271 /// <example>
272 /// <code source="../DocCodeExamples/TimelineEditorExamples.cs" region="declare-refreshReason" title="refreshReason"/>
273 /// </example>
274 /// </remarks>
275 [Flags]
276 public enum RefreshReason
277 {
278 /// <summary>
279 /// Use this flag when a change to the Timeline requires that the Timeline window be redrawn.
280 /// </summary>
281 WindowNeedsRedraw = 1 << 0,
282
283 /// <summary>
284 /// Use this flag when a change to the Timeline requires that the Scene be updated.
285 /// </summary>
286 SceneNeedsUpdate = 1 << 1,
287
288 /// <summary>
289 /// Use this flag when a Timeline element was modified.
290 /// </summary>
291 ContentsModified = 1 << 2,
292
293 /// <summary>
294 /// Use this flag when an element was added to or removed from the Timeline.
295 /// </summary>
296 ContentsAddedOrRemoved = 1 << 3
297 }
298}