Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 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,36 @@
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
/// <summary>
/// Base class of the TimelineWindow.
/// </summary>
public abstract class TimelineEditorWindow : EditorWindow
{
/// <summary>
/// Allows retrieving and and setting the Timeline Window lock state. When the lock is off, the window focus follows the Unity selection.
/// </summary>
/// <remarks>When lock transitions from true to false, the focused timeline will be synchronized with the Unity selection.</remarks>>
public abstract bool locked { get; set; }
/// <summary>
/// Allows setting which TimelineAsset is shown in the TimelineWindow.
/// </summary>
/// <param name="sequence">The asset to show.</param>
/// <remarks>Calling this method will put the window in asset edit mode and certain features might be missing (eg: timeline cannot be evaluated, bindings will not be available, etc).
/// Ignores window lock mode. Calling with null, will clear the displayed timeline.</remarks>
public abstract void SetTimeline(TimelineAsset sequence);
/// <summary>
/// Allows setting which TimelineAsset is shown in the TimelineWindow and which PlayableDirector is used to evaluate it.
/// </summary>
/// <param name="director">The PlayableDirector who's timeline should be shown.</param>
/// <remarks>Ignores window lock mode. Calling with null, will clear the displayed timeline.</remarks>
public abstract void SetTimeline(PlayableDirector director);
/// <summary>
/// Allows clearing the TimelineAsset that is shown in the TimelineWindow.
/// </summary>
/// <remarks>Ignores window lock mode.</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,519 @@
using System;
using System.Collections.Generic;
using UnityEditor.Callbacks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;
using UnityEngine.SceneManagement;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
[EditorWindowTitle(title = "Timeline", useTypeNameAsIconName = true)]
partial class TimelineWindow : TimelineEditorWindow, IHasCustomMenu
{
[Serializable]
public class TimelineWindowPreferences
{
public bool playRangeLoopMode = true;
public EditMode.EditType editType = EditMode.EditType.Mix;
public TimeReferenceMode timeReferenceMode = TimeReferenceMode.Local;
}
[SerializeField] TimelineWindowPreferences m_Preferences = new TimelineWindowPreferences();
public TimelineWindowPreferences preferences { get { return m_Preferences; } }
[SerializeField]
EditorGUIUtility.EditorLockTracker m_LockTracker = new EditorGUIUtility.EditorLockTracker();
readonly PreviewResizer m_PreviewResizer = new PreviewResizer();
bool m_LastFrameHadSequence;
bool m_ForceRefreshLastSelection;
int m_CurrentSceneHashCode = -1;
[NonSerialized]
bool m_HasBeenInitialized;
[SerializeField]
SequenceHierarchy m_SequenceHierarchy;
static SequenceHierarchy s_LastHierarchy;
public static TimelineWindow instance { get; private set; }
public Rect clientArea { get; set; }
public bool isDragging { get; set; }
public static DirectorStyles styles { get { return DirectorStyles.Instance; } }
public List<TimelineTrackBaseGUI> allTracks
{
get
{
return treeView != null ? treeView.allTrackGuis : new List<TimelineTrackBaseGUI>();
}
}
public WindowState state { get; private set; }
public override bool locked
{
get
{
// we can never be in a locked state if there is no timeline asset
if (state.editSequence.asset == null)
return false;
return m_LockTracker.isLocked;
}
set { m_LockTracker.isLocked = value; }
}
public bool hierarchyChangedThisFrame { get; private set; }
public TimelineWindow()
{
InitializeManipulators();
m_LockTracker.lockStateChanged.AddPersistentListener(OnLockStateChanged, UnityEventCallState.EditorAndRuntime);
}
void OnLockStateChanged(bool locked)
{
// Make sure that upon unlocking, any selection change is updated
// Case 1123119 -- only force rebuild if not recording
if (!locked)
RefreshSelection(state != null && !state.recording);
}
void OnEnable()
{
if (m_SequencePath == null)
m_SequencePath = new SequencePath();
if (m_SequenceHierarchy == null)
{
// The sequence hierarchy will become null if maximize on play is used for in/out of playmode
// a static var will hang on to the reference
if (s_LastHierarchy != null)
m_SequenceHierarchy = s_LastHierarchy;
else
m_SequenceHierarchy = SequenceHierarchy.CreateInstance();
state = null;
}
s_LastHierarchy = m_SequenceHierarchy;
titleContent = GetLocalizedTitleContent();
m_PreviewResizer.Init("TimelineWindow");
// Unmaximize fix : when unmaximizing, a new window is enabled and disabled. Prevent it from overriding the instance pointer.
if (instance == null)
instance = this;
AnimationClipCurveCache.Instance.OnEnable();
TrackAsset.OnClipPlayableCreate += m_PlayableLookup.UpdatePlayableLookup;
TrackAsset.OnTrackAnimationPlayableCreate += m_PlayableLookup.UpdatePlayableLookup;
if (state == null)
{
state = new WindowState(this, s_LastHierarchy);
Initialize();
RefreshSelection(true);
m_ForceRefreshLastSelection = true;
}
}
void OnDisable()
{
if (instance == this)
instance = null;
if (state != null)
state.Reset();
if (instance == null)
SelectionManager.RemoveTimelineSelection();
AnimationClipCurveCache.Instance.OnDisable();
TrackAsset.OnClipPlayableCreate -= m_PlayableLookup.UpdatePlayableLookup;
TrackAsset.OnTrackAnimationPlayableCreate -= m_PlayableLookup.UpdatePlayableLookup;
TimelineWindowViewPrefs.SaveAll();
TimelineWindowViewPrefs.UnloadAllViewModels();
}
void OnDestroy()
{
if (state != null)
{
state.OnDestroy();
}
m_HasBeenInitialized = false;
RemoveEditorCallbacks();
AnimationClipCurveCache.Instance.Clear();
TimelineAnimationUtilities.UnlinkAnimationWindow();
}
void OnLostFocus()
{
isDragging = false;
if (state != null)
state.captured.Clear();
Repaint();
}
void OnHierarchyChange()
{
hierarchyChangedThisFrame = true;
Repaint();
}
void OnStateChange()
{
state.UpdateRecordingState();
if (treeView != null && state.editSequence.asset != null)
treeView.Reload();
if (m_MarkerHeaderGUI != null)
m_MarkerHeaderGUI.Rebuild();
}
void OnGUI()
{
InitializeGUIIfRequired();
UpdateGUIConstants();
UpdateViewStateHash();
EditMode.HandleModeClutch(); // TODO We Want that here?
DetectStylesChange();
DetectActiveSceneChanges();
DetectStateChanges();
state.ProcessStartFramePendingUpdates();
var clipRect = new Rect(0.0f, 0.0f, position.width, position.height);
using (new GUIViewportScope(clipRect))
state.InvokeWindowOnGuiStarted(Event.current);
if (Event.current.type == EventType.MouseDrag && state != null && state.mouseDragLag > 0.0f)
{
state.mouseDragLag -= Time.deltaTime;
return;
}
if (PerformUndo())
return;
if (state != null && state.ignorePreview && state.playing)
{
if (state.recording)
state.recording = false;
Repaint();
}
clientArea = position;
PlaybackScroller.AutoScroll(state);
DoLayout();
// overlays
if (state.captured.Count > 0)
{
using (new GUIViewportScope(clipRect))
{
foreach (var o in state.captured)
{
o.Overlay(Event.current, state);
}
Repaint();
}
}
if (state.showQuadTree)
{
var fillColor = new Color(1.0f, 1.0f, 1.0f, 0.1f);
state.spacePartitioner.DebugDraw(fillColor, Color.yellow);
state.headerSpacePartitioner.DebugDraw(fillColor, Color.green);
}
// attempt another rebuild -- this will avoid 1 frame flashes
if (Event.current.type == EventType.Repaint)
{
RebuildGraphIfNecessary();
state.ProcessEndFramePendingUpdates();
}
using (new GUIViewportScope(clipRect))
{
if (Event.current.type == EventType.Repaint)
EditMode.inputHandler.OnGUI(state, Event.current);
}
if (Event.current.type == EventType.Repaint)
hierarchyChangedThisFrame = false;
}
static void DetectStylesChange()
{
DirectorStyles.ReloadStylesIfNeeded();
}
void DetectActiveSceneChanges()
{
if (m_CurrentSceneHashCode == -1)
{
m_CurrentSceneHashCode = SceneManager.GetActiveScene().GetHashCode();
}
if (m_CurrentSceneHashCode != SceneManager.GetActiveScene().GetHashCode())
{
bool isSceneStillLoaded = false;
for (int a = 0; a < SceneManager.sceneCount; a++)
{
var scene = SceneManager.GetSceneAt(a);
if (scene.GetHashCode() == m_CurrentSceneHashCode && scene.isLoaded)
{
isSceneStillLoaded = true;
break;
}
}
if (!isSceneStillLoaded)
{
if (!locked)
ClearTimeline();
m_CurrentSceneHashCode = SceneManager.GetActiveScene().GetHashCode();
}
}
}
void DetectStateChanges()
{
if (state != null)
{
state.editSequence.ResetIsReadOnly(); //Force reset readonly for asset flag for each frame.
// detect if the sequence was removed under our feet
if (m_LastFrameHadSequence && state.editSequence.asset == null)
{
ClearTimeline();
}
m_LastFrameHadSequence = state.editSequence.asset != null;
// the currentDirector can get set to null by a deletion or scene unloading so polling is required
if (state.editSequence.director == null)
{
state.recording = false;
state.previewMode = false;
if (locked)
{
//revert lock if the original context was not asset mode
if(!state.masterSequence.isAssetOnly)
locked = false;
}
if (!locked && m_LastFrameHadSequence)
{
// the user may be adding a new PlayableDirector to a selected GameObject, make sure the timeline editor is shows the proper director if none is already showing
var selectedGameObject = Selection.activeObject != null ? Selection.activeObject as GameObject : null;
var selectedDirector = selectedGameObject != null ? selectedGameObject.GetComponent<PlayableDirector>() : null;
if (selectedDirector != null)
{
SetTimeline(selectedDirector);
}
else
{
state.masterSequence.isAssetOnly = true;
}
}
}
else
{
// the user may have changed the timeline associated with the current director
if (state.editSequence.asset != state.editSequence.director.playableAsset)
{
if (!locked)
{
SetTimeline(state.editSequence.director);
}
else
{
// Keep locked on the current timeline but set the current director to null since it's not the timeline owner anymore
SetTimeline(state.editSequence.asset);
}
}
}
}
}
void Initialize()
{
if (!m_HasBeenInitialized)
{
InitializeStateChange();
InitializeEditorCallbacks();
m_HasBeenInitialized = true;
}
}
void RefreshLastSelectionIfRequired()
{
// case 1088918 - workaround for the instanceID to object cache being update during Awake.
// This corrects any playableDirector ptrs with the correct cached version
// This can happen when going from edit to playmode
if (m_ForceRefreshLastSelection)
{
m_ForceRefreshLastSelection = false;
RestoreLastSelection(true);
}
}
void InitializeGUIIfRequired()
{
RefreshLastSelectionIfRequired();
InitializeTimeArea();
if (treeView == null && state.editSequence.asset != null)
{
treeView = new TimelineTreeViewGUI(this, state.editSequence.asset, position);
}
}
void UpdateGUIConstants()
{
m_HorizontalScrollBarSize =
GUI.skin.horizontalScrollbar.fixedHeight + GUI.skin.horizontalScrollbar.margin.top;
m_VerticalScrollBarSize = (treeView != null && treeView.showingVerticalScrollBar)
? GUI.skin.verticalScrollbar.fixedWidth + GUI.skin.verticalScrollbar.margin.left
: 0;
}
void UpdateViewStateHash()
{
if (Event.current.type == EventType.Layout)
state.UpdateViewStateHash();
}
static bool PerformUndo()
{
if (!Event.current.isKey)
return false;
if (Event.current.keyCode != KeyCode.Z)
return false;
if (!EditorGUI.actionKey)
return false;
return true;
}
public void RebuildGraphIfNecessary(bool evaluate = true)
{
if (state == null || state.editSequence.director == null || state.editSequence.asset == null)
return;
if (state.rebuildGraph)
{
// rebuilding the graph resets the time
double time = state.editSequence.time;
var wasPlaying = false;
// disable preview mode,
if (!state.ignorePreview)
{
wasPlaying = state.playing;
state.previewMode = false;
state.GatherProperties(state.masterSequence.director);
}
state.RebuildPlayableGraph();
state.editSequence.time = time;
if (wasPlaying)
state.Play();
if (evaluate)
{
// put the scene back in the correct state
state.EvaluateImmediate();
// this is necessary to see accurate results when inspector refreshes
// case 1154802 - this will property re-force time on the director, so
// the play head won't snap back to the timeline duration on rebuilds
if (!state.playing)
state.Evaluate();
}
Repaint();
}
state.rebuildGraph = false;
}
// for tests
public new void RepaintImmediately()
{
base.RepaintImmediately();
}
internal static bool IsEditingTimelineAsset(TimelineAsset timelineAsset)
{
return instance != null && instance.state != null && instance.state.editSequence.asset == timelineAsset;
}
internal static void RepaintIfEditingTimelineAsset(TimelineAsset timelineAsset)
{
if (IsEditingTimelineAsset(timelineAsset))
instance.Repaint();
}
internal class DoCreateTimeline : ProjectWindowCallback.EndNameEditAction
{
public override void Action(int instanceId, string pathName, string resourceFile)
{
var timeline = TimelineUtility.CreateAndSaveTimelineAsset(pathName);
ProjectWindowUtil.ShowCreatedAsset(timeline);
}
}
[MenuItem("Assets/Create/Timeline", false, 450)]
public static void CreateNewTimeline()
{
var icon = EditorGUIUtility.IconContent("TimelineAsset Icon").image as Texture2D;
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<DoCreateTimeline>(), "New Timeline.playable", icon, null);
}
[MenuItem("Window/Sequencing/Timeline", false, 1)]
public static void ShowWindow()
{
GetWindow<TimelineWindow>(typeof(SceneView));
instance.Focus();
}
[OnOpenAsset(1)]
public static bool OnDoubleClick(int instanceID, int line)
{
var assetDoubleClicked = EditorUtility.InstanceIDToObject(instanceID) as TimelineAsset;
if (assetDoubleClicked == null)
return false;
ShowWindow();
instance.SetTimeline(assetDoubleClicked);
return true;
}
public virtual void AddItemsToMenu(GenericMenu menu)
{
bool disabled = state == null || state.editSequence.asset == null;
m_LockTracker.AddItemsToMenu(menu, disabled);
}
protected virtual void ShowButton(Rect r)
{
bool disabled = state == null || state.editSequence.asset == null;
m_LockTracker.ShowButton(r, DirectorStyles.Instance.timelineLockButton, disabled);
}
}
}

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,314 @@
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;
}
[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), 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, AnimationWindowState.SnapMode.SnapToClipFrame));
}
public override void GoToNextKeyframe()
{
var newTime = AnimationWindowUtility.GetNextKeyframeTime(GetCurves(), time.time, m_AnimWindowState.clipFrameRate);
GoToTime(m_AnimWindowState.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToClipFrame));
}
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,85 @@
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();
}
}
}
}

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,325 @@
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;
}
// 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;
}
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 || state.rebuildGraph)
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.MarkDirty();
}
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();
}
}
}
}
}

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,472 @@
using System;
using System.Collections.Generic;
#if UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement;
#else
using UnityEditor.Experimental.SceneManagement;
#endif
using UnityEngine;
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");
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 standardFrameRate = false;
for (int i = 0; i < TimelineProjectSettings.framerateValues.Length; i++)
{
standardFrameRate |= AddStandardFrameRateMenu(menu, "Frame Rate/" + TimelineProjectSettings.framerateLabels[i], TimelineProjectSettings.framerateValues[i]);
}
if (standardFrameRate)
menu.AddDisabledItem(L10n.TextContent("Frame Rate/Custom"));
else
menu.AddItem(L10n.TextContent("Frame Rate/Custom (" + state.editSequence.frameRate + ")"), true, () => {});
menu.AddSeparator("");
if (state.playRangeEnabled)
{
menu.AddItem(L10n.TextContent("Play Range Mode/Loop"), state.playRangeLoopMode, () => state.playRangeLoopMode = true);
menu.AddItem(L10n.TextContent("Play Range Mode/Once"), !state.playRangeLoopMode, () => state.playRangeLoopMode = false);
}
else
{
menu.AddDisabledItem(L10n.TextContent("Play Range Mode"));
}
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);
}
}
}
bool AddStandardFrameRateMenu(GenericMenu menu, string name, float value)
{
bool on = state.editSequence.frameRate.Equals(value);
if (state.editSequence.isReadOnly)
{
menu.AddDisabledItem(EditorGUIUtility.TextContent(name), on);
}
else
{
menu.AddItem(EditorGUIUtility.TextContent(name), on, r =>
{
state.editSequence.frameRate = value;
}, value);
}
return on;
}
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, "f4") : "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,131 @@
using System.Linq;
using UnityEngine;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
TimeAreaItem m_PlayRangeEnd;
TimeAreaItem m_PlayRangeStart;
void PlayRangeGUI(TimelineItemArea area)
{
if (!currentMode.ShouldShowPlayRange(state) || treeView == null)
return;
if (state.masterSequence.asset != null && !state.masterSequence.asset.GetRootTracks().Any())
return;
// left Time Cursor
if (m_PlayRangeStart == null || m_PlayRangeStart.style != styles.playTimeRangeStart)
{
m_PlayRangeStart = new TimeAreaItem(styles.playTimeRangeStart, OnTrackHeadMinSelectDrag);
Vector2 offset = new Vector2(-2.0f, 0);
m_PlayRangeStart.boundOffset = offset;
}
// right Time Cursor
if (m_PlayRangeEnd == null || m_PlayRangeEnd.style != styles.playTimeRangeEnd)
{
m_PlayRangeEnd = new TimeAreaItem(styles.playTimeRangeEnd, OnTrackHeadMaxSelectDrag);
Vector2 offset = new Vector2(2.0f, 0);
m_PlayRangeEnd.boundOffset = offset;
}
if (area == TimelineItemArea.Header)
DrawPlayRange(true, false);
else if (area == TimelineItemArea.Lines)
DrawPlayRange(false, true);
}
void DrawPlayRange(bool drawHeads, bool drawLines)
{
Rect timeCursorRect = state.timeAreaRect;
timeCursorRect.height = clientArea.height;
m_PlayRangeEnd.HandleManipulatorsEvents(state);
m_PlayRangeStart.HandleManipulatorsEvents(state);
// The first time a user enable the play range, we put the play range 75% around the current time...
if (state.playRange == TimelineAssetViewModel.NoPlayRangeSet)
{
float minimumPlayRangeTime = 0.01f;
float t0 = Mathf.Max(0.0f, state.PixelToTime(state.timeAreaRect.xMin));
float t1 = Mathf.Min((float)state.masterSequence.duration, state.PixelToTime(state.timeAreaRect.xMax));
if (Mathf.Abs(t1 - t0) <= minimumPlayRangeTime)
{
state.playRange = new Vector2(t0, t1);
return;
}
float deltaT = (t1 - t0) * 0.25f / 2.0f;
t0 += deltaT;
t1 -= deltaT;
if (t1 < t0)
{
float temp = t0;
t0 = t1;
t1 = temp;
}
if (Mathf.Abs(t1 - t0) < minimumPlayRangeTime)
{
if (t0 - minimumPlayRangeTime > 0.0f)
t0 -= minimumPlayRangeTime;
else if (t1 + minimumPlayRangeTime < state.masterSequence.duration)
t1 += minimumPlayRangeTime;
}
state.playRange = new Vector2(t0, t1);
}
// Draw the head or the lines according to the parameters..
m_PlayRangeStart.drawHead = drawHeads;
m_PlayRangeStart.drawLine = drawLines;
m_PlayRangeEnd.drawHead = drawHeads;
m_PlayRangeEnd.drawLine = drawLines;
var playRangeTime = state.playRange;
m_PlayRangeStart.Draw(sequenceContentRect, state, playRangeTime.x);
m_PlayRangeEnd.Draw(sequenceContentRect, state, playRangeTime.y);
// Draw Time Range Box from Start to End...
if (state.playRangeEnabled && m_PlayHead != null)
{
Rect rect =
Rect.MinMaxRect(
Mathf.Clamp(state.TimeToPixel(playRangeTime.x), state.timeAreaRect.xMin, state.timeAreaRect.xMax),
m_PlayHead.bounds.yMax,
Mathf.Clamp(state.TimeToPixel(playRangeTime.y), state.timeAreaRect.xMin, state.timeAreaRect.xMax),
sequenceContentRect.height + state.timeAreaRect.height + timeCursorRect.y
);
EditorGUI.DrawRect(rect, DirectorStyles.Instance.customSkin.colorRange);
rect.height = 3f;
EditorGUI.DrawRect(rect, Color.white);
}
}
void OnTrackHeadMinSelectDrag(double newTime)
{
Vector2 range = state.playRange;
range.x = (float)newTime;
state.playRange = range;
m_PlayRangeStart.showTooltip = true;
}
void OnTrackHeadMaxSelectDrag(double newTime)
{
Vector2 range = state.playRange;
range.y = (float)newTime;
state.playRange = range;
m_PlayRangeEnd.showTooltip = true;
}
}
}

