Tanoda
SerializableDictionaryEditor.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 UnityEditorInternal;
12using System.Collections.Generic;
13
14namespace Leap.Unity {
15
16 [CustomPropertyDrawer(typeof(SerializableDictionaryBase), useForChildren: true)]
17 public class SerializableDictionaryEditor : PropertyDrawer {
18
19 private ReorderableList _list;
20 private SerializedProperty _currProperty;
21
22 private List<Pair> _pairs = new List<Pair>();
23 private class Pair {
24 public int index;
25 public bool isDuplicate;
26 public SerializedProperty a;
27 public SerializedProperty b;
28
29 public Pair(int index, bool isDuplicate, SerializedProperty a, SerializedProperty b) {
30 this.index = index;
31 this.isDuplicate = isDuplicate;
32 this.a = a;
33 this.b = b;
34 }
35 }
36
38 _list = new ReorderableList(_pairs, typeof(Pair),
39 draggable: true,
40 displayHeader: true,
41 displayAddButton: true,
42 displayRemoveButton: true);
43
44 _list.drawElementCallback = drawElementCallback;
45 _list.elementHeightCallback = elementHeightCallback;
46 _list.drawHeaderCallback = drawHeader;
47 _list.onAddCallback = onAddCallback;
48 _list.onRemoveCallback = onRemoveCallback;
49 _list.onReorderCallback = onReorderCallback;
50 }
51
52
53 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
54 if (property.hasMultipleDifferentValues) {
55 GUI.Box(position, "");
56 EditorGUI.LabelField(position, "Multi-object editing not supported for Serialized Dictionaries.", EditorStyles.miniLabel);
57 } else {
58 _currProperty = property;
59
60 updatePairsFromProperty(property);
61
62 EditorGUIUtility.labelWidth /= 2;
63 _list.DoList(position);
64 EditorGUIUtility.labelWidth *= 2;
65 }
66 }
67
68 public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
69 if (property.hasMultipleDifferentValues) {
70 return EditorGUIUtility.singleLineHeight;
71 } else {
72 updatePairsFromProperty(property);
73 return _list.GetHeight();
74 }
75 }
76
77 private void updatePairsFromProperty(SerializedProperty property) {
78 SerializedProperty keys = property.FindPropertyRelative("_keys");
79 SerializedProperty values = property.FindPropertyRelative("_values");
80
81 var dup = (fieldInfo.GetValue(property.serializedObject.targetObject) as ICanReportDuplicateInformation).GetDuplicationInformation();
82
83 _pairs.Clear();
84 int count = keys.arraySize;
85 for (int i = 0; i < count; i++) {
86 SerializedProperty key = keys.GetArrayElementAtIndex(i);
87 SerializedProperty value = values.GetArrayElementAtIndex(i);
88
89 bool isDup = false;
90 if (i < dup.Count) {
91 isDup = dup[i] > 1;
92 }
93
94 _pairs.Add(new Pair(i, isDup, key, value));
95 }
96 }
97
98 private void drawHeader(Rect rect) {
99 EditorGUI.LabelField(rect, _currProperty.displayName);
100 rect.x += rect.width - 110;
101 rect.width = 110;
102 if (GUI.Button(rect, "Clear Duplicates")) {
103 markDirty(_currProperty);
104
105 Undo.RecordObject(_currProperty.serializedObject.targetObject, "Cleared duplicates");
106 (fieldInfo.GetValue(_currProperty.serializedObject.targetObject) as ICanReportDuplicateInformation).ClearDuplicates();
107
108 _currProperty.serializedObject.Update();
109
110 markDirty(_currProperty);
111 updatePairsFromProperty(_currProperty);
112 }
113 }
114
115 private void drawElementCallback(Rect rect, int index, bool isActive, bool isFocused) {
116 Rect leftRect = rect;
117 leftRect.width *= (fieldInfo.GetValue(_currProperty.serializedObject.targetObject) as ISerializableDictionary).KeyDisplayRatio();
118
119 Rect rightRect = rect;
120 rightRect.x += leftRect.width;
121 rightRect.width -= leftRect.width;
122
123 Pair pair = _pairs[index];
124
125 if (pair.isDuplicate) {
126 GUI.contentColor = new Color(1, 0.7f, 0);
127 GUI.color = new Color(1, 0.7f, 0.5f);
128 }
129
130 if (pair.a.propertyType == SerializedPropertyType.ObjectReference && pair.a.objectReferenceValue == null) {
131 GUI.contentColor = new Color(1, 0, 0);
132 GUI.color = new Color(1, 0, 0);
133 }
134
135 drawProp(pair.a, leftRect);
136
137 GUI.contentColor = Color.white;
138 GUI.color = Color.white;
139 GUI.backgroundColor = Color.white;
140
141 drawProp(pair.b, rightRect);
142 }
143
144 private void onAddCallback(ReorderableList list) {
145 SerializedProperty keys = _currProperty.FindPropertyRelative("_keys");
146 SerializedProperty values = _currProperty.FindPropertyRelative("_values");
147
148 keys.arraySize++;
149 values.arraySize++;
150
151 updatePairsFromProperty(_currProperty);
152 }
153
154 private void onRemoveCallback(ReorderableList list) {
155 SerializedProperty keys = _currProperty.FindPropertyRelative("_keys");
156 SerializedProperty values = _currProperty.FindPropertyRelative("_values");
157
158 actuallyDeleteAt(keys, list.index);
159 actuallyDeleteAt(values, list.index);
160
161 updatePairsFromProperty(_currProperty);
162 }
163
164 private void onReorderCallback(ReorderableList list) {
165 SerializedProperty keys = _currProperty.FindPropertyRelative("_keys");
166 SerializedProperty values = _currProperty.FindPropertyRelative("_values");
167
168 int startIndex = -1, endIndex = -1;
169 bool isForward = true;
170
171 for (int i = 0; i < _pairs.Count; i++) {
172 if (i != _pairs[i].index) {
173 if (_pairs[i].index - i > 1) {
174 isForward = false;
175 }
176 startIndex = i;
177 break;
178 }
179 }
180
181 for (int i = _pairs.Count; i-- != 0;) {
182 if (i != _pairs[i].index) {
183 endIndex = i;
184 break;
185 }
186 }
187
188 if (isForward) {
189 keys.MoveArrayElement(startIndex, endIndex);
190 values.MoveArrayElement(startIndex, endIndex);
191 } else {
192 keys.MoveArrayElement(endIndex, startIndex);
193 values.MoveArrayElement(endIndex, startIndex);
194 }
195
196 updatePairsFromProperty(_currProperty);
197 }
198
199 private float elementHeightCallback(int index) {
200 Pair pair = _pairs[index];
201 float size = Mathf.Max(getSize(pair.a), getSize(pair.b));
202 _list.elementHeight = size;
203 return size;
204 }
205
206 private float getSize(SerializedProperty prop) {
207
208 float size = 0;
209 if (prop.propertyType == SerializedPropertyType.Generic) {
210 SerializedProperty copy = prop.Copy();
211 SerializedProperty endProp = copy.GetEndProperty(false);
212
213 copy.NextVisible(true);
214 while (!SerializedProperty.EqualContents(copy, endProp)) {
215 size += EditorGUI.GetPropertyHeight(copy);
216 copy.NextVisible(false);
217 }
218 } else {
219 size = EditorGUI.GetPropertyHeight(prop, GUIContent.none, false);
220 }
221 return size;
222 }
223
224 private void drawProp(SerializedProperty prop, Rect r) {
225 if (prop.propertyType == SerializedPropertyType.Generic) {
226 SerializedProperty copy = prop.Copy();
227 SerializedProperty endProp = copy.GetEndProperty(false);
228 copy.NextVisible(true);
229 while (!SerializedProperty.EqualContents(copy, endProp)) {
230 r.height = EditorGUI.GetPropertyHeight(copy);
231 EditorGUI.PropertyField(r, copy, true);
232 r.y += r.height;
233 copy.NextVisible(false);
234 }
235 } else {
236 r.height = EditorGUI.GetPropertyHeight(prop);
237 EditorGUI.PropertyField(r, prop, GUIContent.none, false);
238 }
239 }
240
241 private void markDirty(SerializedProperty property) {
242 SerializedProperty keys = property.FindPropertyRelative("_keys");
243 int size = keys.arraySize;
244
245 keys.InsertArrayElementAtIndex(size);
246 actuallyDeleteAt(keys, size);
247 }
248
249 private static void actuallyDeleteAt(SerializedProperty property, int index) {
250 int arraySize = property.arraySize;
251
252 while (property.arraySize == arraySize) {
253 property.DeleteArrayElementAtIndex(index);
254 }
255 }
256 }
257}
UnityEngine.Color Color
Definition: TestScript.cs:32
override float GetPropertyHeight(SerializedProperty property, GUIContent label)
override void OnGUI(Rect position, SerializedProperty property, GUIContent label)