TimelineGroupGUI.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEditor.IMGUI.Controls;
  5. using UnityEngine;
  6. using UnityEngine.Timeline;
  7. namespace UnityEditor.Timeline
  8. {
  9. class TimelineGroupGUI : TimelineTrackBaseGUI
  10. {
  11. protected DirectorStyles m_Styles;
  12. protected Rect m_TreeViewRect = new Rect(0, 0, 0, 0);
  13. protected GUIContent m_ProblemIcon = new GUIContent();
  14. bool m_MustRecomputeUnions = true;
  15. int m_GroupDepth;
  16. readonly bool m_IsReferencedTrack;
  17. readonly List<TimelineClipUnion> m_Unions = new List<TimelineClipUnion>();
  18. public override Rect boundingRect
  19. {
  20. get { return ToWindowSpace(m_TreeViewRect); }
  21. }
  22. public Rect ToWindowSpace(Rect localRect)
  23. {
  24. localRect.position += treeViewToWindowTransformation;
  25. return localRect;
  26. }
  27. public override bool expandable
  28. {
  29. get { return !m_IsRoot; }
  30. }
  31. // The expanded rectangle (contains children) as calculated by the the tree gui
  32. public Rect expandedRect { get; set; }
  33. // The row rectangle (header only) as calculated by the tree gui
  34. public Rect rowRect { get; set; }
  35. // the drop rectangle as set by the tree gui when targetted by a drag and drop
  36. public Rect dropRect { get; set; }
  37. public TimelineGroupGUI(TreeViewController treeview, TimelineTreeViewGUI treeviewGUI, int id, int depth, TreeViewItem parent, string displayName, TrackAsset trackAsset, bool isRoot)
  38. : base(id, depth, parent, displayName, trackAsset, treeview, treeviewGUI)
  39. {
  40. m_Styles = DirectorStyles.Instance;
  41. m_IsRoot = isRoot;
  42. var trackPath = AssetDatabase.GetAssetPath(trackAsset);
  43. var sequencePath = AssetDatabase.GetAssetPath(treeviewGUI.TimelineWindow.state.editSequence.asset);
  44. if (trackPath != sequencePath)
  45. m_IsReferencedTrack = true;
  46. m_GroupDepth = CalculateGroupDepth(parent);
  47. }
  48. public virtual float GetHeight(WindowState state)
  49. {
  50. // group tracks don't scale in height
  51. return TrackEditor.DefaultTrackHeight;
  52. }
  53. public override void OnGraphRebuilt() {}
  54. static int CalculateGroupDepth(TreeViewItem parent)
  55. {
  56. int depth = 0;
  57. bool done = false;
  58. do
  59. {
  60. var gui = parent as TimelineGroupGUI;
  61. if (gui == null || gui.track == null)
  62. done = true;
  63. else
  64. {
  65. if (gui.track is GroupTrack)
  66. depth++;
  67. parent = parent.parent;
  68. }
  69. }
  70. while (!done);
  71. return depth;
  72. }
  73. internal static float Spaced(float width)
  74. {
  75. return width > 0 ? width + WindowConstants.trackHeaderButtonSpacing : 0;
  76. }
  77. void DrawTrackButtons(Rect headerRect, WindowState state)
  78. {
  79. const float buttonSize = WindowConstants.trackHeaderButtonSize;
  80. const float padding = WindowConstants.trackHeaderButtonPadding;
  81. var buttonRect = new Rect(headerRect.xMax - buttonSize - padding, headerRect.y + ((headerRect.height - buttonSize) / 2f), buttonSize, buttonSize);
  82. if (GUI.Button(buttonRect, EditorGUIUtility.IconContent("CreateAddNew"), m_Styles.trackGroupAddButton))
  83. {
  84. // the drop down will apply to all selected tracks
  85. if (!SelectionManager.Contains(track))
  86. {
  87. SelectionManager.Clear();
  88. SelectionManager.Add(track);
  89. }
  90. SequencerContextMenu.ShowNewTracksContextMenu(SelectionManager.SelectedTracks().ToArray(), TimelineWindow.state, buttonRect);
  91. }
  92. buttonRect.x -= buttonSize;
  93. buttonRect.x -= Spaced(DrawMuteButton(buttonRect, state));
  94. buttonRect.x -= Spaced(DrawLockButton(buttonRect, state));
  95. }
  96. public void SetExpanded(bool expanded)
  97. {
  98. var collapseChanged = expanded != isExpanded;
  99. isExpanded = expanded;
  100. if (collapseChanged)
  101. {
  102. track.SetCollapsed(!expanded);
  103. m_MustRecomputeUnions = true;
  104. }
  105. }
  106. public override void Draw(Rect headerRect, Rect contentRect, WindowState state)
  107. {
  108. if (track == null || m_IsRoot)
  109. return;
  110. if (m_MustRecomputeUnions)
  111. RecomputeRectUnions();
  112. if (depth == 1)
  113. Graphics.DrawBackgroundRect(state, headerRect);
  114. var background = headerRect;
  115. background.height = expandedRect.height;
  116. var groupColor = TrackResourceCache.GetTrackColor(track);
  117. m_TreeViewRect = contentRect;
  118. var col = groupColor;
  119. var isSelected = SelectionManager.Contains(track);
  120. if (isSelected)
  121. col = DirectorStyles.Instance.customSkin.colorSelection;
  122. else if (isDropTarget)
  123. col = DirectorStyles.Instance.customSkin.colorDropTarget;
  124. else
  125. {
  126. if (m_GroupDepth % 2 == 1)
  127. {
  128. float h, s, v;
  129. Color.RGBToHSV(col, out h, out s, out v);
  130. v += 0.06f;
  131. col = Color.HSVToRGB(h, s, v);
  132. }
  133. }
  134. if (background.width > 0)
  135. {
  136. using (new GUIColorOverride(col))
  137. GUI.Box(background, GUIContent.none, m_Styles.groupBackground);
  138. }
  139. var trackRectBackground = headerRect;
  140. trackRectBackground.xMin += background.width;
  141. trackRectBackground.width = contentRect.width;
  142. trackRectBackground.height = background.height;
  143. if (isSelected)
  144. {
  145. col = state.IsEditingASubTimeline()
  146. ? m_Styles.customSkin.colorTrackSubSequenceBackgroundSelected
  147. : m_Styles.customSkin.colorTrackBackgroundSelected;
  148. }
  149. else
  150. {
  151. col = m_Styles.customSkin.colorGroupTrackBackground;
  152. }
  153. EditorGUI.DrawRect(trackRectBackground, col);
  154. if (!isExpanded && children != null && children.Count > 0)
  155. {
  156. var collapsedTrackRect = contentRect;
  157. foreach (var u in m_Unions)
  158. u.Draw(collapsedTrackRect, state);
  159. }
  160. using (new GUIGroupScope(headerRect))
  161. {
  162. var groupRect = new Rect(0, 0, headerRect.width, headerRect.height);
  163. DrawName(groupRect, isSelected);
  164. DrawTrackButtons(groupRect, state);
  165. }
  166. if (IsTrackRecording(state))
  167. {
  168. using (new GUIColorOverride(DirectorStyles.Instance.customSkin.colorTrackBackgroundRecording))
  169. GUI.Label(background, GUIContent.none, m_Styles.displayBackground);
  170. }
  171. // is this a referenced track?
  172. if (m_IsReferencedTrack)
  173. {
  174. var refRect = contentRect;
  175. refRect.x = state.timeAreaRect.xMax - 20.0f;
  176. refRect.y += 5.0f;
  177. refRect.width = 30.0f;
  178. GUI.Label(refRect, DirectorStyles.referenceTrackLabel, EditorStyles.label);
  179. }
  180. var bgRect = contentRect;
  181. if (track as GroupTrack != null || AllChildrenMuted(this))
  182. bgRect.height = expandedRect.height;
  183. DrawTrackState(contentRect, bgRect, track);
  184. }
  185. void DrawName(Rect rect, bool isSelected)
  186. {
  187. var labelRect = rect;
  188. labelRect.xMin += 20;
  189. var actorName = track != null ? track.name : "missing";
  190. labelRect.width = m_Styles.groupFont.CalcSize(new GUIContent(actorName)).x;
  191. labelRect.width = Math.Max(labelRect.width, 50.0f);
  192. // if we aren't bound to anything, we show a text field that allows to rename the actor
  193. // otherwise we show a ObjectField to allow binding to a go
  194. if (track != null && track is GroupTrack)
  195. {
  196. var textColor = m_Styles.groupFont.normal.textColor;
  197. if (isSelected)
  198. textColor = Color.white;
  199. string newName;
  200. EditorGUI.BeginChangeCheck();
  201. using (new StyleNormalColorOverride(m_Styles.groupFont, textColor))
  202. {
  203. newName = EditorGUI.DelayedTextField(labelRect, GUIContent.none, track.GetInstanceID(), track.name, m_Styles.groupFont);
  204. }
  205. if (EditorGUI.EndChangeCheck() && !string.IsNullOrEmpty(newName))
  206. {
  207. track.name = newName;
  208. displayName = track.name;
  209. }
  210. }
  211. }
  212. protected bool IsSubTrack()
  213. {
  214. if (track == null)
  215. return false;
  216. var parentTrack = track.parent as TrackAsset;
  217. if (parentTrack == null)
  218. return false;
  219. return parentTrack.GetType() != typeof(GroupTrack);
  220. }
  221. protected TrackAsset ParentTrack()
  222. {
  223. if (IsSubTrack())
  224. return track.parent as TrackAsset;
  225. return null;
  226. }
  227. // is there currently a recording track
  228. bool IsTrackRecording(WindowState state)
  229. {
  230. if (!state.recording)
  231. return false;
  232. if (track.GetType() != typeof(GroupTrack))
  233. return false;
  234. return state.GetArmedTrack(track) != null;
  235. }
  236. void RecomputeRectUnions()
  237. {
  238. m_MustRecomputeUnions = false;
  239. m_Unions.Clear();
  240. if (children == null)
  241. return;
  242. foreach (var c in children.OfType<TimelineTrackGUI>())
  243. {
  244. c.RebuildGUICacheIfNecessary();
  245. m_Unions.AddRange(TimelineClipUnion.Build(c.clips));
  246. }
  247. }
  248. static bool AllChildrenMuted(TimelineGroupGUI groupGui)
  249. {
  250. if (!groupGui.track.muted)
  251. return false;
  252. if (groupGui.children == null)
  253. return true;
  254. return groupGui.children.OfType<TimelineGroupGUI>().All(AllChildrenMuted);
  255. }
  256. }
  257. }