View file

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

View file

@ -0,0 +1,79 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
PlayableLookup m_PlayableLookup = new PlayableLookup();
class PlayableLookup
{
const int k_InitialDictionarySize = 10;
readonly Dictionary<AnimationClip, Playable> m_AnimationClipToPlayable =
new Dictionary<AnimationClip, Playable>(k_InitialDictionarySize);
readonly Dictionary<AnimationClip, TimelineClip> m_AnimationClipToTimelineClip =
new Dictionary<AnimationClip, TimelineClip>(k_InitialDictionarySize);
public void UpdatePlayableLookup(TimelineClip clip, GameObject go, Playable p)
{
if (clip == null || go == null || !p.IsValid())
return;
if (clip.curves != null)
m_AnimationClipToTimelineClip[clip.curves] = clip;
UpdatePlayableLookup(clip.GetParentTrack().timelineAsset, clip, go, p);
}
public void UpdatePlayableLookup(TrackAsset track, GameObject go, Playable p)
{
if (track == null || go == null || !p.IsValid())
return;
UpdatePlayableLookup(track.timelineAsset, track, go, p);
}
void UpdatePlayableLookup(TimelineAsset timelineAsset, ICurvesOwner curvesOwner, GameObject go, Playable p)
{
var director = go.GetComponent<PlayableDirector>();
var editingDirector = instance.state.editSequence.director;
// No Asset mode update
if (curvesOwner.curves != null && director != null && director == editingDirector &&
timelineAsset == instance.state.editSequence.asset)
{
m_AnimationClipToPlayable[curvesOwner.curves] = p;
}
}
public bool GetPlayableFromAnimClip(AnimationClip clip, out Playable p)
{
if (clip == null)
{
p = Playable.Null;
return false;
}
return m_AnimationClipToPlayable.TryGetValue(clip, out p);
}
public TimelineClip GetTimelineClipFromCurves(AnimationClip clip)
{
if (clip == null)
return null;
TimelineClip timelineClip = null;
m_AnimationClipToTimelineClip.TryGetValue(clip, out timelineClip);
return timelineClip;
}
public void ClearPlayableLookup()
{
m_AnimationClipToPlayable.Clear();
}
}
}
}

