TrackEditor.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.Playables;
  6. using UnityEngine.Timeline;
  7. namespace UnityEditor.Timeline
  8. {
  9. /// <summary>
  10. /// The user-defined options for drawing a track."
  11. /// </summary>
  12. public struct TrackDrawOptions
  13. {
  14. /// <summary>
  15. /// Text that indicates if the track should display an error.
  16. /// </summary>
  17. /// <remarks>
  18. /// If the error text is not empty or null, then the track displays a warning. The error text is used as the tooltip.
  19. /// </remarks>
  20. public string errorText { get; set; }
  21. /// <summary>
  22. /// The highlight color of the track.
  23. /// </summary>
  24. public Color trackColor { get; set; }
  25. /// <summary>
  26. /// The minimum height of the track.
  27. /// </summary>
  28. public float minimumHeight { get; set; }
  29. /// <summary>
  30. /// The icon displayed on the track header.
  31. /// </summary>
  32. /// <remarks>
  33. /// If this value is null, then the default icon for the track is used.
  34. /// </remarks>
  35. public Texture2D icon { get; set; }
  36. public override bool Equals(object obj)
  37. {
  38. if (!(obj is TrackDrawOptions))
  39. return false;
  40. return Equals((TrackDrawOptions)obj);
  41. }
  42. public bool Equals(TrackDrawOptions other)
  43. {
  44. return errorText == other.errorText &&
  45. trackColor == other.trackColor &&
  46. minimumHeight == other.minimumHeight &&
  47. icon == other.icon;
  48. }
  49. public override int GetHashCode()
  50. {
  51. return HashUtility.CombineHash(
  52. errorText != null ? errorText.GetHashCode() : 0,
  53. trackColor.GetHashCode(),
  54. minimumHeight.GetHashCode(),
  55. icon != null ? icon.GetHashCode() : 0
  56. );
  57. }
  58. public static bool operator==(TrackDrawOptions options1, TrackDrawOptions options2)
  59. {
  60. return options1.Equals(options2);
  61. }
  62. public static bool operator!=(TrackDrawOptions options1, TrackDrawOptions options2)
  63. {
  64. return !options1.Equals(options2);
  65. }
  66. }
  67. /// <summary>
  68. /// The errors displayed for the track binding.
  69. /// </summary>
  70. public enum TrackBindingErrors
  71. {
  72. /// <summary>
  73. /// Select no errors.
  74. /// </summary>
  75. None = 0,
  76. /// <summary>
  77. /// The bound GameObject is disabled.
  78. /// </summary>
  79. BoundGameObjectDisabled = 1 << 0,
  80. /// <summary>
  81. /// The bound GameObject does not have a valid component.
  82. /// </summary>
  83. NoValidComponent = 1 << 1,
  84. /// <summary>
  85. /// The bound Object is a disabled Behaviour.
  86. /// </summary>
  87. BehaviourIsDisabled = 1 << 2,
  88. /// <summary>
  89. /// The bound Object is not of the correct type.
  90. /// </summary>
  91. InvalidBinding = 1 << 3,
  92. /// <summary>
  93. /// The bound Object is part of a prefab, and not an instance.
  94. /// </summary>
  95. PrefabBound = 1 << 4,
  96. /// <summary>
  97. /// Select all errors.
  98. /// </summary>
  99. All = Int32.MaxValue
  100. }
  101. /// <summary>
  102. /// Use this class to customize track types in the TimelineEditor.
  103. /// </summary>
  104. public class TrackEditor
  105. {
  106. static readonly string k_BoundGameObjectDisabled = LocalizationDatabase.GetLocalizedString("The bound GameObject is disabled.");
  107. static readonly string k_NoValidComponent = LocalizationDatabase.GetLocalizedString("Could not find appropriate component on this gameObject");
  108. static readonly string k_RequiredComponentIsDisabled = LocalizationDatabase.GetLocalizedString("The component is disabled");
  109. static readonly string k_InvalidBinding = LocalizationDatabase.GetLocalizedString("The bound object is not the correct type.");
  110. static readonly string k_PrefabBound = LocalizationDatabase.GetLocalizedString("The bound object is a Prefab");
  111. readonly Dictionary<TrackAsset, System.Type> m_BindingCache = new Dictionary<TrackAsset, System.Type>();
  112. /// <summary>
  113. /// The default height of a track.
  114. /// </summary>
  115. public static readonly float DefaultTrackHeight = 30.0f;
  116. /// <summary>
  117. /// The minimum unscaled height of a track.
  118. /// </summary>
  119. public static readonly float MinimumTrackHeight = 10.0f;
  120. /// <summary>
  121. /// The maximum height of a track.
  122. /// </summary>
  123. public static readonly float MaximumTrackHeight = 256.0f;
  124. /// <summary>
  125. /// Implement this method to override the default options for drawing a track.
  126. /// </summary>
  127. /// <param name="track">The track from which track options are retrieved.</param>
  128. /// <param name="binding">The binding for the track.</param>
  129. /// <returns>The options for drawing the track.</returns>
  130. public virtual TrackDrawOptions GetTrackOptions(TrackAsset track, UnityEngine.Object binding)
  131. {
  132. return new TrackDrawOptions()
  133. {
  134. errorText = GetErrorText(track, binding, TrackBindingErrors.All),
  135. minimumHeight = DefaultTrackHeight,
  136. trackColor = GetTrackColor(track),
  137. icon = null
  138. };
  139. }
  140. /// <summary>
  141. /// Gets the error text for the specified track.
  142. /// </summary>
  143. /// <param name="track">The track to retrieve options for.</param>
  144. /// <param name="boundObject">The binding for the track.</param>
  145. /// <param name="detectErrors">The errors to check for.</param>
  146. /// <returns>An error to be displayed on the track, or string.Empty if there is no error.</returns>
  147. public string GetErrorText(TrackAsset track, UnityEngine.Object boundObject, TrackBindingErrors detectErrors)
  148. {
  149. if (track == null || boundObject == null)
  150. return string.Empty;
  151. var bindingType = GetBindingType(track);
  152. if (bindingType != null)
  153. {
  154. // bound to a prefab asset
  155. if (HasFlag(detectErrors, TrackBindingErrors.PrefabBound) && PrefabUtility.IsPartOfPrefabAsset(boundObject))
  156. {
  157. return k_PrefabBound;
  158. }
  159. // If we are a component, allow for bound game objects (legacy)
  160. if (typeof(Component).IsAssignableFrom(bindingType))
  161. {
  162. var gameObject = boundObject as GameObject;
  163. var component = boundObject as Component;
  164. if (component != null)
  165. gameObject = component.gameObject;
  166. // game object is bound with no component
  167. if (HasFlag(detectErrors, TrackBindingErrors.NoValidComponent) && gameObject != null && component == null)
  168. {
  169. component = gameObject.GetComponent(bindingType);
  170. if (component == null)
  171. {
  172. return k_NoValidComponent;
  173. }
  174. }
  175. // attached gameObject is disables (ignores Activation Track)
  176. if (HasFlag(detectErrors, TrackBindingErrors.BoundGameObjectDisabled) && gameObject != null && !gameObject.activeInHierarchy)
  177. {
  178. return k_BoundGameObjectDisabled;
  179. }
  180. // component is disabled
  181. var behaviour = component as Behaviour;
  182. if (HasFlag(detectErrors, TrackBindingErrors.BehaviourIsDisabled) && behaviour != null && !behaviour.enabled)
  183. {
  184. return k_RequiredComponentIsDisabled;
  185. }
  186. // mismatched binding
  187. if (HasFlag(detectErrors, TrackBindingErrors.InvalidBinding) && component != null && !bindingType.IsAssignableFrom(component.GetType()))
  188. {
  189. return k_InvalidBinding;
  190. }
  191. }
  192. // Mismatched binding (non-component)
  193. else if (HasFlag(detectErrors, TrackBindingErrors.InvalidBinding) && !bindingType.IsAssignableFrom(boundObject.GetType()))
  194. {
  195. return k_InvalidBinding;
  196. }
  197. }
  198. return string.Empty;
  199. }
  200. /// <summary>
  201. /// Gets the color information of a track.
  202. /// </summary>
  203. /// <param name="track"></param>
  204. /// <returns>Returns the color for the specified track.</returns>
  205. public Color GetTrackColor(TrackAsset track)
  206. {
  207. return TrackResourceCache.GetTrackColor(track);
  208. }
  209. /// <summary>
  210. /// Gets the binding type for a track.
  211. /// </summary>
  212. /// <param name="track">The track to retrieve the binding type from.</param>
  213. /// <returns>Returns the binding type for the specified track. Returns null if the track does not have binding.</returns>
  214. public System.Type GetBindingType(TrackAsset track)
  215. {
  216. if (track == null)
  217. return null;
  218. System.Type result = null;
  219. if (m_BindingCache.TryGetValue(track, out result))
  220. return result;
  221. result = track.outputs.Select(x => x.outputTargetType).FirstOrDefault();
  222. m_BindingCache[track] = result;
  223. return result;
  224. }
  225. /// <summary>
  226. /// Callback for when a track is created.
  227. /// </summary>
  228. /// <param name="track">The track that is created.</param>
  229. /// <param name="copiedFrom">The source that the track is copied from. This can be set to null if the track is not a copy.</param>
  230. public virtual void OnCreate(TrackAsset track, TrackAsset copiedFrom)
  231. {
  232. }
  233. /// <summary>
  234. /// Callback for when a track is changed.
  235. /// </summary>
  236. /// <param name="track">The track that is changed.</param>
  237. public virtual void OnTrackChanged(TrackAsset track)
  238. {
  239. }
  240. private static bool HasFlag(TrackBindingErrors errors, TrackBindingErrors flag)
  241. {
  242. return (errors & flag) != 0;
  243. }
  244. }
  245. }