first commit

This commit is contained in:
SimonSayeBabu
2025-01-17 13:10:20 +01:00
commit bd1057cec0
16967 changed files with 1048699 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 37472f5179ca2004489ac901814cdbc3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
namespace UnityEditor.Timeline
{
enum TimeReferenceMode
{
Local = 0,
Global = 1
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 34d6f60b171c1004e8335d52c65928a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
namespace UnityEditor.Timeline
{
class TimelineActiveMode : TimelineMode
{
public TimelineActiveMode()
{
headerState = new HeaderState
{
breadCrumb = TimelineModeGUIState.Enabled,
options = TimelineModeGUIState.Enabled,
sequenceSelector = TimelineModeGUIState.Enabled
};
trackOptionsState = new TrackOptionsState
{
newButton = TimelineModeGUIState.Enabled,
editAsAssetButton = TimelineModeGUIState.Hidden
};
mode = TimelineModes.Active;
}
public override bool ShouldShowTimeCursor(WindowState state)
{
return true;
}
public override bool ShouldShowPlayRange(WindowState state)
{
return state.playRangeEnabled;
}
public override TimelineModeGUIState ToolbarState(WindowState state)
{
return TimelineModeGUIState.Enabled;
}
public override TimelineModeGUIState TrackState(WindowState state)
{
return TimelineModeGUIState.Enabled;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 67ee43b2f6148de40861b289b0e00591
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
namespace UnityEditor.Timeline
{
class TimelineAssetEditionMode : TimelineInactiveMode
{
public override TimelineModeGUIState TrackState(WindowState state)
{
return TimelineModeGUIState.Enabled;
}
public TimelineAssetEditionMode()
{
headerState = new HeaderState
{
breadCrumb = TimelineModeGUIState.Enabled,
options = TimelineModeGUIState.Enabled,
sequenceSelector = TimelineModeGUIState.Enabled
};
trackOptionsState = new TrackOptionsState
{
newButton = TimelineModeGUIState.Enabled,
editAsAssetButton = TimelineModeGUIState.Enabled
};
mode = TimelineModes.AssetEdition;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3477d28057cb3e4469c7ea6b8dc23046
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
using UnityEngine;
namespace UnityEditor.Timeline
{
class TimelineDisabledMode : TimelineMode
{
public TimelineDisabledMode()
{
headerState = new HeaderState
{
breadCrumb = TimelineModeGUIState.Enabled,
options = TimelineModeGUIState.Enabled,
sequenceSelector = TimelineModeGUIState.Enabled
};
trackOptionsState = new TrackOptionsState
{
newButton = TimelineModeGUIState.Enabled,
editAsAssetButton = TimelineModeGUIState.Enabled
};
mode = TimelineModes.Disabled;
}
public override bool ShouldShowPlayRange(WindowState state)
{
return false;
}
public override bool ShouldShowTimeCursor(WindowState state)
{
return true;
}
public override TimelineModeGUIState ToolbarState(WindowState state)
{
return TimelineModeGUIState.Disabled;
}
public override TimelineModeGUIState TrackState(WindowState state)
{
return TimelineModeGUIState.Enabled;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c5eb52d37bb6714a98af73df7d9cf2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
namespace UnityEditor.Timeline
{
class TimelineInactiveMode : TimelineMode
{
public TimelineInactiveMode()
{
headerState = new HeaderState
{
breadCrumb = TimelineModeGUIState.Disabled,
options = TimelineModeGUIState.Enabled,
sequenceSelector = TimelineModeGUIState.Enabled
};
trackOptionsState = new TrackOptionsState
{
newButton = TimelineModeGUIState.Disabled,
editAsAssetButton = TimelineModeGUIState.Enabled
};
mode = TimelineModes.Inactive;
}
public override bool ShouldShowPlayRange(WindowState state)
{
return false;
}
public override bool ShouldShowTimeCursor(WindowState state)
{
return false;
}
public override TimelineModeGUIState ToolbarState(WindowState state)
{
return TimelineModeGUIState.Disabled;
}
public override TimelineModeGUIState TrackState(WindowState state)
{
return TimelineModeGUIState.Disabled;
}
public override TimelineModeGUIState PreviewState(WindowState state)
{
return TimelineModeGUIState.Disabled;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5503f95d174761548a68a901beab13c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System;
using UnityEngine;
namespace UnityEditor.Timeline
{
enum TimelineModeGUIState
{
Disabled,
Hidden,
Enabled
}
abstract class TimelineMode
{
public struct HeaderState
{
public TimelineModeGUIState breadCrumb;
public TimelineModeGUIState sequenceSelector;
public TimelineModeGUIState options;
}
public struct TrackOptionsState
{
public TimelineModeGUIState newButton;
public TimelineModeGUIState editAsAssetButton;
}
public HeaderState headerState { get; protected set; }
public TrackOptionsState trackOptionsState { get; protected set; }
public TimelineModes mode { get; protected set; }
public abstract bool ShouldShowPlayRange(WindowState state);
public abstract bool ShouldShowTimeCursor(WindowState state);
public virtual bool ShouldShowTrackBindings(WindowState state)
{
return ShouldShowTimeCursor(state);
}
public virtual bool ShouldShowTimeArea(WindowState state)
{
return !state.IsEditingAnEmptyTimeline();
}
public abstract TimelineModeGUIState TrackState(WindowState state);
public abstract TimelineModeGUIState ToolbarState(WindowState state);
public virtual TimelineModeGUIState PreviewState(WindowState state)
{
return state.ignorePreview ? TimelineModeGUIState.Disabled : TimelineModeGUIState.Enabled;
}
public virtual TimelineModeGUIState EditModeButtonsState(WindowState state)
{
return TimelineModeGUIState.Enabled;
}
}
/// <summary>
/// Different mode for Timeline
/// </summary>
[Flags]
public enum TimelineModes
{
/// <summary>
/// A playable director with a valid timeline is selected in editor.
/// </summary>
Active = 1,
/// <summary>
/// The timeline is not editable. (the TimelineAsset file is either readonly on disk or locked by source control).
/// </summary>
ReadOnly = 2,
/// <summary>
/// The timeline cannot be played or previewed.
/// </summary>
Inactive = 4,
/// <summary>
/// Disabled Timeline.
/// </summary>
Disabled = 8,
/// <summary>
/// Timeline in AssetEditing mode.
/// This mode is enabled when a timeline asset is selected in the project window.
/// </summary>
AssetEdition = 16,
/// <summary>
/// The timeline can be edited (either through playable director or selected timeline asset in project window).
/// </summary>
Default = Active | AssetEdition
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2cb43d6b0c226443be7e176590837a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
namespace UnityEditor.Timeline
{
class TimelineReadOnlyMode : TimelineMode
{
public TimelineReadOnlyMode()
{
headerState = new HeaderState()
{
breadCrumb = TimelineModeGUIState.Enabled,
options = TimelineModeGUIState.Enabled,
sequenceSelector = TimelineModeGUIState.Enabled,
};
trackOptionsState = new TrackOptionsState()
{
newButton = TimelineModeGUIState.Disabled,
editAsAssetButton = TimelineModeGUIState.Disabled,
};
mode = TimelineModes.ReadOnly;
}
public override bool ShouldShowPlayRange(WindowState state)
{
return state.editSequence.director != null && state.playRangeEnabled;
}
public override bool ShouldShowTimeCursor(WindowState state)
{
return state.editSequence.director != null;
}
public override TimelineModeGUIState TrackState(WindowState state)
{
return TimelineModeGUIState.Disabled;
}
public override TimelineModeGUIState ToolbarState(WindowState state)
{
return state.editSequence.director == null ? TimelineModeGUIState.Disabled : TimelineModeGUIState.Enabled;
}
public override TimelineModeGUIState PreviewState(WindowState state)
{
return state.editSequence.director == null ? TimelineModeGUIState.Disabled : TimelineModeGUIState.Enabled;
}
public override TimelineModeGUIState EditModeButtonsState(WindowState state)
{
return TimelineModeGUIState.Disabled;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f8643c1f8dd449e85b548a14edbea2e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using System;
using UnityEngine;
namespace UnityEditor.Timeline
{
readonly struct OverlayDrawer
{
enum OverlayType
{
BackgroundColor,
BackgroundTexture,
TextBox
}
readonly OverlayType m_Type;
readonly Rect m_Rect;
readonly string m_Text;
readonly Texture2D m_Texture;
readonly Color m_Color;
readonly GUIStyle m_BackgroundTextStyle;
readonly GUIStyle m_TextStyle;
OverlayDrawer(Rect rectangle, Color backgroundColor)
{
m_Type = OverlayType.BackgroundColor;
m_Rect = rectangle;
m_Color = backgroundColor;
m_Text = string.Empty;
m_Texture = null;
m_BackgroundTextStyle = null;
m_TextStyle = null;
}
OverlayDrawer(Rect rectangle, Texture2D backTexture)
{
m_Type = OverlayType.BackgroundTexture;
m_Rect = rectangle;
m_Color = Color.clear;
m_Text = string.Empty;
m_Texture = backTexture;
m_BackgroundTextStyle = null;
m_TextStyle = null;
}
OverlayDrawer(Rect rectangle, string msg, GUIStyle textStyle, Color textColor, Color bgTextColor, GUIStyle bgTextStyle)
{
m_Type = OverlayType.TextBox;
m_Rect = rectangle;
m_Text = msg;
m_TextStyle = textStyle;
m_TextStyle.normal.textColor = textColor;
m_BackgroundTextStyle = bgTextStyle;
m_BackgroundTextStyle.normal.textColor = bgTextColor;
m_Texture = null;
m_Color = Color.clear;
}
public static OverlayDrawer CreateColorOverlay(Rect rectangle, Color backgroundColor)
{
return new OverlayDrawer(rectangle, backgroundColor);
}
public static OverlayDrawer CreateTextureOverlay(Rect rectangle, Texture2D backTexture)
{
return new OverlayDrawer(rectangle, backTexture);
}
public static OverlayDrawer CreateTextBoxOverlay(Rect rectangle, string msg, GUIStyle textStyle, Color textColor, Color bgTextColor, GUIStyle bgTextStyle)
{
return new OverlayDrawer(rectangle, msg, textStyle, textColor, bgTextColor, bgTextStyle);
}
public void Draw()
{
Rect overlayRect = GUIClip.Clip(m_Rect);
switch (m_Type)
{
case OverlayType.BackgroundColor:
EditorGUI.DrawRect(overlayRect, m_Color);
break;
case OverlayType.BackgroundTexture:
Graphics.DrawTextureRepeated(overlayRect, m_Texture);
break;
case OverlayType.TextBox:
{
using (new GUIColorOverride(m_BackgroundTextStyle.normal.textColor))
GUI.Box(overlayRect, GUIContent.none, m_BackgroundTextStyle);
Graphics.ShadowLabel(overlayRect, GUIContent.Temp(m_Text), m_TextStyle, m_TextStyle.normal.textColor, Color.black);
break;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4f4398a10f384dacb37698e5b1f8fede
timeCreated: 1597264928

View File

@@ -0,0 +1,67 @@
using UnityEngine;
namespace UnityEditor.Timeline
{
/// <summary>
/// Scrolling mode during playback for the timeline window.
/// </summary>
public enum PlaybackScrollMode
{
/// <summary>
/// Timeline window doesn't change while the playhead is leaving the window.
/// </summary>
None,
/// <summary>
/// Timeline window pans its content when the playhead arrive at the right of the window (like a paging scrolling).
/// </summary>
Pan,
/// <summary>
/// Timeline window move the content as the playhead moves.
/// When the playhead reach the middle of the window, it stays there and the content scroll behind it.
/// </summary>
Smooth
}
static class PlaybackScroller
{
public static void AutoScroll(WindowState state)
{
if (Event.current.type != EventType.Layout)
return;
switch (state.autoScrollMode)
{
case PlaybackScrollMode.Pan:
DoPanScroll(state);
break;
case PlaybackScrollMode.Smooth:
DoSmoothScroll(state);
break;
}
}
static void DoSmoothScroll(WindowState state)
{
if (state.playing)
state.SetPlayHeadToMiddle();
state.UpdateLastFrameTime();
}
static void DoPanScroll(WindowState state)
{
if (!state.playing)
return;
var paddingDeltaTime = state.PixelDeltaToDeltaTime(WindowConstants.autoPanPaddingInPixels);
var showRange = state.timeAreaShownRange;
var rightBoundForPan = showRange.y - paddingDeltaTime;
if (state.editSequence.time > rightBoundForPan)
{
var leftBoundForPan = showRange.x + paddingDeltaTime;
var delta = rightBoundForPan - leftBoundForPan;
state.SetTimeAreaShownRange(showRange.x + delta, showRange.y + delta);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98545765d7a2b614b921715928035ee2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,108 @@
using System;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
/// <summary>
/// A context for the Timeline window (RO)
/// </summary>
/// <remarks>
/// The SequenceContext represents a state of the Timeline window, and is used to interact with <see cref="TimelineNavigator"/>.
/// </remarks>
public readonly struct SequenceContext : IEquatable<SequenceContext>
{
/// <summary>
/// The director associated with the Timeline window in the context. (RO)
/// </summary>
public PlayableDirector director { get; }
/// <summary>
/// The <see cref="TimelineClip"/> associated with the Timeline window in the context. (RO)
/// </summary>
/// <remarks>In a SubTimeline context, the clip is the <see cref="TimelineClip"/> that hosts the SubTimeline in the parent Timeline.
/// In the root context, the clip is <see langword="null"/>.</remarks>
public TimelineClip clip { get; }
/// <summary>
/// Initializes and returns an instance of SequenceContext.
/// </summary>
/// <param name="director">The PlayableDirector associated with the context. Must be a valid PlayableDirector reference. </param>
/// <param name="clip">The TimelineClip reference that controls the sequence. Specify <see langword="null"/> to specify that the sequence is the root. If non-null, the clip must be part of a valid <see cref="TimelineAsset"/>.</param>
/// <exception cref="System.ArgumentNullException"> <paramref name="director"/> is null.</exception>
/// <exception cref="System.ArgumentException"> The <paramref name="clip"/> is not part of a <see cref="TrackAsset"/>.</exception>
/// <exception cref="System.ArgumentException"> The <paramref name="clip"/> is part of a track but not part of a <see cref="TimelineAsset"/>.</exception>
public SequenceContext(PlayableDirector director, TimelineClip clip)
{
if (director == null)
throw new ArgumentNullException(nameof(director));
var parentTrack = clip?.GetParentTrack();
if (clip != null && parentTrack == null)
throw new ArgumentException("The provided clip must be part of a track", nameof(clip));
if (clip != null && parentTrack.timelineAsset == null)
throw new ArgumentException("The provided clip must be part of a Timeline.", nameof(clip));
this.director = director;
this.clip = clip;
m_Valid = true;
}
/// <summary>
/// Assesses the validity of a SequenceContext.
/// </summary>
/// <remarks>To be valid, a SequenceContext must contain a valid PlayableDirector reference.</remarks>
/// <returns><see langword="true" /> if the SequenceContext is valid,<see langword="false" /> otherwise</returns>
public bool IsValid() => m_Valid;
/// <summary>
/// Equality operator overload.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns><see langword="true" /> if operands are equal, <see langword="false" /> otherwise.</returns>
public static bool operator ==(SequenceContext left, SequenceContext right) => left.Equals(right);
/// <summary>
/// Inequality operator overload.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns><see langword="true" /> if operands are not equal, <see langword="false" /> otherwise.</returns>
public static bool operator !=(SequenceContext left, SequenceContext right) => !left.Equals(right);
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// <see langword="true" /> if the current object is equal to the <paramref name="other" /> parameter; otherwise, <see langword="false" />.</returns>
public bool Equals(SequenceContext other)
{
return Equals(director, other.director) && Equals(clip, other.clip);
}
/// <summary>Indicates whether the current object is equal to another object of indeterminate type.</summary>
/// <param name="obj">An object to compare with this object.</param>
/// <returns>
/// <see langword="true" /> if the current object is equal to the <paramref name="obj" /> parameter; otherwise, <see langword="false" />.</returns>
public override bool Equals(object obj)
{
return obj is SequenceContext other && Equals(other);
}
/// <summary>Hash function for SequenceContext.</summary>
/// <returns>
/// Hash code for the SequenceContext.
/// </returns>
public override int GetHashCode()
{
unchecked
{
return ((director != null ? director.GetHashCode() : 0) * 397) ^ (clip != null ? clip.GetHashCode() : 0);
}
}
internal static SequenceContext Invalid = new SequenceContext();
readonly bool m_Valid;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ad2b855cf8b7425483e36e6134f18f9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
/// <summary>
/// Base class of the TimelineWindow.
/// </summary>
public abstract class TimelineEditorWindow : EditorWindow
{
/// <summary>
/// Use this interface to navigate between Timelines and Sub-Timelines. (RO)
/// </summary>
public abstract TimelineNavigator navigator { get; }
/// <summary>
/// Use this interface to control the playback behaviour of the Timeline window. (RO)
/// </summary>
public abstract TimelinePlaybackControls playbackControls { get; }
/// <summary>
/// Retrieves and sets the Timeline Window lock state. When disabled (false), the window focus follows the Unity selection.
/// </summary>
/// <remarks>When the lock state transitions from true to false, the focused timeline is synchronized with the Unity selection.</remarks>>
public abstract bool locked { get; set; }
/// <summary>
/// Sets which TimelineAsset is shown in the TimelineWindow.
/// </summary>
/// <param name="sequence">The TimelineAsset to show. Specify a null to clear the TimelineWindow.</param>
/// <remarks>When you call this method, the TimelineWindow is placed in asset edit mode. This mode does not support all features. For example, bindings are not available and the timeline cannot be evaluated.
/// You can use this method when the TimelineWindow is locked.</remarks>
public abstract void SetTimeline(TimelineAsset sequence);
/// <summary>
/// Sets which TimelineAsset is shown in the TimelineWindow based on the PlayableDirector.
/// </summary>
/// <param name="director">The PlayableDirector associated with the TimelineAsset to show in the TimelineWindow. Specify a null to clear the TimelineWindow.</param>
/// <remarks>You can use this method when the TimelineWindow is locked.</remarks>
public abstract void SetTimeline(PlayableDirector director);
/// <summary>
/// Clears the TimelineAsset that is shown in the TimelineWindow.
/// </summary>
/// <remarks>You can use this method when the TimelineWindow is locked.</remarks>>
public abstract void ClearTimeline();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dfe0d35963084dcc899e4d32cca85455
timeCreated: 1590671897

View File

@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Timeline.Actions;
using UnityEngine;
using UnityEngine.Timeline;
using Object = UnityEngine.Object;
namespace UnityEditor.Timeline
{
class TimelineMarkerHeaderGUI : IRowGUI, ILayerable
{
static readonly GUIContent k_Muted = L10n.TextContent("Muted");
int m_TrackHash;
TimelineAsset timeline { get; }
WindowState state { get; }
MarkersLayer m_Layer;
LayerZOrder m_ZOrder = new LayerZOrder(Layer.MarkerHeaderTrack, 0);
struct DrawData
{
public Rect headerRect;
public Rect contentRect;
public GUIStyle trackHeaderFont;
public Color colorTrackFont;
public bool isMuted;
public bool isSelected;
}
public TimelineMarkerHeaderGUI(TimelineAsset asset, WindowState state)
{
m_TrackHash = -1;
timeline = asset;
this.state = state;
}
public TrackAsset asset => timeline.markerTrack;
public Rect boundingRect { get; private set; }
public bool showMarkers => state.showMarkerHeader;
public bool muted => timeline.markerTrack != null && timeline.markerTrack.muted;
public bool locked => timeline.markerTrack.locked;
public LayerZOrder zOrder => m_ZOrder;
Rect IRowGUI.ToWindowSpace(Rect rect)
{
//header gui is already in global coordinates
return rect;
}
public void Draw(Rect markerHeaderRect, Rect markerContentRect, WindowState state)
{
boundingRect = markerContentRect;
var data = new DrawData
{
headerRect = markerHeaderRect,
contentRect = markerContentRect,
trackHeaderFont = DirectorStyles.Instance.trackHeaderFont,
colorTrackFont = DirectorStyles.Instance.customSkin.colorTrackFont,
isMuted = muted,
isSelected = IsSelected()
};
if (state.showMarkerHeader)
{
DrawMarkerDrawer(data);
if (Event.current.type == EventType.Repaint)
state.spacePartitioner.AddBounds(this, boundingRect);
}
if (asset != null && Hash() != m_TrackHash)
Rebuild();
Rect rect = state.showMarkerHeader ? markerContentRect : state.timeAreaRect;
using (new GUIViewportScope(rect))
{
if (m_Layer != null)
m_Layer.Draw(rect, state);
HandleDragAndDrop();
}
if (state.showMarkerHeader && data.isMuted)
DrawMuteOverlay(data);
}
public void Rebuild()
{
if (asset == null)
return;
m_Layer = new MarkersLayer(Layer.MarkersOnHeader, this);
m_TrackHash = Hash();
}
void HandleDragAndDrop()
{
if (state.editSequence.isReadOnly || !state.showMarkerHeader)
return;
if (Event.current == null || Event.current.type != EventType.DragUpdated &&
Event.current.type != EventType.DragPerform && Event.current.type != EventType.DragExited)
return;
var objectsBeingDropped = DragAndDrop.objectReferences.OfType<Object>();
var candidateTime = TimelineHelpers.GetCandidateTime(Event.current.mousePosition);
var perform = Event.current.type == EventType.DragPerform;
var director = state.editSequence != null ? state.editSequence.director : null;
DragAndDrop.visualMode = TimelineDragging.HandleClipPaneObjectDragAndDrop(objectsBeingDropped, timeline.markerTrack, perform,
timeline, null, director, candidateTime, ResolveType);
if (perform && DragAndDrop.visualMode == DragAndDropVisualMode.Copy)
{
DragAndDrop.AcceptDrag();
}
}
static bool ResolveType(IEnumerable<Type> types, Action<Type> onComplete, string formatString)
{
void CreateMarkerTrackOnComplete(Type type)
{
WindowState state = TimelineWindow.instance.state;
state.editSequence.asset.CreateMarkerTrack();
state.showMarkerHeader = true;
onComplete(type);
}
return TimelineDragging.ResolveType(types, CreateMarkerTrackOnComplete, formatString);
}
int Hash()
{
return timeline.markerTrack == null ? 0 : timeline.markerTrack.Hash();
}
static void DrawMarkerDrawer(DrawData data)
{
DrawMarkerDrawerHeaderBackground(data);
DrawMarkerDrawerHeader(data);
DrawMarkerDrawerContentBackground(data);
}
static void DrawMarkerDrawerHeaderBackground(DrawData data)
{
Color backgroundColor = data.isSelected
? DirectorStyles.Instance.customSkin.colorSelection
: DirectorStyles.Instance.customSkin.markerHeaderDrawerBackgroundColor;
EditorGUI.DrawRect(data.headerRect, backgroundColor);
}
static void DrawMarkerDrawerHeader(DrawData data)
{
var textStyle = data.trackHeaderFont;
textStyle.normal.textColor = data.colorTrackFont;
var labelRect = data.headerRect;
labelRect.x += DirectorStyles.kBaseIndent;
EditorGUI.LabelField(labelRect, DirectorStyles.timelineMarkerTrackHeader);
const float buttonSize = WindowConstants.trackHeaderButtonSize;
const float padding = WindowConstants.trackHeaderButtonPadding;
var x = data.headerRect.xMax - buttonSize - padding - 2f;
var y = data.headerRect.y + (data.headerRect.height - buttonSize) / 2.0f;
var buttonRect = new Rect(x, y, buttonSize, buttonSize);
DrawTrackDropDownMenu(buttonRect);
buttonRect.x -= 21.0f;
DrawMuteButton(buttonRect, data);
}
static void DrawMarkerDrawerContentBackground(DrawData data)
{
Color trackBackgroundColor = DirectorStyles.Instance.customSkin.markerDrawerBackgroundColor;
if (data.isSelected)
trackBackgroundColor = DirectorStyles.Instance.customSkin.colorTrackBackgroundSelected;
EditorGUI.DrawRect(data.contentRect, trackBackgroundColor);
}
static void DrawMuteOverlay(DrawData data)
{
DirectorStyles styles = TimelineWindow.styles;
var colorOverlay = OverlayDrawer.CreateColorOverlay(GUIClip.Unclip(data.contentRect), styles.customSkin.colorTrackDarken);
colorOverlay.Draw();
Rect textRect = Graphics.CalculateTextBoxSize(data.contentRect, styles.fontClip, k_Muted, WindowConstants.overlayTextPadding);
var boxOverlay = OverlayDrawer.CreateTextBoxOverlay(
GUIClip.Unclip(textRect),
k_Muted.text,
styles.fontClip,
Color.white,
styles.customSkin.colorLockTextBG,
styles.displayBackground);
boxOverlay.Draw();
}
static void DrawTrackDropDownMenu(Rect rect)
{
if (GUI.Button(rect, GUIContent.none, DirectorStyles.Instance.trackOptions))
{
SelectionManager.SelectOnly(TimelineEditor.inspectedAsset.markerTrack);
SequencerContextMenu.ShowTrackContextMenu(null);
}
}
static void DrawMuteButton(Rect rect, DrawData data)
{
bool muted = GUI.Toggle(rect, data.isMuted, string.Empty, TimelineWindow.styles.trackMuteButton);
if (muted != data.isMuted)
new[] { TimelineEditor.inspectedAsset.markerTrack }.Invoke<MuteTrack>();
}
bool IsSelected()
{
return SelectionManager.Contains(asset);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4068e97704a16794ea218ba560cdc1e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,97 @@
using System.Collections.Generic;
namespace UnityEditor.Timeline
{
/// <summary>
/// Interface to navigate through Timelines and SubTimelines for the Timeline window.
/// </summary>
/// <remarks>
/// TimelineNavigator gives you access to the Timeline window breadcrumbs functionality. Use it to programmatically
/// dig into SubTimelines, navigate to parent Timelines or navigate Timeline Window breadcrumbs.
/// </remarks>
public sealed class TimelineNavigator
{
TimelineWindow.TimelineNavigatorImpl m_Impl;
internal TimelineNavigator(IWindowStateProvider windowState)
{
m_Impl = new TimelineWindow.TimelineNavigatorImpl(windowState);
}
/// <summary>
/// Gets the SequenceContext associated with the Timeline currently shown in the Timeline window.
/// </summary>
/// <returns>The SequenceContext associated with the Timeline currently shown in the Timeline window.</returns>
/// <remarks>Equivalent to <c>TimelineNavigator.GetBreadCrumbs().Last()</c></remarks>
/// <exception cref="System.InvalidOperationException"> The Window associated to this instance has been destroyed.</exception>
public SequenceContext GetCurrentContext()
{
return m_Impl.GetCurrentContext();
}
/// <summary>
/// Gets the parent SequenceContext for the Timeline currently shown in the Timeline window.
/// </summary>
/// <returns>The parent SequenceContext for the Timeline currently shown in the Timeline window if there is one; an invalid SequenceContext otherwise. <seealso cref="SequenceContext.Invalid"/></returns>
/// <exception cref="System.InvalidOperationException"> The Window associated to this instance has been destroyed.</exception>
public SequenceContext GetParentContext()
{
return m_Impl.GetParentContext();
}
/// <summary>
/// Gets the first SequenceContext in the breadcrumbs.
/// </summary>
/// <returns>The first SequenceContext in the breadcrumbs.</returns>
/// <remarks>Equivalent to <c>TimelineNavigator.GetBreadCrumbs().First()</c></remarks>
/// <exception cref="System.InvalidOperationException"> The Window associated to this instance has been destroyed.</exception>
public SequenceContext GetRootContext()
{
return m_Impl.GetRootContext();
}
/// <summary>
/// Gets the collection of child contexts that can be navigated to from the current context.
/// </summary>
/// <returns>The collection of child contexts that can be navigated to from the current context.</returns>
/// <exception cref="System.InvalidOperationException"> The Window associated to this instance has been destroyed.</exception>
public IEnumerable<SequenceContext> GetChildContexts()
{
return m_Impl.GetChildContexts();
}
/// <summary>
/// Gets the collection of SequenceContexts associated with the breadcrumbs shown in the TimelineEditorWindow.
/// </summary>
/// <remarks>This operation can be expensive. Consider caching the results instead of calling the method multiple times.</remarks>
/// <returns>The collection of SequenceContexts associated with the breadcrumbs shown in the TimelineEditorWindow, from the root context to the current context.</returns>
/// <exception cref="System.InvalidOperationException"> The Window associated to this instance has been destroyed.</exception>
public IEnumerable<SequenceContext> GetBreadcrumbs()
{
return m_Impl.GetBreadcrumbs();
}
/// <summary>
/// Navigates to a new SequenceContext.
/// </summary>
/// <param name="context">The context to navigate to.</param>
/// <remarks>
/// The SequenceContext provided must be a valid navigation destination.
///
/// Valid navigation destinations:
/// * The parent context returned by <see cref="GetParentContext"/>.
/// * The root context returned by <see cref="GetRootContext"/>.
/// * Any SequenceContext returned by <see cref="GetChildContexts"/>.
/// * Any SequenceContext returned by <see cref="GetBreadcrumbs"/>.
///
/// Note: This method cannot be used to change the root SequenceContext. To change the root SequenceContext, use <see cref="TimelineEditorWindow.SetTimeline"/>.
///
/// </remarks>
/// <exception cref="System.InvalidOperationException"> The Window associated to this instance has been destroyed.</exception>
/// <exception cref="System.ArgumentException"> The context is not valid.</exception>
/// <exception cref="System.InvalidOperationException"> The context is not a valid navigation destination.</exception>
public void NavigateTo(SequenceContext context)
{
m_Impl.NavigateTo(context);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c756627eb1aed7a40bd8ba981a07ede5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,144 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Timeline
{
internal interface ITimelinePlaybackControls
{
void Play();
void Pause();
void PreviousFrame();
void NextFrame();
void GoToFirstFrame();
void GoToLastFrame();
void SetCurrentTime(double time, TimelinePlaybackControls.Context context);
void SetCurrentFrame(int frame, TimelinePlaybackControls.Context context);
double GetCurrentTime(TimelinePlaybackControls.Context context);
int GetCurrentFrame(TimelinePlaybackControls.Context context);
}
/// <summary>
/// Use the TimelinePlaybackControls to manage the Timeline window's playback state, playhead location, and play range.
/// </summary>
public sealed class TimelinePlaybackControls
{
TimelineWindow.TimelinePlaybackControlsImpl m_Impl;
internal TimelinePlaybackControls(IWindowStateProvider stateProvider)
{
m_Impl = new TimelineWindow.TimelinePlaybackControlsImpl(stateProvider);
}
/// <summary>
/// Use Context to specify whether the time is based on local time or global time.
/// </summary>
public enum Context
{
/// <summary>
/// Time is relative to the current Timeline
/// </summary>
Local,
/// <summary>
/// Time is relative to the main Timeline
/// </summary>
Global
}
/// <summary>
/// Starts playback.
/// </summary>
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
public void Play() { m_Impl.Play(); }
/// <summary>
/// Pauses playback.
/// </summary>
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
public void Pause() { m_Impl.Pause(); }
/// <summary>
/// Moves the playhead to the previous frame.
/// </summary>
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
public void PreviousFrame() { m_Impl.PreviousFrame(); }
/// <summary>
/// Moves the playhead to the next frame.
/// </summary>
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
public void NextFrame() { m_Impl.NextFrame(); }
/// <summary>
/// Moves the playhead to the first frame.
/// </summary>
/// <exception cref="System.InvalidOperationException"> The Window associated with this instance has been destroyed.</exception>
public void GoToFirstFrame() { m_Impl.GoToFirstFrame(); }
/// <summary>
/// Moves the playhead to the last frame.
/// </summary>
/// <exception cref="System.InvalidOperationException"> The Window associated with this instance has been destroyed.</exception>
public void GoToLastFrame() { m_Impl.GoToLastFrame(); }
/// <summary>
/// Moves the playhead to a specific time.
/// </summary>
/// <param name="time">The time in seconds.</param>
/// <param name="context">
/// Use Context with a Sub-Timeline to specify whether the specified time is relative to the Sub-Timeline or the main Timeline.
/// If the Timeline is not a Sub-Timeline, the context uses local time regardless of the specified context.
/// </param>
/// Use <see cref="Context.Local"/>, the default, to move the playhead relative to the Sub-Timeline or Timeline.
/// Use <see cref="Context.Global"/> to move the playhead relative to the main Timeline.
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
/// <exception cref="System.ArgumentException">The context is invalid.</exception>
public void SetCurrentTime(double time, Context context = Context.Local) { m_Impl.SetCurrentTime(time, context); }
/// <summary>
/// Moves the playhead to a specific frame.
/// </summary>
/// <param name="frame">The frame to move to.</param>
/// <param name="context">
/// Use Context with a Sub-Timeline to specify whether the specified frame is relative to the Sub-Timeline or the main Timeline.
/// If the Timeline is not a Sub-Timeline, the context uses local time regardless of the specified context.
/// </param>
/// Use <see cref="Context.Local"/>, the default, to move the playhead relative to the Sub-Timeine.
/// Use <see cref="Context.Global"/> to move the playhead relative to the main Timeline.
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
/// <exception cref="System.ArgumentException">The context is invalid.</exception>
public void SetCurrentFrame(int frame, Context context = Context.Local) { m_Impl.SetCurrentFrame(frame, context); }
/// <summary>
/// Retrieves the location of the timeline playhead in seconds.
/// </summary>
/// <param name="context">
/// Use Context with a Sub-Timeline to specify whether the returned value is relative to the Sub-Timeline or the main Timeline.
/// If the Timeline is not a Sub-Timeline, the context uses local time regardless of the specified context.
/// </param>
/// Use <see cref="Context.Local"/>, the default, to retrieve the playhead location relative to the Sub-Timeline.
/// Use <see cref="Context.Global"/> to retrive the location relative to the main Timeline.
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
/// <exception cref="System.ArgumentException">The context is invalid.</exception>
/// <returns>The playhead location in seconds.</returns>
public double GetCurrentTime(Context context = Context.Local)
{
return m_Impl.GetCurrentTime(context);
}
/// <summary>
/// Retrieves the location of the timeline playhead in frames.
/// </summary>
/// <param name="context">
/// Use Context with a Sub-Timeline to specify whether the returned value is relative to the Sub-Timeline or the main Timeline.
/// If the Timeline is not a Sub-Timeline, the context uses local time regardless of the specified context.
/// </param>
/// Use <see cref="Context.Local"/>, the default, to retrieve the playhead location relative to the Sub-Timeline.
/// Use <see cref="Context.Global"/> to retrive the playhead location relative to the main Timeline.
/// <exception cref="System.InvalidOperationException">The Window associated with this instance has been destroyed.</exception>
/// <exception cref="System.ArgumentException">The context is invalid.</exception>
/// <returns>The playhead location in frames.</returns>
public int GetCurrentFrame(Context context = Context.Local)
{
return m_Impl.GetCurrentFrame(context);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b662f155e14546d0b72f129800d013d0
timeCreated: 1620849473

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f817a38900380be47942905e17e7d39b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,145 @@
//#define ANALITICS_DEBUG
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
class TimelineWindowAnalytics
{
const string vendorKey = "unity.timeline";
const string eventName = "timeline_editor_info";
const int version = 2;
const int maxEventsPerHour = 1000;
const int maxNumberOfElements = 1000;
[Serializable]
internal struct timeline_asset_stats
{
public string asset_guid;
public double duration;
public double frame_rate;
public List<track_asset_stats> track_stats;
public double mix_samples_count, ripple_samples_count, replace_samples_count;
public string display_format;
}
[Serializable]
internal struct track_asset_stats
{
public string track_type;
public int clip_count;
public int marker_count;
}
class WindowAnalyticsStats
{
internal int[] editModeSamples = new int[3]; // EditModes
}
static WindowAnalyticsStats analyticsStats = new WindowAnalyticsStats();
public void SendPlayEvent(bool start)
{
if (!start || !EditorAnalytics.enabled)
{
return;
}
EditorAnalytics.RegisterEventWithLimit(eventName, maxEventsPerHour, maxNumberOfElements, vendorKey, version);
var ret = GenerateTimelineAssetStats(out var data);
if (!ret)
{
return;
}
#if ANALITICS_DEBUG
Debug.Log(JsonUtility.ToJson(data, true));
#endif
EditorAnalytics.SendEventWithLimit(eventName, data, version);
SendAfterSequenceChangeEvent();
}
public void SendAfterSequenceChangeEvent()
{
analyticsStats = new WindowAnalyticsStats(); // Wipe Window Stats
}
public void SendManipulationEndedEvent()
{
analyticsStats.editModeSamples[(int)EditMode.editType]++;
}
internal static bool GenerateTimelineAssetStats(out timeline_asset_stats data)
{
var timeline = TimelineEditor.inspectedAsset;
if (timeline == null ||
!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(timeline, out var guid, out long _))
{
data = new timeline_asset_stats();
return false;
}
data = new timeline_asset_stats
{
asset_guid = guid,
duration = timeline.duration,
frame_rate = timeline.editorSettings.frameRate,
track_stats = GetTrackAssetStats(timeline),
display_format = TimelinePreferences.instance.timeFormat.ConvertToString(),
mix_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Mix],
ripple_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Ripple],
replace_samples_count = analyticsStats.editModeSamples[(int)EditMode.EditType.Replace],
};
return true;
}
static List<track_asset_stats> GetTrackAssetStats(TimelineAsset timeline)
{
var ret = new List<track_asset_stats>();
foreach (var track in timeline.flattenedTracks)
{
ret.Add(new track_asset_stats
{
track_type = track.GetType().FullName,
clip_count = track.GetClips().Count(),
marker_count = track.GetMarkers().Count()
}
);
}
return ret;
}
}
static class ConversionUtilities
{
internal static string ConvertToString<T>(this T e) where T : Enum
{
return Enum.GetName(typeof(T), e).ToSnakeCase();
}
static string ToSnakeCase(this string str)
{
var sb = new StringBuilder();
for (var i = 0; i < str.Length - 1; ++i)
{
var ch = str[i];
var nCh = str[i + 1];
if (char.IsUpper(ch) && char.IsLower(nCh))
{
sb.Append("_");
}
sb.Append(ch.ToString().ToLower());
}
sb.Append(str[str.Length - 1].ToString().ToLower());
return sb.ToString().TrimStart('_');
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d4de78ba9fbd472a884ea157f740743
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,320 @@
using System;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Timeline;
using Object = UnityEngine.Object;
namespace UnityEditor.Timeline
{
class TimelineWindowTimeControl : IAnimationWindowControl
{
[Serializable]
public struct ClipData
{
public double start;
public double duration;
public TrackAsset track;
}
#if UNITY_2021_2_OR_NEWER
const AnimationWindowState.SnapMode k_SnapMode = AnimationWindowState.SnapMode.SnapToFrame;
#else
const AnimationWindowState.SnapMode k_SnapMode = AnimationWindowState.SnapMode.SnapToClipFrame;
#endif
[SerializeField] ClipData m_ClipData;
[SerializeField] TimelineClip m_Clip;
[SerializeField] AnimationWindowState m_AnimWindowState;
TrackAsset track
{
get
{
if (m_Clip != null)
{
return m_Clip.GetParentTrack();
}
return m_ClipData.track;
}
}
static TimelineWindow window
{
get
{
return TimelineWindow.instance;
}
}
static WindowState state
{
get
{
if (window != null)
return window.state;
return null;
}
}
void OnStateChange()
{
if (state != null && state.dirtyStamp > 0 && m_AnimWindowState != null)
m_AnimWindowState.Repaint();
}
public void Init(AnimationWindowState animState, TimelineClip clip)
{
m_Clip = clip;
m_AnimWindowState = animState;
}
public void Init(AnimationWindowState animState, ClipData clip)
{
m_ClipData = clip;
m_AnimWindowState = animState;
}
public override void OnEnable()
{
if (state != null)
state.OnTimeChange += OnStateChange;
base.OnEnable();
}
public void OnDisable()
{
if (state != null)
state.OnTimeChange -= OnStateChange;
}
public override AnimationKeyTime time
{
get
{
if (state == null)
return AnimationKeyTime.Time(0.0f, 0.0f);
return AnimationKeyTime.Time(ToAnimationClipTime(state.editSequence.time), (float)state.referenceSequence.frameRate);
}
}
void ChangeTime(float newTime)
{
if (state != null && state.editSequence.director != null)
{
// avoid rounding errors
var finalTime = ToGlobalTime(newTime);
if (TimeUtility.OnFrameBoundary(finalTime, state.referenceSequence.frameRate, TimeUtility.kFrameRateEpsilon))
finalTime = TimeUtility.RoundToFrame(finalTime, state.referenceSequence.frameRate);
state.editSequence.time = finalTime;
window.Repaint();
}
}
static void ChangeFrame(int frame)
{
if (state != null)
{
state.editSequence.frame = frame;
window.Repaint();
}
}
public override void GoToTime(float newTime)
{
ChangeTime(newTime);
}
public override void GoToFrame(int frame)
{
ChangeFrame(frame);
}
public override void StartScrubTime() { }
public override void EndScrubTime() { }
public override void ScrubTime(float newTime)
{
ChangeTime(newTime);
}
public override void GoToPreviousFrame()
{
if (state != null)
ChangeFrame(state.editSequence.frame - 1);
}
public override void GoToNextFrame()
{
if (state != null)
ChangeFrame(state.editSequence.frame + 1);
}
AnimationWindowCurve[] GetCurves()
{
var curves =
(m_AnimWindowState.showCurveEditor &&
m_AnimWindowState.activeCurves.Count > 0) ? m_AnimWindowState.activeCurves : m_AnimWindowState.allCurves;
return curves.ToArray();
}
public override void GoToPreviousKeyframe()
{
var newTime = AnimationWindowUtility.GetPreviousKeyframeTime(GetCurves(), time.time, m_AnimWindowState.clipFrameRate);
GoToTime(m_AnimWindowState.SnapToFrame(newTime, k_SnapMode));
}
public override void GoToNextKeyframe()
{
var newTime = AnimationWindowUtility.GetNextKeyframeTime(GetCurves(), time.time, m_AnimWindowState.clipFrameRate);
GoToTime(m_AnimWindowState.SnapToFrame(newTime, k_SnapMode));
}
public override void GoToFirstKeyframe()
{
GoToTime(0);
}
public override void GoToLastKeyframe()
{
double animClipTime = 0;
if (m_Clip != null)
{
var curves = m_Clip.curves;
var animAsset = m_Clip.asset as AnimationPlayableAsset;
if (animAsset != null)
{
animClipTime = animAsset.clip != null ? animAsset.clip.length : 0;
}
else if (curves != null)
{
animClipTime = curves.length;
}
else
{
animClipTime = m_Clip.clipAssetDuration;
}
}
else
{
animClipTime = m_ClipData.duration;
}
GoToTime((float)animClipTime);
}
public override bool canPlay
{
get
{
return state != null && state.previewMode;
}
}
public override bool playing
{
get
{
return state != null && state.playing;
}
}
static void SetPlaybackState(bool playbackState)
{
if (state == null || playbackState == state.playing)
return;
state.SetPlaying(playbackState);
}
public override bool StartPlayback()
{
SetPlaybackState(true);
return state != null && state.playing;
}
public override void StopPlayback()
{
SetPlaybackState(false);
}
public override bool PlaybackUpdate() { return state != null && state.playing; }
public override bool canRecord
{
get { return state != null && state.canRecord; }
}
public override bool recording
{
get { return state != null && state.recording; }
}
public override bool canPreview
{
get { return false; }
}
public override bool previewing
{
get { return false; }
}
public override bool StartRecording(Object targetObject)
{
if (!canRecord)
return false;
if (track != null && state != null && !state.ignorePreview)
{
state.ArmForRecord(track);
return state.recording;
}
return false;
}
public override void StopRecording()
{
if (track != null && state != null && !state.ignorePreview)
state.UnarmForRecord(track);
}
public override void OnSelectionChanged() { }
public override void ResampleAnimation() { }
public override bool StartPreview()
{
if (state != null)
state.previewMode = true;
return state != null && state.previewMode;
}
public override void StopPreview()
{
if (state != null)
state.previewMode = false;
}
public override void ProcessCandidates() { }
public override void ClearCandidates() { }
double ToGlobalTime(float localTime)
{
if (m_Clip != null)
return Math.Max(0, m_Clip.FromLocalTimeUnbound(localTime));
return Math.Max(0, m_ClipData.start + localTime);
}
float ToAnimationClipTime(double globalTime)
{
if (m_Clip != null)
return (float)m_Clip.ToLocalTimeUnbound(globalTime);
return (float)(globalTime - m_ClipData.start);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6f25fb081e85cb743b272c2f7fbc2f6b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
private TimelineAsset m_PreviousMasterSequence;
public override void ClearTimeline()
{
SetCurrentTimeline(null, null, null, true);
}
public override void SetTimeline(TimelineAsset seq)
{
SetCurrentTimeline(seq, null, null);
}
public override void SetTimeline(PlayableDirector director)
{
SetCurrentTimeline(director, null);
}
public void SetCurrentTimeline(PlayableDirector director, TimelineClip hostClip)
{
var asset = director != null ? director.playableAsset as TimelineAsset : null;
SetCurrentTimeline(asset, director, hostClip);
}
void SetCurrentTimeline(TimelineAsset seq, PlayableDirector instanceOfDirector, TimelineClip hostClip, bool force = false)
{
if (state == null)
return;
if (!force &&
state.editSequence.hostClip == hostClip &&
state.editSequence.director == instanceOfDirector &&
state.editSequence.asset == seq)
return;
state.SetCurrentSequence(seq, instanceOfDirector, hostClip);
}
void OnBeforeSequenceChange()
{
treeView = null;
m_MarkerHeaderGUI = null;
m_TimeAreaDirty = true;
state.Reset();
m_PlayableLookup.ClearPlayableLookup();
// clear old editors to caches, like audio previews, get flushed
CustomTimelineEditorCache.ClearCache<ClipEditor>();
CustomTimelineEditorCache.ClearCache<MarkerEditor>();
CustomTimelineEditorCache.ClearCache<TrackEditor>();
m_PreviousMasterSequence = state.masterSequence.asset;
}
void OnAfterSequenceChange()
{
Repaint();
m_SequencePath = state.GetCurrentSequencePath();
m_LastFrameHadSequence = state.editSequence.asset != null;
TimelineWindowViewPrefs.SaveAll();
// this prevent clearing the animation window when going in/out of playmode, but
// clears it when we switch master timelines
// the cast to a object will handle the case where the sequence has been deleted.
object previousMasterSequence = m_PreviousMasterSequence;
bool isDeleted = previousMasterSequence != null && m_PreviousMasterSequence == null;
bool hasChanged = m_PreviousMasterSequence != null && m_PreviousMasterSequence != state.masterSequence.asset;
if (isDeleted || hasChanged)
{
AnimationClipCurveCache.Instance.Clear();
TimelineAnimationUtilities.UnlinkAnimationWindow();
state.analytics.SendAfterSequenceChangeEvent(); // Changing timelines resets analytics that are aggregated in the Timeline Window
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7abcd1a72bb7174ca58e813c6eee9c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
#if UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement;
#else
using UnityEditor.Experimental.SceneManagement;
#endif
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
List<BreadCrumbTitle> m_BreadCrumbLabels = new List<BreadCrumbTitle>(100);
static TitleMode GetTitleMode(ISequenceState sequence)
{
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
// Top level
if (sequence.hostClip == null)
{
if (sequence.director != null && prefabStage != null && prefabStage.IsPartOfPrefabContents(sequence.director.gameObject))
return TitleMode.Prefab;
if (sequence.director != null && PrefabUtility.IsPartOfPrefabAsset(sequence.director))
return TitleMode.PrefabOutOfContext;
if (sequence.director != null && !sequence.director.isActiveAndEnabled)
return TitleMode.DisabledComponent;
if (sequence.director != null)
return TitleMode.GameObject;
if (sequence.asset != null)
return TitleMode.Asset;
}
// Subtimelines only get an error icon
else if (sequence.director != null && !sequence.director.isActiveAndEnabled && !PrefabUtility.IsPartOfPrefabAsset(sequence.director))
return TitleMode.DisabledComponent;
return TitleMode.None;
}
void DrawBreadcrumbs()
{
if (state == null)
return;
var count = 0;
foreach (var sequence in state.GetAllSequences())
{
var title = new BreadCrumbTitle
{
name = DisplayNameHelper.GetDisplayName(sequence),
mode = GetTitleMode(sequence)
};
if (count >= m_BreadCrumbLabels.Count)
m_BreadCrumbLabels.Add(title);
else
m_BreadCrumbLabels[count] = title;
count++;
}
if (m_BreadCrumbLabels.Count > count)
m_BreadCrumbLabels.RemoveRange(count, m_BreadCrumbLabels.Count - count);
using (new EditorGUI.DisabledScope(currentMode.headerState.breadCrumb == TimelineModeGUIState.Disabled))
{
var width = position.width - WindowConstants.playControlsWidth - WindowConstants.cogButtonWidth;
BreadcrumbDrawer.Draw(width, m_BreadCrumbLabels, NavigateToBreadcrumbIndex);
}
}
void NavigateToBreadcrumbIndex(int index)
{
state.PopSequencesUntilCount(index + 1);
}
void DrawSequenceSelector()
{
using (new EditorGUI.DisabledScope(currentMode.headerState.sequenceSelector == TimelineModeGUIState.Disabled))
{
if (EditorGUILayout.DropdownButton(DirectorStyles.timelineSelectorArrow, FocusType.Passive, DirectorStyles.Instance.sequenceSwitcher, GUILayout.Width(WindowConstants.selectorWidth)))
ShowSequenceSelector();
}
}
void ShowSequenceSelector()
{
var allDirectors = TimelineUtility.GetDirectorsInSceneUsingAsset(null);
var formatter = new SequenceMenuNameFormater();
var namesAndDirectors = new List<ValueTuple<string, PlayableDirector>>();
foreach (var d in allDirectors)
{
if (d.playableAsset is TimelineAsset)
{
var text = formatter.Format(DisplayNameHelper.GetDisplayName(d));
namesAndDirectors.Add(new ValueTuple<string, PlayableDirector>(text, d));
}
}
var sequenceMenu = new GenericMenu();
foreach (var (timelineName, playableDirector) in namesAndDirectors.OrderBy(i => i.Item1))
{
var isCurrent = state.masterSequence.director == playableDirector;
sequenceMenu.AddItem(new GUIContent(timelineName), isCurrent, OnSequenceSelected, playableDirector);
}
if (allDirectors.Length == 0)
sequenceMenu.AddDisabledItem(DirectorStyles.noTimelinesInScene);
sequenceMenu.DropDown(EditorGUILayout.s_LastRect);
}
void OnSequenceSelected(object arg)
{
var directorToBindTo = (PlayableDirector)arg;
if (directorToBindTo)
{
// don't just select the object, it may already be selected.
SetTimeline(directorToBindTo);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2cd16a2d73fe7a4c9affa2b790eb5e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,128 @@
using System;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
TimeAreaItem m_TimelineDuration;
void DurationGUI(TimelineItemArea area, double duration)
{
// don't show the duration if the time area is not visible for some other reason.
if (!currentMode.ShouldShowTimeArea(state))
return;
bool headerMode = area == TimelineItemArea.Header;
if (state.IsEditingASubTimeline())
{
if (headerMode)
HighlightTimeAreaRange(state.editSequence.GetEvaluableRange(), DirectorStyles.Instance.customSkin.colorSubSequenceDurationLine);
return;
}
// don't show the duration if there's none.
if (state.editSequence.asset.durationMode == TimelineAsset.DurationMode.BasedOnClips && duration <= 0.0f)
return;
if (m_TimelineDuration == null || m_TimelineDuration.style != styles.endmarker)
{
m_TimelineDuration = new TimeAreaItem(styles.endmarker, OnTrackDurationDrag)
{
tooltip = L10n.Tr("End of sequence marker"),
boundOffset = new Vector2(0.0f, -DirectorStyles.kDurationGuiThickness)
};
}
DrawDuration(headerMode, !headerMode, duration);
}
void DrawDuration(bool drawhead, bool drawline, double duration)
{
if (state.TimeIsInRange((float)duration))
{
// Set the colors based on the mode
Color lineColor = DirectorStyles.Instance.customSkin.colorEndmarker;
Color headColor = Color.white;
bool canMoveHead = !EditorApplication.isPlaying && state.editSequence.asset.durationMode == TimelineAsset.DurationMode.FixedLength;
if (canMoveHead)
{
if (Event.current.type == EventType.MouseDown)
{
if (m_TimelineDuration.bounds.Contains(Event.current.mousePosition))
{
if (m_PlayHead != null && m_PlayHead.bounds.Contains(Event.current.mousePosition))
{
// ignore duration markers if the mouse is over the TimeCursor.
canMoveHead = false;
}
}
}
}
else
{
lineColor.a *= 0.66f;
headColor = DirectorStyles.Instance.customSkin.colorDuration;
}
if (canMoveHead)
m_TimelineDuration.HandleManipulatorsEvents(state);
m_TimelineDuration.lineColor = lineColor;
m_TimelineDuration.headColor = headColor;
m_TimelineDuration.drawHead = drawhead;
m_TimelineDuration.drawLine = drawline;
m_TimelineDuration.canMoveHead = canMoveHead;
// Draw the TimeAreaItem
// Rect trackheadRect = treeviewBounds;
//trackheadRect.height = clientArea.height;
m_TimelineDuration.Draw(sequenceContentRect, state, duration);
}
// Draw Blue line in timeline indicating the duration...
if (state.editSequence.asset != null && drawhead)
{
HighlightTimeAreaRange(state.editSequence.GetEvaluableRange(), DirectorStyles.Instance.customSkin.colorDurationLine);
}
}
void HighlightTimeAreaRange(Range range, Color lineColor)
{
if (range.length <= 0.0 || !state.RangeIsVisible(range)) return;
Rect lineRect = Rect.MinMaxRect(
Math.Max(state.TimeToPixel(range.start), state.timeAreaRect.xMin),
state.timeAreaRect.y - DirectorStyles.kDurationGuiThickness + state.timeAreaRect.height,
Math.Min(state.TimeToPixel(range.end), state.timeAreaRect.xMax),
state.timeAreaRect.y + state.timeAreaRect.height);
EditorGUI.DrawRect(lineRect, lineColor);
}
// Drag handler for the gui
void OnTrackDurationDrag(double newTime)
{
if (state.editSequence.asset.durationMode == TimelineAsset.DurationMode.FixedLength && !state.editSequence.isReadOnly)
{
// this is the first call to the drag
if (m_TimelineDuration.firstDrag)
{
UndoExtensions.RegisterTimeline(state.editSequence.asset, L10n.Tr("Change Duration"));
}
state.editSequence.asset.fixedDuration = newTime;
// when setting a new length, modify the duration of the timeline playable directly instead of
// rebuilding the whole graph
state.UpdateRootPlayableDuration(newTime);
}
m_TimelineDuration.showTooltip = true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b3bd7a976306c9449ba84e0591e8a0f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,348 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.SceneManagement;
using UnityEditor.ShortcutManagement;
using UnityEditor.Timeline.Actions;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
using UnityEngine.SceneManagement;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
private int m_ComponentAddedFrame;
void OnSelectionChangedInactive()
{
// Case 946942 -- when selection changes and the window is open but hidden, timeline
// needs to update selection immediately so preview mode is correctly released
// Case 1123119 -- except when recording
if (!hasFocus)
{
RefreshSelection(!locked && state != null && !state.recording);
}
}
void InitializeEditorCallbacks()
{
Undo.postprocessModifications += PostprocessAnimationRecordingModifications;
Undo.postprocessModifications += ProcessAssetModifications;
Undo.undoRedoPerformed += OnUndoRedo;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
AnimationUtility.onCurveWasModified += OnCurveModified;
EditorApplication.editorApplicationQuit += OnEditorQuit;
Selection.selectionChanged += OnSelectionChangedInactive;
EditorSceneManager.sceneSaved += OnSceneSaved;
ObjectFactory.componentWasAdded += OnComponentWasAdded;
PrefabUtility.prefabInstanceUpdated += OnPrefabApplied;
EditorApplication.pauseStateChanged += OnPlayModePause;
EditorApplication.globalEventHandler += GlobalEventHandler;
#if TIMELINE_FRAMEACCURATE
TimelinePlayable.playableLooped += OnPlayableLooped;
#endif
}
// This callback is needed because the Animation window registers "Animation/Key Selected" as a global hotkey
// and we want to also react to the key.
void GlobalEventHandler()
{
if (instance == null || !state.previewMode)
{
return;
}
var keyBinding = ShortcutManager.instance.GetShortcutBinding("Animation/Key Selected");
if (keyBinding.Equals(ShortcutBinding.empty))
{
return;
}
var evtCombo = KeyCombination.FromKeyboardInput(Event.current);
if (keyBinding.keyCombinationSequence.Contains(evtCombo))
{
Invoker.InvokeWithSelected<KeyAllAnimated>();
}
}
void OnEditorQuit()
{
TimelineWindowViewPrefs.SaveAll();
}
void RemoveEditorCallbacks()
{
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
Undo.undoRedoPerformed -= OnUndoRedo;
Undo.postprocessModifications -= PostprocessAnimationRecordingModifications;
Undo.postprocessModifications -= ProcessAssetModifications;
AnimationUtility.onCurveWasModified -= OnCurveModified;
EditorApplication.editorApplicationQuit -= OnEditorQuit;
Selection.selectionChanged -= OnSelectionChangedInactive;
EditorSceneManager.sceneSaved -= OnSceneSaved;
ObjectFactory.componentWasAdded -= OnComponentWasAdded;
PrefabUtility.prefabInstanceUpdated -= OnPrefabApplied;
EditorApplication.pauseStateChanged -= OnPlayModePause;
EditorApplication.globalEventHandler -= GlobalEventHandler;
#if TIMELINE_FRAMEACCURATE
TimelinePlayable.playableLooped -= OnPlayableLooped;
#endif
}
void OnPlayModePause(PauseState state)
{
// in PlayMode, if the timeline is playing, a constant repaint cycle occurs. Pausing the editor
// breaks the cycle, so this will restart it
Repaint();
}
// Called when a prefab change is applied to the scene.
// Redraw so control tracks that use prefabs can show changes
void OnPrefabApplied(GameObject go)
{
if (!state.previewMode)
return;
// if we added a component this frame, then rebuild, otherwise just let
// the individual playable handle the prefab application
if (Time.frameCount == m_ComponentAddedFrame)
TimelineEditor.Refresh(RefreshReason.ContentsModified);
else
TimelineEditor.Refresh(RefreshReason.SceneNeedsUpdate);
}
// When the scene is save the director time will get reset.
void OnSceneSaved(Scene scene)
{
if (state != null)
state.OnSceneSaved();
}
void OnCurveModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType type)
{
InspectorWindow.RepaintAllInspectors();
if (state == null)
return;
//Force refresh of curve when modified by another editor.
Repaint();
if (state.previewMode == false)
return;
bool hasPlayable = m_PlayableLookup.GetPlayableFromAnimClip(clip, out Playable playable);
// mark the timeline clip as dirty
TimelineClip timelineClip = m_PlayableLookup.GetTimelineClipFromCurves(clip);
if (timelineClip != null)
timelineClip.MarkDirty();
if (type == AnimationUtility.CurveModifiedType.CurveModified)
{
if (hasPlayable)
{
playable.SetAnimatedProperties(clip);
}
// updates the duration of the graph without rebuilding
AnimationUtility.SyncEditorCurves(clip); // deleted keys are not synced when this is sent out, so duration could be incorrect
state.UpdateRootPlayableDuration(state.editSequence.duration);
bool isRecording = TimelineRecording.IsRecordingAnimationTrack;
PlayableDirector masterDirector = TimelineEditor.masterDirector;
bool isGraphValid = masterDirector != null && masterDirector.playableGraph.IsValid();
// don't evaluate if this is caused by recording on an animation track, the extra evaluation can cause hiccups
// Prevent graphs to be resurrected by a changed clip.
if (!isRecording && isGraphValid)
state.Evaluate();
}
else if (EditorUtility.IsDirty(clip)) // curve added/removed, or clip added/removed
{
state.rebuildGraph |= timelineClip != null || hasPlayable;
}
}
void OnPlayModeStateChanged(PlayModeStateChange playModeState)
{
// case 923506 - make sure we save view data before switching modes
if (playModeState == PlayModeStateChange.ExitingEditMode ||
playModeState == PlayModeStateChange.ExitingPlayMode)
TimelineWindowViewPrefs.SaveAll();
bool isPlaymodeAboutToChange = playModeState == PlayModeStateChange.ExitingEditMode || playModeState == PlayModeStateChange.ExitingPlayMode;
// Important to stop the graph on any director so temporary objects are properly cleaned up
if (isPlaymodeAboutToChange && state != null)
state.Stop();
}
UndoPropertyModification[] PostprocessAnimationRecordingModifications(UndoPropertyModification[] modifications)
{
DirtyModifiedObjects(modifications);
var remaining = TimelineRecording.ProcessUndoModification(modifications, state);
// if we've changed, we need to repaint the sequence window to show clip length changes
if (remaining != modifications)
{
// only update if us or the sequencer window has focus
// Prevents color pickers and other dialogs from being wrongly dismissed
bool repaint = (focusedWindow == null) ||
(focusedWindow is InspectorWindow) ||
(focusedWindow is TimelineWindow);
if (repaint)
Repaint();
}
return remaining;
}
void DirtyModifiedObjects(UndoPropertyModification[] modifications)
{
foreach (var m in modifications)
{
if (m.currentValue == null || m.currentValue.target == null)
continue;
var track = m.currentValue.target as TrackAsset;
var playableAsset = m.currentValue.target as PlayableAsset;
var editorClip = m.currentValue.target as EditorClip;
if (track != null)
{
track.MarkDirtyTrackAndClips();
}
else if (playableAsset != null)
{
var clip = TimelineRecording.FindClipWithAsset(state.editSequence.asset, playableAsset);
if (clip != null)
{
clip.MarkDirty();
}
}
else if (editorClip != null && editorClip.clip != null)
{
editorClip.clip.MarkDirty();
}
}
}
UndoPropertyModification[] ProcessAssetModifications(UndoPropertyModification[] modifications)
{
bool rebuildGraph = false;
for (int i = 0; i < modifications.Length && !rebuildGraph; i++)
{
var mod = modifications[i];
if (mod.currentValue != null && mod.currentValue.target is IMarker currentMarker)
{
if (currentMarker.parent != null && currentMarker.parent.timelineAsset == state.editSequence.asset)
{
if (mod.currentValue.target is INotification)
TimelineEditor.Refresh(RefreshReason.ContentsModified);
else
TimelineEditor.Refresh(RefreshReason.WindowNeedsRedraw);
}
}
else if (mod.previousValue != null && mod.previousValue.target is AvatarMask) // check if an Avatar Mask has been modified
{
rebuildGraph = state.editSequence.asset != null &&
state.editSequence.asset.flattenedTracks
.OfType<UnityEngine.Timeline.AnimationTrack>()
.Any(x => mod.previousValue.target == x.avatarMask);
}
}
if (rebuildGraph)
{
state.rebuildGraph = true;
Repaint();
}
return modifications;
}
void OnUndoRedo()
{
var undos = new List<string>();
var redos = new List<string>();
Undo.GetRecords(undos, redos);
var rebuildAll = redos.Any(x => x.StartsWith("Timeline ")) || undos.Any(x => x.StartsWith("Timeline"));
var evalNow = redos.Any(x => x.Contains("Edit Curve")) || undos.Any(x => x.Contains("Edit Curve"));
if (rebuildAll || evalNow)
{
ValidateSelection();
if (state != null)
{
if (evalNow) // when curves change, the new values need to be set in the transform before the inspector handles the undo
state.EvaluateImmediate();
if (rebuildAll)
state.Refresh();
}
Repaint();
}
}
static void ValidateSelection()
{
//get all the clips in the selection
var selectedClips = Selection.GetFiltered<EditorClip>(SelectionMode.Unfiltered).Select(x => x.clip);
foreach (var selectedClip in selectedClips)
{
var parent = selectedClip.GetParentTrack();
if (selectedClip.GetParentTrack() != null)
{
if (!parent.clips.Contains(selectedClip))
{
SelectionManager.Remove(selectedClip);
}
}
}
}
void OnComponentWasAdded(Component c)
{
m_ComponentAddedFrame = Time.frameCount;
var go = c.gameObject;
foreach (var seq in state.GetAllSequences())
{
if (seq.director == null || seq.asset == null)
{
return;
}
var rebind = seq.asset.GetOutputTracks().Any(track => seq.director.GetGenericBinding(track) == go);
// Either the playable director has a binding for the GameObject or it is a sibling of the director.
// The second case is needed since we have timeline top level markerTracks that do not have a binding, but
// are still "targeting" the playable director
if (rebind || seq.director.gameObject == go)
{
seq.director.RebindPlayableGraphOutputs();
}
}
}
#if TIMELINE_FRAMEACCURATE
void OnPlayableLooped(Playable timelinePlayable)
{
if (state == null || !state.playing || state.masterSequence == null || state.masterSequence.director == null
|| !state.masterSequence.director.playableGraph.IsValid())
return;
var masterPlayable = state.masterSequence.director.playableGraph.GetRootPlayable(0);
if (!masterPlayable.Equals(Playable.Null)
&& masterPlayable.Equals(timelinePlayable)
&& timelinePlayable.GetGraph().IsMatchFrameRateEnabled())
timelinePlayable.SetTime(0);
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1c9c1ed454d0594b951eb6a76ac62ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,469 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement;
#else
using UnityEditor.Experimental.SceneManagement;
#endif
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
struct MarkerOverlay
{
public IMarker marker;
public Rect rect;
public bool isSelected;
public bool isCollapsed;
public MarkerEditor editor;
}
enum TimelineItemArea
{
Header,
Lines
}
static internal readonly TimelineMode s_ActiveMode = new TimelineActiveMode();
static internal readonly TimelineMode s_EditAssetMode = new TimelineAssetEditionMode();
static internal readonly TimelineMode s_InactiveMode = new TimelineInactiveMode();
static internal readonly TimelineMode s_DisabledMode = new TimelineDisabledMode();
static internal readonly TimelineMode s_PrefabOutOfContextMode = new TimelineAssetEditionMode();
static internal readonly TimelineMode s_ReadonlyMode = new TimelineReadOnlyMode();
private static readonly GUIContent MenuItemFrames = L10n.TextContent("Frames");
private static readonly GUIContent MenuItemTimecode = L10n.TextContent("Timecode");
private static readonly GUIContent MenuItemSeconds = L10n.TextContent("Seconds");
static readonly string k_FrameRateMenuLabel = L10n.Tr("Frame Rate/{0}");
static readonly string k_CustomFpsLabel = L10n.Tr("{0}: {1:f2} fps");
float m_VerticalScrollBarSize, m_HorizontalScrollBarSize;
List<MarkerOverlay> m_OverlayQueue = new List<MarkerOverlay>(100);
float headerHeight
{
get
{
return WindowConstants.markerRowYPosition + (state.showMarkerHeader ? WindowConstants.markerRowHeight : 0.0f);
}
}
public Rect markerHeaderRect
{
get { return new Rect(0.0f, WindowConstants.markerRowYPosition, state.sequencerHeaderWidth, WindowConstants.markerRowHeight); }
}
public Rect markerContentRect
{
get { return Rect.MinMaxRect(state.sequencerHeaderWidth, WindowConstants.markerRowYPosition, position.width, WindowConstants.markerRowYPosition + WindowConstants.markerRowHeight); }
}
Rect trackRect
{
get
{
var yMinHeight = headerHeight;
return new Rect(0, yMinHeight, position.width, position.height - yMinHeight - horizontalScrollbarHeight);
}
}
public Rect sequenceRect
{
get { return new Rect(0.0f, WindowConstants.markerRowYPosition, position.width - WindowConstants.sliderWidth, position.height - WindowConstants.timeAreaYPosition); }
}
public Rect sequenceHeaderRect
{
get { return new Rect(0.0f, WindowConstants.markerRowYPosition, state.sequencerHeaderWidth, position.height - WindowConstants.timeAreaYPosition); }
}
public Rect headerSplitterRect
{
get
{
return new Rect(state.sequencerHeaderWidth - WindowConstants.headerSplitterWidth / 2.0f, WindowConstants.timeAreaYPosition, WindowConstants.headerSplitterWidth, clientArea.height);
}
}
public Rect sequenceContentRect
{
get
{
return new Rect(
state.sequencerHeaderWidth,
WindowConstants.markerRowYPosition,
position.width - state.sequencerHeaderWidth - (treeView != null && treeView.showingVerticalScrollBar ? WindowConstants.sliderWidth : 0),
position.height - WindowConstants.markerRowYPosition - horizontalScrollbarHeight);
}
}
public float verticalScrollbarWidth
{
get
{
return m_VerticalScrollBarSize;
}
}
public float horizontalScrollbarHeight
{
get { return m_HorizontalScrollBarSize; }
}
internal TimelineMode currentMode
{
get
{
if (state == null || state.editSequence.asset == null)
return s_InactiveMode;
if (state.editSequence.isReadOnly)
return s_ReadonlyMode;
if (state.editSequence.director == null || state.masterSequence.director == null)
return s_EditAssetMode;
if (PrefabUtility.IsPartOfPrefabAsset(state.editSequence.director))
{
var stage = PrefabStageUtility.GetCurrentPrefabStage();
if (stage == null || !stage.IsPartOfPrefabContents(state.editSequence.director.gameObject))
return s_PrefabOutOfContextMode;
}
if (!state.masterSequence.director.isActiveAndEnabled)
return s_DisabledMode;
return s_ActiveMode;
}
}
void DoLayout()
{
EventType rawType = Event.current.rawType;
var mousePosition = Event.current.mousePosition; // mousePosition is also affected by this bug and does not reflect the original position after a Use()
Initialize();
var processManipulators = Event.current.type != EventType.Repaint && Event.current.type != EventType.Layout;
if (processManipulators)
{
// Update what's under mouse the cursor
PickerUtils.DoPick(state, mousePosition);
if (state.editSequence.asset != null)
m_PreTreeViewControl.HandleManipulatorsEvents(state);
}
SequencerGUI();
if (processManipulators)
{
if (state.editSequence.asset != null)
m_PostTreeViewControl.HandleManipulatorsEvents(state);
}
if (state.editSequence.asset != null)
{
m_RectangleSelect.OnGUI(state, rawType, mousePosition);
m_RectangleZoom.OnGUI(state, rawType, mousePosition);
}
}
void SplitterGUI()
{
if (!state.IsEditingAnEmptyTimeline())
{
var splitterVisualRect = new Rect(state.sequencerHeaderWidth - WindowConstants.headerSplitterWidth / 2.0f,
WindowConstants.timeAreaYPosition + 2.0f,
WindowConstants.headerSplitterVisualWidth,
clientArea.height);
EditorGUI.DrawRect(splitterVisualRect, DirectorStyles.Instance.customSkin.colorTopOutline3);
if (GUIUtility.hotControl == 0)
EditorGUIUtility.AddCursorRect(headerSplitterRect, MouseCursor.SplitResizeLeftRight);
}
}
void TrackViewsGUI()
{
using (new GUIViewportScope(trackRect))
{
TracksGUI(trackRect, state, currentMode.TrackState(state));
}
}
void UserOverlaysGUI()
{
if (Event.current.type != EventType.Repaint)
return;
if (m_OverlayQueue.Count == 0)
return;
// the rect containing the time area plus the time ruler
var screenRect = new Rect(
state.sequencerHeaderWidth,
WindowConstants.timeAreaYPosition,
position.width - state.sequencerHeaderWidth - (treeView != null && treeView.showingVerticalScrollBar ? WindowConstants.sliderWidth : 0),
position.height - WindowConstants.timeAreaYPosition - horizontalScrollbarHeight);
var trackOffset = trackRect.y - screenRect.y;
var startTime = state.PixelToTime(screenRect.xMin);
var endTime = state.PixelToTime(screenRect.xMax);
using (new GUIViewportScope(screenRect))
{
foreach (var entry in m_OverlayQueue)
{
var uiState = MarkerUIStates.None;
if (entry.isCollapsed)
uiState |= MarkerUIStates.Collapsed;
if (entry.isSelected)
uiState |= MarkerUIStates.Selected;
var region = new MarkerOverlayRegion(GUIClip.Clip(entry.rect), screenRect, startTime, endTime, trackOffset);
try
{
entry.editor.DrawOverlay(entry.marker, uiState, region);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
}
m_OverlayQueue.Clear();
}
void DrawHeaderBackground()
{
var rect = state.timeAreaRect;
rect.xMin = 0.0f;
EditorGUI.DrawRect(rect, DirectorStyles.Instance.customSkin.colorTimelineBackground);
}
void HandleBottomFillerDragAndDrop(Rect rect)
{
if (Event.current.type != EventType.DragUpdated &&
Event.current.type != EventType.DragExited &&
Event.current.type != EventType.DragPerform)
return;
if (instance.treeView == null || instance.treeView.timelineDragging == null)
return;
if (!rect.Contains(Event.current.mousePosition))
return;
instance.treeView.timelineDragging.DragElement(null, new Rect(), -1);
}
void DrawHeaderBackgroundBottomFiller()
{
var rect = sequenceRect;
rect.yMin = rect.yMax;
rect.yMax = rect.yMax + WindowConstants.sliderWidth;
if (state.editSequence.asset != null && !state.IsEditingAnEmptyTimeline())
{
rect.width = state.sequencerHeaderWidth;
}
using (new GUIViewportScope(rect))
{
Graphics.DrawBackgroundRect(state, rect);
}
HandleBottomFillerDragAndDrop(rect);
}
void SequencerGUI()
{
var duration = state.editSequence.duration;
DrawHeaderBackground();
DurationGUI(TimelineItemArea.Header, duration);
DrawToolbar();
TrackViewsGUI();
MarkerHeaderGUI();
UserOverlaysGUI();
DurationGUI(TimelineItemArea.Lines, duration);
PlayRangeGUI(TimelineItemArea.Lines);
TimeCursorGUI(TimelineItemArea.Lines);
DrawHeaderBackgroundBottomFiller();
SubTimelineRangeGUI();
PlayRangeGUI(TimelineItemArea.Header);
TimeCursorGUI(TimelineItemArea.Header);
SplitterGUI();
}
void DrawToolbar()
{
DrawOptions();
using (new GUILayout.VerticalScope())
{
using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
{
using (new GUILayout.HorizontalScope())
{
DrawTransportToolbar();
}
DrawSequenceSelector();
DrawBreadcrumbs();
GUILayout.FlexibleSpace();
DrawOptions();
}
using (new GUILayout.HorizontalScope())
{
DrawHeaderEditButtons();
DrawTimelineRuler();
}
}
}
void SubTimelineRangeGUI()
{
if (!state.IsEditingASubTimeline() || state.IsEditingAnEmptyTimeline()) return;
var subTimelineOverlayColor = DirectorStyles.Instance.customSkin.colorSubSequenceOverlay;
var range = state.editSequence.GetEvaluableRange();
var area = new Vector2(state.TimeToPixel(range.start), state.TimeToPixel(range.end));
var fullRect = sequenceContentRect;
fullRect.yMin = WindowConstants.timeAreaYPosition + 1.0f;
if (fullRect.xMin < area.x)
{
var before = fullRect;
before.xMin = fullRect.xMin;
before.xMax = Mathf.Min(area.x, fullRect.xMax);
EditorGUI.DrawRect(before, subTimelineOverlayColor);
}
if (fullRect.xMax > area.y)
{
var after = fullRect;
after.xMin = Mathf.Max(area.y, fullRect.xMin);
after.xMax = fullRect.xMax;
EditorGUI.DrawRect(after, subTimelineOverlayColor);
// Space above the vertical scrollbar
after.xMin = after.xMax;
after.width = verticalScrollbarWidth;
after.yMax = state.timeAreaRect.y + state.timeAreaRect.height + (state.showMarkerHeader ? WindowConstants.markerRowHeight : 0.0f);
EditorGUI.DrawRect(after, subTimelineOverlayColor);
}
}
void DrawOptions()
{
if (currentMode.headerState.options == TimelineModeGUIState.Hidden || state.editSequence.asset == null)
return;
using (new EditorGUI.DisabledScope(currentMode.headerState.options == TimelineModeGUIState.Disabled))
{
var rect = new Rect(position.width - WindowConstants.cogButtonWidth, 0, WindowConstants.cogButtonWidth, WindowConstants.timeAreaYPosition);
if (EditorGUI.DropdownButton(rect, DirectorStyles.optionsCogIcon, FocusType.Keyboard, EditorStyles.toolbarButton))
{
GenericMenu menu = new GenericMenu();
menu.AddItem(L10n.TextContent("Preferences Page..."), false, () => SettingsWindow.Show(SettingsScope.User, "Preferences/Timeline"));
menu.AddSeparator("");
menu.AddItem(MenuItemFrames, state.timeFormat == TimeFormat.Frames, () => state.timeFormat = TimeFormat.Frames);
menu.AddItem(MenuItemTimecode, state.timeFormat == TimeFormat.Timecode, () => state.timeFormat = TimeFormat.Timecode);
menu.AddItem(MenuItemSeconds, state.timeFormat == TimeFormat.Seconds, () => state.timeFormat = TimeFormat.Seconds);
menu.AddSeparator("");
TimeAreaContextMenu.AddTimeAreaMenuItems(menu, state);
menu.AddSeparator("");
bool isCustom = !FrameRateDisplayUtility.GetStandardFromFrameRate(state.editSequence.frameRate, out StandardFrameRates option);
var frameRatesLabels = FrameRateDisplayUtility.GetDefaultFrameRatesLabels(option);
if (isCustom)
frameRatesLabels[frameRatesLabels.Length - 1] = String.Format(k_CustomFpsLabel, frameRatesLabels.Last(), state.editSequence.frameRate);
for (var i = 0; i < frameRatesLabels.Length; i++)
{
var currentStandard = (StandardFrameRates)i;
AddStandardFrameRateMenu(menu, currentStandard, frameRatesLabels[i], currentStandard == option);
}
if (Unsupported.IsDeveloperMode())
{
menu.AddSeparator("");
menu.AddItem(L10n.TextContent("Show Snapping Debug"), SnapEngine.displayDebugLayout,
() => SnapEngine.displayDebugLayout = !SnapEngine.displayDebugLayout);
menu.AddItem(L10n.TextContent("Debug TimeArea"), false,
() =>
Debug.LogFormat("translation: {0} scale: {1} rect: {2} shownRange: {3}", m_TimeArea.translation, m_TimeArea.scale, m_TimeArea.rect, m_TimeArea.shownArea));
menu.AddItem(L10n.TextContent("Edit Skin"), false, () => Selection.activeObject = DirectorStyles.Instance.customSkin);
menu.AddItem(L10n.TextContent("Show QuadTree Debugger"), state.showQuadTree,
() => state.showQuadTree = !state.showQuadTree);
}
menu.DropDown(rect);
}
}
}
void AddStandardFrameRateMenu(GenericMenu menu, StandardFrameRates option, string label, bool on)
{
var gui = EditorGUIUtility.TextContent(String.Format(k_FrameRateMenuLabel, label));
if (state.editSequence.isReadOnly)
{
menu.AddDisabledItem(gui, on);
return;
}
FrameRate value = TimeUtility.ToFrameRate(option);
if (!value.IsValid())
menu.AddItem(gui, true, () => { });
else
{
menu.AddItem(gui, on, r =>
{
state.editSequence.frameRate = (float)value.rate;
}, value);
}
}
public void AddUserOverlay(IMarker marker, Rect rect, MarkerEditor editor, bool collapsed, bool selected)
{
if (marker == null)
throw new ArgumentNullException("marker");
if (editor == null)
throw new ArgumentNullException("editor");
m_OverlayQueue.Add(new MarkerOverlay()
{
isCollapsed = collapsed,
isSelected = selected,
marker = marker,
rect = rect,
editor = editor
}
);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a956e5803e95df349bd35832492d4014
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,280 @@
using System.Linq;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
static readonly GUIContent[] k_TimeReferenceGUIContents =
{
L10n.TextContent("Local", "Display time based on the current timeline."),
L10n.TextContent("Global", "Display time based on the master timeline.")
};
TimelineMarkerHeaderGUI m_MarkerHeaderGUI;
void MarkerHeaderGUI()
{
var timelineAsset = state.editSequence.asset;
if (timelineAsset == null)
return;
if (m_MarkerHeaderGUI == null)
m_MarkerHeaderGUI = new TimelineMarkerHeaderGUI(timelineAsset, state);
m_MarkerHeaderGUI.Draw(markerHeaderRect, markerContentRect, state);
}
void DrawTransportToolbar()
{
using (new EditorGUI.DisabledScope(currentMode.PreviewState(state) == TimelineModeGUIState.Disabled))
{
PreviewModeButtonGUI();
}
using (new EditorGUI.DisabledScope(currentMode.ToolbarState(state) == TimelineModeGUIState.Disabled))
{
GotoBeginingSequenceGUI();
PreviousEventButtonGUI();
PlayButtonGUI();
NextEventButtonGUI();
GotoEndSequenceGUI();
PlayRangeButtonGUI();
TimeCodeGUI();
ReferenceTimeGUI();
}
}
void PreviewModeButtonGUI()
{
if (state.ignorePreview && !Application.isPlaying)
{
GUILayout.Label(DirectorStyles.previewDisabledContent, DirectorStyles.Instance.previewButtonDisabled);
return;
}
EditorGUI.BeginChangeCheck();
var enabled = state.previewMode;
enabled = GUILayout.Toggle(enabled, DirectorStyles.previewContent, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck())
{
// turn off auto play as well, so it doesn't auto reenable
if (!enabled)
{
state.SetPlaying(false);
state.recording = false;
}
state.previewMode = enabled;
// if we are successfully enabled, rebuild the graph so initial states work correctly
// Note: testing both values because previewMode setter can "fail"
if (enabled && state.previewMode)
state.rebuildGraph = true;
}
}
void GotoBeginingSequenceGUI()
{
if (GUILayout.Button(DirectorStyles.gotoBeginingContent, EditorStyles.toolbarButton))
{
state.editSequence.time = 0;
state.EnsurePlayHeadIsVisible();
}
}
// in the editor the play button starts/stops simulation
void PlayButtonGUIEditor()
{
EditorGUI.BeginChangeCheck();
var isPlaying = GUILayout.Toggle(state.playing, DirectorStyles.playContent, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck())
{
state.SetPlaying(isPlaying);
}
}
// in playmode the button reflects the playing state.
// needs to disabled if playing is not possible
void PlayButtonGUIPlayMode()
{
bool buttonEnabled = state.masterSequence.director != null &&
state.masterSequence.director.isActiveAndEnabled;
using (new EditorGUI.DisabledScope(!buttonEnabled))
{
PlayButtonGUIEditor();
}
}
void PlayButtonGUI()
{
if (!Application.isPlaying)
PlayButtonGUIEditor();
else
PlayButtonGUIPlayMode();
}
void NextEventButtonGUI()
{
if (GUILayout.Button(DirectorStyles.nextFrameContent, EditorStyles.toolbarButton))
{
state.referenceSequence.frame += 1;
}
}
void PreviousEventButtonGUI()
{
if (GUILayout.Button(DirectorStyles.previousFrameContent, EditorStyles.toolbarButton))
{
state.referenceSequence.frame -= 1;
}
}
void GotoEndSequenceGUI()
{
if (GUILayout.Button(DirectorStyles.gotoEndContent, EditorStyles.toolbarButton))
{
state.editSequence.time = state.editSequence.asset.duration;
state.EnsurePlayHeadIsVisible();
}
}
void PlayRangeButtonGUI()
{
using (new EditorGUI.DisabledScope(state.ignorePreview || state.IsEditingASubTimeline()))
{
state.playRangeEnabled = GUILayout.Toggle(state.playRangeEnabled, DirectorStyles.Instance.playrangeContent, EditorStyles.toolbarButton);
}
}
void AddButtonGUI()
{
if (currentMode.trackOptionsState.newButton == TimelineModeGUIState.Hidden)
return;
using (new EditorGUI.DisabledScope(currentMode.trackOptionsState.newButton == TimelineModeGUIState.Disabled))
{
if (EditorGUILayout.DropdownButton(DirectorStyles.newContent, FocusType.Passive, EditorStyles.toolbarPopup))
{
// if there is 1 and only 1 track selected, AND it's a group, add to that group
var groupTracks = SelectionManager.SelectedTracks().ToList();
if (groupTracks.Any(x => x.GetType() != typeof(GroupTrack) || x.lockedInHierarchy))
groupTracks = null;
SequencerContextMenu.ShowNewTracksContextMenu(groupTracks, state, EditorGUILayout.s_LastRect);
}
}
}
void ShowMarkersButton()
{
var asset = state.editSequence.asset;
if (asset == null)
return;
var content = state.showMarkerHeader ? DirectorStyles.showMarkersOn : DirectorStyles.showMarkersOff;
SetShowMarkerHeader(GUILayout.Toggle(state.showMarkerHeader, content, DirectorStyles.Instance.showMarkersBtn));
}
internal void SetShowMarkerHeader(bool newValue)
{
TimelineAsset asset = state.editSequence.asset;
if (state.showMarkerHeader == newValue || asset == null)
return;
string undoOperation = L10n.Tr("Toggle Show Markers");
if (newValue)
{
//Create the marker track if it does not exist
TimelineUndo.PushUndo(asset, undoOperation);
asset.CreateMarkerTrack();
}
else
{
SelectionManager.Remove(asset.markerTrack);
}
asset.markerTrack.SetShowTrackMarkers(newValue);
}
static void EditModeToolbarGUI(TimelineMode mode)
{
using (new EditorGUI.DisabledScope(mode.EditModeButtonsState(instance.state) == TimelineModeGUIState.Disabled))
{
var editType = EditMode.editType;
EditorGUI.BeginChangeCheck();
var mixIcon = editType == EditMode.EditType.Mix ? DirectorStyles.mixOn : DirectorStyles.mixOff;
GUILayout.Toggle(editType == EditMode.EditType.Mix, mixIcon, DirectorStyles.Instance.editModeBtn);
if (EditorGUI.EndChangeCheck())
EditMode.editType = EditMode.EditType.Mix;
EditorGUI.BeginChangeCheck();
var rippleIcon = editType == EditMode.EditType.Ripple ? DirectorStyles.rippleOn : DirectorStyles.rippleOff;
GUILayout.Toggle(editType == EditMode.EditType.Ripple, rippleIcon, DirectorStyles.Instance.editModeBtn);
if (EditorGUI.EndChangeCheck())
EditMode.editType = EditMode.EditType.Ripple;
EditorGUI.BeginChangeCheck();
var replaceIcon = editType == EditMode.EditType.Replace ? DirectorStyles.replaceOn : DirectorStyles.replaceOff;
GUILayout.Toggle(editType == EditMode.EditType.Replace, replaceIcon, DirectorStyles.Instance.editModeBtn);
if (EditorGUI.EndChangeCheck())
EditMode.editType = EditMode.EditType.Replace;
}
}
// Draws the box to enter the time field
void TimeCodeGUI()
{
const string timeFieldHint = "TimelineWindow-TimeCodeGUI";
EditorGUI.BeginChangeCheck();
var currentTime = state.editSequence.asset != null ? TimeReferenceUtility.ToTimeString(state.editSequence.time, "0.####") : "0";
var r = EditorGUILayout.GetControlRect(false, EditorGUI.kSingleLineHeight, EditorStyles.toolbarTextField, GUILayout.Width(WindowConstants.timeCodeWidth));
var id = GUIUtility.GetControlID(timeFieldHint.GetHashCode(), FocusType.Keyboard, r);
var newCurrentTime = EditorGUI.DelayedTextFieldInternal(r, id, GUIContent.none, currentTime, null, EditorStyles.toolbarTextField);
if (EditorGUI.EndChangeCheck())
state.editSequence.time = TimeReferenceUtility.FromTimeString(newCurrentTime);
}
void ReferenceTimeGUI()
{
if (!state.IsEditingASubTimeline())
return;
EditorGUI.BeginChangeCheck();
state.timeReferenceMode = (TimeReferenceMode)EditorGUILayout.CycleButton((int)state.timeReferenceMode, k_TimeReferenceGUIContents, DirectorStyles.Instance.timeReferenceButton);
if (EditorGUI.EndChangeCheck())
OnTimeReferenceModeChanged();
}
void OnTimeReferenceModeChanged()
{
m_TimeAreaDirty = true;
InitTimeAreaFrameRate();
SyncTimeAreaShownRange();
foreach (var inspector in InspectorWindow.GetAllInspectorWindows())
{
inspector.Repaint();
}
}
void DrawHeaderEditButtons()
{
if (state.editSequence.asset == null)
return;
using (new GUILayout.HorizontalScope(EditorStyles.toolbar, GUILayout.Width(sequenceHeaderRect.width)))
{
GUILayout.Space(DirectorStyles.kBaseIndent);
AddButtonGUI();
GUILayout.FlexibleSpace();
EditModeToolbarGUI(currentMode);
ShowMarkersButton();
EditorGUILayout.Space();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fdd19c82588da3e498a0c98951efa6c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using UnityEngine;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
readonly Control m_PreTreeViewControl = new Control();
readonly Control m_PostTreeViewControl = new Control();
readonly RectangleSelect m_RectangleSelect = new RectangleSelect();
readonly RectangleZoom m_RectangleZoom = new RectangleZoom();
void InitializeManipulators()
{
// Order is important!
// Manipulators that needs to be processed BEFORE the treeView (mainly anything clip related)
m_PreTreeViewControl.AddManipulator(new HeaderSplitterManipulator());
m_PreTreeViewControl.AddManipulator(new TimelinePanManipulator());
m_PreTreeViewControl.AddManipulator(new TrackResize());
m_PreTreeViewControl.AddManipulator(new InlineCurveResize());
m_PreTreeViewControl.AddManipulator(new TrackZoom());
m_PreTreeViewControl.AddManipulator(new Jog());
m_PreTreeViewControl.AddManipulator(TimelineZoomManipulator.Instance);
m_PreTreeViewControl.AddManipulator(new ContextMenuManipulator());
m_PreTreeViewControl.AddManipulator(new EaseClip());
m_PreTreeViewControl.AddManipulator(new TrimClip());
m_PreTreeViewControl.AddManipulator(new SelectAndMoveItem());
m_PreTreeViewControl.AddManipulator(new TrackDoubleClick());
m_PreTreeViewControl.AddManipulator(new DrillIntoClip());
m_PreTreeViewControl.AddManipulator(new InlineCurvesShortcutManipulator());
// Manipulators that needs to be processed AFTER the treeView or any GUI element able to use event (like inline curves)
m_PostTreeViewControl.AddManipulator(new MarkerHeaderTrackManipulator());
m_PostTreeViewControl.AddManipulator(new TimeAreaContextMenu());
m_PostTreeViewControl.AddManipulator(new TrackShortcutManipulator());
m_PostTreeViewControl.AddManipulator(new TimelineShortcutManipulator());
m_PostTreeViewControl.AddManipulator(new ClearSelection());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c3a595c9a8ed19040bb2612fe168759d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
/// <summary>
/// The public Breadcrumb navigation controller, accessible through TimelineEditorWindow
/// </summary>
public override TimelineNavigator navigator => new TimelineNavigator(this);
/// <summary>
/// Implementation of TimelineNavigator
/// </summary>
/// <remarks>
/// Always use TimelineNavigator, not this class.
///
/// The class acts as a handle on the TimelineWindow, and lets users navigate the breadcrumbs and dive into subtimelines
/// </remarks>
internal class TimelineNavigatorImpl
{
/// <summary>
///
/// </summary>
/// <param name="window"></param>
public TimelineNavigatorImpl(IWindowStateProvider window)
{
if (window == null)
throw new ArgumentNullException(nameof(window),
"TimelineNavigator cannot be used with a null window");
m_Window = window;
}
/// <summary>
/// Creates a SequenceContext from the top of the breadcrumb stack
/// </summary>
/// <returns></returns>
public SequenceContext GetCurrentContext()
{
return GetBreadcrumbs().LastOrDefault();
}
/// <summary>
/// Creates a SequenceContext from the second to last breadcrumb in the list
/// </summary>
/// <returns>Valid context if there is a parent, Invalid context otherwise</returns>
public SequenceContext GetParentContext()
{
//If the edit sequence is the master sequence, there is no parent context
if (windowState.editSequence == windowState.masterSequence)
return SequenceContext.Invalid;
var contexts = GetBreadcrumbs();
var length = contexts.Count();
return contexts.ElementAtOrDefault(length - 2);
}
/// <summary>
/// Creates a SequenceContext from the top of the breadcrumb stack
/// </summary>
/// <returns>Always returns a valid SequenceContext</returns>
public SequenceContext GetRootContext()
{
return GetBreadcrumbs().FirstOrDefault();
}
/// <summary>
/// Creates SequenceContexts for all the child Timelines
/// </summary>
/// <returns>Collection of SequenceContexts. Can be empty if there are no valid child contexts</returns>
public IEnumerable<SequenceContext> GetChildContexts()
{
return windowState.GetSubSequences();
}
/// <summary>
/// Creates SequenceContexts from the breadcrumb stack, from top to bottom
/// </summary>
/// <returns>Collection of SequenceContexts. Should never be empty</returns>
public IEnumerable<SequenceContext> GetBreadcrumbs()
{
return CollectBreadcrumbContexts();
}
/// <summary>
/// Changes the current Timeline shown in the TimelineWindow to a new SequenceContext (if different and valid)
/// </summary>
/// <remarks>
/// Should only ever accept SequenceContexts that are in the breadcrumbs. SetTimeline is the proper
/// method to use to switch root Timelines.
/// </remarks>
/// <param name="context">A valid SequenceContext. <paramref name="context"/> should always be found in the breadcrumbs</param>
/// <exception cref="System.ArgumentException"> The context is not valid</exception>
/// <exception cref="System.InvalidOperationException"> The context is not a valid navigation destination.</exception>
public void NavigateTo(SequenceContext context)
{
if (!context.IsValid())
throw new ArgumentException(
$"Argument {nameof(context)} is not valid. Check validity with SequenceContext.IsValid.");
//If the provided context is the current context
if (windowState.editSequence.hostClip == context.clip &&
windowState.editSequence.director == context.director &&
windowState.editSequence.asset == context.director.playableAsset)
{
return; // Nothing to do
}
if (context.clip == null)
{
if (context.director != windowState.masterSequence.director)
throw new InvalidOperationException($"{nameof(context)} is not a valid destination in this context. " +
$"To change the root context, use TimelineEditorWindow.SetTimeline instead.");
}
var children = GetChildContexts().ToArray();
var breadcrumbs = CollectBreadcrumbContexts().ToArray();
if (!children.Contains(context) && !breadcrumbs.Contains(context))
{
throw new InvalidOperationException(
"The provided SequenceContext is not a valid destination. " +
"Use GetChildContexts or GetBreadcrumbs to acquire valid destination contexts.");
}
if (children.Contains(context))
{
windowState.SetCurrentSequence(context.director.playableAsset as TimelineAsset, context.director, context.clip);
return;
}
var idx = Array.IndexOf(breadcrumbs, context);
if (idx != -1)
{
windowState.PopSequencesUntilCount(idx + 1);
}
}
private IWindowState windowState
{
get
{
if (m_Window == null || m_Window.windowState == null)
throw new InvalidOperationException("The Window associated to this instance has been destroyed");
return m_Window.windowState;
}
}
private IEnumerable<SequenceContext> CollectBreadcrumbContexts()
{
return windowState.allSequences?.Select(s => new SequenceContext(s.director, s.hostClip));
}
private readonly IWindowStateProvider m_Window;
}
}
}

Some files were not shown because too many files have changed in this diff Show More