From c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sun, 19 Apr 2020 17:19:32 -0400 Subject: Inital commit --- .../Editor/treeview/ItemGui/ISelectable.cs | 11 + .../Editor/treeview/ItemGui/ISelectable.cs.meta | 11 + .../Editor/treeview/ItemGui/TimelineClipGUI.cs | 760 +++++++++++++++++++++ .../treeview/ItemGui/TimelineClipGUI.cs.meta | 11 + .../Editor/treeview/ItemGui/TimelineItemGUI.cs | 92 +++ .../treeview/ItemGui/TimelineItemGUI.cs.meta | 11 + .../treeview/ItemGui/TimelineMarkerClusterGUI.cs | 150 ++++ .../ItemGui/TimelineMarkerClusterGUI.cs.meta | 11 + .../Editor/treeview/ItemGui/TimelineMarkerGUI.cs | 193 ++++++ .../treeview/ItemGui/TimelineMarkerGUI.cs.meta | 11 + 10 files changed, 1261 insertions(+) create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs.meta create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs.meta create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs.meta create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs.meta create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs.meta (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui') diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs new file mode 100644 index 0000000..5f312c1 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs @@ -0,0 +1,11 @@ +using System; + +namespace UnityEditor.Timeline +{ + interface ISelectable : ILayerable + { + void Select(); + bool IsSelected(); + void Deselect(); + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs.meta new file mode 100644 index 0000000..970ecaa --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4acbfc0398bab674f922f693e58f4afc +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/treeview/ItemGui/TimelineClipGUI.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs new file mode 100644 index 0000000..7d00228 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs @@ -0,0 +1,760 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Playables; +using UnityEngine.Timeline; + +namespace UnityEditor.Timeline +{ + class TimelineClipGUI : TimelineItemGUI, IClipCurveEditorOwner, ISnappable, IAttractable + { + EditorClip m_EditorItem; + + Rect m_ClipCenterSection; + readonly List m_LoopRects = new List(); + + ClipDrawData m_ClipDrawData; + Rect m_MixOutRect = new Rect(); + Rect m_MixInRect = new Rect(); + int m_MinLoopIndex = 1; + + // clip dirty detection + int m_LastDirtyIndex = Int32.MinValue; + bool m_ClipViewDirty = true; + + bool supportResize { get; } + public ClipCurveEditor clipCurveEditor { get; set; } + public TimelineClipGUI previousClip { get; set; } + public TimelineClipGUI nextClip { get; set; } + + static readonly float k_MinMixWidth = 2; + static readonly float k_MaxHandleWidth = 10f; + static readonly float k_MinHandleWidth = 1f; + + bool? m_ShowDrillIcon; + ClipEditor m_ClipEditor; + + static List s_TempSubDirectors = new List(); + + static readonly IconData k_DiggableClipIcon = new IconData(DirectorStyles.LoadIcon("TimelineDigIn")); + + string name + { + get + { + if (string.IsNullOrEmpty(clip.displayName)) + return "(Empty)"; + + return clip.displayName; + } + } + + public bool inlineCurvesSelected + { + get { return SelectionManager.IsCurveEditorFocused(this); } + set + { + if (!value && SelectionManager.IsCurveEditorFocused(this)) + SelectionManager.SelectInlineCurveEditor(null); + else + SelectionManager.SelectInlineCurveEditor(this); + } + } + + public Rect mixOutRect + { + get + { + var percent = clip.mixOutPercentage; + var x = Mathf.Round(treeViewRect.width * (1 - percent)); + var width = Mathf.Round(treeViewRect.width * percent); + m_MixOutRect.Set(x, 0.0f, width, treeViewRect.height); + return m_MixOutRect; + } + } + + public Rect mixInRect + { + get + { + var width = Mathf.Round(treeViewRect.width * clip.mixInPercentage); + m_MixInRect.Set(0.0f, 0.0f, width, treeViewRect.height); + return m_MixInRect; + } + } + + public ClipBlends GetClipBlends() + { + var _mixInRect = mixInRect; + var _mixOutRect = mixOutRect; + + var blendInKind = BlendKind.None; + if (_mixInRect.width > k_MinMixWidth && clip.hasBlendIn) + blendInKind = BlendKind.Mix; + else if (_mixInRect.width > k_MinMixWidth) + blendInKind = BlendKind.Ease; + + var blendOutKind = BlendKind.None; + if (_mixOutRect.width > k_MinMixWidth && clip.hasBlendOut) + blendOutKind = BlendKind.Mix; + else if (_mixOutRect.width > k_MinMixWidth) + blendOutKind = BlendKind.Ease; + + return new ClipBlends(blendInKind, _mixInRect, blendOutKind, _mixOutRect); + } + + public override double start + { + get { return clip.start; } + } + + public override double end + { + get { return clip.end; } + } + + public bool supportsLooping + { + get { return clip.SupportsLooping(); } + } + + // for the inline curve editor, only show loops if we recorded the asset + bool IClipCurveEditorOwner.showLoops + { + get { return clip.SupportsLooping() && (clip.asset is AnimationPlayableAsset); } + } + + TrackAsset IClipCurveEditorOwner.owner + { + get { return clip.parentTrack; } + } + + public bool supportsSubTimelines + { + get { return m_ClipEditor.supportsSubTimelines; } + } + + + public int minLoopIndex + { + get { return m_MinLoopIndex; } + } + + public TrackDrawer drawer + { + get { return ((TimelineTrackGUI)parent).drawer; } + } + + public Rect clippedRect { get; private set; } + + public override void Select() + { + zOrder = zOrderProvider.Next(); + SelectionManager.Add(clip); + } + + public override bool IsSelected() + { + return SelectionManager.Contains(clip); + } + + public override void Deselect() + { + SelectionManager.Remove(clip); + } + + public override ITimelineItem item + { + get { return ItemsUtils.ToItem(clip); } + } + + IZOrderProvider zOrderProvider { get; } + + public TimelineClipHandle leftHandle { get; } + public TimelineClipHandle rightHandle { get; } + + public TimelineClipGUI(TimelineClip clip, IRowGUI parent, IZOrderProvider provider) : base(parent) + { + zOrderProvider = provider; + zOrder = provider.Next(); + + m_EditorItem = EditorClipFactory.GetEditorClip(clip); + m_ClipEditor = CustomTimelineEditorCache.GetClipEditor(clip); + + supportResize = true; + + leftHandle = new TimelineClipHandle(this, TrimEdge.Start); + rightHandle = new TimelineClipHandle(this, TrimEdge.End); + + ItemToItemGui.Add(clip, this); + } + + void CreateInlineCurveEditor(WindowState state) + { + if (clipCurveEditor != null) + return; + + var animationClip = clip.animationClip; + + if (animationClip != null && animationClip.empty) + animationClip = null; + + // prune out clips coming from FBX + if (animationClip != null && !clip.recordable) + return; // don't show, even if there are curves + + if (animationClip == null && !clip.HasAnyAnimatableParameters()) + return; // nothing to show + + state.AddEndFrameDelegate((istate, currentEvent) => + { + clipCurveEditor = new ClipCurveEditor(CurveDataSource.Create(this), TimelineWindow.instance, clip.parentTrack); + return true; + }); + } + + public TimelineClip clip + { + get { return m_EditorItem.clip; } + } + + // Draw the actual clip. Defers to the track drawer for customization + void UpdateDrawData(WindowState state, Rect drawRect, string title, bool selected, bool previousClipSelected, float rectXOffset) + { + m_ClipDrawData.clip = clip; + m_ClipDrawData.targetRect = drawRect; + m_ClipDrawData.clipCenterSection = m_ClipCenterSection; + m_ClipDrawData.unclippedRect = treeViewRect; + m_ClipDrawData.title = title; + m_ClipDrawData.selected = selected; + m_ClipDrawData.inlineCurvesSelected = inlineCurvesSelected; + m_ClipDrawData.previousClip = previousClip != null ? previousClip.clip : null; + m_ClipDrawData.previousClipSelected = previousClipSelected; + + Vector3 shownAreaTime = state.timeAreaShownRange; + m_ClipDrawData.localVisibleStartTime = clip.ToLocalTimeUnbound(Math.Max(clip.start, shownAreaTime.x)); + m_ClipDrawData.localVisibleEndTime = clip.ToLocalTimeUnbound(Math.Min(clip.end, shownAreaTime.y)); + + m_ClipDrawData.clippedRect = new Rect(clippedRect.x - rectXOffset, 0.0f, clippedRect.width, clippedRect.height); + + m_ClipDrawData.minLoopIndex = minLoopIndex; + m_ClipDrawData.loopRects = m_LoopRects; + m_ClipDrawData.supportsLooping = supportsLooping; + m_ClipDrawData.clipBlends = GetClipBlends(); + m_ClipDrawData.clipEditor = m_ClipEditor; + m_ClipDrawData.ClipDrawOptions = UpdateClipDrawOptions(m_ClipEditor, clip); + + UpdateClipIcons(state); + } + + void UpdateClipIcons(WindowState state) + { + // Pass 1 - gather size + int required = 0; + bool requiresDigIn = ShowDrillIcon(state.editSequence.director); + if (requiresDigIn) + required++; + + var icons = m_ClipDrawData.ClipDrawOptions.icons; + foreach (var icon in icons) + { + if (icon != null) + required++; + } + + // Pass 2 - copy icon data + if (required == 0) + { + m_ClipDrawData.rightIcons = null; + return; + } + + if (m_ClipDrawData.rightIcons == null || m_ClipDrawData.rightIcons.Length != required) + m_ClipDrawData.rightIcons = new IconData[required]; + + int index = 0; + if (requiresDigIn) + m_ClipDrawData.rightIcons[index++] = k_DiggableClipIcon; + + foreach (var icon in icons) + { + if (icon != null) + m_ClipDrawData.rightIcons[index++] = new IconData(icon); + } + } + + static ClipDrawOptions UpdateClipDrawOptions(ClipEditor clipEditor, TimelineClip clip) + { + try + { + return clipEditor.GetClipOptions(clip); + } + catch (Exception e) + { + Debug.LogException(e); + } + + return CustomTimelineEditorCache.GetDefaultClipEditor().GetClipOptions(clip); + } + + static void DrawClip(ClipDrawData drawData) + { + ClipDrawer.DrawDefaultClip(drawData); + + if (drawData.clip.asset is AnimationPlayableAsset) + { + var state = TimelineWindow.instance.state; + if (state.recording && state.IsArmedForRecord(drawData.clip.parentTrack)) + { + ClipDrawer.DrawAnimationRecordBorder(drawData); + ClipDrawer.DrawRecordProhibited(drawData); + } + } + } + + public void DrawGhostClip(Rect targetRect) + { + DrawSimpleClip(targetRect, ClipBorder.Selection(), new Color(1.0f, 1.0f, 1.0f, 0.5f)); + } + + public void DrawInvalidClip(Rect targetRect) + { + DrawSimpleClip(targetRect, ClipBorder.Selection(), DirectorStyles.Instance.customSkin.colorInvalidClipOverlay); + } + + void DrawSimpleClip(Rect targetRect, ClipBorder border, Color overlay) + { + var drawOptions = UpdateClipDrawOptions(CustomTimelineEditorCache.GetClipEditor(clip), clip); + ClipDrawer.DrawSimpleClip(clip, targetRect, border, overlay, drawOptions); + } + + void DrawInto(Rect drawRect, WindowState state) + { + if (Event.current.type != EventType.Repaint) + return; + + // create the inline curve editor if not already created + CreateInlineCurveEditor(state); + + // @todo optimization, most of the calculations (rect, offsets, colors, etc.) could be cached + // and rebuilt when the hash of the clip changes. + + if (isInvalid) + { + DrawInvalidClip(treeViewRect); + return; + } + + GUI.BeginClip(drawRect); + + var originRect = new Rect(0.0f, 0.0f, drawRect.width, drawRect.height); + string clipLabel = name; + var selected = SelectionManager.Contains(clip); + var previousClipSelected = previousClip != null && SelectionManager.Contains(previousClip.clip); + + if (selected && 1.0 != clip.timeScale) + clipLabel += " " + clip.timeScale.ToString("F2") + "x"; + + UpdateDrawData(state, originRect, clipLabel, selected, previousClipSelected, drawRect.x); + DrawClip(m_ClipDrawData); + + GUI.EndClip(); + + if (clip.parentTrack != null && !clip.parentTrack.lockedInHierarchy) + { + if (selected && supportResize) + { + var cursorRect = rect; + cursorRect.xMin += leftHandle.boundingRect.width; + cursorRect.xMax -= rightHandle.boundingRect.width; + EditorGUIUtility.AddCursorRect(cursorRect, MouseCursor.MoveArrow); + } + + if (supportResize) + { + var handleWidth = Mathf.Clamp(drawRect.width * 0.3f, k_MinHandleWidth, k_MaxHandleWidth); + + leftHandle.Draw(drawRect, handleWidth, state); + rightHandle.Draw(drawRect, handleWidth, state); + } + } + } + + void CalculateClipRectangle(Rect trackRect, WindowState state) + { + if (m_ClipViewDirty) + { + var clipRect = RectToTimeline(trackRect, state); + treeViewRect = clipRect; + + // calculate clipped rect + clipRect.xMin = Mathf.Max(clipRect.xMin, trackRect.xMin); + clipRect.xMax = Mathf.Min(clipRect.xMax, trackRect.xMax); + + if (clipRect.width > 0 && clipRect.width < 2) + { + clipRect.width = 5.0f; + } + + clippedRect = clipRect; + } + } + + void AddToSpacePartitioner(WindowState state) + { + if (Event.current.type == EventType.Repaint && !parent.locked) + state.spacePartitioner.AddBounds(this, rect); + } + + void CalculateBlendRect() + { + m_ClipCenterSection = treeViewRect; + m_ClipCenterSection.x = 0; + m_ClipCenterSection.y = 0; + + m_ClipCenterSection.xMin = Mathf.Round(treeViewRect.width * clip.mixInPercentage); + m_ClipCenterSection.width = Mathf.Round(treeViewRect.width); + m_ClipCenterSection.xMax -= Mathf.Round(mixOutRect.width + treeViewRect.width * clip.mixInPercentage); + } + + // Entry point to the Clip Drawing... + public override void Draw(Rect trackRect, bool trackRectChanged, WindowState state) + { + // if the clip has changed, fire the appropriate callback + DetectClipChanged(trackRectChanged); + + // update the clip projected rectangle on the timeline + CalculateClipRectangle(trackRect, state); + + AddToSpacePartitioner(state); + + // update the blend rects (when clip overlaps with others) + CalculateBlendRect(); + + // update the loop rects (when clip loops) + CalculateLoopRects(trackRect, state); + + DrawExtrapolation(trackRect, treeViewRect); + + DrawInto(treeViewRect, state); + + ResetClipChanged(); + } + + void DetectClipChanged(bool trackRectChanged) + { + if (Event.current.type == EventType.Layout) + { + if (clip.DirtyIndex != m_LastDirtyIndex) + { + m_ClipViewDirty = true; + + try + { + m_ClipEditor.OnClipChanged(clip); + } + catch (Exception e) + { + Debug.LogException(e); + } + + m_LastDirtyIndex = clip.DirtyIndex; + } + m_ClipViewDirty |= trackRectChanged; + } + } + + void ResetClipChanged() + { + if (Event.current.type == EventType.Repaint) + m_ClipViewDirty = false; + } + + GUIStyle GetExtrapolationIcon(TimelineClip.ClipExtrapolation mode) + { + GUIStyle extrapolationIcon = null; + + switch (mode) + { + case TimelineClip.ClipExtrapolation.None: return null; + case TimelineClip.ClipExtrapolation.Hold: extrapolationIcon = m_Styles.extrapolationHold; break; + case TimelineClip.ClipExtrapolation.Loop: extrapolationIcon = m_Styles.extrapolationLoop; break; + case TimelineClip.ClipExtrapolation.PingPong: extrapolationIcon = m_Styles.extrapolationPingPong; break; + case TimelineClip.ClipExtrapolation.Continue: extrapolationIcon = m_Styles.extrapolationContinue; break; + } + + return extrapolationIcon; + } + + Rect GetPreExtrapolationBounds(Rect trackRect, Rect clipRect, GUIStyle icon) + { + float x = clipRect.xMin - (icon.fixedWidth + 10.0f); + float y = trackRect.yMin + (trackRect.height - icon.fixedHeight) / 2.0f; + + if (previousClip != null) + { + float distance = Mathf.Abs(treeViewRect.xMin - previousClip.treeViewRect.xMax); + + if (distance < icon.fixedWidth) + return new Rect(0.0f, 0.0f, 0.0f, 0.0f); + + if (distance < icon.fixedWidth + 20.0f) + { + float delta = (distance - icon.fixedWidth) / 2.0f; + x = clipRect.xMin - (icon.fixedWidth + delta); + } + } + + return new Rect(x, y, icon.fixedWidth, icon.fixedHeight); + } + + Rect GetPostExtrapolationBounds(Rect trackRect, Rect clipRect, GUIStyle icon) + { + float x = clipRect.xMax + 10.0f; + float y = trackRect.yMin + (trackRect.height - icon.fixedHeight) / 2.0f; + + if (nextClip != null) + { + float distance = Mathf.Abs(nextClip.treeViewRect.xMin - treeViewRect.xMax); + + if (distance < icon.fixedWidth) + return new Rect(0.0f, 0.0f, 0.0f, 0.0f); + + if (distance < icon.fixedWidth + 20.0f) + { + float delta = (distance - icon.fixedWidth) / 2.0f; + x = clipRect.xMax + delta; + } + } + + return new Rect(x, y, icon.fixedWidth, icon.fixedHeight); + } + + static void DrawExtrapolationIcon(Rect rect, GUIStyle icon) + { + GUI.Label(rect, GUIContent.none, icon); + } + + void DrawExtrapolation(Rect trackRect, Rect clipRect) + { + if (clip.hasPreExtrapolation) + { + GUIStyle icon = GetExtrapolationIcon(clip.preExtrapolationMode); + + if (icon != null) + { + Rect iconBounds = GetPreExtrapolationBounds(trackRect, clipRect, icon); + + if (iconBounds.width > 1 && iconBounds.height > 1) + DrawExtrapolationIcon(iconBounds, icon); + } + } + + if (clip.hasPostExtrapolation) + { + GUIStyle icon = GetExtrapolationIcon(clip.postExtrapolationMode); + + if (icon != null) + { + Rect iconBounds = GetPostExtrapolationBounds(trackRect, clipRect, icon); + + if (iconBounds.width > 1 && iconBounds.height > 1) + DrawExtrapolationIcon(iconBounds, icon); + } + } + } + + static Rect ProjectRectOnTimeline(Rect rect, Rect trackRect, WindowState state) + { + Rect newRect = rect; + // transform clipRect into pixel-space + newRect.x *= state.timeAreaScale.x; + newRect.width *= state.timeAreaScale.x; + + newRect.x += state.timeAreaTranslation.x + trackRect.xMin; + + // adjust clipRect height and vertical centering + const int clipPadding = 2; + newRect.y = trackRect.y + clipPadding; + newRect.height = trackRect.height - (2 * clipPadding); + return newRect; + } + + void CalculateLoopRects(Rect trackRect, WindowState state) + { + if (!m_ClipViewDirty) + return; + + m_LoopRects.Clear(); + if (clip.duration < WindowState.kTimeEpsilon) + return; + + var times = TimelineHelpers.GetLoopTimes(clip); + var loopDuration = TimelineHelpers.GetLoopDuration(clip); + m_MinLoopIndex = -1; + + // we have a hold, no need to compute all loops + if (!supportsLooping) + { + if (times.Length > 1) + { + var t = times[1]; + float loopTime = (float)(clip.duration - t); + m_LoopRects.Add(ProjectRectOnTimeline(new Rect((float)(t + clip.start), 0, loopTime, 0), trackRect, state)); + } + return; + } + + var range = state.timeAreaShownRange; + var visibleStartTime = range.x - clip.start; + var visibleEndTime = range.y - clip.start; + + for (int i = 1; i < times.Length; i++) + { + var t = times[i]; + + // don't draw off screen loops + if (t > visibleEndTime) + break; + + float loopTime = Mathf.Min((float)(clip.duration - t), (float)loopDuration); + var loopEnd = t + loopTime; + + if (loopEnd < visibleStartTime) + continue; + + m_LoopRects.Add(ProjectRectOnTimeline(new Rect((float)(t + clip.start), 0, loopTime, 0), trackRect, state)); + + if (m_MinLoopIndex == -1) + m_MinLoopIndex = i; + } + } + + public override Rect RectToTimeline(Rect trackRect, WindowState state) + { + var offsetFromTimeSpaceToPixelSpace = state.timeAreaTranslation.x + trackRect.xMin; + + var start = (float)(DiscreteTime)clip.start; + var end = (float)(DiscreteTime)clip.end; + + return Rect.MinMaxRect( + Mathf.Round(start * state.timeAreaScale.x + offsetFromTimeSpaceToPixelSpace), Mathf.Round(trackRect.yMin), + Mathf.Round(end * state.timeAreaScale.x + offsetFromTimeSpaceToPixelSpace), Mathf.Round(trackRect.yMax) + ); + } + + public IEnumerable SnappableEdgesFor(IAttractable attractable, ManipulateEdges manipulateEdges) + { + var edges = new List(); + + bool canAddEdges = !parent.muted; + + if (canAddEdges) + { + // Hack: Trim Start in Ripple mode should not have any snap point added + if (EditMode.editType == EditMode.EditType.Ripple && manipulateEdges == ManipulateEdges.Left) + return edges; + + if (attractable != this) + { + if (EditMode.editType == EditMode.EditType.Ripple) + { + bool skip = false; + + // Hack: Since Trim End and Move in Ripple mode causes other snap point to move on the same track (which is not supported), disable snapping for this special cases... + // TODO Find a proper way to have different snap edges for each edit mode. + if (manipulateEdges == ManipulateEdges.Right) + { + var otherClipGUI = attractable as TimelineClipGUI; + skip = otherClipGUI != null && otherClipGUI.parent == parent; + } + else if (manipulateEdges == ManipulateEdges.Both) + { + var moveHandler = attractable as MoveItemHandler; + skip = moveHandler != null && moveHandler.movingItems.Any(clips => clips.targetTrack == clip.parentTrack && clip.start >= clips.start); + } + + if (skip) + return edges; + } + + AddEdge(edges, clip.start); + AddEdge(edges, clip.end); + } + else + { + if (manipulateEdges == ManipulateEdges.Right) + { + var d = TimelineHelpers.GetClipAssetEndTime(clip); + + if (d < double.MaxValue) + { + if (clip.SupportsLooping()) + { + var l = TimelineHelpers.GetLoopDuration(clip); + + var shownTime = TimelineWindow.instance.state.timeAreaShownRange; + do + { + AddEdge(edges, d, false); + d += l; + } + while (d < shownTime.y); + } + else + { + AddEdge(edges, d, false); + } + } + } + + if (manipulateEdges == ManipulateEdges.Left) + { + var clipInfo = AnimationClipCurveCache.Instance.GetCurveInfo(clip.animationClip); + if (clipInfo != null && clipInfo.keyTimes.Any()) + AddEdge(edges, clip.FromLocalTimeUnbound(clipInfo.keyTimes.Min()), false); + } + } + } + return edges; + } + + public bool ShouldSnapTo(ISnappable snappable) + { + return true; + } + + bool ShowDrillIcon(PlayableDirector resolver) + { + if (!m_ShowDrillIcon.HasValue || TimelineWindow.instance.hierarchyChangedThisFrame) + { + var nestable = m_ClipEditor.supportsSubTimelines; + m_ShowDrillIcon = nestable && resolver != null; + if (m_ShowDrillIcon.Value) + { + s_TempSubDirectors.Clear(); + try + { + m_ClipEditor.GetSubTimelines(clip, resolver, s_TempSubDirectors); + } + catch (Exception e) + { + Debug.LogException(e); + } + + m_ShowDrillIcon &= s_TempSubDirectors.Count > 0; + } + } + + return m_ShowDrillIcon.Value; + } + + static void AddEdge(List edges, double time, bool showEdgeHint = true) + { + var shownTime = TimelineWindow.instance.state.timeAreaShownRange; + if (time >= shownTime.x && time <= shownTime.y) + edges.Add(new Edge(time, showEdgeHint)); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs.meta new file mode 100644 index 0000000..4e94156 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c01b61b3a6887c49a15276fd38be918 +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/treeview/ItemGui/TimelineItemGUI.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs new file mode 100644 index 0000000..522b35e --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Timeline; +using UnityEngine; + +namespace UnityEditor.Timeline +{ + static class ItemToItemGui + { + static Dictionary s_ItemToItemGUI = + new Dictionary(); + + public static void Add(TimelineClip clip, TimelineItemGUI gui) + { + s_ItemToItemGUI[clip] = gui; + } + + public static void Add(IMarker marker, TimelineItemGUI gui) + { + s_ItemToItemGUI[marker] = gui; + } + + public static TimelineClipGUI GetGuiForClip(TimelineClip clip) + { + return GetGuiForItem(clip) as TimelineClipGUI; + } + + public static TimelineMarkerGUI GetGuiForMarker(IMarker marker) + { + return GetGuiForItem(marker) as TimelineMarkerGUI; + } + + static TimelineItemGUI GetGuiForItem(object item) + { + if (item == null) + return null; + + TimelineItemGUI gui; + s_ItemToItemGUI.TryGetValue(item, out gui); + return gui; + } + } + + abstract class TimelineItemGUI : ISelectable + { + protected readonly DirectorStyles m_Styles; + + public abstract ITimelineItem item { get; } + public abstract double start { get; } + public abstract double end { get; } + public abstract void Draw(Rect rect, bool rectChanged, WindowState state); + public abstract Rect RectToTimeline(Rect trackRect, WindowState state); + + public virtual void Select() {} + public virtual bool IsSelected() { return false; } + public virtual void Deselect() {} + + public virtual void StartDrag() {} + public virtual void StopDrag() {} + + public LayerZOrder zOrder { get; set; } + + public bool visible { get; set; } + public bool isInvalid { get; set; } + + public IRowGUI parent { get; } + + public Rect rect + { + get { return parent.ToWindowSpace(treeViewRect); } + } + + public Rect treeViewRect + { + get { return m_TreeViewRect; } + protected set + { + m_TreeViewRect = value; + if (value.width < 0.0f) + m_TreeViewRect.width = 1.0f; + } + } + + Rect m_TreeViewRect; + + protected TimelineItemGUI(IRowGUI parent) + { + this.parent = parent; + m_Styles = DirectorStyles.Instance; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs.meta new file mode 100644 index 0000000..a38143d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f515f8ecd3b6a546b90abaae2553f99 +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/treeview/ItemGui/TimelineMarkerClusterGUI.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs new file mode 100644 index 0000000..b0ffeac --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +using UnityObject = UnityEngine.Object; + +namespace UnityEditor.Timeline +{ + class TimelineMarkerClusterGUI : TimelineItemGUI + { + readonly List m_MarkerGUIs; + readonly IZOrderProvider m_ZOrderProvider; + + public TimelineMarkerGUI topMarker + { + get { return m_MarkerGUIs.LastOrDefault(); } + } + + TimelineMarkerGUI m_ManipulatedMarker; + + public TimelineMarkerClusterGUI(List guis, IRowGUI parent, + IZOrderProvider zOrderProvider, LayerZOrder layerZOrder) + : base(parent) + { + m_MarkerGUIs = guis; + m_ZOrderProvider = zOrderProvider; + zOrder = layerZOrder; + SortMarkers(); + topMarker.onStartDrag += OnDragTopMarker; + } + + public override double start + { + get { return topMarker.start; } + } + + public override double end + { + get { return topMarker.end; } + } + + public override ITimelineItem item + { + get { return topMarker.item; } + } + + public override void Select() + { + foreach (var marker in m_MarkerGUIs) + { + if (!marker.IsSelected()) + marker.Select(); + } + } + + public override void Deselect() + { + foreach (var marker in m_MarkerGUIs) + { + if (marker.IsSelected()) + marker.Deselect(); + } + } + + public override void Draw(Rect trackRect, bool trackRectChanged, WindowState state) + { + RegisterRect(state); + + topMarker.Draw(trackRect, trackRectChanged, state); + + if (m_MarkerGUIs.Count > 1) + GUI.Box(treeViewRect, String.Empty, DirectorStyles.Instance.markerMultiOverlay); + + if (m_ManipulatedMarker != null) + m_ManipulatedMarker.Draw(trackRect, trackRectChanged, state); + } + + public override Rect RectToTimeline(Rect trackRect, WindowState state) + { + return topMarker.RectToTimeline(trackRect, state); + } + + public void CycleTop() + { + if (m_MarkerGUIs.Count < 2) + return; + + topMarker.onStartDrag -= OnDragTopMarker; + + var last = topMarker; + for (int i = 0; i < m_MarkerGUIs.Count; ++i) + { + var next = m_MarkerGUIs[i]; + m_MarkerGUIs[i] = last; + last = next; + } + + topMarker.zOrder = m_ZOrderProvider.Next(); + + topMarker.onStartDrag += OnDragTopMarker; + } + + void OnDragTopMarker() + { + m_ManipulatedMarker = topMarker; + m_ManipulatedMarker.onStartDrag -= OnDragTopMarker; + m_MarkerGUIs.RemoveAt(m_MarkerGUIs.Count - 1); + } + + void SortMarkers() + { + m_MarkerGUIs.Sort((lhs, rhs) => lhs.zOrder.CompareTo(rhs.zOrder)); + } + + void RegisterRect(WindowState state) + { + treeViewRect = topMarker.treeViewRect; + + if (Event.current.type == EventType.Repaint && !parent.locked) + state.spacePartitioner.AddBounds(this, rect); + } + + public static bool CanCycleMarkers() + { + if (!SelectionManager.SelectedMarkers().Any()) + return false; + + var cluster = PickerUtils.PickedLayerableOfType(); + + if (cluster == null) + return false; + + // Only cycle if the marker is selected and nothing else is selected + return cluster.topMarker.IsSelected() && SelectionManager.Count() == 1; + } + + public static void CycleMarkers() + { + var cluster = PickerUtils.PickedLayerableOfType(); + + if (cluster == null) + return; + + cluster.topMarker.Deselect(); + cluster.CycleTop(); + cluster.topMarker.Select(); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs.meta new file mode 100644 index 0000000..692661f --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c03ae9aa36a4fd44a983831f44654be +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/treeview/ItemGui/TimelineMarkerGUI.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs new file mode 100644 index 0000000..5f054f7 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Timeline; +using UnityObject = UnityEngine.Object; + +namespace UnityEditor.Timeline +{ + class TimelineMarkerGUI : TimelineItemGUI, ISnappable, IAttractable + { + public event Action onStartDrag; + + int m_ProjectedClipHash; + int m_MarkerHash; + bool m_Selectable; + + MarkerDrawOptions m_MarkerDrawOptions; + MarkerEditor m_Editor; + + IMarker marker { get; } + + bool selectable + { + get { return m_Selectable; } + } + + public double time + { + get { return marker.time; } + } + + public override double start + { + get { return time; } + } + + public override double end + { + get { return time; } + } + + public override void Select() + { + zOrder = zOrderProvider.Next(); + SelectionManager.Add(marker); + TimelineWindowViewPrefs.GetTrackViewModelData(parent.asset).markerTimeStamps[m_MarkerHash] = DateTime.UtcNow.Ticks; + } + + public override bool IsSelected() + { + return SelectionManager.Contains(marker); + } + + public override void Deselect() + { + SelectionManager.Remove(marker); + } + + public override ITimelineItem item + { + get { return ItemsUtils.ToItem(marker); } + } + + IZOrderProvider zOrderProvider { get; } + + public TimelineMarkerGUI(IMarker theMarker, IRowGUI parent, IZOrderProvider provider) : base(parent) + { + marker = theMarker; + m_Selectable = marker.GetType().IsSubclassOf(typeof(UnityObject)); + + m_MarkerHash = 0; + var o = marker as object; + if (!o.Equals(null)) + m_MarkerHash = o.GetHashCode(); + + zOrderProvider = provider; + zOrder = zOrderProvider.Next(); + ItemToItemGui.Add(marker, this); + m_Editor = CustomTimelineEditorCache.GetMarkerEditor(theMarker); + } + + int ComputeDirtyHash() + { + return time.GetHashCode(); + } + + static void DrawMarker(Rect drawRect, Type type, bool isSelected, bool isCollapsed, MarkerDrawOptions options) + { + if (Event.current.type == EventType.Repaint) + { + bool hasError = !string.IsNullOrEmpty(options.errorText); + + var style = StyleManager.UssStyleForType(type); + style.Draw(drawRect, GUIContent.none, false, false, !isCollapsed, isSelected); + + // case1141836: Use of GUI.Box instead of GUI.Label causes desync in UI controlID + if (hasError) + GUI.Label(drawRect, String.Empty, DirectorStyles.Instance.markerWarning); + + var tooltip = hasError ? options.errorText : options.tooltip; + if (!string.IsNullOrEmpty(tooltip) && drawRect.Contains(Event.current.mousePosition)) + { + GUIStyle.SetMouseTooltip(tooltip, drawRect); + } + } + } + + void UpdateDrawData() + { + if (Event.current.type == EventType.Layout) + { + try + { + m_MarkerDrawOptions = m_Editor.GetMarkerOptions(marker); + } + catch (Exception e) + { + Debug.LogException(e); + m_MarkerDrawOptions = CustomTimelineEditorCache.GetDefaultMarkerEditor().GetMarkerOptions(marker); + } + } + } + + public override void Draw(Rect trackRect, bool trackRectChanged, WindowState state) + { + UpdateDrawData(); + + // compute marker hash + var currentMarkerHash = ComputeDirtyHash(); + + // update the clip projected rectangle on the timeline + CalculateClipRectangle(trackRect, state, currentMarkerHash, trackRectChanged); + + var isSelected = selectable && SelectionManager.Contains(marker); + var showMarkers = parent.showMarkers; + + QueueOverlay(treeViewRect, isSelected, !showMarkers); + DrawMarker(treeViewRect, marker.GetType(), isSelected, !showMarkers, m_MarkerDrawOptions); + + if (Event.current.type == EventType.Repaint && showMarkers && !parent.locked) + state.spacePartitioner.AddBounds(this, rect); + } + + public void QueueOverlay(Rect rect, bool isSelected, bool isCollapsed) + { + if (Event.current.type == EventType.Repaint && m_Editor.supportsDrawOverlay) + { + rect = GUIClip.Unclip(rect); + TimelineWindow.instance.AddUserOverlay(marker, rect, m_Editor, isCollapsed, isSelected); + } + } + + public override void StartDrag() + { + if (onStartDrag != null) + onStartDrag.Invoke(); + } + + void CalculateClipRectangle(Rect trackRect, WindowState state, int projectedClipHash, bool trackRectChanged) + { + if (m_ProjectedClipHash == projectedClipHash && !trackRectChanged) + return; + + m_ProjectedClipHash = projectedClipHash; + treeViewRect = RectToTimeline(trackRect, state); + } + + public override Rect RectToTimeline(Rect trackRect, WindowState state) + { + var style = StyleManager.UssStyleForType(marker.GetType()); + var width = style.fixedWidth; + var height = style.fixedHeight; + var x = ((float)marker.time * state.timeAreaScale.x) + state.timeAreaTranslation.x + trackRect.xMin; + x -= 0.5f * width; + return new Rect(x, trackRect.y, width, height); + } + + public IEnumerable SnappableEdgesFor(IAttractable attractable, ManipulateEdges manipulateEdges) + { + var edges = new List(); + var attractableGUI = attractable as TimelineMarkerGUI; + var canAddEdges = !(attractableGUI != null && attractableGUI.parent == parent); + if (canAddEdges) + edges.Add(new Edge(time)); + return edges; + } + + public bool ShouldSnapTo(ISnappable snappable) + { + return snappable != this; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs.meta new file mode 100644 index 0000000..ecfff45 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d34348f8b97a334291f5cf31adc5d67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- cgit v1.2.3