CustomTimelineEditorCache.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Playables;
  6. using UnityEngine.Timeline;
  7. namespace UnityEditor.Timeline
  8. {
  9. class CustomTimelineEditorCache
  10. {
  11. static class SubClassCache<TEditorClass> where TEditorClass : class, new()
  12. {
  13. private static Type[] s_SubClasses = null;
  14. private static readonly TEditorClass s_DefaultInstance = new TEditorClass();
  15. private static readonly Dictionary<System.Type, TEditorClass> s_TypeMap = new Dictionary<Type, TEditorClass>();
  16. public static TEditorClass DefaultInstance
  17. {
  18. get { return s_DefaultInstance; }
  19. }
  20. static Type[] SubClasses
  21. {
  22. get
  23. {
  24. // order the subclass array by built-ins then user defined so built-in classes are chosen first
  25. return s_SubClasses ??
  26. (s_SubClasses = TypeCache.GetTypesDerivedFrom<TEditorClass>().OrderBy(t => t.Assembly == typeof(UnityEditor.Timeline.TimelineEditor).Assembly ? 1 : 0).ToArray());
  27. }
  28. }
  29. public static TEditorClass GetEditorForType(Type type)
  30. {
  31. TEditorClass editorClass = null;
  32. if (!s_TypeMap.TryGetValue(type, out editorClass) || editorClass == null)
  33. {
  34. Type editorClassType = null;
  35. Type searchType = type;
  36. while (searchType != null)
  37. {
  38. // search our way up the runtime class hierarchy so we get the best match
  39. editorClassType = GetExactEditorClassForType(searchType);
  40. if (editorClassType != null)
  41. break;
  42. searchType = searchType.BaseType;
  43. }
  44. if (editorClassType == null)
  45. {
  46. editorClass = s_DefaultInstance;
  47. }
  48. else
  49. {
  50. try
  51. {
  52. editorClass = (TEditorClass)Activator.CreateInstance(editorClassType);
  53. }
  54. catch (Exception e)
  55. {
  56. Debug.LogWarningFormat("Could not create a Timeline editor class of type {0}: {1}", editorClassType, e.Message);
  57. editorClass = s_DefaultInstance;
  58. }
  59. }
  60. s_TypeMap[type] = editorClass;
  61. }
  62. return editorClass;
  63. }
  64. private static Type GetExactEditorClassForType(Type type)
  65. {
  66. foreach (var subClass in SubClasses)
  67. {
  68. // first check for exact match
  69. var attr = (CustomTimelineEditorAttribute)Attribute.GetCustomAttribute(subClass, typeof(CustomTimelineEditorAttribute), false);
  70. if (attr != null && attr.classToEdit == type)
  71. {
  72. return subClass;
  73. }
  74. }
  75. return null;
  76. }
  77. public static void Clear()
  78. {
  79. s_TypeMap.Clear();
  80. s_SubClasses = null;
  81. }
  82. }
  83. public static TEditorClass GetEditorForType<TEditorClass, TRuntimeClass>(Type type) where TEditorClass : class, new()
  84. {
  85. if (type == null)
  86. throw new ArgumentNullException(nameof(type));
  87. if (!typeof(TRuntimeClass).IsAssignableFrom(type))
  88. throw new ArgumentException(type.FullName + " does not inherit from" + typeof(TRuntimeClass));
  89. return SubClassCache<TEditorClass>.GetEditorForType(type);
  90. }
  91. public static void ClearCache<TEditorClass>() where TEditorClass : class, new()
  92. {
  93. SubClassCache<TEditorClass>.Clear();
  94. }
  95. public static ClipEditor GetClipEditor(TimelineClip clip)
  96. {
  97. if (clip == null)
  98. throw new ArgumentNullException(nameof(clip));
  99. var type = typeof(IPlayableAsset);
  100. if (clip.asset != null)
  101. type = clip.asset.GetType();
  102. if (!typeof(IPlayableAsset).IsAssignableFrom(type))
  103. return GetDefaultClipEditor();
  104. return GetEditorForType<ClipEditor, IPlayableAsset>(type);
  105. }
  106. public static ClipEditor GetDefaultClipEditor()
  107. {
  108. return SubClassCache<ClipEditor>.DefaultInstance;
  109. }
  110. public static TrackEditor GetTrackEditor(TrackAsset track)
  111. {
  112. if (track == null)
  113. throw new ArgumentNullException(nameof(track));
  114. return GetEditorForType<TrackEditor, TrackAsset>(track.GetType());
  115. }
  116. public static TrackEditor GetDefaultTrackEditor()
  117. {
  118. return SubClassCache<TrackEditor>.DefaultInstance;
  119. }
  120. public static MarkerEditor GetMarkerEditor(IMarker marker)
  121. {
  122. if (marker == null)
  123. throw new ArgumentNullException(nameof(marker));
  124. return GetEditorForType<MarkerEditor, IMarker>(marker.GetType());
  125. }
  126. public static MarkerEditor GetDefaultMarkerEditor()
  127. {
  128. return SubClassCache<MarkerEditor>.DefaultInstance;
  129. }
  130. }
  131. }