public static void ConvertToClipMode(this AnimationTrack track) { if (track.CanConvertToClipMode()) { TimelineUndo.PushUndo(track, "Convert To Clip"); if (!track.animClip.get_empty()) { TimelineUndo.PushUndo(track.animClip, "Convert To Clip"); float num = AnimationClipCurveCache.Instance.GetCurveInfo(track.animClip).keyTimes.FirstOrDefault <float>(); track.animClip.ShiftBySeconds(-num); TimelineClip timelineClip = track.CreateClipFromAsset(track.animClip); TimelineCreateUtilities.SaveAssetIntoObject(timelineClip.asset, track); timelineClip.start = (double)num; timelineClip.preExtrapolationMode = track.openClipPreExtrapolation; timelineClip.postExtrapolationMode = track.openClipPostExtrapolation; timelineClip.recordable = true; if (Math.Abs(timelineClip.duration) < 1.4012984643248171E-45) { timelineClip.duration = 1.0; } AnimationPlayableAsset animationPlayableAsset = timelineClip.asset as AnimationPlayableAsset; if (animationPlayableAsset) { animationPlayableAsset.position = track.openClipOffsetPosition; animationPlayableAsset.rotation = track.openClipOffsetRotation; track.openClipOffsetPosition = Vector3.get_zero(); track.openClipOffsetRotation = Quaternion.get_identity(); } track.CalculateExtrapolationTimes(); } track.animClip = null; EditorUtility.SetDirty(track); } }
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() && !TimelineWindow.instance.state.editSequence.isReadOnly) { EditorGUI.BeginChangeCheck(); var newName = EditorGUI.DelayedTextField(titleRect, marker.name); if (EditorGUI.EndChangeCheck()) { TimelineUndo.PushUndo(marker, Styles.UndoCommand); marker.name = newName; } } else { base.OnHeaderTitleGUI(titleRect, marker.name); } } else { var typeName = TypeUtility.GetDisplayName(target.GetType()); EditorGUILayout.LabelField(typeName); } }
public virtual void Delete(WindowState state) { // we dont support deleting the summary if (m_DopeLines.index < 1) { return; } if (m_ClipDataSource == null) { return; } var clip = m_ClipDataSource.animationClip; if (clip == null) { return; } int curveIndexToDelete = m_DopeLines.index - 1; var bindings = AnimationUtility.GetCurveBindings(clip); if (curveIndexToDelete >= bindings.Length) { return; } TimelineUndo.PushUndo(clip, "Delete Curve"); AnimationUtility.SetEditorCurve(clip, bindings[m_DopeLines.index - 1], null); state.rebuildGraph = true; }
internal static ItemsPerTrack DuplicateItems(ItemsPerTrack items, TrackAsset target, WindowState state, string undoOperation) { var duplicatedItems = new List <ITimelineItem>(); PlayableDirector director = null; if (state != null) { director = state.editSequence.director; } var clips = items.clips.ToList(); if (clips.Any()) { TimelineUndo.PushUndo(target, undoOperation); duplicatedItems.AddRange(DuplicateClips(clips, director, target).ToItems()); TimelineUndo.PushUndo(target, undoOperation); // second undo causes reference fixups on redo (case 1063868) } var markers = items.markers.ToList(); if (markers.Any()) { duplicatedItems.AddRange(MarkerModifier.CloneMarkersToParent(markers, target).ToItems()); } return(new ItemsPerTrack(target, duplicatedItems.ToArray())); }
internal static void DuplicateBindings(TrackAsset track, TrackAsset newTrack, PlayableDirector director) { var originalTracks = track.GetFlattenedChildTracks().Append(track); var newTracks = newTrack.GetFlattenedChildTracks().Append(newTrack); var toBind = new List <Tuple <TrackAsset, Object> >(); // Collect all track bindings to duplicate var originalIt = originalTracks.GetEnumerator(); var newIt = newTracks.GetEnumerator(); while (originalIt.MoveNext() && newIt.MoveNext()) { var binding = director.GetGenericBinding(originalIt.Current); if (binding != null) { toBind.Add(new Tuple <TrackAsset, Object>(newIt.Current, binding)); } } //Only create Director undo if there are bindings to duplicate if (toBind.Count > 0) { TimelineUndo.PushUndo(TimelineEditor.inspectedDirector, L10n.Tr("Duplicate")); } //Assign bindings for all tracks after undo. foreach (var binding in toBind) { TimelineEditor.inspectedDirector.SetGenericBinding(binding.Item1, binding.Item2); } }
public void FinializeTrack(TrackAsset track, TimelineWindow.TimelineState state) { AnimationTrack animationTrack = track as AnimationTrack; if (!animationTrack.inClipMode) { EditorUtility.SetDirty(animationTrack.GetOrCreateClip()); } if (this.recordClip != null) { if (!this.m_ProcessedClips.Contains(this.recordClip.animationClip)) { this.m_ProcessedClips.Add(this.recordClip.animationClip); } if (this.m_ClipTime > this.recordClip.duration) { TimelineUndo.PushUndo(track, "Add Key"); this.recordClip.duration = this.m_ClipTime; this.m_RefreshState = true; } track.CalculateExtrapolationTimes(); } this.recordClip = null; this.m_ClipTime = 0.0; if (this.m_needRebuildRects) { state.CalculateRowRects(); this.m_needRebuildRects = false; } }
public static void RemoveCurve(UnityEngine.Object target, IEnumerable <PropertyModification> modifications, WindowState state) { AnimationClip clip = null; double keyTime = 0; var inRange = false; // not used for curves if (!GetClipAndRelativeTime(target, state, out clip, out keyTime, out inRange)) { return; } TimelineUndo.PushUndo(clip, "Remove Curve"); foreach (var mod in modifications) { EditorCurveBinding temp; if (HasBinding(target, mod, clip, out temp)) { if (temp.isPPtrCurve) { AnimationUtility.SetObjectReferenceCurve(clip, temp, null); } else { AnimationUtility.SetEditorCurve(clip, temp, null); } } } state.ResetPreviewMode(); }
public override bool Execute(WindowState state, TrackAsset[] tracks) { if (tracks.Any()) { SelectionManager.RemoveTimelineSelection(); } foreach (var track in TrackExtensions.FilterTracks(tracks)) { var newTrack = track.Duplicate(TimelineEditor.inspectedDirector, TimelineEditor.inspectedDirector); SelectionManager.Add(newTrack); foreach (var childTrack in newTrack.GetFlattenedChildTracks()) { SelectionManager.Add(childTrack); } if (TimelineEditor.inspectedDirector != null) { var binding = TimelineEditor.inspectedDirector.GetGenericBinding(track); if (binding != null) { TimelineUndo.PushUndo(TimelineEditor.inspectedDirector, "Duplicate"); TimelineEditor.inspectedDirector.SetGenericBinding(newTrack, binding); } } } state.Refresh(); return(true); }
public override bool Execute(IEnumerable <TrackAsset> tracks) { tracks = tracks.RemoveTimelineMarkerTrackFromList(TimelineEditor.inspectedAsset); if (tracks.Any()) { SelectionManager.RemoveTimelineSelection(); } foreach (var track in TrackExtensions.FilterTracks(tracks)) { var newTrack = track.Duplicate(TimelineEditor.inspectedDirector, TimelineEditor.inspectedDirector); SelectionManager.Add(newTrack); foreach (var childTrack in newTrack.GetFlattenedChildTracks()) { SelectionManager.Add(childTrack); } if (TimelineEditor.inspectedDirector != null) { var binding = TimelineEditor.inspectedDirector.GetGenericBinding(track); if (binding != null) { TimelineUndo.PushUndo(TimelineEditor.inspectedDirector, L10n.Tr("Duplicate")); TimelineEditor.inspectedDirector.SetGenericBinding(newTrack, binding); } } } TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved); return(true); }
public static void Bind(TrackAsset track, Object obj, PlayableDirector director) { if (director != null && track != null) { var bindType = TypeUtility.GetTrackBindingAttribute(track.GetType()); if (bindType == null || bindType.type == null) { return; } if (obj == null || bindType.type.IsInstanceOfType(obj)) { TimelineUndo.PushUndo(director, "Bind Track"); director.SetGenericBinding(track, obj); } else if (obj is GameObject && typeof(Component).IsAssignableFrom(bindType.type)) { var component = (obj as GameObject).GetComponent(bindType.type); if (component == null) { component = Undo.AddComponent(obj as GameObject, bindType.type); } TimelineUndo.PushUndo(director, "Bind Track"); director.SetGenericBinding(track, component); } } }
float DrawInlineCurveButton(Rect rect, WindowState state) { if (!CanDrawInlineCurve()) { return(0.0f); } // Override enable state to display "Show Inline Curves" button in disabled state. bool prevEnabledState = GUI.enabled; GUI.enabled = true; var newValue = GUI.Toggle(rect, track.GetShowInlineCurves(), GUIContent.none, DirectorStyles.Instance.curves); GUI.enabled = prevEnabledState; if (newValue != track.GetShowInlineCurves()) { if (!state.editSequence.isReadOnly) { TimelineUndo.PushUndo(track, newValue ? "Show Inline Curves" : "Hide Inline Curves"); } track.SetShowInlineCurves(newValue); state.GetWindow().treeView.CalculateRowRects(); } return(WindowConstants.trackHeaderButtonSize); }
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; TimelineUndo.PushUndo(uiClip.clip.parentTrack, undoName); m_UndoSaved = true; } double d = state.PixelDeltaToDeltaTime(evt.delta.x); if (m_Edges == ManipulateEdges.Left) { m_Clip.easeInDuration = Math.Max(0, m_Clip.easeInDuration + d); } else if (m_Edges == ManipulateEdges.Right) { m_Clip.easeOutDuration = 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 foreach (var t in clips.Select(x => x.parentTrack).Distinct()) { TimelineUndo.PushUndo(t, kInsertTime); } // push the clips foreach (var clip in clips) { clip.start += amount; } // push undos and move the markers foreach (var marker in markers) { var obj = marker as UnityEngine.Object; if (obj != null) { TimelineUndo.PushUndo(obj, kInsertTime); } marker.time += amount; } TimelineEditor.Refresh(RefreshReason.ContentsModified); }
void DrawTrackBinding(Rect rect, Rect headerRect) { if (m_TrackDrawData.m_ShowTrackBindings) { DoTrackBindingGUI(rect, headerRect); return; } var textStyle = m_Styles.trackHeaderFont; textStyle.normal.textColor = SelectionManager.Contains(track) ? Color.white : m_Styles.customSkin.colorTrackFont; string trackName = track.name; EditorGUI.BeginChangeCheck(); // by default the size is just the width of the string (for selection purposes) rect.width = m_Styles.trackHeaderFont.CalcSize(new GUIContent(trackName)).x; // if we are editing, supply the entire width of the header if (GUIUtility.keyboardControl == track.GetInstanceID()) { rect.width = (headerRect.xMax - rect.xMin) - (5 * WindowConstants.trackHeaderButtonSize); } trackName = EditorGUI.DelayedTextField(rect, GUIContent.none, track.GetInstanceID(), track.name, textStyle); if (EditorGUI.EndChangeCheck()) { TimelineUndo.PushUndo(track, "Rename Track"); track.name = trackName; } }
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 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 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 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 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); }
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"); } }
static ScriptableObject CloneReferencedPlayableAsset(ScriptableObject original, PlayableDirector directorInstance) { var clone = Object.Instantiate(original); TimelineUndo.RegisterCreatedObjectUndo(clone, "Create clip"); if (clone == null || (clone as IPlayableAsset) == null) { throw new InvalidCastException("could not cast instantiated object into IPlayableAsset"); } if (directorInstance != null) { // Use serialize object to make a copy var originalObject = new SerializedObject(original); var cloneObject = new SerializedObject(clone); SerializedProperty prop = originalObject.GetIterator(); if (prop.Next(true)) { do { cloneObject.CopyFromSerializedProperty(prop); } while (prop.Next(false)); } cloneObject.ApplyModifiedProperties(); EditorUtility.SetDirty(directorInstance); // The exposedName of exposed properties needs to be cleared otherwise the clone will act as an instance var exposedRefs = clone.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(f => f.FieldType.IsGenericType && f.FieldType.GetGenericTypeDefinition() == typeof(ExposedReference <>)).ToList(); foreach (FieldInfo fi in exposedRefs) { var exposedRefInstance = fi.GetValue(clone); var exposedNameProperty = exposedRefInstance.GetType().GetField("exposedName"); if (exposedNameProperty != null) { var exposedNameValue = (PropertyName)exposedNameProperty.GetValue(exposedRefInstance); bool isValid = false; var originalReference = directorInstance.GetReferenceValue(exposedNameValue, out isValid); if (isValid) { // generate new reference in directorInstance var newPropertyName = new PropertyName(GUID.Generate().ToString()); directorInstance.SetReferenceValue(newPropertyName, originalReference); exposedNameProperty.SetValue(exposedRefInstance, newPropertyName); if (!EditorApplication.isPlaying) { EditorSceneManager.MarkSceneDirty(directorInstance.gameObject.scene); } } } fi.SetValue(clone, exposedRefInstance); } } return(clone); }
public static void SetBindingInDirector(PlayableDirector director, Object bindTo, Object objectToBind) { if (!(director == null) && !(bindTo == null)) { TimelineUndo.PushUndo(director, "PlayableDirector Binding"); director.SetGenericBinding(bindTo, objectToBind); } }
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 ToggleMute(WindowState state) { var timeline = state.editSequence.asset; timeline.CreateMarkerTrack(); TimelineUndo.PushUndo(timeline.markerTrack, "Toggle Mute"); timeline.markerTrack.muted = !timeline.markerTrack.muted; }
void AssignSignalAsset(SignalAsset newAsset) { foreach (var o in targets) { var signalEmitter = (SignalEmitter)o; TimelineUndo.PushUndo(signalEmitter, Styles.UndoCreateSignalAsset); signalEmitter.asset = newAsset; } }
public static bool DeleteTrack(TimelineAsset timeline, TrackAsset track) { if (TimelineEditor.inspectedDirector != null) { TimelineUndo.PushUndo(TimelineEditor.inspectedDirector, "Delete Track"); TimelineEditor.inspectedDirector.ClearGenericBinding(track); } return(timeline.DeleteTrack(track)); }
public static void SetLockState(TrackAsset[] tracks, bool shouldLock, WindowState state = null) { if (tracks.Length == 0) { return; } foreach (var track in tracks) { if (TimelineUtility.IsLockedFromGroup(track)) { continue; } if (track as GroupTrack == null) { SetLockState(track.GetChildTracks().ToArray(), shouldLock, state); } TimelineUndo.PushUndo(track, "Lock Tracks"); track.locked = shouldLock; } if (state != null) { // find the tracks we've locked. unselect anything locked and remove recording. foreach (var track in tracks) { if (TimelineUtility.IsLockedFromGroup(track) || !track.locked) { continue; } var flattenedChildTracks = track.GetFlattenedChildTracks(); foreach (var i in track.clips) { SelectionManager.Remove(i); } state.UnarmForRecord(track); foreach (var child in flattenedChildTracks) { SelectionManager.Remove(child); state.UnarmForRecord(child); foreach (var clip in child.GetClips()) { SelectionManager.Remove(clip); } } } // no need to rebuild, just repaint (including inspectors) InspectorWindow.RepaintAllInspectors(); state.editorWindow.Repaint(); } }
public static bool MatchDuration(TimelineClip[] clips) { double duration = clips[0].duration; for (int i = 1; i < clips.Length; i++) { TimelineUndo.PushUndo(clips[i].parentTrack, "Match Clip Duration"); clips[i].duration = duration; } return(true); }
private void CreateExistingMarker(string key, ITimelineMarkerContainer container, ITimelineState state) { Vector3 mousePosition = (this.trackMenuContext.clipTimeCreation != TrackDrawer.TrackMenuContext.ClipTimeCreation.Mouse) ? TimelineHelpers.sInvalidMousePosition : this.trackMenuContext.mousePosition; double time = TrackDrawer.CalculateMarkerTimeForMousePosition(container as TrackAsset, state, mousePosition); TimelineUndo.PushUndo(container as Object, "Create Marker"); TimelineMarker newEvent = container.CreateMarker(key, time); TrackDrawer.SelectMarkerInInspector(state, newEvent); state.Refresh(); }
public static TimelineClip DuplicateAtTime(this TimelineClip clip, TrackAsset track, double time, PlayableDirector director) { TimelineUndo.PushUndo(track, "Clone Clip"); TimelineClip timelineClip = TimelineHelpers.Clone(clip, director); timelineClip.start = time; timelineClip.parentTrack = track; track.AddClip(timelineClip); track.SortClips(); TrackExtensions.ComputeBlendsFromOverlaps(track.clips); return(timelineClip); }