暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

BreadcrumbDrawer.cs 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. using System;
  2. using System.Collections.Generic;
  3. #if UNITY_2021_2_OR_NEWER
  4. using UnityEditor.SceneManagement;
  5. #else
  6. using UnityEditor.Experimental.SceneManagement;
  7. #endif
  8. using UnityEngine;
  9. namespace UnityEditor.Timeline
  10. {
  11. enum TitleMode
  12. {
  13. None,
  14. DisabledComponent,
  15. Prefab,
  16. PrefabOutOfContext,
  17. Asset,
  18. GameObject
  19. }
  20. struct BreadCrumbTitle
  21. {
  22. public string name;
  23. public TitleMode mode;
  24. }
  25. class BreadcrumbDrawer
  26. {
  27. static readonly GUIContent s_TextContent = new GUIContent();
  28. static readonly string k_DisabledComponentText = L10n.Tr("The PlayableDirector is disabled");
  29. static readonly string k_PrefabOutOfContext = L10n.Tr("Prefab Isolation not enabled. Click to Enable.");
  30. static readonly GUIStyle k_BreadCrumbLeft;
  31. static readonly GUIStyle k_BreadCrumbMid;
  32. static readonly GUIStyle k_BreadCrumbLeftBg;
  33. static readonly GUIStyle k_BreadCrumbMidBg;
  34. static readonly GUIStyle k_BreadCrumbMidSelected;
  35. static readonly GUIStyle k_BreadCrumbMidBgSelected;
  36. static readonly Texture k_TimelineIcon;
  37. const string k_Elipsis = "…";
  38. static BreadcrumbDrawer()
  39. {
  40. k_BreadCrumbLeft = "GUIEditor.BreadcrumbLeft";
  41. k_BreadCrumbMid = "GUIEditor.BreadcrumbMid";
  42. k_BreadCrumbLeftBg = "GUIEditor.BreadcrumbLeftBackground";
  43. k_BreadCrumbMidBg = "GUIEditor.BreadcrumbMidBackground";
  44. k_BreadCrumbMidSelected = k_BreadCrumbMid;
  45. k_BreadCrumbMidSelected.normal = k_BreadCrumbMidSelected.onNormal;
  46. k_BreadCrumbMidBgSelected = k_BreadCrumbMidBg;
  47. k_BreadCrumbMidBgSelected.normal = k_BreadCrumbMidBgSelected.onNormal;
  48. k_TimelineIcon = EditorGUIUtility.IconContent("TimelineAsset Icon").image;
  49. }
  50. static string FitTextInArea(float areaWidth, string text, GUIStyle style)
  51. {
  52. var borderWidth = style.border.left + style.border.right;
  53. var textWidth = style.CalcSize(EditorGUIUtility.TextContent(text)).x;
  54. if (borderWidth + textWidth < areaWidth)
  55. return text;
  56. // Need to truncate the text to fit in the areaWidth
  57. var textAreaWidth = areaWidth - borderWidth;
  58. var pixByChar = textWidth / text.Length;
  59. var charNeeded = (int)Mathf.Floor(textAreaWidth / pixByChar);
  60. charNeeded -= k_Elipsis.Length;
  61. if (charNeeded <= 0)
  62. return k_Elipsis;
  63. if (charNeeded <= text.Length)
  64. return k_Elipsis + " " + text.Substring(text.Length - charNeeded);
  65. return k_Elipsis;
  66. }
  67. public static void Draw(float breadcrumbAreaWidth, List<BreadCrumbTitle> labels, Action<int> navigateToBreadcrumbIndex)
  68. {
  69. GUILayout.BeginHorizontal();
  70. {
  71. var labelWidth = (int)(breadcrumbAreaWidth / labels.Count);
  72. for (var i = 0; i < labels.Count; i++)
  73. {
  74. var label = labels[i];
  75. var style = i == 0 ? k_BreadCrumbLeft : k_BreadCrumbMid;
  76. var backgroundStyle = i == 0 ? k_BreadCrumbLeftBg : k_BreadCrumbMidBg;
  77. if (i == labels.Count - 1)
  78. {
  79. if (i > 0) // Only tint last breadcrumb if we are dug-in
  80. DrawBreadcrumbAsSelectedSubSequence(labelWidth, label, k_BreadCrumbMidSelected, k_BreadCrumbMidBgSelected);
  81. else
  82. DrawActiveBreadcrumb(labelWidth, label, style, backgroundStyle);
  83. }
  84. else
  85. {
  86. var previousContentColor = GUI.contentColor;
  87. GUI.contentColor = new Color(previousContentColor.r,
  88. previousContentColor.g,
  89. previousContentColor.b,
  90. previousContentColor.a * 0.6f);
  91. var content = GetTextContent(labelWidth, label, style);
  92. var rect = GetBreadcrumbLayoutRect(content, style);
  93. if (Event.current.type == EventType.Repaint)
  94. backgroundStyle.Draw(rect, GUIContent.none, 0);
  95. if (GUI.Button(rect, content, style))
  96. navigateToBreadcrumbIndex.Invoke(i);
  97. GUI.contentColor = previousContentColor;
  98. }
  99. }
  100. }
  101. GUILayout.EndHorizontal();
  102. }
  103. static GUIContent GetTextContent(int width, BreadCrumbTitle text, GUIStyle style)
  104. {
  105. s_TextContent.tooltip = string.Empty;
  106. s_TextContent.image = null;
  107. if (text.mode == TitleMode.DisabledComponent)
  108. {
  109. s_TextContent.tooltip = k_DisabledComponentText;
  110. s_TextContent.image = EditorGUIUtility.GetHelpIcon(MessageType.Warning);
  111. }
  112. else if (text.mode == TitleMode.Prefab)
  113. s_TextContent.image = PrefabUtility.GameObjectStyles.prefabIcon;
  114. else if (text.mode == TitleMode.GameObject)
  115. s_TextContent.image = PrefabUtility.GameObjectStyles.gameObjectIcon;
  116. else if (text.mode == TitleMode.Asset)
  117. s_TextContent.image = k_TimelineIcon;
  118. else if (text.mode == TitleMode.PrefabOutOfContext)
  119. {
  120. s_TextContent.image = PrefabUtility.GameObjectStyles.prefabIcon;
  121. if (!TimelineWindow.instance.locked)
  122. s_TextContent.tooltip = k_PrefabOutOfContext;
  123. }
  124. if (s_TextContent.image != null)
  125. width = Math.Max(0, width - s_TextContent.image.width);
  126. s_TextContent.text = FitTextInArea(width, text.name, style);
  127. return s_TextContent;
  128. }
  129. static void DrawBreadcrumbAsSelectedSubSequence(int width, BreadCrumbTitle label, GUIStyle style, GUIStyle backgroundStyle)
  130. {
  131. var rect = DrawActiveBreadcrumb(width, label, style, backgroundStyle);
  132. const float underlineThickness = 2.0f;
  133. const float underlineVerticalOffset = 0.0f;
  134. var underlineHorizontalOffset = backgroundStyle.border.right * 0.333f;
  135. var underlineRect = Rect.MinMaxRect(
  136. rect.xMin - underlineHorizontalOffset,
  137. rect.yMax - underlineThickness - underlineVerticalOffset,
  138. rect.xMax - underlineHorizontalOffset,
  139. rect.yMax - underlineVerticalOffset);
  140. EditorGUI.DrawRect(underlineRect, DirectorStyles.Instance.customSkin.colorSubSequenceDurationLine);
  141. }
  142. static Rect GetBreadcrumbLayoutRect(GUIContent content, GUIStyle style)
  143. {
  144. // the image makes the button far too big compared to non-image versions
  145. var image = content.image;
  146. content.image = null;
  147. var size = style.CalcSizeWithConstraints(content, Vector2.zero);
  148. content.image = image;
  149. if (image != null)
  150. size.x += size.y; // assumes square image, constrained by height
  151. return GUILayoutUtility.GetRect(content, style, GUILayout.MaxWidth(size.x));
  152. }
  153. static Rect DrawActiveBreadcrumb(int width, BreadCrumbTitle label, GUIStyle style, GUIStyle backgroundStyle)
  154. {
  155. var content = GetTextContent(width, label, style);
  156. var rect = GetBreadcrumbLayoutRect(content, style);
  157. if (Event.current.type == EventType.Repaint)
  158. {
  159. backgroundStyle.Draw(rect, GUIContent.none, 0);
  160. }
  161. if (GUI.Button(rect, content, style))
  162. {
  163. UnityEngine.Object target = TimelineEditor.inspectedDirector;
  164. if (target == null)
  165. target = TimelineEditor.inspectedAsset;
  166. if (target != null)
  167. {
  168. bool ping = true;
  169. if (label.mode == TitleMode.PrefabOutOfContext)
  170. {
  171. var gameObject = PrefabUtility.GetRootGameObject(target);
  172. if (gameObject != null)
  173. {
  174. target = gameObject; // ping the prefab root if it's locked.
  175. if (!TimelineWindow.instance.locked)
  176. {
  177. var assetPath = AssetDatabase.GetAssetPath(gameObject);
  178. if (!string.IsNullOrEmpty(assetPath))
  179. {
  180. var stage = PrefabStageUtility.OpenPrefab(assetPath);
  181. if (stage != null)
  182. ping = false;
  183. }
  184. }
  185. }
  186. }
  187. if (ping)
  188. {
  189. EditorGUIUtility.PingObject(target);
  190. }
  191. }
  192. }
  193. return rect;
  194. }
  195. }
  196. }