View file

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

View file

@ -0,0 +1,84 @@
using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
void OnPreviewPlayModeChanged(bool isPlaying)
{
if (state != null && !state.ignorePreview && isPlaying)
{
PreparePreviewPlay();
EditorApplication.update += OnPreviewPlay;
}
else
{
EditorApplication.update -= OnPreviewPlay;
}
}
void PreparePreviewPlay()
{
if (state == null || state.masterSequence.asset == null || state.masterSequence.director == null)
return;
if (state.playRangeEnabled && !state.isJogging)
{
EnsurePlayRangeIsRespected();
}
}
internal void OnPreviewPlay()
{
if (state == null || state.masterSequence.asset == null || state.masterSequence.director == null)
return;
var director = state.masterSequence.director;
if (director.timeUpdateMode == DirectorUpdateMode.Manual)
{
Repaint();
return;
}
if (state.isJogging)
{
ApplyJog();
}
else if (state.playRangeEnabled)
{
EnsurePlayRangeIsRespected();
}
if (director.extrapolationMode == DirectorWrapMode.None && director.playableGraph.IsValid() && !state.playRangeEnabled && director.playableGraph.IsDone())
{
//reset time if we hit the end of the timeline
state.masterSequence.time = 0.0;
state.Pause();
}
Repaint();
AudioMixerWindow.RepaintAudioMixerWindow();
}
void ApplyJog()
{
state.masterSequence.time = Math.Max(0.0, Math.Min(state.masterSequence.duration, state.masterSequence.time + state.playbackSpeed));
}
void EnsurePlayRangeIsRespected()
{
var playRangeTime = state.playRange;
var time = state.masterSequence.time;
if (Math.Abs(time - playRangeTime.y) < TimeUtility.kFrameRateEpsilon || time > playRangeTime.y || time < playRangeTime.x)
{
state.masterSequence.time = playRangeTime.x;
// case 1215926 : Special case to make the director mode to play if the wrap mode is None.
// In that mode, the engine stop the graph before we can ensure play range is respected.
if (!state.playing && state.masterSequence.director.extrapolationMode == DirectorWrapMode.None)
state.Play();
}
}
}
}

