Maze / Library /PackageCache /com.unity.timeline@1.6.5 /Editor /Actions /Menus /TimelineContextMenu.cs
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using UnityEditor.Timeline.Actions; | |
| using UnityEngine; | |
| using UnityEngine.Timeline; | |
| using Object = UnityEngine.Object; | |
| namespace UnityEditor.Timeline | |
| { | |
| static class SequencerContextMenu | |
| { | |
| 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 ShowNewTracksContextMenu(ICollection<TrackAsset> tracks, WindowState state) | |
| { | |
| var menu = new GenericMenu(); | |
| List<MenuActionItem> items = new List<MenuActionItem>(100); | |
| BuildNewTracksContextMenu(items, tracks, state); | |
| ActionManager.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); | |
| ActionManager.BuildMenu(menu, items); | |
| menu.DropDown(rect); | |
| } | |
| public static void ShowTrackContextMenu(Vector2? mousePosition) | |
| { | |
| var items = new List<MenuActionItem>(); | |
| var menu = new GenericMenu(); | |
| BuildTrackContextMenu(items, mousePosition); | |
| ActionManager.BuildMenu(menu, items); | |
| menu.ShowAsContext(); | |
| } | |
| public static void ShowItemContextMenu(Vector2 mousePosition) | |
| { | |
| var menu = new GenericMenu(); | |
| var items = new List<MenuActionItem>(); | |
| BuildItemContextMenu(items, mousePosition); | |
| ActionManager.BuildMenu(menu, items); | |
| menu.ShowAsContext(); | |
| } | |
| public static void BuildItemContextMenu(List<MenuActionItem> items, Vector2 mousePosition) | |
| { | |
| ActionManager.GetMenuEntries(ActionManager.TimelineActions, mousePosition, items); | |
| ActionManager.GetMenuEntries(ActionManager.ClipActions, items); | |
| ActionManager.GetMenuEntries(ActionManager.MarkerActions, items); | |
| var clips = TimelineEditor.selectedClips; | |
| if (clips.Length > 0) | |
| AddMarkerMenuCommands(items, clips.Select(c => c.GetParentTrack()).Distinct().ToList(), TimelineHelpers.GetCandidateTime(mousePosition)); | |
| } | |
| public 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 = ActionValidity.Valid; | |
| if (state.editSequence.isReadOnly) | |
| menuState = ActionValidity.Invalid; | |
| if (parentTracks.Any() && parentTracks.Any(t => t != null && t.lockedInHierarchy)) | |
| menuState = ActionValidity.Invalid; | |
| 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, | |
| isActiveInMode = true, | |
| priority = MenuPriority.AddItem.addGroup, | |
| state = menuState, | |
| isChecked = false, | |
| callback = command | |
| } | |
| ); | |
| var allTypes = TypeUtility.AllTrackTypes().Where(x => x != typeof(GroupTrack) && !TypeUtility.IsHiddenInMenu(x)).ToList(); | |
| int builtInPriority = MenuPriority.AddItem.addTrack; | |
| int customPriority = MenuPriority.AddItem.addCustomTrack; | |
| 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)), | |
| isActiveInMode = true, | |
| priority = TypeUtility.IsBuiltIn(trackType) ? builtInPriority++ : customPriority++, | |
| state = menuState, | |
| callback = command | |
| } | |
| ); | |
| } | |
| } | |
| public static void BuildTrackContextMenu(List<MenuActionItem> items, Vector2? mousePosition) | |
| { | |
| var tracks = SelectionManager.SelectedTracks().ToArray(); | |
| if (tracks.Length == 0) | |
| return; | |
| ActionManager.GetMenuEntries(ActionManager.TimelineActions, mousePosition, items); | |
| ActionManager.GetMenuEntries(ActionManager.TrackActions, 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(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 = MenuPriority.AddTrackMenu.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, | |
| isActiveInMode = true, | |
| priority = priority++, | |
| state = enabled ? ActionValidity.Valid : ActionValidity.Invalid, | |
| 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 = MenuPriority.AddItem.addClip; | |
| int customPriority = MenuPriority.AddItem.addCustomClip; | |
| 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)), | |
| isActiveInMode = true, | |
| priority = TypeUtility.IsBuiltIn(assetType) ? builtInPriority++ : customPriority++, | |
| state = enabled ? ActionValidity.Valid : ActionValidity.Invalid, | |
| 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, | |
| isActiveInMode = true, | |
| priority = TypeUtility.IsBuiltIn(assetItemType) ? builtInPriority++ : customPriority++, | |
| state = enabled ? ActionValidity.Valid : ActionValidity.Invalid, | |
| callback = command | |
| } | |
| ); | |
| } | |
| } | |
| static void AddMarkerMenuCommands(List<MenuActionItem> menu, IEnumerable<Type> markerTypes, Action<Type, Object> addMarkerCommand, bool enabled) | |
| { | |
| int builtInPriority = MenuPriority.AddItem.addMarker; | |
| int customPriority = MenuPriority.AddItem.addCustomMarker; | |
| 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)), | |
| isActiveInMode = true, | |
| priority = TypeUtility.IsBuiltIn(markerType) ? builtInPriority++ : customPriority++, | |
| state = enabled ? ActionValidity.Valid : ActionValidity.Invalid, | |
| callback = () => addMarkerCommand(markerItemType, null) | |
| } | |
| ); | |
| foreach (var objectReference in TypeUtility.ObjectReferencesForType(markerType)) | |
| { | |
| var isSceneReference = objectReference.isSceneReference; | |
| GenericMenu.MenuFunction menuCallback = () => | |
| { | |
| Type assetDataType = objectReference.type; | |
| ObjectSelector.get.titleContent = EditorGUIUtility.TrTextContent(string.Format(Styles.typeSelectorTemplate, TypeUtility.GetDisplayName(assetDataType))); | |
| ObjectSelector.get.Show(null, assetDataType, null, isSceneReference, null, obj => | |
| { | |
| if (obj != null) | |
| addMarkerCommand(markerItemType, obj); | |
| }, null); | |
| }; | |
| menu.Add( | |
| new MenuActionItem | |
| { | |
| category = TimelineHelpers.GetItemCategoryName(markerItemType), | |
| entryName = string.Format(Styles.addItemFromAssetTemplate, TypeUtility.GetDisplayName(markerType), TypeUtility.GetDisplayName(objectReference.type)), | |
| isActiveInMode = true, | |
| priority = TypeUtility.IsBuiltIn(markerType) ? builtInPriority++ : customPriority++, | |
| state = enabled ? ActionValidity.Valid : ActionValidity.Invalid, | |
| 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); | |
| } | |
| } | |
| } | |