public static bool Tile(IEnumerable <TimelineClip> clips) { if (clips.Count() < 2) { return(false); } var clipsByTracks = clips.GroupBy(x => x.GetParentTrack()) .Select(track => new { track.Key, Items = track.OrderBy(c => c.start) }); foreach (var track in clipsByTracks) { UndoExtensions.RegisterTrack(track.Key, L10n.Tr("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); }
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; UndoExtensions.RegisterClip(clip, L10n.Tr("Trim Clip Last Loop")); TrimClipWithEditMode(clip, TrimEdge.End, newEnd); }
public void FinializeTrack(TrackAsset track, WindowState state) { // make sure we dirty the clip if we are in non clip mode var animTrack = track as AnimationTrack; if (!animTrack.inClipMode) { EditorUtility.SetDirty(animTrack.GetOrCreateClip()); } // in clip mode we need to do some extra work if (recordClip != null) { // stretch the clip out to meet the new recording time if (m_ClipTime > recordClip.duration) { UndoExtensions.RegisterTrack(track, "Add Key"); recordClip.duration = m_ClipTime; } track.CalculateExtrapolationTimes(); } recordClip = null; m_ClipTime = 0; if (m_needRebuildRects) { state.CalculateRowRects(); m_needRebuildRects = false; } }
public static bool Split(IEnumerable <TimelineClip> clips, double splitTime, PlayableDirector director) { var result = false; foreach (var clip in clips) { if (clip.start >= splitTime) { continue; } if (clip.end <= splitTime) { continue; } UndoExtensions.RegisterClip(clip, L10n.Tr("Split Clip")); TimelineClip newClip = TimelineHelpers.Clone(clip, director, director, clip.start); clip.easeInDuration = 0; newClip.easeOutDuration = 0; SetStart(clip, splitTime, false); SetEnd(newClip, splitTime, false); // Sort produced by cloning clips on top of each other is unpredictable (it varies between mono runtimes) clip.GetParentTrack().SortClips(); result = true; } return(result); }
public void Drop() { if (IsValidDrop()) { foreach (var grabbedItems in movingItems) { var track = grabbedItems.targetTrack; UndoExtensions.RegisterTrack(track, L10n.Tr("Move Items")); if (EditModeUtils.IsInfiniteTrack(track) && grabbedItems.clips.Any()) { ((AnimationTrack)track).ConvertToClipMode(); } } EditMode.FinishMove(); Done(); } else { Cancel(); } EditMode.ClearEditMode(); }
protected override bool MouseDrag(Event evt, WindowState state) { if (!m_IsCaptured) { return(false); } if (!m_UndoSaved) { var uiClip = m_EaseClipHandler.clipGUI; string undoName = m_Edges == ManipulateEdges.Left ? EaseInClipText : EaseOutClipText; UndoExtensions.RegisterClip(uiClip.clip, undoName); m_UndoSaved = true; } double d = state.PixelDeltaToDeltaTime(evt.delta.x); var duration = m_Clip.duration; var easeInDurationLimit = duration - m_Clip.easeOutDuration; var easeOutDurationLimit = duration - m_Clip.easeInDuration; if (m_Edges == ManipulateEdges.Left) { m_Clip.easeInDuration = Math.Min(easeInDurationLimit, Math.Max(0, m_Clip.easeInDuration + d)); } else if (m_Edges == ManipulateEdges.Right) { m_Clip.easeOutDuration = Math.Min(easeOutDurationLimit, Math.Max(0, m_Clip.easeOutDuration - d)); } RefreshOverlayStrings(m_EaseClipHandler, state); return(true); }
public static void Insert(TimelineAsset asset, double at, double amount, double tolerance) { var tracks = asset.flattenedTracks.Where(x => x.lockedInHierarchy == false).ToList(); // gather all clips var clips = tracks.SelectMany(x => x.clips).Where(x => (x.start - at) >= -tolerance).ToList(); var markers = tracks.SelectMany(x => x.GetMarkers()).Where(x => (x.time - at) >= -tolerance).ToList(); // push undo on the tracks for the clips that are being modified UndoExtensions.RegisterClips(clips, kInsertTime); // push the clips foreach (var clip in clips) { clip.start += amount; } // push undos and move the markers UndoExtensions.RegisterMarkers(markers, kInsertTime); foreach (var marker in markers) { marker.time += amount; } TimelineEditor.Refresh(RefreshReason.ContentsModified); }
internal override void OnHeaderTitleGUI(Rect titleRect, string header) { if (targets.Length > 1) { var multiSelectTitle = string.Format(Styles.MultipleMarkerSelectionTitle, targets.Length); base.OnHeaderTitleGUI(titleRect, multiSelectTitle); return; } var marker = target as Marker; if (marker != null) { if (marker.parent.GetShowMarkers() && TimelineUtility.IsCurrentSequenceValid() && !IsCurrentSequenceReadOnly()) { EditorGUI.BeginChangeCheck(); var newName = EditorGUI.DelayedTextField(titleRect, marker.name); if (EditorGUI.EndChangeCheck()) { UndoExtensions.RegisterMarker(marker, Styles.UndoCommand); marker.name = newName; } } else { base.OnHeaderTitleGUI(titleRect, marker.name); } } else { var typeName = TypeUtility.GetDisplayName(target.GetType()); EditorGUILayout.LabelField(typeName); } }
public static bool MatchContent(TimelineClip clip) { if (clip.asset == null) { return(false); } UndoExtensions.RegisterClip(clip, L10n.Tr("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 bool TrimStart(TimelineClip clip, double trimTime) { if (clip.asset == null) { return(false); } if (clip.start > trimTime) { return(false); } if (clip.end < trimTime) { return(false); } UndoExtensions.RegisterClip(clip, L10n.Tr("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, false); clip.ConformEaseValues(); return(true); }
internal static void ConvertFromClipMode(this AnimationTrack track, TimelineAsset timeline) { if (!track.CanConvertFromClipMode()) { return; } UndoExtensions.RegisterTrack(track, L10n.Tr("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, L10n.Tr("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); track.infiniteClip = animClip; EditorUtility.SetDirty(track); }
static void AddMarkerToParent(ScriptableObject marker, TrackAsset parent) { TimelineCreateUtilities.SaveAssetIntoObject(marker, parent); TimelineUndo.RegisterCreatedObjectUndo(marker, L10n.Tr("Duplicate Marker")); UndoExtensions.RegisterTrack(parent, L10n.Tr("Duplicate Marker")); if (parent != null) { parent.AddMarker(marker); ((IMarker)marker).Initialize(parent); } }
public static bool MatchDuration(IEnumerable <TimelineClip> clips) { double referenceDuration = clips.First().duration; UndoExtensions.RegisterClips(clips, L10n.Tr("Match Clip Duration")); foreach (var clip in clips) { var newEnd = clip.start + referenceDuration; TrimClipWithEditMode(clip, TrimEdge.End, newEnd); } return(true); }
public static bool HalfSpeed(IEnumerable <TimelineClip> clips) { foreach (var clip in clips) { if (clip.SupportsSpeedMultiplier()) { UndoExtensions.RegisterClip(clip, L10n.Tr("Half Clip Speed")); clip.timeScale = clip.timeScale * 0.5f; } } return(true); }
public static bool DoubleSpeed(IEnumerable <TimelineClip> clips) { foreach (var clip in clips) { if (clip.SupportsSpeedMultiplier()) { UndoExtensions.RegisterClip(clip, "Double Clip Speed"); clip.timeScale = clip.timeScale * 2.0f; } } return(true); }
public static bool ResetSpeed(IEnumerable <TimelineClip> clips) { foreach (var clip in clips) { if (clip.timeScale != 1.0) { UndoExtensions.RegisterClip(clip, L10n.Tr("Reset Clip Speed")); clip.timeScale = 1.0; } } return(true); }
internal static void ConvertToClipMode(this AnimationTrack track) { if (!track.CanConvertToClipMode()) { return; } UndoExtensions.RegisterTrack(track, L10n.Tr("Convert To Clip")); if (!track.infiniteClip.empty) { var animClip = track.infiniteClip; TimelineUndo.PushUndo(animClip, L10n.Tr("Convert To Clip")); UndoExtensions.RegisterTrack(track, L10n.Tr("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 BeginTrim(ITimelineItem item, TrimEdge trimDirection) { var itemToTrim = item as ITrimmable; if (itemToTrim == null) { return; } s_CurrentTrimItem = itemToTrim; s_CurrentTrimDirection = trimDirection; trimMode.OnBeforeTrim(itemToTrim, trimDirection); UndoExtensions.RegisterTrack(itemToTrim.parentTrack, L10n.Tr("Trim Clip")); }
private void ConvertToRecordableClip(AnimationTrack track) { if (track == null || !track.hasClips) { return; } UndoExtensions.RegisterTrack(track, L10n.Tr("ConvertToRecordableClip")); var clip = track.GetClips().First(); var delta = (float)clip.start; var duration = clip.duration; var animationAsset = clip.asset as AnimationPlayableAsset; if (animationAsset == null) { return; } var animationClipSource = animationAsset.clip; var animationName = animationClipSource.name; foreach (var c in track.GetClips()) { track.DeleteClip(c); } var recordableClip = track.CreateRecordableClip(animationName); recordableClip.start = delta; recordableClip.duration = duration; var newAnimationClip = (recordableClip.asset as AnimationPlayableAsset).clip; newAnimationClip.name = animationName; var setting = AnimationUtility.GetAnimationClipSettings(animationClipSource); AnimationUtility.SetAnimationClipSettings(newAnimationClip, setting); newAnimationClip.frameRate = animationClipSource.frameRate; EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(animationClipSource); for (int i = 0; i < curveBindings.Length; i++) { AnimationUtility.SetEditorCurve(newAnimationClip, curveBindings[i], AnimationUtility.GetEditorCurve(animationClipSource, curveBindings[i])); } EditorUtility.SetDirty(track); }
protected override bool MouseDrag(Event evt, WindowState state) { if (state.editSequence.isReadOnly) { return(false); } if (!m_IsCaptured) { return(false); } var uiClip = m_TrimClipHandler.clipGUI; if (!m_UndoSaved) { UndoExtensions.RegisterClip(uiClip.clip, "Trim Clip"); if (TimelineUtility.IsRecordableAnimationClip(uiClip.clip)) { TimelineUndo.PushUndo(uiClip.clip.animationClip, "Trim Clip"); } m_UndoSaved = true; } //Reset to original ease values. The trim operation will calculate the proper blend values. uiClip.clip.easeInDuration = m_OriginalEaseInDuration; uiClip.clip.easeOutDuration = m_OriginalEaseOutDuration; if (m_SnapEngine != null) { m_SnapEngine.Snap(evt.mousePosition, evt.modifiers); } RefreshOverlayStrings(m_TrimClipHandler, state); if (Selection.activeObject != null) { EditorUtility.SetDirty(Selection.activeObject); } // updates the duration of the graph without rebuilding state.UpdateRootPlayableDuration(state.editSequence.duration); return(true); }
// 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 as TrackAsset != 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) { UndoExtensions.RegisterTrack(parentTrack, L10n.Tr("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) { UndoExtensions.RegisterPlayableAsset(parentTimeline, L10n.Tr("Remove Track")); parentTimeline.trackObjects.RemoveAt(index); parentTimeline.Invalidate(); Undo.DestroyObjectImmediate(track); return(true); } } return(false); }
void DoOffsetManipulator() { if (targets.Length > 1) //do not edit the track offset on a multiple selection { return; } if (timelineWindow == null || timelineWindow.state == null || timelineWindow.state.editSequence.director == null) { return; } AnimationTrack animationTrack = target as AnimationTrack; if (animationTrack != null && (animationTrack.trackOffset == TrackOffset.ApplyTransformOffsets) && m_OffsetEditMode != TimelineAnimationUtilities.OffsetEditMode.None) { var boundObject = TimelineUtility.GetSceneGameObject(timelineWindow.state.editSequence.director, animationTrack); var boundObjectTransform = boundObject != null ? boundObject.transform : null; var offsets = TimelineAnimationUtilities.GetTrackOffsets(animationTrack, boundObjectTransform); EditorGUI.BeginChangeCheck(); switch (m_OffsetEditMode) { case TimelineAnimationUtilities.OffsetEditMode.Translation: offsets.position = Handles.PositionHandle(offsets.position, (Tools.pivotRotation == PivotRotation.Global) ? Quaternion.identity : offsets.rotation); break; case TimelineAnimationUtilities.OffsetEditMode.Rotation: offsets.rotation = Handles.RotationHandle(offsets.rotation, offsets.position); break; } if (EditorGUI.EndChangeCheck()) { UndoExtensions.RegisterTrack(animationTrack, L10n.Tr("Inspector")); TimelineAnimationUtilities.UpdateTrackOffset(animationTrack, boundObjectTransform, offsets); Evaluate(); Repaint(); } } }
public static bool ResetEditing(TimelineClip clip) { if (clip.asset == null) { return(false); } UndoExtensions.RegisterClip(clip, L10n.Tr("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); }
// Drag handler for the gui void OnTrackDurationDrag(double newTime) { if (state.editSequence.asset.durationMode == TimelineAsset.DurationMode.FixedLength && !state.editSequence.isReadOnly) { // this is the first call to the drag if (m_TimelineDuration.firstDrag) { UndoExtensions.RegisterTimeline(state.editSequence.asset, L10n.Tr("Change Duration")); } state.editSequence.asset.fixedDuration = newTime; // when setting a new length, modify the duration of the timeline playable directly instead of // rebuilding the whole graph state.UpdateRootPlayableDuration(newTime); } m_TimelineDuration.showTooltip = true; }
static void SelectDurationCallback(WindowState state, TimelineAsset.DurationMode mode) { if (mode == state.editSequence.asset.durationMode) { return; } UndoExtensions.RegisterTimeline(state.editSequence.asset, "Duration Mode"); // if we switched from Auto to Fixed, use the auto duration as the new fixed duration so the end marker stay in the same position. if (state.editSequence.asset.durationMode == TimelineAsset.DurationMode.BasedOnClips && mode == TimelineAsset.DurationMode.FixedLength) { state.editSequence.asset.UpdateFixedDurationWithItemsDuration(); } state.editSequence.asset.durationMode = mode; state.UpdateRootPlayableDuration(state.editSequence.duration); }
public void HandleTrackSwitch(IEnumerable <ItemsPerTrack> itemsGroups) { foreach (var itemsGroup in itemsGroups) { var targetTrack = itemsGroup.targetTrack; if (targetTrack != null && itemsGroup.items.Any()) { var compatible = itemsGroup.items.First().IsCompatibleWithTrack(targetTrack) && !EditModeUtils.IsInfiniteTrack(targetTrack); var track = compatible ? targetTrack : null; UndoExtensions.RegisterTrack(track, L10n.Tr("Move Items")); EditModeUtils.SetParentTrack(itemsGroup.items, track); } else { EditModeUtils.SetParentTrack(itemsGroup.items, null); } } }
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); } UndoExtensions.RegisterClip(clip, L10n.Tr("Trim Clip End")); TrimClipWithEditMode(clip, TrimEdge.End, trimTime); return(true); }
void DoManipulators() { if (m_EditorClip == null || m_EditorClip.clip == null) { return; } AnimationPlayableAsset animationPlayable = m_EditorClip.clip.asset as AnimationPlayableAsset; AnimationTrack track = m_EditorClip.clip.parentTrack as AnimationTrack; Transform transform = GetTransform(); if (transform != null && animationPlayable != null && m_OffsetEditMode != TimelineAnimationUtilities.OffsetEditMode.None && track != null) { UndoExtensions.RegisterPlayableAsset(animationPlayable, "Inspector"); Vector3 position = transform.position; Quaternion rotation = transform.rotation; EditorGUI.BeginChangeCheck(); if (m_OffsetEditMode == TimelineAnimationUtilities.OffsetEditMode.Translation) { position = Handles.PositionHandle(position, Tools.pivotRotation == PivotRotation.Global ? Quaternion.identity : rotation); } else if (m_OffsetEditMode == TimelineAnimationUtilities.OffsetEditMode.Rotation) { rotation = Handles.RotationHandle(rotation, position); } if (EditorGUI.EndChangeCheck()) { var res = TimelineAnimationUtilities.UpdateClipOffsets(animationPlayable, track, transform, position, rotation); animationPlayable.position = res.position; animationPlayable.eulerAngles = AnimationUtility.GetClosestEuler(res.rotation, animationPlayable.eulerAngles, RotationOrder.OrderZXY); Reevaluate(); Repaint(); } } }
public void PushUndo(string operation) { UndoExtensions.RegisterMarker(m_Marker, operation); }
public void PushUndo(string operation) { UndoExtensions.RegisterClip(m_Clip, operation); }