/Library/PackageCache/com.unity.timeline@1.2.18/Editor/Utilities/ClipModifier.cs
C# | 386 lines | 296 code | 84 blank | 6 comment | 48 complexity | ed56d2480de896446bd072fe95850bce MD5 | raw file
- 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;
- }
- }
- }