Tanoda
CombinablePropertyDrawer.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using UnityEngine;
10using UnityEditor;
11using System.Linq;
12using System.Reflection;
13using System.Collections.Generic;
14using Leap.Unity.Query;
15
17
18 [CustomPropertyDrawer(typeof(CombinablePropertyAttribute), true)]
19 public class CombinablePropertyDrawer : PropertyDrawer {
20
21 private static Dictionary<FieldInfo, List<CombinablePropertyAttribute>> _cachedAttributes = new Dictionary<FieldInfo, List<CombinablePropertyAttribute>>();
22
23 private List<CombinablePropertyAttribute> attributes = new List<CombinablePropertyAttribute>();
24 private void getAttributes(SerializedProperty property) {
25 GetAttributes(property, fieldInfo, out attributes);
26 }
27
28 public static void GetAttributes(SerializedProperty property,
29 FieldInfo fieldInfo, out List<CombinablePropertyAttribute> outAttributes)
30 {
31 if (!_cachedAttributes.TryGetValue(fieldInfo, out outAttributes)) {
32 outAttributes = new List<CombinablePropertyAttribute>();
33
34 foreach (object o in fieldInfo.GetCustomAttributes(typeof(CombinablePropertyAttribute), true)) {
36 if (combinableProperty != null) {
37 if (combinableProperty.SupportedTypes.Count() != 0 && !combinableProperty.SupportedTypes.Contains(property.propertyType)) {
38 Debug.LogError("Property attribute " +
39 combinableProperty.GetType().Name +
40 " does not support property type " +
41 property.propertyType + ".");
42 continue;
43 }
44 outAttributes.Add(combinableProperty);
45 }
46 }
47
48 _cachedAttributes[fieldInfo] = outAttributes;
49 }
50 }
51
52 public override float GetPropertyHeight(SerializedProperty property,
53 GUIContent label)
54 {
55 getAttributes(property);
56
57 var topPanelDrawer = attributes.Query().Cast<ITopPanelDrawer>()
58 .Where(o => o != null).FirstOrDefault();
59 if (topPanelDrawer != null) {
60 return topPanelDrawer.GetHeight() + EditorGUI.GetPropertyHeight(property,
61 includeChildren: true);
62 }
63
64 return EditorGUI.GetPropertyHeight(property, includeChildren: true);
65 }
66
67 public override bool CanCacheInspectorGUI(SerializedProperty property) {
68 return false;
69 }
70
71 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
72 getAttributes(property);
73
74 CombinablePropertyDrawer.OnGUI(this.attributes, this.fieldInfo, position,
75 property, label);
76 }
77
78 public static void OnGUI(List<CombinablePropertyAttribute> attributes,
79 FieldInfo fieldInfo, Rect position, SerializedProperty property,
80 GUIContent label)
81 {
82 float defaultLabelWidth = EditorGUIUtility.labelWidth;
83 float fieldWidth = position.width - EditorGUIUtility.labelWidth;
84
85 bool canUseDefaultDrawer = true;
86 bool shouldDisable = false;
87
88 RangeAttribute rangeAttribute = null;
89 if (fieldInfo != null) {
90 rangeAttribute = fieldInfo.GetCustomAttributes(typeof(RangeAttribute), true).FirstOrDefault() as RangeAttribute;
91 }
92
93 ISupportDragAndDrop dragAndDropSupport = null;
94
95 IFullPropertyDrawer fullPropertyDrawer = null;
96 ITopPanelDrawer topPanelDrawer = null;
97 foreach (var a in attributes) {
98 if (fieldInfo != null) {
99 a.Init(fieldInfo, property.serializedObject.targetObjects);
100 }
101
103 EditorGUIUtility.labelWidth -= (a as IBeforeLabelAdditiveDrawer).GetWidth();
104 }
105
106 if (a is IAfterLabelAdditiveDrawer) {
107 EditorGUIUtility.labelWidth -= (a as IAfterLabelAdditiveDrawer).GetWidth();
108 canUseDefaultDrawer = false;
109 }
110
112 fieldWidth -= (a as IBeforeFieldAdditiveDrawer).GetWidth();
113 canUseDefaultDrawer = false;
114 }
115
116 if (a is IAfterFieldAdditiveDrawer) {
117 fieldWidth -= (a as IAfterFieldAdditiveDrawer).GetWidth();
118 }
119
120 if (a is IPropertyDisabler) {
121 shouldDisable |= (a as IPropertyDisabler).ShouldDisable(property);
122 }
123
124 if (a is IFullPropertyDrawer) {
125 if (fullPropertyDrawer != null) {
126 Debug.LogError("Cannot have 2 advanced attributes that both override the field drawing");
127 return;
128 }
129 fullPropertyDrawer = a as IFullPropertyDrawer;
130 }
131
132 if (a is ISupportDragAndDrop) {
133 dragAndDropSupport = (a as ISupportDragAndDrop);
134 }
135
136 if (a is ITopPanelDrawer) {
137 topPanelDrawer = (a as ITopPanelDrawer);
138 }
139 }
140
141 if (fullPropertyDrawer != null && !canUseDefaultDrawer) {
142 Debug.LogError("Cannot have an advanced attribute drawer that draws a custom field, and also have an advanced attribute drawer that draws between label and field!");
143 return;
144 }
145
146 Rect r = position;
147 Rect topPanel = new Rect();
148 if (topPanelDrawer != null) {
149 // Y = 0 is the top, so take the Rect's "bottom" for top panel.
150 topPanel = r.TakeBottom(topPanelDrawer.GetHeight(), out r);
151 }
152
153 if (dragAndDropSupport != null) {
154 processDragAndDrop(dragAndDropSupport, ref r, property);
155 }
156
157 EditorGUI.BeginChangeCheck();
158 EditorGUI.BeginDisabledGroup(shouldDisable);
159
160 if (topPanelDrawer != null) {
161 topPanelDrawer.Draw(topPanel, property);
162 }
163
164 drawAdditive<IBeforeLabelAdditiveDrawer>(attributes, ref r, property);
165
166 if (canUseDefaultDrawer) {
167 r.width = EditorGUIUtility.labelWidth + fieldWidth;
168
169 if (fullPropertyDrawer != null) {
170 fullPropertyDrawer.DrawProperty(r, property, label);
171 } else {
172 if (rangeAttribute != null) {
173 if (property.propertyType == SerializedPropertyType.Integer) {
174 property.intValue = EditorGUI.IntSlider(r, label, property.intValue, (int)rangeAttribute.min, (int)rangeAttribute.max);
175 } else if (property.propertyType == SerializedPropertyType.Float) {
176 property.floatValue = EditorGUI.Slider(r, label, property.floatValue, rangeAttribute.min, rangeAttribute.max);
177 } else {
178 EditorGUI.PropertyField(r, property, label, includeChildren: true);
179 }
180 } else {
181 EditorGUI.PropertyField(r, property, label, includeChildren: true);
182 }
183 }
184
185 r.x += r.width;
186 }
187 else {
188 r.width = EditorGUIUtility.labelWidth;
189 r = EditorGUI.PrefixLabel(r, label);
190
191 drawAdditive<IAfterLabelAdditiveDrawer>(attributes, ref r, property);
192 drawAdditive<IBeforeFieldAdditiveDrawer>(attributes, ref r, property);
193
194 r.width = fieldWidth;
195 EditorGUI.PropertyField(r, property, GUIContent.none,
196 includeChildren: true);
197 r.x += r.width;
198 }
199
200 drawAdditive<IAfterFieldAdditiveDrawer>(attributes, ref r, property);
201
202 EditorGUI.EndDisabledGroup();
203
204 bool didChange = false;
205 try {
206 didChange = EditorGUI.EndChangeCheck();
207 }
208 catch (System.Exception e) {
209 Debug.LogWarning("CombinablePropertyDrawer exception getting didChange: " +
210 e.ToString());
211 }
212
213 if (didChange || !property.hasMultipleDifferentValues) {
214 foreach (var a in attributes) {
215 if (a is IPropertyConstrainer) {
216 (a as IPropertyConstrainer).ConstrainValue(property);
217 }
218 }
219 }
220
221 if (didChange) {
222 foreach (var a in attributes) {
223 a.OnPropertyChanged(property);
224 }
225 }
226
227 EditorGUIUtility.labelWidth = defaultLabelWidth;
228 }
229
230 private static void drawAdditive<T>(List<CombinablePropertyAttribute> attributes,
231 ref Rect r, SerializedProperty property)
232 where T : class, IAdditiveDrawer {
233 foreach (var a in attributes) {
234 if (a is T) {
235 T t = a as T;
236 r.width = t.GetWidth();
237 t.Draw(r, property);
238 r.x += r.width;
239 }
240 }
241 }
242
243 private static void processDragAndDrop(ISupportDragAndDrop dragAndDropSupport,
244 ref Rect r, SerializedProperty property) {
245 Event curEvent = Event.current;
246 Rect dropArea = dragAndDropSupport.GetDropArea(r, property);
247
248 switch (curEvent.type) {
249 case EventType.Repaint:
250 case EventType.DragUpdated:
251 case EventType.DragPerform:
252 if (!dropArea.Contains(curEvent.mousePosition, allowInverse: true)) {
253 break;
254 }
255
256 bool isValidDrop = dragAndDropSupport.IsDropValid(
257 DragAndDrop.objectReferences, property);
258
259 if (isValidDrop) {
260 DragAndDrop.visualMode = DragAndDropVisualMode.Link;
261 } else {
262 DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
263 }
264
265 if (curEvent.type == EventType.DragPerform && isValidDrop) {
266 DragAndDrop.AcceptDrag();
267
268 dragAndDropSupport.ProcessDroppedObjects(
269 DragAndDrop.objectReferences, property);
270 }
271
272 break;
273 }
274 }
275 }
276}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
static void GetAttributes(SerializedProperty property, FieldInfo fieldInfo, out List< CombinablePropertyAttribute > outAttributes)
override float GetPropertyHeight(SerializedProperty property, GUIContent label)
override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
static void OnGUI(List< CombinablePropertyAttribute > attributes, FieldInfo fieldInfo, Rect position, SerializedProperty property, GUIContent label)
override bool CanCacheInspectorGUI(SerializedProperty property)