View file

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

View file

@ -0,0 +1,84 @@
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
[SerializeField]
SequencePath m_SequencePath;
void OnSelectionChange()
{
//Sanitize the inline curve selection
SelectionManager.GetCurrentInlineEditorCurve()?.ValidateCurvesSelection();
RefreshSelection(false);
}
void RefreshSelection(bool forceRebuild)
{
// if we're in Locked mode, keep current selection - don't use locked property because the
// sequence hierarchy may need to be rebuilt and it assumes no asset == unlocked
if (m_LockTracker.isLocked || (state != null && state.recording))
{
RestoreLastSelection(forceRebuild);
return;
}
// selection is a TimelineAsset
Object selectedObject = Selection.activeObject as TimelineAsset;
if (selectedObject != null)
{
SetCurrentSelection(Selection.activeObject);
return;
}
// selection is a GameObject, or a prefab with a director
var selectedGO = Selection.activeGameObject;
if (selectedGO != null)
{
bool isSceneObject = !PrefabUtility.IsPartOfPrefabAsset(selectedGO);
bool hasDirector = selectedGO.GetComponent<PlayableDirector>() != null;
if (isSceneObject || hasDirector)
{
SetCurrentSelection(selectedGO);
return;
}
}
// otherwise, keep the same selection.
RestoreLastSelection(forceRebuild);
}
void RestoreLastSelection(bool forceRebuild)
{
state.SetCurrentSequencePath(m_SequencePath, forceRebuild);
//case 1201405 and 1278598: unlock the window if there is no valid asset, since the lock button is disabled
if (m_LockTracker.isLocked && state.editSequence.asset == null)
m_LockTracker.isLocked = false;
}
void SetCurrentSelection(Object obj)
{
var selectedGameObject = obj as GameObject;
if (selectedGameObject != null)
{
PlayableDirector director = TimelineUtility.GetDirectorComponentForGameObject(selectedGameObject);
SetTimeline(director);
}
else
{
var selectedSequenceAsset = obj as TimelineAsset;
if (selectedSequenceAsset != null)
{
SetTimeline(selectedSequenceAsset);
}
}
Repaint();
}
}
}

