330 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using UnityEngine;
 | |
| using UnityEngine.Timeline;
 | |
| 
 | |
| #if UNITY_6000_2_OR_NEWER
 | |
| using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController<int>;
 | |
| using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem<int>;
 | |
| #else
 | |
| using UnityEditor.IMGUI.Controls;
 | |
| #endif
 | |
| 
 | |
| namespace UnityEditor.Timeline
 | |
| {
 | |
|     class TimelineGroupGUI : TimelineTrackBaseGUI
 | |
|     {
 | |
|         protected DirectorStyles m_Styles;
 | |
|         protected Rect m_TreeViewRect = new Rect(0, 0, 0, 0);
 | |
|         protected GUIContent m_ProblemIcon = new GUIContent();
 | |
| 
 | |
|         bool m_MustRecomputeUnions = true;
 | |
|         int m_GroupDepth;
 | |
|         readonly bool m_IsReferencedTrack;
 | |
|         readonly List<TimelineClipUnion> m_Unions = new List<TimelineClipUnion>();
 | |
| 
 | |
|         public override Rect boundingRect
 | |
|         {
 | |
|             get { return ToWindowSpace(m_TreeViewRect); }
 | |
|         }
 | |
| 
 | |
|         public Rect ToWindowSpace(Rect localRect)
 | |
|         {
 | |
|             localRect.position += treeViewToWindowTransformation;
 | |
|             return localRect;
 | |
|         }
 | |
| 
 | |
|         public override bool expandable
 | |
|         {
 | |
|             get { return !m_IsRoot; }
 | |
|         }
 | |
| 
 | |
|         // The expanded rectangle (contains children) as calculated by the the tree gui
 | |
|         public Rect expandedRect { get; set; }
 | |
|         // The row rectangle (header only) as calculated by the tree gui
 | |
|         public Rect rowRect { get; set; }
 | |
|         // the drop rectangle as set by the tree gui when targetted by a drag and drop
 | |
|         public Rect dropRect { get; set; }
 | |
| 
 | |
|         public TimelineGroupGUI(TreeViewController treeview, TimelineTreeViewGUI treeviewGUI, int id, int depth, TreeViewItem parent, string displayName, TrackAsset trackAsset, bool isRoot)
 | |
|             : base(id, depth, parent, displayName, trackAsset, treeview, treeviewGUI)
 | |
|         {
 | |
|             m_Styles = DirectorStyles.Instance;
 | |
|             m_IsRoot = isRoot;
 | |
| 
 | |
|             var trackPath = AssetDatabase.GetAssetPath(trackAsset);
 | |
|             var sequencePath = AssetDatabase.GetAssetPath(treeviewGUI.TimelineWindow.state.editSequence.asset);
 | |
|             if (trackPath != sequencePath)
 | |
|                 m_IsReferencedTrack = true;
 | |
| 
 | |
|             m_GroupDepth = CalculateGroupDepth(parent);
 | |
|         }
 | |
| 
 | |
|         public virtual float GetHeight(WindowState state)
 | |
|         {
 | |
|             // group tracks don't scale in height
 | |
|             return TrackEditor.DefaultTrackHeight;
 | |
|         }
 | |
| 
 | |
|         public override void OnGraphRebuilt() { }
 | |
| 
 | |
|         static int CalculateGroupDepth(TreeViewItem parent)
 | |
|         {
 | |
|             int depth = 0;
 | |
| 
 | |
|             bool done = false;
 | |
|             do
 | |
|             {
 | |
|                 var gui = parent as TimelineGroupGUI;
 | |
|                 if (gui == null || gui.track == null)
 | |
|                     done = true;
 | |
|                 else
 | |
|                 {
 | |
|                     if (gui.track is GroupTrack)
 | |
|                         depth++;
 | |
| 
 | |
|                     parent = parent.parent;
 | |
|                 }
 | |
|             }
 | |
|             while (!done);
 | |
| 
 | |
|             return depth;
 | |
|         }
 | |
| 
 | |
|         void DrawTrackButtons(Rect headerRect, WindowState state)
 | |
|         {
 | |
|             const float buttonSize = WindowConstants.trackHeaderButtonSize;
 | |
|             const float padding = WindowConstants.trackHeaderButtonPadding;
 | |
| 
 | |
|             var buttonRect = new Rect(headerRect.xMax - buttonSize - padding, headerRect.y + ((headerRect.height - buttonSize) / 2f), buttonSize, buttonSize);
 | |
| 
 | |
|             if (GUI.Button(buttonRect, EditorGUIUtility.IconContent("CreateAddNew"), m_Styles.trackGroupAddButton))
 | |
|             {
 | |
|                 // the drop down will apply to all selected tracks
 | |
|                 if (!SelectionManager.Contains(track))
 | |
|                 {
 | |
|                     SelectionManager.Clear();
 | |
|                     SelectionManager.Add(track);
 | |
|                 }
 | |
|                 SequencerContextMenu.ShowNewTracksContextMenu(SelectionManager.SelectedTracks().ToArray(), TimelineWindow.state, buttonRect);
 | |
|             }
 | |
|             buttonRect.x -= buttonSize;
 | |
| 
 | |
|             var suitePadding = DrawButtonSuite(2, ref buttonRect);
 | |
| 
 | |
|             DrawMuteButton(buttonRect, state);
 | |
|             buttonRect.x -= buttonSize + padding;
 | |
|             DrawLockButton(buttonRect, state);
 | |
|             buttonRect.x -= suitePadding;
 | |
|         }
 | |
| 
 | |
|         public void SetExpanded(bool expanded)
 | |
|         {
 | |
|             var collapseChanged = expanded != isExpanded;
 | |
|             isExpanded = expanded;
 | |
|             if (collapseChanged)
 | |
|             {
 | |
|                 track.SetCollapsed(!expanded);
 | |
|                 m_MustRecomputeUnions = true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void Draw(Rect headerRect, Rect contentRect, WindowState state)
 | |
|         {
 | |
|             if (track == null || m_IsRoot)
 | |
|                 return;
 | |
| 
 | |
|             if (m_MustRecomputeUnions)
 | |
|                 RecomputeRectUnions();
 | |
| 
 | |
|             if (depth == 1)
 | |
|                 Graphics.DrawBackgroundRect(state, headerRect);
 | |
| 
 | |
|             var background = headerRect;
 | |
|             background.height = expandedRect.height;
 | |
| 
 | |
|             var groupColor = TrackResourceCache.GetTrackColor(track);
 | |
| 
 | |
|             m_TreeViewRect = contentRect;
 | |
| 
 | |
|             var col = groupColor;
 | |
| 
 | |
|             var isSelected = SelectionManager.Contains(track);
 | |
| 
 | |
|             if (isSelected)
 | |
|                 col = DirectorStyles.Instance.customSkin.colorSelection;
 | |
|             else if (isDropTarget)
 | |
|                 col = DirectorStyles.Instance.customSkin.colorDropTarget;
 | |
|             else
 | |
|             {
 | |
|                 if (m_GroupDepth % 2 == 1)
 | |
|                 {
 | |
|                     float h, s, v;
 | |
|                     Color.RGBToHSV(col, out h, out s, out v);
 | |
|                     v += 0.06f;
 | |
|                     col = Color.HSVToRGB(h, s, v);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (background.width > 0)
 | |
|             {
 | |
|                 using (new GUIColorOverride(col))
 | |
|                     GUI.Box(background, GUIContent.none, m_Styles.groupBackground);
 | |
|             }
 | |
| 
 | |
|             var trackRectBackground = headerRect;
 | |
|             trackRectBackground.xMin += background.width;
 | |
|             trackRectBackground.width = contentRect.width;
 | |
|             trackRectBackground.height = background.height;
 | |
| 
 | |
|             if (isSelected)
 | |
|             {
 | |
|                 col = state.IsEditingASubTimeline()
 | |
|                     ? m_Styles.customSkin.colorTrackSubSequenceBackgroundSelected
 | |
|                     : m_Styles.customSkin.colorTrackBackgroundSelected;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 col = m_Styles.customSkin.colorGroupTrackBackground;
 | |
|             }
 | |
| 
 | |
|             EditorGUI.DrawRect(trackRectBackground, col);
 | |
|             if (!isExpanded && children != null && children.Count > 0)
 | |
|             {
 | |
|                 var collapsedTrackRect = contentRect;
 | |
| 
 | |
|                 foreach (var u in m_Unions)
 | |
|                     u.Draw(collapsedTrackRect, state);
 | |
|             }
 | |
| 
 | |
|             using (new GUIGroupScope(headerRect))
 | |
|             {
 | |
|                 var groupRect = new Rect(0, 0, headerRect.width, headerRect.height);
 | |
|                 DrawName(groupRect, isSelected);
 | |
|                 DrawTrackButtons(groupRect, state);
 | |
|             }
 | |
| 
 | |
|             if (IsTrackRecording(state))
 | |
|             {
 | |
|                 using (new GUIColorOverride(DirectorStyles.Instance.customSkin.colorTrackBackgroundRecording))
 | |
|                     GUI.Label(background, GUIContent.none, m_Styles.displayBackground);
 | |
|             }
 | |
| 
 | |
|             // is this a referenced track?
 | |
|             if (m_IsReferencedTrack)
 | |
|             {
 | |
|                 var refRect = contentRect;
 | |
|                 refRect.x = state.timeAreaRect.xMax - 20.0f;
 | |
|                 refRect.y += 5.0f;
 | |
|                 refRect.width = 30.0f;
 | |
|                 GUI.Label(refRect, DirectorStyles.referenceTrackLabel, EditorStyles.label);
 | |
|             }
 | |
| 
 | |
|             var bgRect = contentRect;
 | |
|             if (track as GroupTrack != null || AllChildrenMuted(this))
 | |
|                 bgRect.height = expandedRect.height;
 | |
|             DrawTrackState(contentRect, bgRect, track);
 | |
|         }
 | |
| 
 | |
|         void DrawName(Rect rect, bool isSelected)
 | |
|         {
 | |
|             var labelRect = rect;
 | |
|             labelRect.xMin += 20;
 | |
|             var actorName = track != null ? track.name : "missing";
 | |
|             labelRect.width = m_Styles.groupFont.CalcSize(new GUIContent(actorName)).x;
 | |
|             labelRect.width = Math.Max(labelRect.width, 50.0f);
 | |
| 
 | |
|             // if we aren't bound to anything, we show a text field that allows to rename the actor
 | |
|             // otherwise we show a ObjectField to allow binding to a go
 | |
|             if (track != null && track is GroupTrack)
 | |
|             {
 | |
|                 var textColor = m_Styles.groupFont.normal.textColor;
 | |
| 
 | |
|                 if (isSelected)
 | |
|                     textColor = Color.white;
 | |
| 
 | |
|                 string newName;
 | |
| 
 | |
|                 EditorGUI.BeginChangeCheck();
 | |
|                 using (new StyleNormalColorOverride(m_Styles.groupFont, textColor))
 | |
|                 {
 | |
|                     newName = EditorGUI.DelayedTextField(labelRect, GUIContent.none, track.GetInstanceID(), track.name, m_Styles.groupFont);
 | |
|                 }
 | |
| 
 | |
|                 if (EditorGUI.EndChangeCheck() && !string.IsNullOrEmpty(newName))
 | |
|                 {
 | |
|                     track.SetNameWithUndo(newName);
 | |
|                     displayName = track.name;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected bool IsSubTrack()
 | |
|         {
 | |
|             if (track == null)
 | |
|                 return false;
 | |
| 
 | |
|             var parentTrack = track.parent as TrackAsset;
 | |
|             if (parentTrack == null)
 | |
|                 return false;
 | |
| 
 | |
|             return parentTrack.GetType() != typeof(GroupTrack);
 | |
|         }
 | |
| 
 | |
|         protected TrackAsset ParentTrack()
 | |
|         {
 | |
|             if (IsSubTrack())
 | |
|                 return track.parent as TrackAsset;
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         // is there currently a recording track
 | |
|         bool IsTrackRecording(WindowState state)
 | |
|         {
 | |
|             if (!state.recording)
 | |
|                 return false;
 | |
|             if (track.GetType() != typeof(GroupTrack))
 | |
|                 return false;
 | |
| 
 | |
|             return state.GetArmedTrack(track) != null;
 | |
|         }
 | |
| 
 | |
|         void RecomputeRectUnions()
 | |
|         {
 | |
|             m_MustRecomputeUnions = false;
 | |
|             m_Unions.Clear();
 | |
|             if (children == null)
 | |
|                 return;
 | |
| 
 | |
|             foreach (var c in children.OfType<TimelineTrackGUI>())
 | |
|             {
 | |
|                 c.RebuildGUICacheIfNecessary();
 | |
|                 m_Unions.AddRange(TimelineClipUnion.Build(c.clips));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         static bool AllChildrenMuted(TimelineGroupGUI groupGui)
 | |
|         {
 | |
|             if (!groupGui.track.muted)
 | |
|                 return false;
 | |
|             if (groupGui.children == null)
 | |
|                 return true;
 | |
|             return groupGui.children.OfType<TimelineGroupGUI>().All(AllChildrenMuted);
 | |
|         }
 | |
| 
 | |
|         protected static float DrawButtonSuite(int numberOfButtons, ref Rect buttonRect)
 | |
|         {
 | |
|             var style = DirectorStyles.Instance.trackButtonSuite;
 | |
|             var buttonWidth = WindowConstants.trackHeaderButtonSize * numberOfButtons + WindowConstants.trackHeaderButtonPadding * Math.Max(0, numberOfButtons - 1);
 | |
|             var suiteWidth = buttonWidth + style.padding.right + style.padding.left;
 | |
| 
 | |
|             var rect = new Rect(buttonRect.xMax - style.margin.right - suiteWidth, buttonRect.y + style.margin.top, suiteWidth, buttonRect.height);
 | |
|             if (Event.current.type == EventType.Repaint)
 | |
|                 style.Draw(rect, false, false, false, false);
 | |
|             buttonRect.x -= style.margin.right + style.padding.right;
 | |
|             return style.margin.left + style.padding.left;
 | |
|         }
 | |
|     }
 | |
| }
 |