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