View file

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

View file

@ -0,0 +1,56 @@
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
void InitializeStateChange()
{
state.OnPlayStateChange += OnPreviewPlayModeChanged;
state.OnDirtyStampChange += OnStateChange;
state.OnBeforeSequenceChange += OnBeforeSequenceChange;
state.OnAfterSequenceChange += OnAfterSequenceChange;
state.OnRebuildGraphChange += () =>
{
// called when the graph is rebuild, since the UI tree isn't necessarily rebuilt.
if (!state.rebuildGraph)
{
// send callbacks to the tacks
if (treeView != null)
{
var allTrackGuis = treeView.allTrackGuis;
if (allTrackGuis != null)
{
for (int i = 0; i < allTrackGuis.Count; i++)
allTrackGuis[i].OnGraphRebuilt();
}
}
}
};
state.OnTimeChange += () =>
{
if (EditorApplication.isPlaying == false)
{
state.UpdateRecordingState();
EditorApplication.SetSceneRepaintDirty();
}
if (state.ignorePreview && state.IsPlayableGraphDone())
state.Pause();
// the time is sync'd prior to the callback
state.Evaluate(); // will do the repaint
InspectorWindow.RepaintAllInspectors();
};
state.OnRecordingChange += () =>
{
if (!state.recording)
{
TrackAssetRecordingExtensions.ClearRecordingState();
}
};
}
}
}

View file

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

View file

@ -0,0 +1,107 @@
using System;
using UnityEngine;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
[NonSerialized] TimelineTimeArea m_TimeArea;
public TimeArea timeArea { get { return m_TimeArea; } }
internal static class Styles
{
public static string DurationModeText = L10n.Tr("Duration Mode/{0}");
}
float m_LastFrameRate;
bool m_TimeAreaDirty = true;
void InitializeTimeArea()
{
if (m_TimeArea == null)
{
m_TimeArea = new TimelineTimeArea(state, false)
{
hRangeLocked = false,
vRangeLocked = true,
margin = 10,
scaleWithWindow = true,
hSlider = true,
vSlider = false,
hBaseRangeMin = 0.0f,
hBaseRangeMax = WindowState.kMaxShownTime,
hRangeMin = 0.0f,
hScaleMax = WindowConstants.maxTimeAreaScaling,
rect = state.timeAreaRect
};
m_TimeAreaDirty = true;
InitTimeAreaFrameRate();
SyncTimeAreaShownRange();
}
}
void DrawTimelineRuler()
{
if (!currentMode.ShouldShowTimeArea(state))
return;
Rect rect = state.timeAreaRect;
m_TimeArea.rect = new Rect(rect.x, rect.y, rect.width, clientArea.height - rect.y);
if (m_LastFrameRate != state.referenceSequence.frameRate)
InitTimeAreaFrameRate();
SyncTimeAreaShownRange();
m_TimeArea.BeginViewGUI();
m_TimeArea.TimeRuler(rect, state.referenceSequence.frameRate, true, false, 1.0f, state.timeFormat.ToTimeAreaFormat());
m_TimeArea.EndViewGUI();
}
void InitTimeAreaFrameRate()
{
m_LastFrameRate = state.referenceSequence.frameRate;
m_TimeArea.hTicks.SetTickModulosForFrameRate(m_LastFrameRate);
}
void SyncTimeAreaShownRange()
{
var range = state.timeAreaShownRange;
if (!Mathf.Approximately(range.x, m_TimeArea.shownArea.x) || !Mathf.Approximately(range.y, m_TimeArea.shownArea.xMax))
{
// set view data onto the time area
if (m_TimeAreaDirty)
{
m_TimeArea.SetShownHRange(range.x, range.y);
m_TimeAreaDirty = false;
}
else
{
// set time area data onto the view data
state.TimeAreaChanged();
}
}
m_TimeArea.hBaseRangeMax = (float)state.editSequence.duration;
}
class TimelineTimeArea : TimeArea
{
readonly WindowState m_State;
public TimelineTimeArea(WindowState state, bool minimalGUI) : base(minimalGUI)
{
m_State = state;
}
public override string FormatTickTime(float time, float frameRate, TimeFormat timeFormat)
{
time = m_State.timeReferenceMode == TimeReferenceMode.Global ?
(float)m_State.editSequence.ToGlobalTime(time) : time;
return FormatTime(time, frameRate, timeFormat);
}
}
}
}

View file

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

View file

