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