first commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Action context to be used by actions.
|
||||
/// </summary>
|
||||
/// <seealso cref="Invoker"/>
|
||||
/// <seealso cref="TimelineAction"/>
|
||||
public struct ActionContext
|
||||
{
|
||||
IEnumerable<TrackAsset> m_Tracks;
|
||||
IEnumerable<TimelineClip> m_Clips;
|
||||
IEnumerable<IMarker> m_Markers;
|
||||
|
||||
/// <summary>
|
||||
/// The Timeline asset that is currently opened in the Timeline window.
|
||||
/// </summary>
|
||||
public TimelineAsset timeline;
|
||||
|
||||
/// <summary>
|
||||
/// The PlayableDirector that is used to play the current Timeline asset.
|
||||
/// </summary>
|
||||
public PlayableDirector director;
|
||||
|
||||
/// <summary>
|
||||
/// Time based on the position of the cursor on the timeline (in seconds).
|
||||
/// null if the time is not available (in case of a shortcut for example).
|
||||
/// </summary>
|
||||
public double? invocationTime;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks that will be used by the actions.
|
||||
/// </summary>
|
||||
public IEnumerable<TrackAsset> tracks
|
||||
{
|
||||
get => m_Tracks ?? Enumerable.Empty<TrackAsset>();
|
||||
set => m_Tracks = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clips that will be used by the actions.
|
||||
/// </summary>
|
||||
public IEnumerable<TimelineClip> clips
|
||||
{
|
||||
get => m_Clips ?? Enumerable.Empty<TimelineClip>();
|
||||
set => m_Clips = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Markers that will be used by the actions.
|
||||
/// </summary>
|
||||
public IEnumerable<IMarker> markers
|
||||
{
|
||||
get => m_Markers ?? Enumerable.Empty<IMarker>();
|
||||
set => m_Markers = value;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e79d50dea5c9c74d9297cce6cd6d053
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,306 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b185b14d428805c46aceb7c663825b2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a clip action.
|
||||
/// Inherit from this class to make an action that would react on selected clips after a menu click and/or a key shortcut.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Simple Clip Action example (with context menu and shortcut support).
|
||||
/// <code source="../../DocCodeExamples/ActionExamples.cs" region="declare-sampleClipAction" title="SampleClipAction"/>
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// To add an action as a menu item in the Timeline context menu, add <see cref="MenuEntryAttribute"/> on the action class.
|
||||
/// To make an action to react to a shortcut, use the Shortcut Manager API with <see cref="TimelineShortcutAttribute"/>.
|
||||
/// <seealso cref="UnityEditor.ShortcutManagement.ShortcutAttribute"/>
|
||||
/// </remarks>
|
||||
[ActiveInMode(TimelineModes.Default)]
|
||||
public abstract class ClipAction : IAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Execute the action based on clips.
|
||||
/// </summary>
|
||||
/// <param name="clips">clips that the action will act on.</param>
|
||||
/// <returns>Returns true if the action has been correctly executed, false otherwise.</returns>
|
||||
public abstract bool Execute(IEnumerable<TimelineClip> clips);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the validity of an Action for a given set of clips.
|
||||
/// </summary>
|
||||
/// <param name="clips">The clips that the action will act on.</param>
|
||||
/// <returns>The validity of the set of clips.</returns>
|
||||
public abstract ActionValidity Validate(IEnumerable<TimelineClip> clips);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa130a47ff26ad84f867961fc32334af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,392 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEditor.Timeline.Actions;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEditor.Timeline
|
||||
{
|
||||
[MenuEntry("Edit in Animation Window", MenuPriority.ClipEditActionSection.editInAnimationWindow), UsedImplicitly]
|
||||
class EditClipInAnimationWindow : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
if (!GetEditableClip(clips, out _, out _))
|
||||
return ActionValidity.NotApplicable;
|
||||
return ActionValidity.Valid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
TimelineClip clip;
|
||||
AnimationClip clipToEdit;
|
||||
if (!GetEditableClip(clips, out clip, out clipToEdit))
|
||||
return false;
|
||||
|
||||
GameObject gameObject = null;
|
||||
if (TimelineEditor.inspectedDirector != null)
|
||||
gameObject = TimelineUtility.GetSceneGameObject(TimelineEditor.inspectedDirector, clip.GetParentTrack());
|
||||
|
||||
var timeController = TimelineAnimationUtilities.CreateTimeController(clip);
|
||||
TimelineAnimationUtilities.EditAnimationClipWithTimeController(
|
||||
clipToEdit, timeController, clip.animationClip != null ? gameObject : null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool GetEditableClip(IEnumerable<TimelineClip> clips, out TimelineClip clip, out AnimationClip animClip)
|
||||
{
|
||||
clip = null;
|
||||
animClip = null;
|
||||
|
||||
if (clips.Count() != 1)
|
||||
return false;
|
||||
|
||||
clip = clips.FirstOrDefault();
|
||||
if (clip == null)
|
||||
return false;
|
||||
|
||||
if (clip.animationClip != null)
|
||||
animClip = clip.animationClip;
|
||||
else if (clip.curves != null && !clip.curves.empty)
|
||||
animClip = clip.curves;
|
||||
|
||||
return animClip != null;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Edit Sub-Timeline", MenuPriority.ClipEditActionSection.editSubTimeline), UsedImplicitly]
|
||||
class EditSubTimeline : ClipAction
|
||||
{
|
||||
private static readonly string MultiItemPrefix = "Edit Sub-Timelines/";
|
||||
private static readonly string SingleItemPrefix = "Edit ";
|
||||
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
if (clips == null || clips.Count() != 1 || TimelineEditor.inspectedDirector == null)
|
||||
return ActionValidity.NotApplicable;
|
||||
|
||||
var clip = clips.First();
|
||||
var directors = TimelineUtility.GetSubTimelines(clip, TimelineEditor.inspectedDirector);
|
||||
return directors.Any(x => x != null) ? ActionValidity.Valid : ActionValidity.NotApplicable;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
if (Validate(clips) != ActionValidity.Valid) return false;
|
||||
|
||||
var clip = clips.First();
|
||||
|
||||
var directors = TimelineUtility.GetSubTimelines(clip, TimelineEditor.inspectedDirector);
|
||||
ExecuteInternal(directors, 0, clip);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ExecuteInternal(IList<PlayableDirector> directors, int directorIndex, TimelineClip clip)
|
||||
{
|
||||
SelectionManager.Clear();
|
||||
TimelineWindow.instance.SetCurrentTimeline(directors[directorIndex], clip);
|
||||
}
|
||||
|
||||
internal void AddMenuItem(List<MenuActionItem> menuItems)
|
||||
{
|
||||
var clips = TimelineEditor.selectedClips;
|
||||
if (clips == null || clips.Length != 1)
|
||||
return;
|
||||
|
||||
var mode = TimelineWindow.instance.currentMode.mode;
|
||||
MenuEntryAttribute menuAttribute = GetType().GetCustomAttributes(typeof(MenuEntryAttribute), false).OfType<MenuEntryAttribute>().FirstOrDefault();
|
||||
var menuItem = new MenuActionItem()
|
||||
{
|
||||
category = menuAttribute.subMenuPath ?? string.Empty,
|
||||
entryName = menuAttribute.name,
|
||||
isActiveInMode = this.IsActionActiveInMode(mode),
|
||||
priority = menuAttribute.priority,
|
||||
state = Validate(clips),
|
||||
callback = null
|
||||
};
|
||||
|
||||
var subDirectors = TimelineUtility.GetSubTimelines(clips[0], TimelineEditor.inspectedDirector);
|
||||
if (subDirectors.Count == 1)
|
||||
{
|
||||
menuItem.entryName = SingleItemPrefix + DisplayNameHelper.GetDisplayName(subDirectors[0]);
|
||||
menuItem.callback = () =>
|
||||
{
|
||||
Execute(clips);
|
||||
};
|
||||
menuItems.Add(menuItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < subDirectors.Count; i++)
|
||||
{
|
||||
var index = i;
|
||||
menuItem.category = MultiItemPrefix;
|
||||
menuItem.entryName = DisplayNameHelper.GetDisplayName(subDirectors[i]);
|
||||
menuItem.callback = () =>
|
||||
{
|
||||
ExecuteInternal(subDirectors, index, clips[0]);
|
||||
};
|
||||
menuItems.Add(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Trim Start", MenuPriority.ClipActionSection.trimStart)]
|
||||
[Shortcut(Shortcuts.Clip.trimStart), UsedImplicitly]
|
||||
class TrimStart : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return clips.All(x => TimelineEditor.inspectedSequenceTime <= x.start || TimelineEditor.inspectedSequenceTime >= x.start + x.duration) ? ActionValidity.Invalid : ActionValidity.Valid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.TrimStart(clips, TimelineEditor.inspectedSequenceTime);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Trim End", MenuPriority.ClipActionSection.trimEnd), UsedImplicitly]
|
||||
[Shortcut(Shortcuts.Clip.trimEnd)]
|
||||
class TrimEnd : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return clips.All(x => TimelineEditor.inspectedSequenceTime <= x.start || TimelineEditor.inspectedSequenceTime >= x.start + x.duration) ? ActionValidity.Invalid : ActionValidity.Valid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.TrimEnd(clips, TimelineEditor.inspectedSequenceTime);
|
||||
}
|
||||
}
|
||||
|
||||
[Shortcut(Shortcuts.Clip.split)]
|
||||
[MenuEntry("Editing/Split", MenuPriority.ClipActionSection.split), UsedImplicitly]
|
||||
class Split : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return clips.All(x => TimelineEditor.inspectedSequenceTime <= x.start || TimelineEditor.inspectedSequenceTime >= x.start + x.duration) ? ActionValidity.Invalid : ActionValidity.Valid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool success = ClipModifier.Split(clips, TimelineEditor.inspectedSequenceTime, TimelineEditor.inspectedDirector);
|
||||
if (success)
|
||||
TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Complete Last Loop", MenuPriority.ClipActionSection.completeLastLoop), UsedImplicitly]
|
||||
class CompleteLastLoop : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration);
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.CompleteLastLoop(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Trim Last Loop", MenuPriority.ClipActionSection.trimLastLoop), UsedImplicitly]
|
||||
class TrimLastLoop : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration);
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.TrimLastLoop(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Match Duration", MenuPriority.ClipActionSection.matchDuration), UsedImplicitly]
|
||||
class MatchDuration : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return clips.Count() > 1 ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.MatchDuration(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Double Speed", MenuPriority.ClipActionSection.doubleSpeed), UsedImplicitly]
|
||||
class DoubleSpeed : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.All(x => x.SupportsSpeedMultiplier());
|
||||
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.DoubleSpeed(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Half Speed", MenuPriority.ClipActionSection.halfSpeed), UsedImplicitly]
|
||||
class HalfSpeed : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.All(x => x.SupportsSpeedMultiplier());
|
||||
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.HalfSpeed(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Reset Duration", MenuPriority.ClipActionSection.resetDuration), UsedImplicitly]
|
||||
class ResetDuration : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration);
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.ResetEditing(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Reset Speed", MenuPriority.ClipActionSection.resetSpeed), UsedImplicitly]
|
||||
class ResetSpeed : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.All(x => x.SupportsSpeedMultiplier());
|
||||
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.ResetSpeed(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Editing/Reset All", MenuPriority.ClipActionSection.resetAll), UsedImplicitly]
|
||||
class ResetAll : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
bool canDisplay = clips.Any(TimelineHelpers.HasUsableAssetDuration) || clips.All(x => x.SupportsSpeedMultiplier());
|
||||
|
||||
return canDisplay ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
var speedResult = ClipModifier.ResetSpeed(clips);
|
||||
var editResult = ClipModifier.ResetEditing(clips);
|
||||
return speedResult || editResult;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Tile", MenuPriority.ClipActionSection.tile), UsedImplicitly]
|
||||
class Tile : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return clips.Count() > 1 ? ActionValidity.Valid : ActionValidity.Invalid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
return ClipModifier.Tile(clips);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuEntry("Find Source Asset", MenuPriority.ClipActionSection.findSourceAsset), UsedImplicitly]
|
||||
[ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
|
||||
class FindSourceAsset : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
if (clips.Count() > 1)
|
||||
return ActionValidity.Invalid;
|
||||
|
||||
if (GetUnderlyingAsset(clips.First()) == null)
|
||||
return ActionValidity.Invalid;
|
||||
|
||||
return ActionValidity.Valid;
|
||||
}
|
||||
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
EditorGUIUtility.PingObject(GetUnderlyingAsset(clips.First()));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static UnityEngine.Object GetExternalPlayableAsset(TimelineClip clip)
|
||||
{
|
||||
if (clip.asset == null)
|
||||
return null;
|
||||
|
||||
if ((clip.asset.hideFlags & HideFlags.HideInHierarchy) != 0)
|
||||
return null;
|
||||
|
||||
return clip.asset;
|
||||
}
|
||||
|
||||
private static UnityEngine.Object GetUnderlyingAsset(TimelineClip clip)
|
||||
{
|
||||
var asset = clip.asset as ScriptableObject;
|
||||
if (asset == null)
|
||||
return null;
|
||||
|
||||
var fields = ObjectReferenceField.FindObjectReferences(asset.GetType());
|
||||
if (fields.Length == 0)
|
||||
return GetExternalPlayableAsset(clip);
|
||||
|
||||
// Find the first non-null field
|
||||
foreach (var field in fields)
|
||||
{
|
||||
// skip scene refs in asset mode
|
||||
if (TimelineEditor.inspectedDirector == null && field.isSceneReference)
|
||||
continue;
|
||||
var obj = field.Find(asset, TimelineEditor.inspectedDirector);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
}
|
||||
|
||||
return GetExternalPlayableAsset(clip);
|
||||
}
|
||||
}
|
||||
|
||||
class CopyClipsToClipboard : ClipAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<TimelineClip> clips) => ActionValidity.Valid;
|
||||
public override bool Execute(IEnumerable<TimelineClip> clips)
|
||||
{
|
||||
TimelineEditor.clipboard.CopyItems(clips.ToItems());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b721099b5d509d4093e516f59ad9ad6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor.ShortcutManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// interface indicating an Action class
|
||||
interface IAction { }
|
||||
|
||||
/// extension methods for IActions
|
||||
static class ActionExtensions
|
||||
{
|
||||
const string kActionPostFix = "Action";
|
||||
|
||||
public static string GetUndoName(this IAction action)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
|
||||
var attr = action.GetType().GetCustomAttribute<ApplyDefaultUndoAttribute>(false);
|
||||
if (attr != null && !string.IsNullOrWhiteSpace(attr.UndoTitle))
|
||||
return attr.UndoTitle;
|
||||
|
||||
return action.GetDisplayName();
|
||||
}
|
||||
|
||||
public static string GetMenuEntryName(this IAction action)
|
||||
{
|
||||
var menuAction = action as IMenuName;
|
||||
if (menuAction != null && !string.IsNullOrWhiteSpace(menuAction.menuName))
|
||||
return menuAction.menuName;
|
||||
|
||||
var attr = action.GetType().GetCustomAttribute<MenuEntryAttribute>(false);
|
||||
if (attr != null && !string.IsNullOrWhiteSpace(attr.name))
|
||||
return attr.name;
|
||||
|
||||
return action.GetDisplayName();
|
||||
}
|
||||
|
||||
public static string GetDisplayName(this IAction action)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
|
||||
var attr = action.GetType().GetCustomAttribute<DisplayNameAttribute>(false);
|
||||
if (attr != null && !string.IsNullOrEmpty(attr.DisplayName))
|
||||
return attr.DisplayName;
|
||||
|
||||
var name = action.GetType().Name;
|
||||
if (name.EndsWith(kActionPostFix))
|
||||
return ObjectNames.NicifyVariableName(name.Substring(0, name.Length - kActionPostFix.Length));
|
||||
|
||||
return ObjectNames.NicifyVariableName(name);
|
||||
}
|
||||
|
||||
public static bool HasAutoUndo(this IAction action)
|
||||
{
|
||||
return action != null && ActionManager.ActionsWithAutoUndo.Contains(action.GetType());
|
||||
}
|
||||
|
||||
public static bool IsChecked(this IAction action)
|
||||
{
|
||||
return (action is IMenuChecked menuAction) && menuAction.isChecked;
|
||||
}
|
||||
|
||||
public static bool IsActionActiveInMode(this IAction action, TimelineModes mode)
|
||||
{
|
||||
var attr = action.GetType().GetCustomAttribute<ActiveInModeAttribute>(true);
|
||||
return attr != null && (attr.modes & mode) != 0;
|
||||
}
|
||||
|
||||
public static string GetShortcut(this IAction action)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
|
||||
var shortcutAttribute = GetShortcutAttributeForAction(action);
|
||||
var shortCut = shortcutAttribute == null ? string.Empty : shortcutAttribute.GetMenuShortcut();
|
||||
if (string.IsNullOrWhiteSpace(shortCut))
|
||||
{
|
||||
//Check if there is a static method with attribute
|
||||
var customShortcutMethod = action.GetType().GetMethods().FirstOrDefault(m => m.GetCustomAttribute<TimelineShortcutAttribute>(true) != null);
|
||||
if (customShortcutMethod != null)
|
||||
{
|
||||
var shortcutId = customShortcutMethod.GetCustomAttribute<TimelineShortcutAttribute>(true).identifier;
|
||||
var shortcut = ShortcutIntegration.instance.directory.FindShortcutEntry(shortcutId);
|
||||
if (shortcut != null && shortcut.combinations.Any())
|
||||
shortCut = KeyCombination.SequenceToMenuString(shortcut.combinations);
|
||||
}
|
||||
}
|
||||
|
||||
return shortCut;
|
||||
}
|
||||
|
||||
static ShortcutAttribute GetShortcutAttributeForAction(this IAction action)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
|
||||
var shortcutAttributes = action.GetType()
|
||||
.GetCustomAttributes(typeof(ShortcutAttribute), true)
|
||||
.Cast<ShortcutAttribute>();
|
||||
|
||||
foreach (var shortcutAttribute in shortcutAttributes)
|
||||
{
|
||||
if (shortcutAttribute is ShortcutPlatformOverrideAttribute shortcutOverride)
|
||||
{
|
||||
if (shortcutOverride.MatchesCurrentPlatform())
|
||||
return shortcutOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shortcutAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de11c48878ba1b44b8b641af54dba8c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Timeline
|
||||
{
|
||||
interface IMenuChecked
|
||||
{
|
||||
bool isChecked { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0939c83f40ef46e584340aa87b3cadfe
|
||||
timeCreated: 1591130283
|
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Timeline
|
||||
{
|
||||
interface IMenuName
|
||||
{
|
||||
string menuName { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 512ac45650d443f3be59379c2ecbf068
|
||||
timeCreated: 1591130274
|
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing methods to invoke actions.
|
||||
/// </summary>
|
||||
public static class Invoker
|
||||
{
|
||||
/// <summary>
|
||||
/// Execute a given action with a context parameter.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <param name="context">Context for the action.</param>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool Invoke<T>(this ActionContext context) where T : TimelineAction
|
||||
{
|
||||
var action = ActionManager.TimelineActions.GetCachedAction<T, TimelineAction>();
|
||||
return ActionManager.ExecuteTimelineAction(action, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given action with tracks
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <param name="tracks">Tracks that the action will act on.</param>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool Invoke<T>(this IEnumerable<TrackAsset> tracks) where T : TrackAction
|
||||
{
|
||||
var action = ActionManager.TrackActions.GetCachedAction<T, TrackAction>();
|
||||
return ActionManager.ExecuteTrackAction(action, tracks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given action with clips
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <param name="clips">Clips that the action will act on.</param>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool Invoke<T>(this IEnumerable<TimelineClip> clips) where T : ClipAction
|
||||
{
|
||||
var action = ActionManager.ClipActions.GetCachedAction<T, ClipAction>();
|
||||
return ActionManager.ExecuteClipAction(action, clips);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given action with markers
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <param name="markers">Markers that the action will act on.</param>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool Invoke<T>(this IEnumerable<IMarker> markers) where T : MarkerAction
|
||||
{
|
||||
var action = ActionManager.MarkerActions.GetCachedAction<T, MarkerAction>();
|
||||
return ActionManager.ExecuteMarkerAction(action, markers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given timeline action with the selected clips, tracks and markers.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool InvokeWithSelected<T>() where T : TimelineAction
|
||||
{
|
||||
return Invoke<T>(TimelineEditor.CurrentContext());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given clip action with the selected clips.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool InvokeWithSelectedClips<T>() where T : ClipAction
|
||||
{
|
||||
return Invoke<T>(SelectionManager.SelectedClips());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given track action with the selected tracks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool InvokeWithSelectedTracks<T>() where T : TrackAction
|
||||
{
|
||||
return Invoke<T>(SelectionManager.SelectedTracks());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute a given marker action with the selected markers.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Action type to execute.</typeparam>
|
||||
/// <returns>True if the action has been executed, false otherwise.</returns>
|
||||
public static bool InvokeWithSelectedMarkers<T>() where T : MarkerAction
|
||||
{
|
||||
return Invoke<T>(SelectionManager.SelectedMarkers());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c379d496c819c14b8b5377d7830a59a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a marker action.
|
||||
/// Inherit from this class to make an action that would react on selected markers after a menu click and/or a key shortcut.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Simple track Action example (with context menu and shortcut support).
|
||||
/// <code source="../../DocCodeExamples/ActionExamples.cs" region="declare-sampleMarkerAction" title="SampleMarkerAction"/>
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// To add an action as a menu item in the Timeline context menu, add <see cref="MenuEntryAttribute"/> on the action class.
|
||||
/// To make an action to react to a shortcut, use the Shortcut Manager API with <see cref="TimelineShortcutAttribute"/>.
|
||||
/// <seealso cref="UnityEditor.ShortcutManagement.ShortcutAttribute"/>
|
||||
/// </remarks>
|
||||
[ActiveInMode(TimelineModes.Default)]
|
||||
public abstract class MarkerAction : IAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Execute the action.
|
||||
/// </summary>
|
||||
/// <param name="markers">Markers that will be used for the action. </param>
|
||||
/// <returns>true if the action has been executed. false otherwise</returns>
|
||||
public abstract bool Execute(IEnumerable<IMarker> markers);
|
||||
/// <summary>
|
||||
/// Defines the validity of an Action for a given set of markers.
|
||||
/// </summary>
|
||||
/// <param name="markers">Markers that will be used for the action. </param>
|
||||
/// <returns>The validity of the set of markers.</returns>
|
||||
public abstract ActionValidity Validate(IEnumerable<IMarker> markers);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03d19e545aea1b446b1c56530a4438ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEditor.Timeline.Actions;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline
|
||||
{
|
||||
[UsedImplicitly]
|
||||
class CopyMarkersToClipboard : MarkerAction
|
||||
{
|
||||
public override ActionValidity Validate(IEnumerable<IMarker> markers) => ActionValidity.Valid;
|
||||
|
||||
public override bool Execute(IEnumerable<IMarker> markers)
|
||||
{
|
||||
TimelineEditor.clipboard.CopyItems(markers.ToItems());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5da77d4d078922b4c8466e9e35fb3f5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 985eed4bc2fbee941b761b8816d9055d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,36 @@
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the validity of an action for a given data set.
|
||||
/// </summary>
|
||||
public enum ActionValidity
|
||||
{
|
||||
/// <summary>
|
||||
/// Action is valid in the provided context.
|
||||
/// If the action is linked to a menu item, the menu item will be visible.
|
||||
/// </summary>
|
||||
Valid,
|
||||
/// <summary>
|
||||
/// Action is not applicable in the current context.
|
||||
/// If the action is linked to a menu item, the menu item will not be shown.
|
||||
/// </summary>
|
||||
NotApplicable,
|
||||
/// <summary>
|
||||
/// Action is not valid in the current context.
|
||||
/// If the action is linked to a menu item, the menu item will be shown but grayed out.
|
||||
/// </summary>
|
||||
Invalid
|
||||
}
|
||||
|
||||
struct MenuActionItem
|
||||
{
|
||||
public string category;
|
||||
public string entryName;
|
||||
public string shortCut;
|
||||
public int priority;
|
||||
public bool isActiveInMode;
|
||||
public ActionValidity state;
|
||||
public bool isChecked;
|
||||
public GenericMenu.MenuFunction callback;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5882d0e4313310143acb11d1a66c597f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,381 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de86b4ed8106fd84a8bc2f5d69798d53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,34 @@
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a timeline action.
|
||||
/// Inherit from this class to make an action on a timeline after a menu click and/or a key shortcut.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To add an action as a menu item in the Timeline context menu, add <see cref="MenuEntryAttribute"/> on the action class.
|
||||
/// To make an action to react to a shortcut, use the Shortcut Manager API with <see cref="TimelineShortcutAttribute"/>.
|
||||
/// <seealso cref="UnityEditor.ShortcutManagement.ShortcutAttribute"/>
|
||||
/// <seealso cref="ActiveInModeAttribute"/>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// Simple Timeline Action example (with context menu and shortcut support).
|
||||
/// <code source="../../DocCodeExamples/ActionExamples.cs" region="declare-sampleTimelineAction" title="SampleTimelineAction"/>
|
||||
/// </example>
|
||||
[ActiveInMode(TimelineModes.Default)]
|
||||
public abstract class TimelineAction : IAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Execute the action.
|
||||
/// </summary>
|
||||
/// <param name="context">Context for the action.</param>
|
||||
/// <returns>true if the action has been executed. false otherwise</returns>
|
||||
public abstract bool Execute(ActionContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the validity of an Action based on the context.
|
||||
/// </summary>
|
||||
/// <param name="context">Context for the action.</param>
|
||||
/// <returns>Visual state of the menu for the action.</returns>
|
||||
public abstract ActionValidity Validate(ActionContext context);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38eaad816666dfb428c3f123a09413c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1c789407b55e3a4c9cc86135a714e33
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a track action.
|
||||
/// Inherit from this class to make an action that would react on selected tracks after a menu click and/or a key shortcut.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Simple track Action example (with context menu and shortcut support).
|
||||
/// <code source="../../DocCodeExamples/ActionExamples.cs" region="declare-sampleTrackAction" title="SampleTrackAction"/>
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// To add an action as a menu item in the Timeline context menu, add <see cref="MenuEntryAttribute"/> on the action class.
|
||||
/// To make an action to react to a shortcut, use the Shortcut Manager API with <see cref="TimelineShortcutAttribute"/>.
|
||||
/// <seealso cref="UnityEditor.ShortcutManagement.ShortcutAttribute"/>
|
||||
/// </remarks>
|
||||
[ActiveInMode(TimelineModes.Default)]
|
||||
public abstract class TrackAction : IAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Execute the action.
|
||||
/// </summary>
|
||||
/// <param name="tracks">Tracks that will be used for the action. </param>
|
||||
/// <returns>true if the action has been executed. false otherwise</returns>
|
||||
public abstract bool Execute(IEnumerable<TrackAsset> tracks);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the validity of an Action for a given set of tracks.
|
||||
/// </summary>
|
||||
/// <param name="tracks">tracks that the action would act on.</param>
|
||||
/// <returns>The validity of the set of tracks.</returns>
|
||||
public abstract ActionValidity Validate(IEnumerable<TrackAsset> tracks);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcac94f4ceb0c8049bf47480708ca7e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fda82b5ca7a4c5f40b497c4f5f4bd950
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user