@ -0,0 +1,81 @@
using System;
using UnityEngine;
using UnityEngine.Timeline;
using UnityEngine.Playables;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
TimeAreaItem m_PlayHead;
void TimeCursorGUI(TimelineItemArea area)
{
DrawTimeOnSlider();
if (!CanDrawTimeCursor(area))
return;
if (m_PlayHead == null || m_PlayHead.style != styles.timeCursor)
{
m_PlayHead = new TimeAreaItem(styles.timeCursor, OnTrackHeadDrag);
m_PlayHead.AddManipulator(new PlayheadContextMenu(m_PlayHead));
}
var headerMode = area == TimelineItemArea.Header;
DrawTimeCursor(headerMode, !headerMode);
}
bool CanDrawTimeCursor(TimelineItemArea area)
{
if (!currentMode.ShouldShowTimeCursor(state))
return false;
if (treeView == null || state.editSequence.asset == null || (state.editSequence.asset != null && state.IsEditingAnEmptyTimeline()))
return false;
if (area == TimelineItemArea.Lines && !state.TimeIsInRange((float)state.editSequence.time))
return false;
return true;
}
void DrawTimeOnSlider()
{
if (currentMode.ShouldShowTimeCursor(state))
{
var colorDimFactor = EditorGUIUtility.isProSkin ? 0.7f : 0.9f;
var c = styles.timeCursor.normal.textColor * colorDimFactor;
float time = Mathf.Max((float)state.editSequence.time, 0);
float duration = (float)state.editSequence.duration;
m_TimeArea.DrawTimeOnSlider(time, c, duration, DirectorStyles.kDurationGuiThickness);
}
}
void DrawTimeCursor(bool drawHead, bool drawline)
{
m_PlayHead.HandleManipulatorsEvents(state);
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
{
if (state.timeAreaRect.Contains(Event.current.mousePosition))
{
state.SetPlaying(false);
m_PlayHead.HandleManipulatorsEvents(state);
state.editSequence.time = Math.Max(0.0, state.GetSnappedTimeAtMousePosition(Event.current.mousePosition));
}
}
m_PlayHead.drawLine = drawline;
m_PlayHead.drawHead = drawHead;
m_PlayHead.Draw(sequenceContentRect, state, state.editSequence.time);
}
void OnTrackHeadDrag(double newTime)
{
state.editSequence.time = Math.Max(0.0, newTime);
m_PlayHead.showTooltip = true;
}
}
}

View file

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

