123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditor.ShortcutManagement;
- using UnityEditor.Timeline.Actions;
- using UnityEngine;
- using UnityEngine.Playables;
- using UnityEngine.Timeline;
-
- namespace UnityEditor.Timeline
- {
- [MenuEntry("Copy", MenuPriority.TimelineActionSection.copy)]
- [Shortcut("Main Menu/Edit/Copy", EventCommandNames.Copy)]
- class CopyAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context)
- {
- if (SelectionManager.Count() == 0)
- return ActionValidity.NotApplicable;
- if (context.tracks.ContainsTimelineMarkerTrack(context.timeline))
- return ActionValidity.NotApplicable;
-
- return ActionValidity.Valid;
- }
-
- public override bool Execute(ActionContext context)
- {
- TimelineEditor.clipboard.Clear();
-
- var clips = context.clips;
- if (clips.Any())
- {
- clips.Invoke<CopyClipsToClipboard>();
- }
- var markers = context.markers;
- if (markers.Any())
- {
- markers.Invoke<CopyMarkersToClipboard>();
- }
- var tracks = context.tracks;
- if (tracks.Any())
- {
- CopyTracksToClipboard.Do(tracks.ToArray());
- }
-
- return true;
- }
- }
-
- [MenuEntry("Paste", MenuPriority.TimelineActionSection.paste)]
- [Shortcut("Main Menu/Edit/Paste", EventCommandNames.Paste)]
- class PasteAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context)
- {
- return CanPaste(context.invocationTime) ? ActionValidity.Valid : ActionValidity.Invalid;
- }
-
- public override bool Execute(ActionContext context)
- {
- if (!CanPaste(context.invocationTime))
- return false;
-
- PasteItems(context.invocationTime);
- PasteTracks();
-
- TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
- return true;
- }
-
- static bool CanPaste(double? invocationTime)
- {
- var copiedItems = TimelineEditor.clipboard.GetCopiedItems().ToList();
-
- if (!copiedItems.Any())
- return TimelineEditor.clipboard.GetTracks().Any();
-
- return CanPasteItems(copiedItems, invocationTime);
- }
-
- static bool CanPasteItems(ICollection<ItemsPerTrack> itemsGroups, double? invocationTime)
- {
- var hasItemsCopiedFromMultipleTracks = itemsGroups.Count > 1;
- var allItemsCopiedFromCurrentAsset = itemsGroups.All(x => x.targetTrack.timelineAsset == TimelineEditor.inspectedAsset);
- var hasUsedShortcut = invocationTime == null;
- var anySourceLocked = itemsGroups.Any(x => x.targetTrack != null && x.targetTrack.lockedInHierarchy);
-
- var targetTrack = GetPickedTrack();
- if (targetTrack == null)
- targetTrack = SelectionManager.SelectedTracks().FirstOrDefault();
-
- //do not paste if the user copied items from another timeline
- //if the copied items comes from > 1 track (since we do not know where to paste the copied items)
- //or if a keyboard shortcut was used (since the user will not see the paste result)
- if (!allItemsCopiedFromCurrentAsset)
- {
- var isSelectedTrackInCurrentAsset = targetTrack != null && targetTrack.timelineAsset == TimelineEditor.inspectedAsset;
- if (hasItemsCopiedFromMultipleTracks || (hasUsedShortcut && !isSelectedTrackInCurrentAsset))
- return false;
- }
-
- // pasting to items to their source track, if items from multiple tracks are selected
- // and no track is in the selection items will each be pasted to their respective track.
- if (targetTrack == null || itemsGroups.All(x => x.targetTrack == targetTrack))
- return !anySourceLocked;
-
- if (hasItemsCopiedFromMultipleTracks)
- {
- //do not paste if the track which received the paste action does not contain a copied clip
- return !anySourceLocked && itemsGroups.Select(x => x.targetTrack).Contains(targetTrack);
- }
-
- var copiedItems = itemsGroups.SelectMany(i => i.items);
- return IsTrackValidForItems(targetTrack, copiedItems);
- }
-
- static void PasteItems(double? invocationTime)
- {
- var copiedItems = TimelineEditor.clipboard.GetCopiedItems().ToList();
- var numberOfUniqueParentsInClipboard = copiedItems.Count();
-
- if (numberOfUniqueParentsInClipboard == 0) return;
- List<ITimelineItem> newItems;
-
- //if the copied items were on a single parent, then use the mouse position to get the parent OR the original parent
- if (numberOfUniqueParentsInClipboard == 1)
- {
- var itemsGroup = copiedItems.First();
- TrackAsset target = null;
- if (invocationTime.HasValue)
- target = GetPickedTrack();
- if (target == null)
- target = FindSuitableParentForSingleTrackPasteWithoutMouse(itemsGroup);
-
- var candidateTime = invocationTime ?? TimelineHelpers.GetCandidateTime(null, target);
- newItems = TimelineHelpers.DuplicateItemsUsingCurrentEditMode(TimelineEditor.clipboard.exposedPropertyTable, TimelineEditor.inspectedDirector, itemsGroup, target, candidateTime, "Paste Items").ToList();
- }
- //if copied items were on multiple parents, then the destination parents are the same as the original parents
- else
- {
- var time = invocationTime ?? TimelineHelpers.GetCandidateTime(null, copiedItems.Select(c => c.targetTrack).ToArray());
- newItems = TimelineHelpers.DuplicateItemsUsingCurrentEditMode(TimelineEditor.clipboard.exposedPropertyTable, TimelineEditor.inspectedDirector, copiedItems, time, "Paste Items").ToList();
- }
-
- TimelineHelpers.FrameItems(newItems);
- SelectionManager.RemoveTimelineSelection();
- foreach (var item in newItems)
- {
- SelectionManager.Add(item);
- }
- }
-
- static TrackAsset FindSuitableParentForSingleTrackPasteWithoutMouse(ItemsPerTrack itemsGroup)
- {
- var groupParent = itemsGroup.targetTrack; //set a main parent in the clipboard
- var selectedTracks = SelectionManager.SelectedTracks();
-
- if (selectedTracks.Contains(groupParent))
- {
- return groupParent;
- }
-
- //find a selected track suitable for all items
- var itemsToPaste = itemsGroup.items;
- var compatibleTrack = selectedTracks.FirstOrDefault(t => IsTrackValidForItems(t, itemsToPaste));
- return compatibleTrack != null ? compatibleTrack : groupParent;
- }
-
- static bool IsTrackValidForItems(TrackAsset track, IEnumerable<ITimelineItem> items)
- {
- if (track == null || track.lockedInHierarchy) return false;
- return items.All(i => i.IsCompatibleWithTrack(track));
- }
-
- static TrackAsset GetPickedTrack()
- {
- if (PickerUtils.pickedElements == null)
- return null;
-
- var rowGUI = PickerUtils.pickedElements.OfType<IRowGUI>().FirstOrDefault();
- if (rowGUI != null)
- return rowGUI.asset;
-
- return null;
- }
-
- static void PasteTracks()
- {
- var trackData = TimelineEditor.clipboard.GetTracks().ToList();
- if (trackData.Any())
- {
- SelectionManager.RemoveTimelineSelection();
- }
-
- foreach (var track in trackData)
- {
- var newTrack = track.item.Duplicate(TimelineEditor.clipboard.exposedPropertyTable, TimelineEditor.inspectedDirector, TimelineEditor.inspectedAsset);
- var newTracks = newTrack.GetFlattenedChildTracks().Append(newTrack);
-
- var bindingIt = track.bindings.GetEnumerator();
- var newTrackIt = newTracks.GetEnumerator();
-
- while (bindingIt.MoveNext() && newTrackIt.MoveNext())
- {
- if (bindingIt.Current != null)
- BindingUtility.Bind(TimelineEditor.inspectedDirector, newTrackIt.Current, bindingIt.Current);
- }
-
- SelectionManager.Add(newTrack);
- foreach (var childTrack in newTrack.GetFlattenedChildTracks())
- {
- SelectionManager.Add(childTrack);
- }
-
- if (track.parent != null && track.parent.timelineAsset == TimelineEditor.inspectedAsset)
- {
- TrackExtensions.ReparentTracks(new List<TrackAsset> { newTrack }, track.parent, track.item);
- }
- }
- }
- }
-
- [MenuEntry("Duplicate", MenuPriority.TimelineActionSection.duplicate)]
- [Shortcut("Main Menu/Edit/Duplicate", EventCommandNames.Duplicate)]
- class DuplicateAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context)
- {
- IEnumerable<TrackAsset> tracks = context.tracks.RemoveTimelineMarkerTrackFromList(context.timeline);
- return context.clips.Any() || tracks.Any() || context.markers.Any() ? ActionValidity.Valid : ActionValidity.NotApplicable;
- }
-
- public bool Execute(Func<ITimelineItem, ITimelineItem, double> gapBetweenItems)
- {
- return Execute(TimelineEditor.CurrentContext(), gapBetweenItems);
- }
-
- public override bool Execute(ActionContext context)
- {
- return Execute(context, (item1, item2) => ItemsUtils.TimeGapBetweenItems(item1, item2));
- }
-
- internal bool Execute(ActionContext context, Func<ITimelineItem, ITimelineItem, double> gapBetweenItems)
- {
- List<ITimelineItem> items = new List<ITimelineItem>();
- items.AddRange(context.clips.Select(p => p.ToItem()));
- items.AddRange(context.markers.Select(p => p.ToItem()));
- List<ItemsPerTrack> selectedItems = items.ToItemsPerTrack().ToList();
- if (selectedItems.Any())
- {
- var requestedTime = CalculateDuplicateTime(selectedItems, gapBetweenItems);
- var duplicatedItems = TimelineHelpers.DuplicateItemsUsingCurrentEditMode(TimelineEditor.inspectedDirector, TimelineEditor.inspectedDirector, selectedItems, requestedTime, "Duplicate Items");
-
- TimelineHelpers.FrameItems(duplicatedItems);
- SelectionManager.RemoveTimelineSelection();
- foreach (var item in duplicatedItems)
- SelectionManager.Add(item);
- }
-
- var tracks = context.tracks.ToArray();
- if (tracks.Length > 0)
- tracks.Invoke<DuplicateTracks>();
-
- TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
- return true;
- }
-
- static double CalculateDuplicateTime(IEnumerable<ItemsPerTrack> duplicatedItems, Func<ITimelineItem, ITimelineItem, double> gapBetweenItems)
- {
- //Find the end time of the rightmost item
- var itemsOnTracks = duplicatedItems.SelectMany(i => i.targetTrack.GetItems()).ToList();
- var time = itemsOnTracks.Max(i => i.end);
-
- //From all the duplicated items, select the leftmost items
- var firstDuplicatedItems = duplicatedItems.Select(i => i.leftMostItem);
- var leftMostDuplicatedItems = firstDuplicatedItems.OrderBy(i => i.start).GroupBy(i => i.start).FirstOrDefault();
- if (leftMostDuplicatedItems == null) return 0.0;
-
- foreach (var leftMostItem in leftMostDuplicatedItems)
- {
- var siblings = leftMostItem.parentTrack.GetItems();
- var rightMostSiblings = siblings.OrderByDescending(i => i.end).GroupBy(i => i.end).FirstOrDefault();
- if (rightMostSiblings == null) continue;
-
- foreach (var sibling in rightMostSiblings)
- time = Math.Max(time, sibling.end + gapBetweenItems(leftMostItem, sibling));
- }
-
- return time;
- }
- }
-
- [MenuEntry("Delete", MenuPriority.TimelineActionSection.delete)]
- [Shortcut("Main Menu/Edit/Delete", EventCommandNames.Delete)]
- [ShortcutPlatformOverride(RuntimePlatform.OSXEditor, KeyCode.Backspace, ShortcutModifiers.Action)]
- [ActiveInMode(TimelineModes.Disabled | TimelineModes.Default)]
- class DeleteAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context)
- {
- return CanDelete(context) ? ActionValidity.Valid : ActionValidity.Invalid;
- }
-
- static bool CanDelete(ActionContext context)
- {
- if (TimelineWindow.instance.state.editSequence.isReadOnly)
- return false;
-
- if (context.tracks.ContainsTimelineMarkerTrack(context.timeline))
- return false;
-
- // All() returns true when empty
- return context.tracks.All(x => !x.lockedInHierarchy) &&
- context.clips.All(x => x.GetParentTrack() == null || !x.GetParentTrack().lockedInHierarchy) &&
- context.markers.All(x => x.parent == null || !x.parent.lockedInHierarchy);
- }
-
- public override bool Execute(ActionContext context)
- {
- if (!CanDelete(context))
- return false;
-
- var selectedItems = context.clips.Select(p => p.ToItem()).ToList();
- selectedItems.AddRange(context.markers.Select(p => p.ToItem()));
- DeleteItems(selectedItems);
-
- if (context.tracks.Any() && SelectionManager.GetCurrentInlineEditorCurve() == null)
- context.tracks.Invoke<DeleteTracks>();
-
- TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
- return selectedItems.Any() || context.tracks.Any();
- }
-
- internal static void DeleteItems(IEnumerable<ITimelineItem> items)
- {
- var tracks = items.GroupBy(c => c.parentTrack);
-
- foreach (var track in tracks)
- TimelineUndo.PushUndo(track.Key, L10n.Tr("Delete Items"));
-
- TimelineAnimationUtilities.UnlinkAnimationWindowFromClips(items.OfType<ClipItem>().Select(i => i.clip));
-
- EditMode.PrepareItemsDelete(ItemsUtils.ToItemsPerTrack(items));
- EditModeUtils.Delete(items);
-
- SelectionManager.RemoveAllClips();
- }
- }
-
- [MenuEntry("Match Content", MenuPriority.TimelineActionSection.matchContent)]
- [Shortcut(Shortcuts.Timeline.matchContent)]
- class MatchContent : TimelineAction
- {
- public override ActionValidity Validate(ActionContext actionContext)
- {
- var clips = actionContext.clips;
-
- if (!clips.Any())
- return ActionValidity.NotApplicable;
-
- return clips.Any(TimelineHelpers.HasUsableAssetDuration)
- ? ActionValidity.Valid
- : ActionValidity.Invalid;
- }
-
- public override bool Execute(ActionContext actionContext)
- {
- var clips = actionContext.clips;
- return clips.Any() && ClipModifier.MatchContent(clips);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.play)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class PlayTimelineAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- var currentState = TimelineEditor.state.playing;
- TimelineEditor.state.SetPlaying(!currentState);
- return true;
- }
- }
-
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectAllAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- // otherwise select all tracks.
- SelectionManager.Clear();
- TimelineWindow.instance.allTracks.ForEach(x => SelectionManager.Add(x.track));
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.previousFrame)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class PreviousFrameAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- if (TimelineEditor.inspectedAsset == null)
- return false;
- TimelineEditor.inspectedSequenceTime = TimeUtility.PreviousFrameTime(TimelineEditor.inspectedSequenceTime, TimelineEditor.inspectedAsset.editorSettings.frameRate);
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.nextFrame)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class NextFrameAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- if (TimelineEditor.inspectedAsset == null)
- return false;
- TimelineEditor.inspectedSequenceTime = TimeUtility.NextFrameTime(TimelineEditor.inspectedSequenceTime, TimelineEditor.inspectedAsset.editorSettings.frameRate);
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.frameAll)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class FrameAllAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context)
- {
- if (context.timeline != null && !context.timeline.flattenedTracks.Any())
- return ActionValidity.NotApplicable;
-
- return ActionValidity.Valid;
- }
-
- public override bool Execute(ActionContext actionContext)
- {
- var inlineCurveEditor = SelectionManager.GetCurrentInlineEditorCurve();
- if (FrameSelectedAction.ShouldHandleInlineCurve(inlineCurveEditor))
- {
- FrameSelectedAction.FrameInlineCurves(inlineCurveEditor, false);
- return true;
- }
-
- if (TimelineWindow.instance.state.IsCurrentEditingASequencerTextField())
- return false;
-
- var visibleTracks = TimelineWindow.instance.treeView.visibleTracks.ToList();
-
- if (TimelineEditor.inspectedAsset != null && TimelineEditor.inspectedAsset.markerTrack != null)
- visibleTracks.Add(TimelineEditor.inspectedAsset.markerTrack);
-
- if (visibleTracks.Count == 0)
- return false;
-
- var startTime = float.MaxValue;
- var endTime = float.MinValue;
-
- foreach (var t in visibleTracks)
- {
- if (t == null)
- continue;
-
- // time range based on track's curves and clips.
- double trackStart, trackEnd, trackDuration;
- t.GetSequenceTime(out trackStart, out trackDuration);
- trackEnd = trackStart + trackDuration;
-
- // take track's markers into account
- double itemsStart, itemsEnd;
- ItemsUtils.GetItemRange(t, out itemsStart, out itemsEnd);
-
- startTime = Mathf.Min(startTime, (float)trackStart, (float)itemsStart);
- endTime = Mathf.Max(endTime, (float)(trackEnd), (float)itemsEnd);
- }
-
- FrameSelectedAction.FrameRange(startTime, endTime);
- return true;
- }
- }
-
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class FrameSelectedAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public static void FrameRange(float startTime, float endTime)
- {
- if (startTime > endTime)
- {
- return;
- }
-
- var halfDuration = endTime - Math.Max(0.0f, startTime);
-
- if (halfDuration > 0.0f)
- {
- TimelineEditor.visibleTimeRange = new Vector2(Mathf.Max(0.0f, startTime - (halfDuration * 0.1f)), endTime + (halfDuration * 0.1f));
- }
- else
- {
- // start == end
- // keep the zoom level constant, only pan the time area to center the item
- var currentRange = TimelineEditor.visibleTimeRange.y - TimelineEditor.visibleTimeRange.x;
- TimelineEditor.visibleTimeRange = new Vector2(startTime - currentRange / 2, startTime + currentRange / 2);
- }
-
- TimelineZoomManipulator.InvalidateWheelZoom();
- TimelineEditor.Refresh(RefreshReason.SceneNeedsUpdate);
- }
-
- public override bool Execute(ActionContext actionContext)
- {
- var inlineCurveEditor = SelectionManager.GetCurrentInlineEditorCurve();
- if (ShouldHandleInlineCurve(inlineCurveEditor))
- {
- FrameInlineCurves(inlineCurveEditor, true);
- return true;
- }
-
- if (TimelineWindow.instance.state.IsCurrentEditingASequencerTextField())
- return false;
-
- if (SelectionManager.Count() == 0)
- {
- actionContext.Invoke<FrameAllAction>();
- return true;
- }
-
- var startTime = float.MaxValue;
- var endTime = float.MinValue;
-
- var clips = actionContext.clips.Select(ItemToItemGui.GetGuiForClip);
- var markers = actionContext.markers;
- if (!clips.Any() && !markers.Any())
- return false;
-
- foreach (var c in clips)
- {
- startTime = Mathf.Min(startTime, (float)c.clip.start);
- endTime = Mathf.Max(endTime, (float)c.clip.end);
- if (c.clipCurveEditor != null)
- {
- c.clipCurveEditor.FrameClip();
- }
- }
-
- foreach (var marker in markers)
- {
- startTime = Mathf.Min(startTime, (float)marker.time);
- endTime = Mathf.Max(endTime, (float)marker.time);
- }
-
- FrameRange(startTime, endTime);
-
- return true;
- }
-
- public static bool ShouldHandleInlineCurve(IClipCurveEditorOwner curveEditorOwner)
- {
- return curveEditorOwner?.clipCurveEditor != null &&
- curveEditorOwner.inlineCurvesSelected &&
- curveEditorOwner.owner != null &&
- curveEditorOwner.owner.GetShowInlineCurves();
- }
-
- public static void FrameInlineCurves(IClipCurveEditorOwner curveEditorOwner, bool selectionOnly)
- {
- var curveEditor = curveEditorOwner.clipCurveEditor.curveEditor;
- var frameBounds = selectionOnly ? curveEditor.GetSelectionBounds() : curveEditor.GetClipBounds();
-
- var clipGUI = curveEditorOwner as TimelineClipGUI;
- var areaOffset = 0.0f;
-
- if (clipGUI != null)
- {
- areaOffset = (float)Math.Max(0.0, clipGUI.clip.FromLocalTimeUnbound(0.0));
-
- var timeScale = (float)clipGUI.clip.timeScale; // Note: The getter for clip.timeScale is guaranteed to never be zero.
-
- // Apply scaling
- var newMin = frameBounds.min.x / timeScale;
- var newMax = (frameBounds.max.x - frameBounds.min.x) / timeScale + newMin;
-
- frameBounds.SetMinMax(
- new Vector3(newMin, frameBounds.min.y, frameBounds.min.z),
- new Vector3(newMax, frameBounds.max.y, frameBounds.max.z));
- }
-
- curveEditor.Frame(frameBounds, true, true);
-
- var area = curveEditor.shownAreaInsideMargins;
- area.x += areaOffset;
-
- var curveStart = curveEditorOwner.clipCurveEditor.dataSource.start;
- FrameRange(curveStart + frameBounds.min.x, curveStart + frameBounds.max.x);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.previousKey)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class PrevKeyAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- if (TimelineEditor.inspectedAsset == null)
- return false;
- var keyTraverser = new Utilities.KeyTraverser(TimelineEditor.inspectedAsset, 0.01f / (float)TimelineEditor.inspectedAsset.editorSettings.frameRate);
- var time = keyTraverser.GetPrevKey((float)TimelineEditor.inspectedSequenceTime, TimelineWindow.instance.state.dirtyStamp);
- if (time != TimelineEditor.inspectedSequenceTime)
- {
- TimelineEditor.inspectedSequenceTime = time;
- }
-
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.nextKey)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class NextKeyAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- if (TimelineEditor.inspectedAsset == null)
- return false;
- var keyTraverser = new Utilities.KeyTraverser(TimelineEditor.inspectedAsset, 0.01f / (float)TimelineEditor.inspectedAsset.editorSettings.frameRate);
- var time = keyTraverser.GetNextKey((float)TimelineEditor.inspectedSequenceTime, TimelineWindow.instance.state.dirtyStamp);
- if (time != TimelineEditor.inspectedSequenceTime)
- {
- TimelineEditor.inspectedSequenceTime = time;
- }
-
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.goToStart)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class GotoStartAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- TimelineEditor.inspectedSequenceTime = 0.0f;
- TimelineWindow.instance.state.EnsurePlayHeadIsVisible();
-
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.goToEnd)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class GotoEndAction : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- TimelineEditor.inspectedSequenceTime = TimelineWindow.instance.state.editSequence.duration;
- TimelineWindow.instance.state.EnsurePlayHeadIsVisible();
-
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.zoomIn)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class ZoomIn : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- TimelineZoomManipulator.Instance.DoZoom(1.15f);
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.zoomOut)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class ZoomOut : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- TimelineZoomManipulator.Instance.DoZoom(0.85f);
- return true;
- }
- }
-
- [Shortcut(Shortcuts.Timeline.navigateLeft)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class NavigateLeft : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.NavigateLeft(actionContext.tracks);
- }
- }
-
-
- [Shortcut(Shortcuts.Timeline.navigateRight)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class NavigateRight : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.NavigateRight(actionContext.tracks);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.toggleCollapseTrack)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class ToggleCollapseGroup : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.ToggleCollapseGroup(actionContext.tracks);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.selectLeftItem)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectLeftClip : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- // Switches to track header if no left track exists
- return KeyboardNavigation.SelectLeftItem();
- }
- }
-
- [Shortcut(Shortcuts.Timeline.selectRightItem)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectRightClip : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectRightItem();
- }
- }
-
- [Shortcut(Shortcuts.Timeline.selectUpItem)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectUpClip : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectUpItem();
- }
- }
-
- [Shortcut(Shortcuts.Timeline.selectUpTrack)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectUpTrack : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectUpTrack();
- }
- }
-
- [Shortcut(Shortcuts.Timeline.selectDownItem)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectDownClip : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectDownItem();
- }
- }
-
- [Shortcut(Shortcuts.Timeline.selectDownTrack)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class SelectDownTrack : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- if (!KeyboardNavigation.ClipAreaActive() && !KeyboardNavigation.TrackHeadActive())
- return KeyboardNavigation.FocusFirstVisibleItem();
- else
- return KeyboardNavigation.SelectDownTrack();
- }
- }
-
- [Shortcut(Shortcuts.Timeline.multiSelectLeft)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class MultiselectLeftClip : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectLeftItem(true);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.multiSelectRight)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class MultiselectRightClip : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectRightItem(true);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.multiSelectUp)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class MultiselectUpTrack : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectUpTrack(true);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.multiSelectDown)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class MultiselectDownTrack : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
- public override bool Execute(ActionContext actionContext)
- {
- return KeyboardNavigation.SelectDownTrack(true);
- }
- }
-
- [Shortcut(Shortcuts.Timeline.toggleClipTrackArea)]
- [ActiveInMode(TimelineModes.Default | TimelineModes.ReadOnly)]
- class ToggleClipTrackArea : TimelineAction
- {
- public override ActionValidity Validate(ActionContext context) => ActionValidity.Valid;
-
-
- public override bool Execute(ActionContext actionContext)
- {
- if (KeyboardNavigation.TrackHeadActive())
- return KeyboardNavigation.FocusFirstVisibleItem(actionContext.tracks);
-
- if (!KeyboardNavigation.ClipAreaActive())
- return KeyboardNavigation.FocusFirstVisibleItem();
-
- var item = KeyboardNavigation.GetVisibleSelectedItems().LastOrDefault();
- if (item != null)
- SelectionManager.SelectOnly(item.parentTrack);
- return true;
- }
- }
-
- [MenuEntry("Key All Animated", MenuPriority.TimelineActionSection.keyAllAnimated)]
- [Shortcut(Shortcuts.Timeline.keyAllAnimated)]
- class KeyAllAnimated : TimelineAction
- {
- public override ActionValidity Validate(ActionContext actionContext)
- {
- return CanExecute(TimelineEditor.state, actionContext)
- ? ActionValidity.Valid
- : ActionValidity.NotApplicable;
- }
-
- public override bool Execute(ActionContext actionContext)
- {
- WindowState state = TimelineEditor.state;
- PlayableDirector director = TimelineEditor.inspectedDirector;
-
- if (!CanExecute(state, actionContext) || director == null)
- return false;
-
- IEnumerable<TrackAsset> keyableTracks = GetKeyableTracks(state, actionContext);
-
- var curveSelected = SelectionManager.GetCurrentInlineEditorCurve();
- if (curveSelected != null)
- {
- var sel = curveSelected.clipCurveEditor.GetSelectedProperties().ToList();
- var go = (director.GetGenericBinding(curveSelected.owner) as Component).gameObject;
- if (sel.Count > 0)
- {
- TimelineRecording.KeyProperties(go, state, sel);
- }
- else
- {
- var binding = director.GetGenericBinding(curveSelected.owner) as Component;
- TimelineRecording.KeyAllProperties(binding, state);
- }
- }
- else
- {
- foreach (var track in keyableTracks)
- {
- var binding = director.GetGenericBinding(track) as Component;
- TimelineRecording.KeyAllProperties(binding, state);
- }
- }
- return true;
- }
-
- static IEnumerable<TrackAsset> GetKeyableTracks(WindowState state, ActionContext context)
- {
- if (!context.clips.Any() && !context.tracks.Any()) //no selection -> animate all recorded tracks
- return context.timeline.flattenedTracks.Where(state.IsArmedForRecord);
-
- List<TrackAsset> parentTracks = context.tracks.ToList();
- parentTracks.AddRange(context.clips.Select(clip => clip.GetParentTrack()).Distinct());
-
- if (!parentTracks.All(state.IsArmedForRecord))
- return Enumerable.Empty<TrackAsset>();
-
- return parentTracks;
- }
-
- static bool CanExecute(WindowState state, ActionContext context)
- {
- if (context.timeline == null)
- return false;
-
- if (context.markers.Any())
- return false;
-
- if (context.tracks.ContainsTimelineMarkerTrack(context.timeline))
- return false;
-
- IClipCurveEditorOwner curveSelected = SelectionManager.GetCurrentInlineEditorCurve();
- // Can't have an inline curve selected and have multiple tracks also.
- if (curveSelected != null)
- {
- return state.IsArmedForRecord(curveSelected.owner);
- }
-
- return GetKeyableTracks(state, context).Any();
- }
- }
- }
|