summaryrefslogtreecommitdiff
path: root/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ClipModifier.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ClipModifier.cs')
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ClipModifier.cs386
1 files changed, 386 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ClipModifier.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ClipModifier.cs
new file mode 100644
index 0000000..8c54f4d
--- /dev/null
+++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ClipModifier.cs
@@ -0,0 +1,386 @@
+using System;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Timeline;
+using UnityEngine.Playables;
+
+namespace UnityEditor.Timeline
+{
+ static class ClipModifier
+ {
+ public static bool Delete(TimelineAsset timeline, TimelineClip clip)
+ {
+ return timeline.DeleteClip(clip);
+ }
+
+ public static bool Tile(TimelineClip[] clips)
+ {
+ if (clips.Length < 2)
+ return false;
+
+ var clipsByTracks = clips.GroupBy(x => x.parentTrack)
+ .Select(track => new {track.Key, Items = track.OrderBy(c => c.start)});
+
+ foreach (var track in clipsByTracks)
+ {
+ TimelineUndo.PushUndo(track.Key, "Tile");
+ }
+
+ foreach (var track in clipsByTracks)
+ {
+ double newStart = track.Items.First().start;
+ foreach (var c in track.Items)
+ {
+ c.start = newStart;
+ newStart += c.duration;
+ }
+ }
+
+ return true;
+ }
+
+ public static bool TrimStart(TimelineClip[] clips, double trimTime)
+ {
+ var result = false;
+
+ foreach (var clip in clips)
+ result |= TrimStart(clip, trimTime);
+
+ return result;
+ }
+
+ public static bool TrimStart(TimelineClip clip, double trimTime)
+ {
+ if (clip.asset == null)
+ return false;
+
+ if (clip.start > trimTime)
+ return false;
+
+ if (clip.end < trimTime)
+ return false;
+
+ TimelineUndo.PushUndo(clip.parentTrack, "Trim Clip Start");
+
+ // Note: We are NOT using edit modes in this case because we want the same result
+ // regardless of the selected EditMode: split at cursor and delete left part
+ SetStart(clip, trimTime);
+
+ return true;
+ }
+
+ public static bool TrimEnd(TimelineClip[] clips, double trimTime)
+ {
+ var result = false;
+
+ foreach (var clip in clips)
+ result |= TrimEnd(clip, trimTime);
+
+ return result;
+ }
+
+ public static bool TrimEnd(TimelineClip clip, double trimTime)
+ {
+ if (clip.asset == null)
+ return false;
+
+ if (clip.start > trimTime)
+ return false;
+
+ if (clip.end < trimTime)
+ return false;
+
+ TimelineUndo.PushUndo(clip.parentTrack, "Trim Clip End");
+ TrimClipWithEditMode(clip, TrimEdge.End, trimTime);
+
+ return true;
+ }
+
+ public static bool MatchDuration(TimelineClip[] clips)
+ {
+ double referenceDuration = clips[0].duration;
+ foreach (var clip in clips)
+ {
+ TimelineUndo.PushUndo(clip.parentTrack, "Match Clip Duration");
+
+ var newEnd = clip.start + referenceDuration;
+ TrimClipWithEditMode(clip, TrimEdge.End, newEnd);
+ }
+
+ return true;
+ }
+
+ public static bool Split(TimelineClip[] clips, double splitTime, PlayableDirector director)
+ {
+ var result = false;
+
+ foreach (var clip in clips)
+ {
+ if (clip.start >= splitTime)
+ continue;
+
+ if (clip.end <= splitTime)
+ continue;
+
+ TimelineUndo.PushUndo(clip.parentTrack, "Split Clip");
+
+ TimelineClip newClip = TimelineHelpers.Clone(clip, director, director, clip.start);
+
+ SetStart(clip, splitTime);
+ SetEnd(newClip, splitTime, false);
+
+ // Sort produced by cloning clips on top of each other is unpredictable (it varies between mono runtimes)
+ clip.parentTrack.SortClips();
+
+ result = true;
+ }
+
+ return result;
+ }
+
+ public static void SetStart(TimelineClip clip, double time)
+ {
+ var supportsClipIn = clip.SupportsClipIn();
+ var supportsPadding = TimelineUtility.IsRecordableAnimationClip(clip);
+
+ // treat empty recordable clips as not supporting clip in (there are no keys to modify)
+ if (supportsPadding && (clip.animationClip == null || clip.animationClip.empty))
+ {
+ supportsClipIn = false;
+ }
+
+ if (supportsClipIn && !supportsPadding)
+ {
+ var minStart = clip.FromLocalTimeUnbound(0.0);
+ if (time < minStart)
+ time = minStart;
+ }
+
+ var maxStart = clip.end - TimelineClip.kMinDuration;
+ if (time > maxStart)
+ time = maxStart;
+
+ var timeOffset = time - clip.start;
+ var duration = clip.duration - timeOffset;
+
+ if (supportsClipIn)
+ {
+ if (supportsPadding)
+ {
+ double clipInGlobal = clip.clipIn / clip.timeScale;
+ double keyShift = -timeOffset;
+ if (timeOffset < 0) // left drag, eliminate clipIn before shifting
+ {
+ double clipInDelta = Math.Max(-clipInGlobal, timeOffset);
+ keyShift = -Math.Min(0, timeOffset - clipInDelta);
+ clip.clipIn += clipInDelta * clip.timeScale;
+ }
+ else if (timeOffset > 0) // right drag, elimate padding in animation clip before adding clip in
+ {
+ var clipInfo = AnimationClipCurveCache.Instance.GetCurveInfo(clip.animationClip);
+ double keyDelta = clip.FromLocalTimeUnbound(clipInfo.keyTimes.Min()) - clip.start;
+ keyShift = -Math.Max(0, Math.Min(timeOffset, keyDelta));
+ clip.clipIn += Math.Max(timeOffset + keyShift, 0) * clip.timeScale;
+ }
+ if (keyShift != 0)
+ {
+ AnimationTrackRecorder.ShiftAnimationClip(clip.animationClip, (float)(keyShift * clip.timeScale));
+ }
+ }
+ else
+ {
+ clip.clipIn += timeOffset * clip.timeScale;
+ }
+ }
+
+ clip.start = time;
+ clip.duration = duration;
+ }
+
+ public static void SetEnd(TimelineClip clip, double time, bool affectTimeScale)
+ {
+ var duration = Math.Max(time - clip.start, TimelineClip.kMinDuration);
+
+ if (affectTimeScale && clip.SupportsSpeedMultiplier())
+ {
+ var f = clip.duration / duration;
+ clip.timeScale *= f;
+ }
+
+ clip.duration = duration;
+ }
+
+ public static bool ResetEditing(TimelineClip[] clips)
+ {
+ var result = false;
+
+ foreach (var clip in clips)
+ result = result || ResetEditing(clip);
+
+ return result;
+ }
+
+ public static bool ResetEditing(TimelineClip clip)
+ {
+ if (clip.asset == null)
+ return false;
+
+ TimelineUndo.PushUndo(clip.parentTrack, "Reset Clip Editing");
+
+ clip.clipIn = 0.0;
+
+ if (clip.clipAssetDuration < double.MaxValue)
+ {
+ var duration = clip.clipAssetDuration / clip.timeScale;
+ TrimClipWithEditMode(clip, TrimEdge.End, clip.start + duration);
+ }
+
+ return true;
+ }
+
+ public static bool MatchContent(TimelineClip[] clips)
+ {
+ var result = false;
+
+ foreach (var clip in clips)
+ result = result || MatchContent(clip);
+
+ return result;
+ }
+
+ public static bool MatchContent(TimelineClip clip)
+ {
+ if (clip.asset == null)
+ return false;
+
+ TimelineUndo.PushUndo(clip.parentTrack, "Match Clip Content");
+
+ var newStartCandidate = clip.start - clip.clipIn / clip.timeScale;
+ var newStart = newStartCandidate < 0.0 ? 0.0 : newStartCandidate;
+
+ TrimClipWithEditMode(clip, TrimEdge.Start, newStart);
+
+ // In case resetting the start was blocked by edit mode or timeline start, we do the best we can
+ clip.clipIn = (clip.start - newStartCandidate) * clip.timeScale;
+ if (clip.clipAssetDuration > 0 && TimelineHelpers.HasUsableAssetDuration(clip))
+ {
+ var duration = TimelineHelpers.GetLoopDuration(clip);
+ var offset = (clip.clipIn / clip.timeScale) % duration;
+ TrimClipWithEditMode(clip, TrimEdge.End, clip.start - offset + duration);
+ }
+
+ return true;
+ }
+
+ public static void TrimClipWithEditMode(TimelineClip clip, TrimEdge edge, double time)
+ {
+ var clipItem = ItemsUtils.ToItem(clip);
+ EditMode.BeginTrim(clipItem, edge);
+ if (edge == TrimEdge.Start)
+ EditMode.TrimStart(clipItem, time);
+ else
+ EditMode.TrimEnd(clipItem, time, false);
+ EditMode.FinishTrim();
+ }
+
+ public static bool CompleteLastLoop(TimelineClip[] clips)
+ {
+ foreach (var clip in clips)
+ {
+ CompleteLastLoop(clip);
+ }
+
+ return true;
+ }
+
+ public static void CompleteLastLoop(TimelineClip clip)
+ {
+ FixLoops(clip, true);
+ }
+
+ public static bool TrimLastLoop(TimelineClip[] clips)
+ {
+ foreach (var clip in clips)
+ {
+ TrimLastLoop(clip);
+ }
+
+ return true;
+ }
+
+ public static void TrimLastLoop(TimelineClip clip)
+ {
+ FixLoops(clip, false);
+ }
+
+ static void FixLoops(TimelineClip clip, bool completeLastLoop)
+ {
+ if (!TimelineHelpers.HasUsableAssetDuration(clip))
+ return;
+
+ var loopDuration = TimelineHelpers.GetLoopDuration(clip);
+ var firstLoopDuration = loopDuration - clip.clipIn * (1.0 / clip.timeScale);
+
+ // Making sure we don't trim to zero
+ if (!completeLastLoop && firstLoopDuration > clip.duration)
+ return;
+
+ var numLoops = (clip.duration - firstLoopDuration) / loopDuration;
+ var numCompletedLoops = Math.Floor(numLoops);
+
+ if (!(numCompletedLoops < numLoops))
+ return;
+
+ if (completeLastLoop)
+ numCompletedLoops += 1;
+
+ var newEnd = clip.start + firstLoopDuration + loopDuration * numCompletedLoops;
+
+ TimelineUndo.PushUndo(clip.parentTrack, "Trim Clip Last Loop");
+
+ TrimClipWithEditMode(clip, TrimEdge.End, newEnd);
+ }
+
+ public static bool DoubleSpeed(TimelineClip[] clips)
+ {
+ foreach (var clip in clips)
+ {
+ if (clip.SupportsSpeedMultiplier())
+ {
+ TimelineUndo.PushUndo(clip.parentTrack, "Double Clip Speed");
+ clip.timeScale = clip.timeScale * 2.0f;
+ }
+ }
+
+ return true;
+ }
+
+ public static bool HalfSpeed(TimelineClip[] clips)
+ {
+ foreach (var clip in clips)
+ {
+ if (clip.SupportsSpeedMultiplier())
+ {
+ TimelineUndo.PushUndo(clip.parentTrack, "Half Clip Speed");
+ clip.timeScale = clip.timeScale * 0.5f;
+ }
+ }
+
+ return true;
+ }
+
+ public static bool ResetSpeed(TimelineClip[] clips)
+ {
+ foreach (var clip in clips)
+ {
+ if (clip.timeScale != 1.0)
+ {
+ TimelineUndo.PushUndo(clip.parentTrack, "Reset Clip Speed");
+ clip.timeScale = 1.0;
+ }
+ }
+
+ return true;
+ }
+ }
+}