View file

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Playables;
namespace UnityEditor.Timeline
{
partial class TimelineWindow
{
public TimelineTreeViewGUI treeView { get; private set; }
void TracksGUI(Rect clientRect, WindowState state, TimelineModeGUIState trackState)
{
if (Event.current.type == EventType.Repaint && treeView != null)
{
state.headerSpacePartitioner.Clear();
state.spacePartitioner.Clear();
}
if (state.IsEditingASubTimeline() && !state.IsEditingAnEmptyTimeline())
{
var headerRect = clientRect;
headerRect.width = state.sequencerHeaderWidth;
Graphics.DrawBackgroundRect(state, headerRect);
var clipRect = clientRect;
clipRect.xMin = headerRect.xMax;
Graphics.DrawBackgroundRect(state, clipRect, subSequenceMode: true);
}
else
{
Graphics.DrawBackgroundRect(state, clientRect);
}
if (!state.IsEditingAnEmptyTimeline())
m_TimeArea.DrawMajorTicks(sequenceContentRect, state.referenceSequence.frameRate);
GUILayout.BeginVertical();
{
GUILayout.Space(5.0f);
GUILayout.BeginHorizontal();
if (this.state.editSequence.asset == null)
DrawNoSequenceGUI(state);
else
DrawTracksGUI(clientRect, trackState);
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
Graphics.DrawShadow(clientRect);
}
void DrawNoSequenceGUI(WindowState windowState)
{
bool showCreateButton = false;
var currentlySelectedGo = UnityEditor.Selection.activeObject != null ? UnityEditor.Selection.activeObject as GameObject : null;
var textContent = DirectorStyles.noTimelineAssetSelected;
var existingDirector = currentlySelectedGo != null ? currentlySelectedGo.GetComponent<PlayableDirector>() : null;
var existingAsset = existingDirector != null ? existingDirector.playableAsset : null;
if (currentlySelectedGo != null && !TimelineUtility.IsPrefabOrAsset(currentlySelectedGo) && existingAsset == null)
{
showCreateButton = true;
textContent = new GUIContent(String.Format(DirectorStyles.createTimelineOnSelection.text, currentlySelectedGo.name, L10n.Tr("a Director component and a Timeline asset")));
}
GUILayout.FlexibleSpace();
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
GUILayout.Label(textContent);
if (showCreateButton)
{
GUILayout.BeginHorizontal();
var textSize = GUI.skin.label.CalcSize(textContent);
GUILayout.Space((textSize.x / 2.0f) - (WindowConstants.createButtonWidth / 2.0f));
if (GUILayout.Button(L10n.Tr("Create"), GUILayout.Width(WindowConstants.createButtonWidth)))
{
var message = DirectorStyles.createNewTimelineText.text + " '" + currentlySelectedGo.name + "'";
var defaultName = currentlySelectedGo.name.EndsWith(DirectorStyles.newTimelineDefaultNameSuffix, StringComparison.OrdinalIgnoreCase)
? currentlySelectedGo.name
: currentlySelectedGo.name + DirectorStyles.newTimelineDefaultNameSuffix;
// Use the project window path by default only if it's under the asset folder.
// Otherwise the saveFilePanel will reject the save (case 1289923)
var defaultPath = ProjectWindowUtil.GetActiveFolderPath();
if (!defaultPath.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
defaultPath = "Assets";
string newSequencePath = EditorUtility.SaveFilePanelInProject(DirectorStyles.createNewTimelineText.text, defaultName, "playable", message, defaultPath);
if (!string.IsNullOrEmpty(newSequencePath))
{
var newAsset = TimelineUtility.CreateAndSaveTimelineAsset(newSequencePath);
Undo.IncrementCurrentGroup();
if (existingDirector == null)
{
existingDirector = Undo.AddComponent<PlayableDirector>(currentlySelectedGo);
}
existingDirector.playableAsset = newAsset;
SetTimeline(existingDirector);
windowState.previewMode = false;
}
// If we reach this point, the state of the panel has changed; skip the rest of this GUI phase
// Fixes: case 955831 - [OSX] NullReferenceException when creating a timeline on a selected object
GUIUtility.ExitGUI();
}
GUILayout.EndHorizontal();
}
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
GUILayout.FlexibleSpace();
}
internal List<OverlayDrawer> OverlayDrawData = new List<OverlayDrawer>();
void DrawTracksGUI(Rect clientRect, TimelineModeGUIState trackState)
{
GUILayout.BeginVertical(GUILayout.Height(clientRect.height));
if (treeView != null)
{
if (Event.current.type == EventType.Layout)
{
OverlayDrawData.Clear();
}
treeView.OnGUI(clientRect);
if (Event.current.type == EventType.Repaint)
{
foreach (var overlayData in OverlayDrawData)
{
using (new GUIViewportScope(sequenceContentRect))
overlayData.Draw();
}
}
}
GUILayout.EndVertical();
}
}
}

View file

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

View file

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

View file

@ -0,0 +1,119 @@
using System;
using System.IO;
using UnityEditorInternal;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Timeline
{
class ScriptableObjectViewPrefs<TViewModel> : IDisposable where TViewModel : ScriptableObject
{
const string k_DefaultFilePath = "Library/";
const string k_Extension = ".pref";
readonly string m_RelativePath;
readonly string m_AbsolutePath;
readonly string m_FileName;
ScriptableObject m_Asset;
TViewModel m_ViewModel;
bool isSavable
{
get
{
return m_Asset != null &&
m_ViewModel != null &&
!string.IsNullOrEmpty(m_FileName);
}
}
public ScriptableObjectViewPrefs(ScriptableObject asset, string relativeSavePath)
{
m_Asset = asset;
m_RelativePath = string.IsNullOrEmpty(relativeSavePath) ? k_DefaultFilePath : relativeSavePath;
if (!m_RelativePath.EndsWith("/", StringComparison.Ordinal))
m_RelativePath += "/";
m_AbsolutePath = Application.dataPath + "/../" + m_RelativePath;
var assetKey = GetAssetKey(asset);
m_FileName = string.IsNullOrEmpty(assetKey) ? string.Empty : assetKey + k_Extension;
}
public TViewModel viewModel
{
get
{
if (m_ViewModel == null)
{
if (m_Asset == null)
m_ViewModel = CreateViewModel();
else
m_ViewModel = LoadViewModel() ?? CreateViewModel();
}
return m_ViewModel;
}
}
public void Save()
{
if (!isSavable)
return;
// make sure the path exists or file write will fail
if (!Directory.Exists(m_AbsolutePath))
Directory.CreateDirectory(m_AbsolutePath);
const bool saveAsText = true;
InternalEditorUtility.SaveToSerializedFileAndForget(new UnityObject[] { m_ViewModel }, m_RelativePath + m_FileName, saveAsText);
}
public void DeleteFile()
{
if (!isSavable)
return;
var path = m_AbsolutePath + m_FileName;
if (!File.Exists(path))
return;
File.Delete(path);
}
public void Dispose()
{
if (m_ViewModel != null)
UnityObject.DestroyImmediate(m_ViewModel);
m_Asset = null;
}
public static TViewModel CreateViewModel()
{
var model = ScriptableObject.CreateInstance<TViewModel>();
model.hideFlags |= HideFlags.HideAndDontSave;
return model;
}
TViewModel LoadViewModel()
{
if (string.IsNullOrEmpty(m_FileName))
return null;
var objects = InternalEditorUtility.LoadSerializedFileAndForget(m_RelativePath + m_FileName);
if (objects.Length <= 0 || objects[0] == null)
return null;
var model = (TViewModel)objects[0];
model.hideFlags |= HideFlags.HideAndDontSave;
return model;
}
static string GetAssetKey(UnityObject asset)
{
return asset == null ? string.Empty : AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(asset));
}
}
}

View file

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

View file

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.Timeline;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Timeline
{
[Serializable]
class TrackViewModelData : ISerializationCallbackReceiver
{
public static readonly float DefaultinlineAnimationCurveHeight = 100.0f;
public bool collapsed = true;
public bool showMarkers = true;
public bool showInlineCurves = false;
public float inlineAnimationCurveHeight = DefaultinlineAnimationCurveHeight;
public int lastInlineCurveDataID = -1;
public TreeViewState inlineCurvesState = null;
public Rect inlineCurvesShownAreaInsideMargins = new Rect(1, 1, 1, 1);
public int trackHeightExtension;
public Dictionary<int, long> markerTimeStamps = new Dictionary<int, long>();
[SerializeField] List<int> m_MarkerTimeStampsKeys;
[SerializeField] List<long> m_MarkerTimeStampsValues;
public void OnBeforeSerialize()
{
if (markerTimeStamps == null)
return;
m_MarkerTimeStampsKeys = new List<int>(markerTimeStamps.Count);
m_MarkerTimeStampsValues = new List<long>(markerTimeStamps.Count);
foreach (var kvp in markerTimeStamps)
{
m_MarkerTimeStampsKeys.Add(kvp.Key);
m_MarkerTimeStampsValues.Add(kvp.Value);
}
}
public void OnAfterDeserialize()
{
markerTimeStamps = new Dictionary<int, long>();
if (m_MarkerTimeStampsKeys == null || m_MarkerTimeStampsValues == null ||
m_MarkerTimeStampsKeys.Count != m_MarkerTimeStampsValues.Count)
return;
for (int i = 0; i < m_MarkerTimeStampsKeys.Count; ++i)
markerTimeStamps.Add(m_MarkerTimeStampsKeys[i], m_MarkerTimeStampsValues[i]);
}
}
[Serializable]
class TimelineAssetViewModel : ScriptableObject, ISerializationCallbackReceiver
{
public const float DefaultTrackScale = 1.0f;
public const float DefaultVerticalScroll = 0;
public static readonly Vector2 TimeAreaDefaultRange = new Vector2(-WindowConstants.timeAreaShownRangePadding, 5.0f); // in seconds. Hack: using negative value to force the UI to have a left margin at 0.
public static readonly Vector2 NoPlayRangeSet = new Vector2(float.MaxValue, float.MaxValue);
public Vector2 timeAreaShownRange = TimeAreaDefaultRange;
public float trackScale = DefaultTrackScale;
public bool playRangeEnabled;
public Vector2 timeAreaPlayRange = NoPlayRangeSet;
public double windowTime;
public float verticalScroll = DefaultVerticalScroll;
public float sequencerHeaderWidth = WindowConstants.defaultHeaderWidth;
public Dictionary<TrackAsset, TrackViewModelData> tracksViewModelData = new Dictionary<TrackAsset, TrackViewModelData>();
// Used only for serialization of the dictionary
[SerializeField] List<TrackAsset> m_Keys = new List<TrackAsset>();
[SerializeField] List<TrackViewModelData> m_Vals = new List<TrackViewModelData>();
public void OnBeforeSerialize()
{
m_Keys.Clear();
m_Vals.Clear();
foreach (var data in tracksViewModelData)
{
// Assets that don't save, will create nulls when deserializeds
if (data.Key != null && data.Value != null && (data.Key.hideFlags & HideFlags.DontSave) == 0)
{
m_Keys.Add(data.Key);
m_Vals.Add(data.Value);
}
}
}
public void OnAfterDeserialize()
{
}
public void OnEnable()
{
if (m_Keys.Count == m_Vals.Count)
{
tracksViewModelData.Clear();
for (int i = 0; i < m_Keys.Count; i++)
{
if (m_Keys[i] != null) // if the asset is overwritten the tracks can be null
tracksViewModelData[m_Keys[i]] = m_Vals[i];
}
}
m_Keys.Clear();
m_Vals.Clear();
}
}
}

View file

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

View file

@ -0,0 +1,184 @@
using UnityEngine;
using UnityEngine.Timeline;
using UnityObject = UnityEngine.Object;
using ViewModelsMap = System.Collections.Generic.Dictionary<UnityEngine.Timeline.TimelineAsset, UnityEditor.Timeline.ScriptableObjectViewPrefs<UnityEditor.Timeline.TimelineAssetViewModel>>;
using ViewModelsList = System.Collections.Generic.List<UnityEditor.Timeline.ScriptableObjectViewPrefs<UnityEditor.Timeline.TimelineAssetViewModel>>;
namespace UnityEditor.Timeline
{
static class TimelineWindowViewPrefs
{
public const string FilePath = "Library/Timeline";
static readonly ViewModelsMap k_ViewModelsMap = new ViewModelsMap();
static readonly ViewModelsList k_UnassociatedViewModels = new ViewModelsList();
public static int viewModelCount
{
get { return k_ViewModelsMap.Count + k_UnassociatedViewModels.Count; }
}
public static TimelineAssetViewModel GetOrCreateViewModel(TimelineAsset asset)
{
if (asset == null)
return CreateUnassociatedViewModel();
ScriptableObjectViewPrefs<TimelineAssetViewModel> vm;
if (k_ViewModelsMap.TryGetValue(asset, out vm))
return vm.viewModel;
return CreateViewModel(asset).viewModel;
}
public static TimelineAssetViewModel CreateUnassociatedViewModel()
{
var vm = new ScriptableObjectViewPrefs<TimelineAssetViewModel>(null, FilePath);
k_UnassociatedViewModels.Add(vm);
return vm.viewModel;
}
static ScriptableObjectViewPrefs<TimelineAssetViewModel> CreateViewModel(TimelineAsset asset)
{
var vm = new ScriptableObjectViewPrefs<TimelineAssetViewModel>(asset, FilePath);
k_ViewModelsMap.Add(asset, vm);
return vm;
}
public static void SaveViewModel(TimelineAsset asset)
{
if (asset == null)
return;
ScriptableObjectViewPrefs<TimelineAssetViewModel> vm;
if (!k_ViewModelsMap.TryGetValue(asset, out vm))
vm = CreateViewModel(asset);
vm.Save();
}
public static void SaveAll()
{
foreach (var kvp in k_ViewModelsMap)
kvp.Value.Save();
}
public static void UnloadViewModel(TimelineAsset asset)
{
ScriptableObjectViewPrefs<TimelineAssetViewModel> vm;
if (k_ViewModelsMap.TryGetValue(asset, out vm))
{
vm.Dispose();
k_ViewModelsMap.Remove(asset);
}
}
public static void UnloadAllViewModels()
{
foreach (var kvp in k_ViewModelsMap)
kvp.Value.Dispose();
foreach (var vm in k_UnassociatedViewModels)
vm.Dispose();
k_ViewModelsMap.Clear();
k_UnassociatedViewModels.Clear();
}
public static TrackViewModelData GetTrackViewModelData(TrackAsset track)
{
if (track == null)
return new TrackViewModelData();
if (track.timelineAsset == null)
return new TrackViewModelData();
var prefs = GetOrCreateViewModel(track.timelineAsset);
TrackViewModelData trackData;
if (prefs.tracksViewModelData.TryGetValue(track, out trackData))
{
return trackData;
}
trackData = new TrackViewModelData();
prefs.tracksViewModelData[track] = trackData;
return trackData;
}
public static bool IsTrackCollapsed(TrackAsset track)
{
if (track == null)
return true;
return GetTrackViewModelData(track).collapsed;
}
public static void SetTrackCollapsed(TrackAsset track, bool collapsed)
{
if (track == null)
return;
GetTrackViewModelData(track).collapsed = collapsed;
}
public static bool IsShowMarkers(TrackAsset track)
{
if (track == null)
return true;
return GetTrackViewModelData(track).showMarkers;
}
public static void SetTrackShowMarkers(TrackAsset track, bool collapsed)
{
if (track == null)
return;
GetTrackViewModelData(track).showMarkers = collapsed;
}
public static bool GetShowInlineCurves(TrackAsset track)
{
if (track == null)
return false;
return GetTrackViewModelData(track).showInlineCurves;
}
public static void SetShowInlineCurves(TrackAsset track, bool inlineOn)
{
if (track == null)
return;
GetTrackViewModelData(track).showInlineCurves = inlineOn;
}
public static float GetInlineCurveHeight(TrackAsset asset)
{
if (asset == null)
return TrackViewModelData.DefaultinlineAnimationCurveHeight;
return GetTrackViewModelData(asset).inlineAnimationCurveHeight;
}
public static void SetInlineCurveHeight(TrackAsset asset, float height)
{
if (asset != null)
GetTrackViewModelData(asset).inlineAnimationCurveHeight = height;
}
public static int GetTrackHeightExtension(TrackAsset asset)
{
if (asset == null)
return 0;
return GetTrackViewModelData(asset).trackHeightExtension;
}
public static void SetTrackHeightExtension(TrackAsset asset, int height)
{
if (asset != null)
GetTrackViewModelData(asset).trackHeightExtension = height;
}
}
}

View file

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

View file

@ -0,0 +1,47 @@
namespace UnityEditor.Timeline
{
static class WindowConstants
{
public const float timeAreaYPosition = 19.0f;
public const float timeAreaHeight = 22.0f;
public const float timeAreaMinWidth = 50.0f;
public const float timeAreaShownRangePadding = 5.0f;
public const float markerRowHeight = 18.0f;
public const float markerRowYPosition = timeAreaYPosition + timeAreaHeight;
public const float defaultHeaderWidth = 315.0f;
public const float defaultBindingAreaWidth = 40.0f;
public const float minHeaderWidth = 195.0f;
public const float maxHeaderWidth = 650.0f;
public const float headerSplitterWidth = 6.0f;
public const float headerSplitterVisualWidth = 2.0f;
public const float maxTimeAreaScaling = 90000.0f;
public const float timeCodeWidth = 100.0f; // Enough space to display up to 9999 without clipping
public const float sliderWidth = 15;
public const float shadowUnderTimelineHeight = 15.0f;
public const float createButtonWidth = 70.0f;
public const float selectorWidth = 23.0f;
public const float cogButtonWidth = 25.0f;
public const float trackHeaderBindingHeight = 18.0f;
public const float trackHeaderButtonSize = 16.0f;
public const float trackHeaderButtonPadding = 2.0f;
public const float trackBindingMaxSize = 300.0f;
public const float trackBindingPadding = 5.0f;
public const float trackInsertionMarkerHeight = 1f;
public const float trackResizeHandleHeight = 7f;
public const float inlineCurveContentPadding = 2.0f;
public const float playControlsWidth = 300;
public const int autoPanPaddingInPixels = 50;
public const float overlayTextPadding = 40.0f;
}
}

View file

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