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(); 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 types, Action 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(); } bool IsSelected() { return SelectionManager.Contains(asset); } } }