123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using UnityEngine.Playables;
- using UnityEngine.Timeline;
- using Object = UnityEngine.Object;
- namespace UnityEditor.Timeline
- {
- static class SequencerContextMenu
- {
- static readonly TimelineAction[] MarkerHeaderCommonOperations =
- {
- new PasteAction()
- };
- public static readonly TimelineAction[] MarkerHeaderMenuItems =
- TimelineAction.AllActions.OfType<MarkerHeaderAction>().
- Where(a => a.showInMenu).
- Union(MarkerHeaderCommonOperations).
- ToArray();
- static class Styles
- {
- public static readonly string addItemFromAssetTemplate = L10n.Tr("Add {0} From {1}");
- public static readonly string addSingleItemFromAssetTemplate = L10n.Tr("Add From {1}");
- public static readonly string addItemTemplate = L10n.Tr("Add {0}");
- public static readonly string typeSelectorTemplate = L10n.Tr("Select {0}");
- public static readonly string trackGroup = L10n.Tr("Track Group");
- public static readonly string trackSubGroup = L10n.Tr("Track Sub-Group");
- public static readonly string addTrackLayer = L10n.Tr("Add Layer");
- public static readonly string layerName = L10n.Tr("Layer {0}");
- }
- public static void ShowMarkerHeaderContextMenu(Vector2? mousePosition, WindowState state)
- {
- var menu = new GenericMenu();
- List<MenuActionItem> items = new List<MenuActionItem>(100);
- BuildMarkerHeaderContextMenu(items, mousePosition, state);
- MenuItemActionBase.BuildMenu(menu, items);
- menu.ShowAsContext();
- }
- public static void ShowNewTracksContextMenu(ICollection<TrackAsset> tracks, WindowState state)
- {
- var menu = new GenericMenu();
- List<MenuActionItem> items = new List<MenuActionItem>(100);
- BuildNewTracksContextMenu(items, tracks, state);
- MenuItemActionBase.BuildMenu(menu, items);
- menu.ShowAsContext();
- }
- public static void ShowNewTracksContextMenu(ICollection<TrackAsset> tracks, WindowState state, Rect rect)
- {
- var menu = new GenericMenu();
- List<MenuActionItem> items = new List<MenuActionItem>(100);
- BuildNewTracksContextMenu(items, tracks, state);
- MenuItemActionBase.BuildMenu(menu, items);
- menu.DropDown(rect);
- }
- public static void ShowTrackContextMenu(TrackAsset[] tracks, Vector2? mousePosition)
- {
- if (tracks == null || tracks.Length == 0)
- return;
- var items = new List<MenuActionItem>();
- var menu = new GenericMenu();
- BuildTrackContextMenu(items, tracks, mousePosition);
- MenuItemActionBase.BuildMenu(menu, items);
- menu.ShowAsContext();
- }
- public static void ShowItemContextMenu(Vector2 mousePosition, TimelineClip[] clips, IMarker[] markers)
- {
- var menu = new GenericMenu();
- var items = new List<MenuActionItem>();
- BuildItemContextMenu(items, mousePosition, clips, markers);
- MenuItemActionBase.BuildMenu(menu, items);
- menu.ShowAsContext();
- }
- internal static void BuildItemContextMenu(List<MenuActionItem> items, Vector2 mousePosition, TimelineClip[] clips, IMarker[] markers)
- {
- var state = TimelineWindow.instance.state;
- TimelineAction.GetMenuEntries(TimelineAction.MenuActions, mousePosition, items);
- ItemAction<TimelineClip>.GetMenuEntries(clips, items);
- ItemAction<IMarker>.GetMenuEntries(markers, items);
- if (clips.Length > 0)
- AddMarkerMenuCommands(items, clips.Select(c => c.parentTrack).Distinct().ToList(), TimelineHelpers.GetCandidateTime(state, mousePosition));
- }
- internal static void BuildNewTracksContextMenu(List<MenuActionItem> menuItems, ICollection<TrackAsset> parentTracks, WindowState state, string format = null)
- {
- if (parentTracks == null)
- parentTracks = new TrackAsset[0];
- if (string.IsNullOrEmpty(format))
- format = "{0}";
- // Add Group or SubGroup
- var title = string.Format(format, parentTracks.Any(t => t != null) ? Styles.trackSubGroup : Styles.trackGroup);
- var menuState = MenuActionDisplayState.Visible;
- if (state.editSequence.isReadOnly)
- menuState = MenuActionDisplayState.Disabled;
- if (parentTracks.Any() && parentTracks.Any(t => t != null && t.lockedInHierarchy))
- menuState = MenuActionDisplayState.Disabled;
- GenericMenu.MenuFunction command = () =>
- {
- SelectionManager.Clear();
- if (parentTracks.Count == 0)
- Selection.Add(TimelineHelpers.CreateTrack<GroupTrack>(null, title));
- foreach (var parentTrack in parentTracks)
- Selection.Add(TimelineHelpers.CreateTrack<GroupTrack>(parentTrack, title));
- TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
- };
- menuItems.Add(
- new MenuActionItem()
- {
- category = string.Empty,
- entryName = title,
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = MenuOrder.AddGroupItemStart,
- state = menuState,
- callback = command
- }
- );
- var allTypes = TypeUtility.AllTrackTypes().Where(x => x != typeof(GroupTrack) && !TypeUtility.IsHiddenInMenu(x)).ToList();
- int builtInPriority = MenuOrder.AddTrackItemStart;
- int customPriority = MenuOrder.AddCustomTrackItemStart;
- foreach (var trackType in allTypes)
- {
- var trackItemType = trackType;
- command = () =>
- {
- SelectionManager.Clear();
- if (parentTracks.Count == 0)
- SelectionManager.Add(TimelineHelpers.CreateTrack((Type)trackItemType, null));
- foreach (var parentTrack in parentTracks)
- SelectionManager.Add(TimelineHelpers.CreateTrack((Type)trackItemType, parentTrack));
- };
- menuItems.Add(
- new MenuActionItem()
- {
- category = TimelineHelpers.GetTrackCategoryName(trackType),
- entryName = string.Format(format, TimelineHelpers.GetTrackMenuName(trackItemType)),
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = TypeUtility.IsBuiltIn(trackType) ? builtInPriority++ : customPriority++,
- state = menuState,
- callback = command
- }
- );
- }
- }
- internal static void BuildMarkerHeaderContextMenu(List<MenuActionItem> menu, Vector2? mousePosition, WindowState state)
- {
- TimelineAction.GetMenuEntries(MarkerHeaderMenuItems, null, menu);
- var timeline = state.editSequence.asset;
- var time = TimelineHelpers.GetCandidateTime(state, mousePosition);
- var enabled = timeline.markerTrack == null || !timeline.markerTrack.lockedInHierarchy;
- var addMarkerCommand = new Action<Type, Object>
- (
- (type, obj) => AddSingleMarkerCallback(type, time, timeline, state.editSequence.director, obj)
- );
- AddMarkerMenuCommands(menu, new TrackAsset[] {timeline.markerTrack}, addMarkerCommand, enabled);
- }
- internal static void BuildTrackContextMenu(List<MenuActionItem> items, TrackAsset[] tracks, Vector2? mousePosition)
- {
- if (tracks == null || tracks.Length == 0)
- return;
- TimelineAction.GetMenuEntries(TimelineAction.MenuActions, mousePosition, items);
- TrackAction.GetMenuEntries(TimelineWindow.instance.state, mousePosition, tracks, items);
- AddLayeredTrackCommands(items, tracks);
- var first = tracks.First().GetType();
- var allTheSame = tracks.All(t => t.GetType() == first);
- if (allTheSame)
- {
- if (first != typeof(GroupTrack))
- {
- var candidateTime = TimelineHelpers.GetCandidateTime(TimelineWindow.instance.state, mousePosition, tracks);
- AddClipMenuCommands(items, tracks, candidateTime);
- AddMarkerMenuCommands(items, tracks, candidateTime);
- }
- else
- {
- BuildNewTracksContextMenu(items, tracks, TimelineWindow.instance.state, Styles.addItemTemplate);
- }
- }
- }
- static void AddLayeredTrackCommands(List<MenuActionItem> menuItems, ICollection<TrackAsset> tracks)
- {
- if (tracks.Count == 0)
- return;
- var layeredType = tracks.First().GetType();
- // animation tracks have a special menu.
- if (layeredType == typeof(AnimationTrack))
- return;
- // must implement ILayerable
- if (!typeof(UnityEngine.Timeline.ILayerable).IsAssignableFrom(layeredType))
- return;
- if (tracks.Any(t => t.GetType() != layeredType))
- return;
- // only supported on the master track no nesting.
- if (tracks.Any(t => t.isSubTrack))
- return;
- var enabled = tracks.All(t => t != null && !t.lockedInHierarchy) && !TimelineWindow.instance.state.editSequence.isReadOnly;
- int priority = MenuOrder.TrackAddMenu.AddLayerTrack;
- GenericMenu.MenuFunction menuCallback = () =>
- {
- foreach (var track in tracks)
- TimelineHelpers.CreateTrack(layeredType, track, string.Format(Styles.layerName, track.GetChildTracks().Count() + 1));
- };
- var entryName = Styles.addTrackLayer;
- menuItems.Add(
- new MenuActionItem()
- {
- category = string.Empty,
- entryName = entryName,
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = priority++,
- state = enabled ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled,
- callback = menuCallback
- }
- );
- }
- static void AddClipMenuCommands(List<MenuActionItem> menuItems, ICollection<TrackAsset> tracks, double candidateTime)
- {
- if (!tracks.Any())
- return;
- var trackAsset = tracks.First();
- var trackType = trackAsset.GetType();
- if (tracks.Any(t => t.GetType() != trackType))
- return;
- var enabled = tracks.All(t => t != null && !t.lockedInHierarchy) && !TimelineWindow.instance.state.editSequence.isReadOnly;
- var assetTypes = TypeUtility.GetPlayableAssetsHandledByTrack(trackType);
- var visibleAssetTypes = TypeUtility.GetVisiblePlayableAssetsHandledByTrack(trackType);
- // skips the name if there is only a single type
- var commandNameTemplate = assetTypes.Count() == 1 ? Styles.addSingleItemFromAssetTemplate : Styles.addItemFromAssetTemplate;
- int builtInPriority = MenuOrder.AddClipItemStart;
- int customPriority = MenuOrder.AddCustomClipItemStart;
- foreach (var assetType in assetTypes)
- {
- var assetItemType = assetType;
- var category = TimelineHelpers.GetItemCategoryName(assetType);
- Action<Object> onObjectChanged = obj =>
- {
- if (obj != null)
- {
- foreach (var t in tracks)
- {
- TimelineHelpers.CreateClipOnTrack(assetItemType, obj, t, candidateTime);
- }
- }
- };
- foreach (var objectReference in TypeUtility.ObjectReferencesForType(assetType))
- {
- var isSceneReference = objectReference.isSceneReference;
- var dataType = objectReference.type;
- GenericMenu.MenuFunction menuCallback = () =>
- {
- ObjectSelector.get.Show(null, dataType, null, isSceneReference, null, (obj) => onObjectChanged(obj), null);
- ObjectSelector.get.titleContent = EditorGUIUtility.TrTextContent(string.Format(Styles.typeSelectorTemplate, TypeUtility.GetDisplayName(dataType)));
- };
- menuItems.Add(
- new MenuActionItem()
- {
- category = category,
- entryName = string.Format(commandNameTemplate, TypeUtility.GetDisplayName(assetType), TypeUtility.GetDisplayName(objectReference.type)),
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = TypeUtility.IsBuiltIn(assetType) ? builtInPriority++ : customPriority++,
- state = enabled ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled,
- callback = menuCallback
- }
- );
- }
- }
- foreach (var assetType in visibleAssetTypes)
- {
- var assetItemType = assetType;
- var category = TimelineHelpers.GetItemCategoryName(assetType);
- var commandName = string.Format(Styles.addItemTemplate, TypeUtility.GetDisplayName(assetType));
- GenericMenu.MenuFunction command = () =>
- {
- foreach (var t in tracks)
- {
- TimelineHelpers.CreateClipOnTrack(assetItemType, t, candidateTime);
- }
- };
- menuItems.Add(
- new MenuActionItem()
- {
- category = category,
- entryName = commandName,
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = TypeUtility.IsBuiltIn(assetItemType) ? builtInPriority++ : customPriority++,
- state = enabled ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled,
- callback = command
- }
- );
- }
- }
- static void AddMarkerMenuCommands(List<MenuActionItem> menu, IEnumerable<Type> markerTypes, Action<Type, Object> addMarkerCommand, bool enabled)
- {
- int builtInPriority = MenuOrder.AddMarkerItemStart;
- int customPriority = MenuOrder.AddCustomMarkerItemStart;
- foreach (var markerType in markerTypes)
- {
- var markerItemType = markerType;
- string category = TimelineHelpers.GetItemCategoryName(markerItemType);
- menu.Add(
- new MenuActionItem()
- {
- category = category,
- entryName = string.Format(Styles.addItemTemplate, TypeUtility.GetDisplayName(markerType)),
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = TypeUtility.IsBuiltIn(markerType) ? builtInPriority++ : customPriority++,
- state = enabled ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled,
- callback = () => addMarkerCommand(markerItemType, null)
- }
- );
- foreach (var objectReference in TypeUtility.ObjectReferencesForType(markerType))
- {
- var isSceneReference = objectReference.isSceneReference;
- GenericMenu.MenuFunction menuCallback = () =>
- {
- var dataType = markerItemType;
- ObjectSelector.get.Show(null, dataType, null, isSceneReference, null, (obj) => addMarkerCommand(markerItemType, obj), null);
- ObjectSelector.get.titleContent = EditorGUIUtility.TrTextContent(string.Format(Styles.typeSelectorTemplate, TypeUtility.GetDisplayName(dataType)));
- };
- menu.Add(
- new MenuActionItem()
- {
- category = TimelineHelpers.GetItemCategoryName(markerItemType),
- entryName = string.Format(Styles.addItemFromAssetTemplate, TypeUtility.GetDisplayName(markerType), TypeUtility.GetDisplayName(objectReference.type)),
- shortCut = string.Empty,
- isActiveInMode = true,
- isChecked = false,
- priority = TypeUtility.IsBuiltIn(markerType) ? builtInPriority++ : customPriority++,
- state = enabled ? MenuActionDisplayState.Visible : MenuActionDisplayState.Disabled,
- callback = menuCallback
- }
- );
- }
- }
- }
- static void AddMarkerMenuCommands(List<MenuActionItem> menuItems, ICollection<TrackAsset> tracks, double candidateTime)
- {
- if (tracks.Count == 0)
- return;
- var enabled = tracks.All(t => !t.lockedInHierarchy) && !TimelineWindow.instance.state.editSequence.isReadOnly;
- var addMarkerCommand = new Action<Type, Object>((type, obj) => AddMarkersCallback(tracks, type, candidateTime, obj));
- AddMarkerMenuCommands(menuItems, tracks, addMarkerCommand, enabled);
- }
- static void AddMarkerMenuCommands(List<MenuActionItem> menuItems, ICollection<TrackAsset> tracks, Action<Type, Object> command, bool enabled)
- {
- var markerTypes = TypeUtility.GetBuiltInMarkerTypes().Union(TypeUtility.GetUserMarkerTypes());
- if (tracks != null)
- markerTypes = markerTypes.Where(x => tracks.All(track => (track == null) || TypeUtility.DoesTrackSupportMarkerType(track, x))); // null track indicates marker track to be created
- AddMarkerMenuCommands(menuItems, markerTypes, command, enabled);
- }
- static void AddMarkersCallback(ICollection<TrackAsset> targets, Type markerType, double time, Object obj)
- {
- SelectionManager.Clear();
- foreach (var target in targets)
- {
- var marker = TimelineHelpers.CreateMarkerOnTrack(markerType, obj, target, time);
- SelectionManager.Add(marker);
- }
- TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
- }
- static void AddSingleMarkerCallback(Type markerType, double time, TimelineAsset timeline, PlayableDirector director, Object assignableObject)
- {
- timeline.CreateMarkerTrack();
- var markerTrack = timeline.markerTrack;
- SelectionManager.Clear();
- var marker = TimelineHelpers.CreateMarkerOnTrack(markerType, assignableObject, markerTrack, time);
- SelectionManager.Add(marker);
- if (typeof(INotification).IsAssignableFrom(markerType) && director != null)
- {
- if (director != null && director.GetGenericBinding(markerTrack) == null)
- director.SetGenericBinding(markerTrack, director.gameObject);
- }
- TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
- }
- }
- }
|