diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
| commit | c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 (patch) | |
| tree | ee4d51c7c1d633e11f46453ef1edd3c77c4ef9f7 /Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions | |
| download | Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.gz Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.bz2 Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.zip | |
Inital commit
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions')
6 files changed, 812 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimatedParameterExtensions.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimatedParameterExtensions.cs new file mode 100644 index 0000000..06f5e47 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimatedParameterExtensions.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + static class AnimatedParameterExtensions + { + public static bool HasAnyAnimatableParameters(this ICurvesOwner curvesOwner) + { + return AnimatedParameterUtility.HasAnyAnimatableParameters(curvesOwner.asset); + } + + public static IEnumerable<SerializedProperty> GetAllAnimatableParameters(this ICurvesOwner curvesOwner) + { + return AnimatedParameterUtility.GetAllAnimatableParameters(curvesOwner.asset); + } + + public static bool IsParameterAnimatable(this ICurvesOwner curvesOwner, string parameterName) + { + return AnimatedParameterUtility.IsParameterAnimatable(curvesOwner.asset, parameterName); + } + + public static bool IsParameterAnimated(this ICurvesOwner curvesOwner, string parameterName) + { + return AnimatedParameterUtility.IsParameterAnimated(curvesOwner.asset, curvesOwner.curves, parameterName); + } + + public static EditorCurveBinding GetCurveBinding(this ICurvesOwner curvesOwner, string parameterName) + { + return AnimatedParameterUtility.GetCurveBinding(curvesOwner.asset, parameterName); + } + + public static string GetUniqueRecordedClipName(this ICurvesOwner curvesOwner) + { + return AnimationTrackRecorder.GetUniqueRecordedClipName(curvesOwner.assetOwner, curvesOwner.defaultCurvesName); + } + + public static AnimationCurve GetAnimatedParameter(this ICurvesOwner curvesOwner, string bindingName) + { + return AnimatedParameterUtility.GetAnimatedParameter(curvesOwner.asset, curvesOwner.curves, bindingName); + } + + public static bool AddAnimatedParameterValueAt(this ICurvesOwner curvesOwner, string parameterName, float value, float time) + { + if (!curvesOwner.IsParameterAnimatable(parameterName)) + return false; + + if (curvesOwner.curves == null) + curvesOwner.CreateCurves(curvesOwner.GetUniqueRecordedClipName()); + + var binding = curvesOwner.GetCurveBinding(parameterName); + var curve = AnimationUtility.GetEditorCurve(curvesOwner.curves, binding) ?? new AnimationCurve(); + + var serializedObject = AnimatedParameterUtility.GetSerializedPlayableAsset(curvesOwner.asset); + var property = serializedObject.FindProperty(parameterName); + + bool isStepped = property.propertyType == SerializedPropertyType.Boolean || + property.propertyType == SerializedPropertyType.Integer || + property.propertyType == SerializedPropertyType.Enum; + + CurveEditUtility.AddKeyFrameToCurve(curve, time, curvesOwner.curves.frameRate, value, isStepped); + AnimationUtility.SetEditorCurve(curvesOwner.curves, binding, curve); + + return true; + } + + public static void SanitizeCurvesData(this ICurvesOwner curvesOwner) + { + var curves = curvesOwner.curves; + if (curves == null) + return; + + // Remove any 0-length curves + foreach (var binding in AnimationUtility.GetCurveBindings(curves)) + { + var curve = AnimationUtility.GetEditorCurve(curves, binding); + if (curve.length == 0) + AnimationUtility.SetEditorCurve(curves, binding, null); + } + + // If no curves remain, delete the curves asset + if (curves.empty) + { + var track = curvesOwner.targetTrack; + var timeline = track != null ? track.timelineAsset : null; + TimelineUndo.PushDestroyUndo(timeline, track, curves, "Delete Parameter Curves"); + } + } + + public static bool AddAnimatedParameter(this ICurvesOwner curvesOwner, string parameterName) + { + var newBinding = new EditorCurveBinding(); + + SerializedProperty property; + if (!InternalAddParameter(curvesOwner, parameterName, ref newBinding, out property)) + return false; + + var duration = (float)curvesOwner.duration; + CurveEditUtility.AddKey(curvesOwner.curves, newBinding, property, 0); + CurveEditUtility.AddKey(curvesOwner.curves, newBinding, property, duration); + return true; + } + + public static bool RemoveAnimatedParameter(this ICurvesOwner curvesOwner, string parameterName) + { + if (!curvesOwner.IsParameterAnimated(parameterName) || curvesOwner.curves == null) + return false; + + var binding = curvesOwner.GetCurveBinding(parameterName); + AnimationUtility.SetEditorCurve(curvesOwner.curves, binding, null); + return true; + } + + // Set an animated parameter. Requires the field identifier 'position.x', but will add default curves to all fields + public static bool SetAnimatedParameter(this ICurvesOwner curvesOwner, string parameterName, AnimationCurve curve) + { + // this will add a basic curve for all the related parameters + if (!curvesOwner.IsParameterAnimated(parameterName) && !curvesOwner.AddAnimatedParameter(parameterName)) + return false; + + var binding = curvesOwner.GetCurveBinding(parameterName); + AnimationUtility.SetEditorCurve(curvesOwner.curves, binding, curve); + return true; + } + + static bool InternalAddParameter([NotNull] ICurvesOwner curvesOwner, string parameterName, ref EditorCurveBinding binding, out SerializedProperty property) + { + property = null; + + if (curvesOwner.IsParameterAnimated(parameterName)) + return false; + + var serializedObject = AnimatedParameterUtility.GetSerializedPlayableAsset(curvesOwner.asset); + if (serializedObject == null) + return false; + + property = serializedObject.FindProperty(parameterName); + if (property == null || !AnimatedParameterUtility.IsTypeAnimatable(property.propertyType)) + return false; + + if (curvesOwner.curves == null) + curvesOwner.CreateCurves(curvesOwner.GetUniqueRecordedClipName()); + + binding = curvesOwner.GetCurveBinding(parameterName); + return true; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimatedParameterExtensions.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimatedParameterExtensions.cs.meta new file mode 100644 index 0000000..21de3d3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimatedParameterExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d3aa106cfe752241997b3759bf80163 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimationTrackExtensions.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimationTrackExtensions.cs new file mode 100644 index 0000000..41677ec --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimationTrackExtensions.cs @@ -0,0 +1,134 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + static class AnimationTrackExtensions + { + public static void ConvertToClipMode(this AnimationTrack track) + { + if (!track.CanConvertToClipMode()) + return; + + TimelineUndo.PushUndo(track, "Convert To Clip"); + + if (!track.infiniteClip.empty) + { + var animClip = track.infiniteClip; + TimelineUndo.PushUndo(animClip, "Convert To Clip"); + TimelineUndo.PushUndo(track, "Convert To Clip"); + var start = AnimationClipCurveCache.Instance.GetCurveInfo(animClip).keyTimes.FirstOrDefault(); + animClip.ShiftBySeconds(-start); + + track.infiniteClip = null; + var clip = track.CreateClip(animClip); + + clip.start = start; + clip.preExtrapolationMode = track.infiniteClipPreExtrapolation; + clip.postExtrapolationMode = track.infiniteClipPostExtrapolation; + clip.recordable = true; + if (Mathf.Abs(animClip.length) < TimelineClip.kMinDuration) + { + clip.duration = 1; + } + + var animationAsset = clip.asset as AnimationPlayableAsset; + if (animationAsset) + { + animationAsset.position = track.infiniteClipOffsetPosition; + animationAsset.eulerAngles = track.infiniteClipOffsetEulerAngles; + + // going to / from infinite mode should reset this. infinite mode + animationAsset.removeStartOffset = track.infiniteClipRemoveOffset; + animationAsset.applyFootIK = track.infiniteClipApplyFootIK; + animationAsset.loop = track.infiniteClipLoop; + + track.infiniteClipOffsetPosition = Vector3.zero; + track.infiniteClipOffsetEulerAngles = Vector3.zero; + } + + track.CalculateExtrapolationTimes(); + } + + track.infiniteClip = null; + + EditorUtility.SetDirty(track); + } + + public static void ConvertFromClipMode(this AnimationTrack track, TimelineAsset timeline) + { + if (!track.CanConvertFromClipMode()) + return; + + TimelineUndo.PushUndo(track, "Convert From Clip"); + + var clip = track.clips[0]; + var delta = (float)clip.start; + track.infiniteClipTimeOffset = 0.0f; + track.infiniteClipPreExtrapolation = clip.preExtrapolationMode; + track.infiniteClipPostExtrapolation = clip.postExtrapolationMode; + + var animAsset = clip.asset as AnimationPlayableAsset; + if (animAsset) + { + track.infiniteClipOffsetPosition = animAsset.position; + track.infiniteClipOffsetEulerAngles = animAsset.eulerAngles; + track.infiniteClipRemoveOffset = animAsset.removeStartOffset; + track.infiniteClipApplyFootIK = animAsset.applyFootIK; + track.infiniteClipLoop = animAsset.loop; + } + + // clone it, it may not be in the same asset + var animClip = clip.animationClip; + + float scale = (float)clip.timeScale; + if (!Mathf.Approximately(scale, 1.0f)) + { + if (!Mathf.Approximately(scale, 0.0f)) + scale = 1.0f / scale; + animClip.ScaleTime(scale); + } + + TimelineUndo.PushUndo(animClip, "Convert From Clip"); + animClip.ShiftBySeconds(delta); + + // manually delete the clip + var asset = clip.asset; + clip.asset = null; + + // Remove the clip, remove old assets + ClipModifier.Delete(timeline, clip); + TimelineUndo.PushDestroyUndo(null, track, asset, "Convert From Clip"); + + track.infiniteClip = animClip; + + EditorUtility.SetDirty(track); + } + + public static bool CanConvertToClipMode(this AnimationTrack track) + { + if (track == null || track.inClipMode) + return false; + return (track.infiniteClip != null && !track.infiniteClip.empty); + } + + // Requirements to go from clip mode + // - one clip, recordable, and animation clip belongs to the same asset as the track + public static bool CanConvertFromClipMode(this AnimationTrack track) + { + if ((track == null) || + (!track.inClipMode) || + (track.clips.Length != 1) || + (track.clips[0].start < 0) || + (!track.clips[0].recordable)) + return false; + + var asset = track.clips[0].asset as AnimationPlayableAsset; + if (asset == null) + return false; + + return TimelineHelpers.HaveSameContainerAsset(track, asset.clip); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimationTrackExtensions.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimationTrackExtensions.cs.meta new file mode 100644 index 0000000..df81151 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/AnimationTrackExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5a31542ccf4e8584ca4f60843e9d02d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/TrackExtensions.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/TrackExtensions.cs new file mode 100644 index 0000000..637e239 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/TrackExtensions.cs @@ -0,0 +1,495 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Timeline; +using UnityEngine.Playables; + +namespace UnityEditor.Timeline +{ + // Editor-only extension methods on track assets + static class TrackExtensions + { + public static readonly double kMinOverlapTime = TimeUtility.kTimeEpsilon * 1000; + + public static AnimationClip GetOrCreateClip(this AnimationTrack track) + { + if (track.infiniteClip == null && !track.inClipMode) + track.CreateInfiniteClip(AnimationTrackRecorder.GetUniqueRecordedClipName(track, AnimationTrackRecorder.kRecordClipDefaultName)); + + return track.infiniteClip; + } + + public static TimelineClip CreateClip(this TrackAsset track, double time) + { + var attr = track.GetType().GetCustomAttributes(typeof(TrackClipTypeAttribute), true); + + if (attr.Length == 0) + return null; + + if (TimelineWindow.instance.state == null) + return null; + + if (attr.Length == 1) + { + var clipClass = (TrackClipTypeAttribute)attr[0]; + + var clip = TimelineHelpers.CreateClipOnTrack(clipClass.inspectedType, track, TimelineWindow.instance.state); + clip.start = time; + return clip; + } + + return null; + } + + static bool Overlaps(TimelineClip blendOut, TimelineClip blendIn) + { + if (blendIn == blendOut) + return false; + + if (Math.Abs(blendIn.start - blendOut.start) < TimeUtility.kTimeEpsilon) + { + return blendIn.duration >= blendOut.duration; + } + + return blendIn.start >= blendOut.start && blendIn.start < blendOut.end; + } + + public static void ComputeBlendsFromOverlaps(this TrackAsset asset) + { + ComputeBlendsFromOverlaps(asset.clips); + } + + internal static void ComputeBlendsFromOverlaps(TimelineClip[] clips) + { + foreach (var clip in clips) + { + clip.blendInDuration = -1; + clip.blendOutDuration = -1; + } + + foreach (var clip in clips) + { + var blendIn = clip; + var blendOut = clips + .Where(c => Overlaps(c, blendIn)) + .OrderBy(c => c.start) + .FirstOrDefault(); + + if (blendOut != null) + { + UpdateClipIntersection(blendOut, blendIn); + } + } + } + + internal static void UpdateClipIntersection(TimelineClip blendOutClip, TimelineClip blendInClip) + { + if (!blendOutClip.SupportsBlending() || !blendInClip.SupportsBlending()) + return; + + if (blendInClip.end < blendOutClip.end) + return; + + double duration = Math.Max(0, blendOutClip.start + blendOutClip.duration - blendInClip.start); + duration = duration <= kMinOverlapTime ? 0 : duration; + blendOutClip.blendOutDuration = duration; + blendInClip.blendInDuration = duration; + + var blendInMode = blendInClip.blendInCurveMode; + var blendOutMode = blendOutClip.blendOutCurveMode; + + if (blendInMode == TimelineClip.BlendCurveMode.Manual && blendOutMode == TimelineClip.BlendCurveMode.Auto) + { + blendOutClip.mixOutCurve = CurveEditUtility.CreateMatchingCurve(blendInClip.mixInCurve); + } + else if (blendInMode == TimelineClip.BlendCurveMode.Auto && blendOutMode == TimelineClip.BlendCurveMode.Manual) + { + blendInClip.mixInCurve = CurveEditUtility.CreateMatchingCurve(blendOutClip.mixOutCurve); + } + else if (blendInMode == TimelineClip.BlendCurveMode.Auto && blendOutMode == TimelineClip.BlendCurveMode.Auto) + { + blendInClip.mixInCurve = null; // resets to default curves + blendOutClip.mixOutCurve = null; + } + } + + internal static void RecursiveSubtrackClone(TrackAsset source, TrackAsset duplicate, IExposedPropertyTable sourceTable, IExposedPropertyTable destTable, PlayableAsset assetOwner) + { + var subtracks = source.GetChildTracks(); + foreach (var sub in subtracks) + { + var newSub = TimelineHelpers.Clone(duplicate, sub, sourceTable, destTable, assetOwner); + duplicate.AddChild(newSub); + RecursiveSubtrackClone(sub, newSub, sourceTable, destTable, assetOwner); + + // Call the custom editor on Create + var customEditor = CustomTimelineEditorCache.GetTrackEditor(newSub); + try + { + customEditor.OnCreate(newSub, sub); + } + catch (Exception e) + { + Debug.LogException(e); + } + + // registration has to happen AFTER recursion + TimelineCreateUtilities.SaveAssetIntoObject(newSub, assetOwner); + TimelineUndo.RegisterCreatedObjectUndo(newSub, "Duplicate"); + } + } + + internal static TrackAsset Duplicate(this TrackAsset track, IExposedPropertyTable sourceTable, IExposedPropertyTable destTable, + TimelineAsset destinationTimeline = null) + { + if (track == null) + return null; + + // if the destination is us, clear to avoid bad parenting (case 919421) + if (destinationTimeline == track.timelineAsset) + destinationTimeline = null; + + var timelineParent = track.parent as TimelineAsset; + var trackParent = track.parent as TrackAsset; + if (timelineParent == null && trackParent == null) + { + Debug.LogWarning("Cannot duplicate track because it is not parented to known type"); + return null; + } + + // Determine who the final parent is. If we are pasting into another track, it's always the timeline. + // Otherwise it's the original parent + PlayableAsset finalParent = destinationTimeline != null ? destinationTimeline : track.parent; + + // grab the list of tracks to generate a name from (923360) to get the list of names + // no need to do this part recursively + var finalTrackParent = finalParent as TrackAsset; + var finalTimelineAsset = finalParent as TimelineAsset; + var otherTracks = (finalTimelineAsset != null) ? finalTimelineAsset.trackObjects : finalTrackParent.subTracksObjects; + + // Important to create the new objects before pushing the original undo, or redo breaks the + // sequence + var newTrack = TimelineHelpers.Clone(finalParent, track, sourceTable, destTable, finalParent); + newTrack.name = TimelineCreateUtilities.GenerateUniqueActorName(otherTracks, newTrack.name); + + RecursiveSubtrackClone(track, newTrack, sourceTable, destTable, finalParent); + TimelineCreateUtilities.SaveAssetIntoObject(newTrack, finalParent); + TimelineUndo.RegisterCreatedObjectUndo(newTrack, "Duplicate"); + TimelineUndo.PushUndo(finalParent, "Duplicate"); + + if (destinationTimeline != null) // other timeline + destinationTimeline.AddTrackInternal(newTrack); + else if (timelineParent != null) // this timeline, no parent + ReparentTracks(new List<TrackAsset> { newTrack }, timelineParent, timelineParent.GetRootTracks().Last(), false); + else // this timeline, with parent + trackParent.AddChild(newTrack); + + // Call the custom editor. this check prevents the call when copying to the clipboard + if (destinationTimeline == null || destinationTimeline == TimelineEditor.inspectedAsset) + { + var customEditor = CustomTimelineEditorCache.GetTrackEditor(newTrack); + try + { + customEditor.OnCreate(newTrack, track); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + return newTrack; + } + + // Reparents a list of tracks to a new parent + // the new parent cannot be null (has to be track asset or sequence) + // the insertAfter can be null (will not reorder) + internal static bool ReparentTracks(List<TrackAsset> tracksToMove, PlayableAsset targetParent, + TrackAsset insertMarker = null, bool insertBefore = false) + { + var targetParentTrack = targetParent as TrackAsset; + var targetSequenceTrack = targetParent as TimelineAsset; + + if (tracksToMove == null || tracksToMove.Count == 0 || (targetParentTrack == null && targetSequenceTrack == null)) + return false; + + // invalid parent type on a track + if (targetParentTrack != null && tracksToMove.Any(x => !TimelineCreateUtilities.ValidateParentTrack(targetParentTrack, x.GetType()))) + return false; + + // no valid tracks means this is simply a rearrangement + var validTracks = tracksToMove.Where(x => x.parent != targetParent).ToList(); + if (insertMarker == null && !validTracks.Any()) + return false; + + var parents = validTracks.Select(x => x.parent).Where(x => x != null).Distinct().ToList(); + + // push the current state of the tracks that will change + foreach (var p in parents) + { + TimelineUndo.PushUndo(p, "Reparent"); + } + foreach (var t in validTracks) + { + TimelineUndo.PushUndo(t, "Reparent"); + } + TimelineUndo.PushUndo(targetParent, "Reparent"); + + // need to reparent tracks first, before moving them. + foreach (var t in validTracks) + { + if (t.parent != targetParent) + { + TrackAsset toMoveParent = t.parent as TrackAsset; + TimelineAsset toMoveTimeline = t.parent as TimelineAsset; + if (toMoveTimeline != null) + { + toMoveTimeline.RemoveTrack(t); + } + else if (toMoveParent != null) + { + toMoveParent.RemoveSubTrack(t); + } + + if (targetParentTrack != null) + { + targetParentTrack.AddChild(t); + targetParentTrack.SetCollapsed(false); + } + else + { + targetSequenceTrack.AddTrackInternal(t); + } + } + } + + + if (insertMarker != null) + { + // re-ordering track. This is using internal APIs, so invalidation of the tracks must be done manually to avoid + // cache mismatches + var children = targetParentTrack != null ? targetParentTrack.subTracksObjects : targetSequenceTrack.trackObjects; + TimelineUtility.ReorderTracks(children, tracksToMove, insertMarker, insertBefore); + if (targetParentTrack != null) + targetParentTrack.Invalidate(); + if (insertMarker.timelineAsset != null) + insertMarker.timelineAsset.Invalidate(); + } + + return true; + } + + internal static IEnumerable<TrackAsset> FilterTracks(IEnumerable<TrackAsset> tracks) + { + var nTracks = tracks.Count(); + // Duplicate is recursive. If should not have parent and child in the list + var hash = new HashSet<TrackAsset>(tracks); + var take = new Dictionary<TrackAsset, bool>(nTracks); + + foreach (var track in tracks) + { + var parent = track.parent as TrackAsset; + var foundParent = false; + // go up the hierarchy + while (parent != null && !foundParent) + { + if (hash.Contains(parent)) + { + foundParent = true; + } + + parent = parent.parent as TrackAsset; + } + + take[track] = !foundParent; + } + + foreach (var track in tracks) + { + if (take[track]) + yield return track; + } + } + + internal static bool IsVisibleRecursive(this TrackAsset track) + { + var t = track; + while ((t = t.parent as TrackAsset) != null) + { + if (t.GetCollapsed()) + return false; + } + + return true; + } + + internal static bool GetCollapsed(this TrackAsset track) + { + return TimelineWindowViewPrefs.IsTrackCollapsed(track); + } + + internal static void SetCollapsed(this TrackAsset track, bool collapsed) + { + TimelineWindowViewPrefs.SetTrackCollapsed(track, collapsed); + } + + internal static bool GetShowMarkers(this TrackAsset track) + { + return TimelineWindowViewPrefs.IsShowMarkers(track); + } + + internal static void SetShowMarkers(this TrackAsset track, bool collapsed) + { + TimelineWindowViewPrefs.SetTrackShowMarkers(track, collapsed); + } + + internal static bool GetShowInlineCurves(this TrackAsset track) + { + return TimelineWindowViewPrefs.GetShowInlineCurves(track); + } + + internal static void SetShowInlineCurves(this TrackAsset track, bool inlineOn) + { + TimelineWindowViewPrefs.SetShowInlineCurves(track, inlineOn); + } + + internal static bool ShouldShowInfiniteClipEditor(this TrackAsset track) + { + var animationTrack = track as AnimationTrack; + if (animationTrack != null) + return animationTrack.ShouldShowInfiniteClipEditor(); + + return track.HasAnyAnimatableParameters(); + } + + internal static bool ShouldShowInfiniteClipEditor(this AnimationTrack track) + { + return track != null && !track.inClipMode && track.infiniteClip != null; + } + + // Special method to remove a track that is in a broken state. i.e. the script won't load + internal static bool RemoveBrokenTrack(PlayableAsset parent, ScriptableObject track) + { + var parentTrack = parent as TrackAsset; + var parentTimeline = parent as TimelineAsset; + + if (parentTrack == null && parentTimeline == null) + throw new ArgumentException("parent is not a valid parent type", "parent"); + + // this object must be a Unity null, but not actually null; + object trackAsObject = track; + if (trackAsObject == null || track != null) // yes, this is correct + throw new ArgumentException("track is not in a broken state"); + + // this belongs to a parent track + if (parentTrack != null) + { + int index = parentTrack.subTracksObjects.FindIndex(t => t.GetInstanceID() == track.GetInstanceID()); + if (index >= 0) + { + TimelineUndo.PushUndo(parentTrack, "Remove Track"); + parentTrack.subTracksObjects.RemoveAt(index); + parentTrack.Invalidate(); + Undo.DestroyObjectImmediate(track); + return true; + } + } + else if (parentTimeline != null) + { + int index = parentTimeline.trackObjects.FindIndex(t => t.GetInstanceID() == track.GetInstanceID()); + if (index >= 0) + { + TimelineUndo.PushUndo(parentTimeline, "Remove Track"); + parentTimeline.trackObjects.RemoveAt(index); + parentTimeline.Invalidate(); + Undo.DestroyObjectImmediate(track); + return true; + } + } + + return false; + } + + // Find the gap at the given time + // return true if there is a gap, false if there is an intersection + // endGap will be Infinity if the gap has no end + internal static bool GetGapAtTime(this TrackAsset track, double time, out double startGap, out double endGap) + { + startGap = 0; + endGap = Double.PositiveInfinity; + + if (track == null || !track.GetClips().Any()) + { + return false; + } + + var discreteTime = new DiscreteTime(time); + + track.SortClips(); + var sortedByStartTime = track.clips; + for (int i = 0; i < sortedByStartTime.Length; i++) + { + var clip = sortedByStartTime[i]; + + // intersection + if (discreteTime >= new DiscreteTime(clip.start) && discreteTime < new DiscreteTime(clip.end)) + { + endGap = time; + startGap = time; + return false; + } + + if (clip.end < time) + { + startGap = clip.end; + } + if (clip.start > time) + { + endGap = clip.start; + break; + } + } + + if (endGap - startGap < TimelineClip.kMinDuration) + { + startGap = time; + endGap = time; + return false; + } + + return true; + } + + public static bool IsCompatibleWithClip(this TrackAsset track, TimelineClip clip) + { + if (track == null || clip == null || clip.asset == null) + return false; + + return TypeUtility.GetPlayableAssetsHandledByTrack(track.GetType()).Contains(clip.asset.GetType()); + } + + // Get a flattened list of all child tracks + public static void GetFlattenedChildTracks(this TrackAsset asset, List<TrackAsset> list) + { + if (asset == null || list == null) + return; + + foreach (var track in asset.GetChildTracks()) + { + list.Add(track); + GetFlattenedChildTracks(track, list); + } + } + + public static IEnumerable<TrackAsset> GetFlattenedChildTracks(this TrackAsset asset) + { + if (asset == null || !asset.GetChildTracks().Any()) + return Enumerable.Empty<TrackAsset>(); + + var flattenedChildTracks = new List<TrackAsset>(); + GetFlattenedChildTracks(asset, flattenedChildTracks); + return flattenedChildTracks; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/TrackExtensions.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/TrackExtensions.cs.meta new file mode 100644 index 0000000..1e9f0c2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Extensions/TrackExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b24618beecc3bf41acadfcf2246d772 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |
