123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using UnityEngine;
- using UnityEngine.Timeline;
-
- namespace UnityEditor.Timeline.Actions
- {
- static class ActionManager
- {
- static bool s_ShowActionTriggeredByShortcut = false;
-
- public static readonly IReadOnlyList<TimelineAction> TimelineActions = InstantiateClassesOfType<TimelineAction>();
- public static readonly IReadOnlyList<ClipAction> ClipActions = InstantiateClassesOfType<ClipAction>();
- public static readonly IReadOnlyList<TrackAction> TrackActions = InstantiateClassesOfType<TrackAction>();
- public static readonly IReadOnlyList<MarkerAction> MarkerActions = InstantiateClassesOfType<MarkerAction>();
-
- public static readonly IReadOnlyList<TimelineAction> TimelineActionsWithShortcuts = ActionsWithShortCuts(TimelineActions);
- public static readonly IReadOnlyList<ClipAction> ClipActionsWithShortcuts = ActionsWithShortCuts(ClipActions);
- public static readonly IReadOnlyList<TrackAction> TrackActionsWithShortcuts = ActionsWithShortCuts(TrackActions);
- public static readonly IReadOnlyList<MarkerAction> MarkerActionsWithShortcuts = ActionsWithShortCuts(MarkerActions);
-
- public static readonly HashSet<Type> ActionsWithAutoUndo = TypesWithAttribute<ApplyDefaultUndoAttribute>();
-
- public static TU GetCachedAction<T, TU>(this IReadOnlyList<TU> list) where T : TU
- {
- return list.FirstOrDefault(x => x.GetType() == typeof(T));
- }
-
- public static void GetMenuEntries(IReadOnlyList<TimelineAction> actions, Vector2? mousePos, List<MenuActionItem> menuItems)
- {
- var globalContext = TimelineEditor.CurrentContext(mousePos);
- foreach (var action in actions)
- {
- try
- {
- BuildMenu(action, globalContext, menuItems);
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- }
-
- public static void GetMenuEntries(IReadOnlyList<TrackAction> actions, List<MenuActionItem> menuItems)
- {
- var tracks = SelectionManager.SelectedTracks();
- if (!tracks.Any())
- return;
-
- foreach (var action in actions)
- {
- try
- {
- BuildMenu(action, tracks, menuItems);
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- }
-
- public static void GetMenuEntries(IReadOnlyList<ClipAction> actions, List<MenuActionItem> menuItems)
- {
- var clips = SelectionManager.SelectedClips();
- bool any = clips.Any();
- if (!clips.Any())
- return;
-
- foreach (var action in actions)
- {
- try
- {
- if (action is EditSubTimeline editSubTimelineAction)
- editSubTimelineAction.AddMenuItem(menuItems);
- else if (any)
- BuildMenu(action, clips, menuItems);
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- }
-
- public static void GetMenuEntries(IReadOnlyList<MarkerAction> actions, List<MenuActionItem> menuItems)
- {
- var markers = SelectionManager.SelectedMarkers();
- if (!markers.Any())
- return;
-
- foreach (var action in actions)
- {
- try
- {
- BuildMenu(action, markers, menuItems);
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- }
-
- static void BuildMenu(TimelineAction action, ActionContext context, List<MenuActionItem> menuItems)
- {
- BuildMenu(action, action.Validate(context), () => ExecuteTimelineAction(action, context), menuItems);
- }
-
- static void BuildMenu(TrackAction action, IEnumerable<TrackAsset> tracks, List<MenuActionItem> menuItems)
- {
- BuildMenu(action, action.Validate(tracks), () => ExecuteTrackAction(action, tracks), menuItems);
- }
-
- static void BuildMenu(ClipAction action, IEnumerable<TimelineClip> clips, List<MenuActionItem> menuItems)
- {
- BuildMenu(action, action.Validate(clips), () => ExecuteClipAction(action, clips), menuItems);
- }
-
- static void BuildMenu(MarkerAction action, IEnumerable<IMarker> markers, List<MenuActionItem> menuItems)
- {
- BuildMenu(action, action.Validate(markers), () => ExecuteMarkerAction(action, markers), menuItems);
- }
-
- static void BuildMenu(IAction action, ActionValidity validity, GenericMenu.MenuFunction executeFunction, List<MenuActionItem> menuItems)
- {
- var menuAttribute = action.GetType().GetCustomAttribute<MenuEntryAttribute>(false);
- if (menuAttribute == null)
- return;
-
- if (validity == ActionValidity.NotApplicable)
- return;
-
- var menuActionItem = new MenuActionItem
- {
- state = validity,
- entryName = action.GetMenuEntryName(),
- priority = menuAttribute.priority,
- category = menuAttribute.subMenuPath,
- isActiveInMode = action.IsActionActiveInMode(TimelineWindow.instance.currentMode.mode),
- shortCut = action.GetShortcut(),
- callback = executeFunction,
- isChecked = action.IsChecked()
- };
- menuItems.Add(menuActionItem);
- }
-
- internal static void BuildMenu(GenericMenu menu, List<MenuActionItem> items)
- {
- // sorted the outer menu by priority, then sort the innermenu by priority
- var sortedItems =
- items.GroupBy(x => string.IsNullOrEmpty(x.category) ? x.entryName : x.category).OrderBy(x => x.Min(y => y.priority)).SelectMany(x => x.OrderBy(z => z.priority));
-
- int lastPriority = Int32.MinValue;
- string lastCategory = string.Empty;
-
- foreach (var s in sortedItems)
- {
- if (s.state == ActionValidity.NotApplicable)
- continue;
-
- var priority = s.priority;
- if (lastPriority != int.MinValue && priority / MenuPriority.separatorAt > lastPriority / MenuPriority.separatorAt)
- {
- string path = string.Empty;
- if (lastCategory == s.category)
- path = s.category;
- menu.AddSeparator(path);
- }
-
- lastPriority = priority;
- lastCategory = s.category;
-
- string entry = s.category + s.entryName;
- if (!string.IsNullOrEmpty(s.shortCut))
- entry += " " + s.shortCut;
-
- if (s.state == ActionValidity.Valid && s.isActiveInMode)
- menu.AddItem(new GUIContent(entry), s.isChecked, s.callback);
- else
- menu.AddDisabledItem(new GUIContent(entry), s.isChecked);
- }
- }
-
- public static bool HandleShortcut(Event evt)
- {
- if (EditorGUI.IsEditingTextField())
- return false;
-
- return HandleShortcut(evt, TimelineActionsWithShortcuts, (x) => ExecuteTimelineAction(x, TimelineEditor.CurrentContext())) ||
- HandleShortcut(evt, ClipActionsWithShortcuts, (x => ExecuteClipAction(x, SelectionManager.SelectedClips()))) ||
- HandleShortcut(evt, TrackActionsWithShortcuts, (x => ExecuteTrackAction(x, SelectionManager.SelectedTracks()))) ||
- HandleShortcut(evt, MarkerActionsWithShortcuts, (x => ExecuteMarkerAction(x, SelectionManager.SelectedMarkers())));
- }
-
- public static bool HandleShortcut<T>(Event evt, IReadOnlyList<T> actions, Func<T, bool> invoke) where T : class, IAction
- {
- for (int i = 0; i < actions.Count; i++)
- {
- var action = actions[i];
- var attr = action.GetType().GetCustomAttributes(typeof(ShortcutAttribute), true);
-
- foreach (ShortcutAttribute shortcut in attr)
- {
- if (shortcut.MatchesEvent(evt))
- {
- if (s_ShowActionTriggeredByShortcut)
- Debug.Log(action.GetType().Name);
-
- if (!action.IsActionActiveInMode(TimelineWindow.instance.currentMode.mode))
- continue;
-
- if (invoke(action))
- return true;
- }
- }
- }
-
- return false;
- }
-
- public static bool ExecuteTimelineAction(TimelineAction timelineAction, ActionContext context)
- {
- if (timelineAction.Validate(context) == ActionValidity.Valid)
- {
- if (timelineAction.HasAutoUndo())
- UndoExtensions.RegisterContext(context, timelineAction.GetUndoName());
- return timelineAction.Execute(context);
- }
- return false;
- }
-
- public static bool ExecuteTrackAction(TrackAction trackAction, IEnumerable<TrackAsset> tracks)
- {
- if (tracks != null && tracks.Any() && trackAction.Validate(tracks) == ActionValidity.Valid)
- {
- if (trackAction.HasAutoUndo())
- UndoExtensions.RegisterTracks(tracks, trackAction.GetUndoName());
- return trackAction.Execute(tracks);
- }
- return false;
- }
-
- public static bool ExecuteClipAction(ClipAction clipAction, IEnumerable<TimelineClip> clips)
- {
- if (clips != null && clips.Any() && clipAction.Validate(clips) == ActionValidity.Valid)
- {
- if (clipAction.HasAutoUndo())
- UndoExtensions.RegisterClips(clips, clipAction.GetUndoName());
- return clipAction.Execute(clips);
- }
- return false;
- }
-
- public static bool ExecuteMarkerAction(MarkerAction markerAction, IEnumerable<IMarker> markers)
- {
- if (markers != null && markers.Any() && markerAction.Validate(markers) == ActionValidity.Valid)
- {
- if (markerAction.HasAutoUndo())
- UndoExtensions.RegisterMarkers(markers, markerAction.GetUndoName());
- return markerAction.Execute(markers);
- }
- return false;
- }
-
- static List<T> InstantiateClassesOfType<T>() where T : class
- {
- var typeCollection = TypeCache.GetTypesDerivedFrom(typeof(T));
- var list = new List<T>(typeCollection.Count);
- for (int i = 0; i < typeCollection.Count; i++)
- {
- if (typeCollection[i].IsAbstract || typeCollection[i].IsGenericType)
- continue;
-
- if (typeCollection[i].GetConstructor(Type.EmptyTypes) == null)
- {
- Debug.LogWarning($"{typeCollection[i].FullName} requires a default constructor to be automatically instantiated by Timeline");
- continue;
- }
-
- list.Add((T)Activator.CreateInstance(typeCollection[i]));
- }
- return list;
- }
-
- static List<T> ActionsWithShortCuts<T>(IReadOnlyList<T> list)
- {
- return list.Where(x => x.GetType().GetCustomAttributes(typeof(ShortcutAttribute), true).Length > 0).ToList();
- }
-
- static HashSet<System.Type> TypesWithAttribute<T>() where T : Attribute
- {
- var hashSet = new HashSet<System.Type>();
- var typeCollection = TypeCache.GetTypesWithAttribute(typeof(T));
- for (int i = 0; i < typeCollection.Count; i++)
- {
- hashSet.Add(typeCollection[i]);
- }
-
- return hashSet;
- }
- }
- }
|