ClipsActions.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. using System.Collections.Generic;
  2. using System.ComponentModel;
  3. using System.Linq;
  4. using JetBrains.Annotations;
  5. using UnityEngine;
  6. using UnityEngine.Timeline;
  7. using UnityEngine.Playables;
  8. using ClipAction = UnityEditor.Timeline.ItemAction<UnityEngine.Timeline.TimelineClip>;
  9. namespace UnityEditor.Timeline
  10. {
  11. [MenuEntry("Edit in Animation Window", MenuOrder.ClipEditAction.EditInAnimationWindow), UsedImplicitly]
  12. class EditClipInAnimationWindow : ClipAction
  13. {
  14. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  15. {
  16. if (clips.Length == 1 && clips[0].animationClip != null)
  17. return MenuActionDisplayState.Visible;
  18. return MenuActionDisplayState.Hidden;
  19. }
  20. public override bool Execute(WindowState state, TimelineClip[] clips)
  21. {
  22. var clip = clips[0];
  23. if (clip.curves != null || clip.animationClip != null)
  24. {
  25. var clipToEdit = clip.animationClip != null ? clip.animationClip : clip.curves;
  26. if (clipToEdit == null)
  27. return false;
  28. var gameObject = state.GetSceneReference(clip.parentTrack);
  29. var timeController = TimelineAnimationUtilities.CreateTimeController(state, clip);
  30. TimelineAnimationUtilities.EditAnimationClipWithTimeController(
  31. clipToEdit, timeController, clip.animationClip != null ? gameObject : null);
  32. return true;
  33. }
  34. return false;
  35. }
  36. }
  37. [MenuEntry("Edit Sub-Timeline", MenuOrder.ClipEditAction.EditSubTimeline), UsedImplicitly]
  38. class EditSubTimeline : ClipAction
  39. {
  40. private static readonly string MultiItemPrefix = "Edit Sub-Timelines/";
  41. private static readonly string SingleItemPrefix = "Edit ";
  42. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  43. {
  44. return IsValid(state, clips) ? MenuActionDisplayState.Visible : MenuActionDisplayState.Hidden;
  45. }
  46. bool IsValid(WindowState state, TimelineClip[] clips)
  47. {
  48. if (clips.Length != 1 || state == null || state.editSequence.director == null) return false;
  49. var clip = clips[0];
  50. var directors = TimelineUtility.GetSubTimelines(clip, state.editSequence.director);
  51. return directors.Any(x => x != null);
  52. }
  53. public override bool Execute(WindowState state, TimelineClip[] clips)
  54. {
  55. if (!IsValid(state, clips)) return false;
  56. var clip = clips[0];
  57. var directors = TimelineUtility.GetSubTimelines(clip, state.editSequence.director);
  58. ExecuteInternal(state, directors, 0, clip);
  59. return true;
  60. }
  61. static void ExecuteInternal(WindowState state, IList<PlayableDirector> directors, int directorIndex, TimelineClip clip)
  62. {
  63. SelectionManager.Clear();
  64. state.GetWindow().SetCurrentTimeline(directors[directorIndex], clip);
  65. }
  66. protected override void AddMenuItem(WindowState state, TimelineClip[] items, List<MenuActionItem> menuItems)
  67. {
  68. if (items == null || items.Length != 1)
  69. return;
  70. var mode = TimelineWindow.instance.currentMode.mode;
  71. var menuItem = new MenuActionItem()
  72. {
  73. category = category,
  74. entryName = GetDisplayName(items),
  75. shortCut = string.Empty,
  76. isChecked = false,
  77. isActiveInMode = IsActionActiveInMode(this, mode),
  78. priority = priority,
  79. state = GetDisplayState(state, items),
  80. callback = null
  81. };
  82. var subDirectors = TimelineUtility.GetSubTimelines(items[0], state.editSequence.director);
  83. if (subDirectors.Count == 1)
  84. {
  85. menuItem.entryName = SingleItemPrefix + DisplayNameHelper.GetDisplayName(subDirectors[0]);
  86. menuItem.callback = () => Execute(state, items);
  87. menuItems.Add(menuItem);
  88. }
  89. else
  90. {
  91. for (int i = 0; i < subDirectors.Count; i++)
  92. {
  93. var index = i;
  94. menuItem.category = MultiItemPrefix;
  95. menuItem.entryName = DisplayNameHelper.GetDisplayName(subDirectors[i]);
  96. menuItem.callback = () => ExecuteInternal(state, subDirectors, index, items[0]);
  97. menuItems.Add(menuItem);
  98. }
  99. }
  100. }
  101. }
  102. [MenuEntry("Editing/Trim Start", MenuOrder.ClipAction.TrimStart)]
  103. [Shortcut(Shortcuts.Clip.trimStart), UsedImplicitly]
  104. class TrimStart : ItemAction<TimelineClip>
  105. {
  106. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  107. {
  108. return clips.All(x => state.editSequence.time <= x.start || state.editSequence.time >= x.start + x.duration) ?
  109. MenuActionDisplayState.Disabled : MenuActionDisplayState.Visible;
  110. }
  111. public override bool Execute(WindowState state, TimelineClip[] clips)
  112. {
  113. return ClipModifier.TrimStart(clips, state.editSequence.time);
  114. }
  115. }
  116. [MenuEntry("Editing/Trim End", MenuOrder.ClipAction.TrimEnd), UsedImplicitly]
  117. [Shortcut(Shortcuts.Clip.trimEnd)]
  118. class TrimEnd : ItemAction<TimelineClip>
  119. {
  120. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  121. {
  122. return clips.All(x => state.editSequence.time <= x.start || state.editSequence.time >= x.start + x.duration) ?
  123. MenuActionDisplayState.Disabled : MenuActionDisplayState.Visible;
  124. }
  125. public override bool Execute(WindowState state, TimelineClip[] clips)
  126. {
  127. return ClipModifier.TrimEnd(clips, state.editSequence.time);
  128. }
  129. }
  130. [Shortcut(Shortcuts.Clip.split), MenuEntry("Editing/Split", MenuOrder.ClipAction.Split), UsedImplicitly]
  131. class Split : ClipAction
  132. {
  133. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  134. {
  135. return clips.All(x => state.editSequence.time <= x.start || state.editSequence.time >= x.start + x.duration) ?
  136. MenuActionDisplayState.Disabled : MenuActionDisplayState.Visible;
  137. }
  138. public override bool Execute(WindowState state, TimelineClip[] clips)
  139. {
  140. bool success = ClipModifier.Split(clips, state.editSequence.time, state.editSequence.director);
  141. if (success)
  142. state.Refresh();
  143. return success;
  144. }
  145. }
  146. [MenuEntry("Editing/Complete Last Loop", MenuOrder.ClipAction.CompleteLastLoop), UsedImplicitly]
  147. class CompleteLastLoop : ClipAction
  148. {
  149. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  150. {
  151. bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration);
  152. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  153. }
  154. public override bool Execute(WindowState state, TimelineClip[] clips)
  155. {
  156. return ClipModifier.CompleteLastLoop(clips);
  157. }
  158. }
  159. [MenuEntry("Editing/Trim Last Loop", MenuOrder.ClipAction.TrimLastLoop), UsedImplicitly]
  160. class TrimLastLoop : ClipAction
  161. {
  162. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  163. {
  164. bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration);
  165. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  166. }
  167. public override bool Execute(WindowState state, TimelineClip[] clips)
  168. {
  169. return ClipModifier.TrimLastLoop(clips);
  170. }
  171. }
  172. [MenuEntry("Editing/Match Duration", MenuOrder.ClipAction.MatchDuration), UsedImplicitly]
  173. class MatchDuration : ClipAction
  174. {
  175. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  176. {
  177. return clips.Length > 1 ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  178. }
  179. public override bool Execute(WindowState state, TimelineClip[] clips)
  180. {
  181. return ClipModifier.MatchDuration(clips);
  182. }
  183. }
  184. [MenuEntry("Editing/Double Speed", MenuOrder.ClipAction.DoubleSpeed), UsedImplicitly]
  185. class DoubleSpeed : ClipAction
  186. {
  187. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  188. {
  189. bool canDisplay = clips.All(x => x.SupportsSpeedMultiplier());
  190. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  191. }
  192. public override bool Execute(WindowState state, TimelineClip[] clips)
  193. {
  194. return ClipModifier.DoubleSpeed(clips);
  195. }
  196. }
  197. [MenuEntry("Editing/Half Speed", MenuOrder.ClipAction.HalfSpeed), UsedImplicitly]
  198. class HalfSpeed : ClipAction
  199. {
  200. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  201. {
  202. bool canDisplay = clips.All(x => x.SupportsSpeedMultiplier());
  203. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  204. }
  205. public override bool Execute(WindowState state, TimelineClip[] clips)
  206. {
  207. return ClipModifier.HalfSpeed(clips);
  208. }
  209. }
  210. [MenuEntry("Editing/Reset Duration", MenuOrder.ClipAction.ResetDuration), UsedImplicitly]
  211. class ResetDuration : ClipAction
  212. {
  213. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  214. {
  215. bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration);
  216. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  217. }
  218. public override bool Execute(WindowState state, TimelineClip[] clips)
  219. {
  220. return ClipModifier.ResetEditing(clips);
  221. }
  222. }
  223. [MenuEntry("Editing/Reset Speed", MenuOrder.ClipAction.ResetSpeed), UsedImplicitly]
  224. class ResetSpeed : ClipAction
  225. {
  226. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  227. {
  228. bool canDisplay = clips.All(x => x.SupportsSpeedMultiplier());
  229. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  230. }
  231. public override bool Execute(WindowState state, TimelineClip[] clips)
  232. {
  233. return ClipModifier.ResetSpeed(clips);
  234. }
  235. }
  236. [MenuEntry("Editing/Reset All", MenuOrder.ClipAction.ResetAll), UsedImplicitly]
  237. class ResetAll : ClipAction
  238. {
  239. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  240. {
  241. bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration) ||
  242. clips.All(x => x.SupportsSpeedMultiplier());
  243. return canDisplay ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  244. }
  245. public override bool Execute(WindowState state, TimelineClip[] clips)
  246. {
  247. var speedResult = ClipModifier.ResetSpeed(clips);
  248. var editResult = ClipModifier.ResetEditing(clips);
  249. return speedResult || editResult;
  250. }
  251. }
  252. [MenuEntry("Tile", MenuOrder.ClipAction.Tile), UsedImplicitly]
  253. class Tile : ClipAction
  254. {
  255. protected override MenuActionDisplayState GetDisplayState(WindowState state, TimelineClip[] clips)
  256. {
  257. return clips.Length > 1 ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled;
  258. }
  259. public override bool Execute(WindowState state, TimelineClip[] clips)
  260. {
  261. return ClipModifier.Tile(clips);
  262. }
  263. }
  264. [MenuEntry("Find Source Asset", MenuOrder.ClipAction.FindSourceAsset), UsedImplicitly]
  265. [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
  266. class FindSourceAsset : ClipAction
  267. {
  268. protected override MenuActionDisplayState GetDisplayState(WindowState state,
  269. TimelineClip[] clips)
  270. {
  271. if (clips.Length > 1)
  272. return MenuActionDisplayState.Disabled;
  273. if (GetUnderlyingAsset(state, clips[0]) == null)
  274. return MenuActionDisplayState.Disabled;
  275. return MenuActionDisplayState.Visible;
  276. }
  277. public override bool Execute(WindowState state, TimelineClip[] clips)
  278. {
  279. EditorGUIUtility.PingObject(GetUnderlyingAsset(state, clips[0]));
  280. return true;
  281. }
  282. private static UnityEngine.Object GetExternalPlayableAsset(TimelineClip clip)
  283. {
  284. if (clip.asset == null)
  285. return null;
  286. if ((clip.asset.hideFlags & HideFlags.HideInHierarchy) != 0)
  287. return null;
  288. return clip.asset;
  289. }
  290. private static UnityEngine.Object GetUnderlyingAsset(WindowState state, TimelineClip clip)
  291. {
  292. var asset = clip.asset as ScriptableObject;
  293. if (asset == null)
  294. return null;
  295. var fields = ObjectReferenceField.FindObjectReferences(asset.GetType());
  296. if (fields.Length == 0)
  297. return GetExternalPlayableAsset(clip);
  298. // Find the first non-null field
  299. foreach (var field in fields)
  300. {
  301. // skip scene refs in asset mode
  302. if (state.editSequence.director == null && field.isSceneReference)
  303. continue;
  304. var obj = field.Find(asset, state.editSequence.director);
  305. if (obj != null)
  306. return obj;
  307. }
  308. return GetExternalPlayableAsset(clip);
  309. }
  310. }
  311. class CopyClipsToClipboard : ClipAction
  312. {
  313. public override bool Execute(WindowState state, TimelineClip[] clips)
  314. {
  315. TimelineEditor.clipboard.CopyItems(clips.ToItems());
  316. return true;
  317. }
  318. }
  319. }