summaryrefslogtreecommitdiff
path: root/Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2020-04-19 17:19:32 -0400
committerAndrew Lee <alee14498@protonmail.com>2020-04-19 17:19:32 -0400
commitc55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 (patch)
treeee4d51c7c1d633e11f46453ef1edd3c77c4ef9f7 /Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui
downloadProject-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/treeview/ItemGui')
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs11
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/ISelectable.cs.meta11
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs760
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineClipGUI.cs.meta11
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs92
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineItemGUI.cs.meta11
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs150
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerClusterGUI.cs.meta11
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs193
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/treeview/ItemGui/TimelineMarkerGUI.cs.meta11
10 files changed, 1261 insertions, 0 deletions
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<Rect> m_LoopRects = new List<Rect>();
+
+ 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<PlayableDirector> s_TempSubDirectors = new List<PlayableDirector>();
+
+ 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<Edge> SnappableEdgesFor(IAttractable attractable, ManipulateEdges manipulateEdges)
+ {
+ var edges = new List<Edge>();
+
+ 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<Edge> 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<object, TimelineItemGUI> s_ItemToItemGUI =
+ new Dictionary<object, TimelineItemGUI>();
+
+ 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<TimelineMarkerGUI> m_MarkerGUIs;
+ readonly IZOrderProvider m_ZOrderProvider;
+
+ public TimelineMarkerGUI topMarker
+ {
+ get { return m_MarkerGUIs.LastOrDefault(); }
+ }
+
+ TimelineMarkerGUI m_ManipulatedMarker;
+
+ public TimelineMarkerClusterGUI(List<TimelineMarkerGUI> 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<TimelineMarkerClusterGUI>();
+
+ 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<TimelineMarkerClusterGUI>();
+
+ 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<Edge> SnappableEdgesFor(IAttractable attractable, ManipulateEdges manipulateEdges)
+ {
+ var edges = new List<Edge>();
+ 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: