Skip to content

Commit 5744ecc

Browse files
committed
Add (nested) generic type method/type support.
Now it is able to call generic methods within inspector+. Implemented type selection quick dropdown (together with generic method resolver). Prevent property auto fetches in some unwanted cases.
1 parent 30e6346 commit 5744ecc

File tree

8 files changed

+427
-102
lines changed

8 files changed

+427
-102
lines changed

Editor/UInspectorPlus/ComponentMethodDrawer.cs

Lines changed: 103 additions & 77 deletions
Large diffs are not rendered by default.

Editor/UInspectorPlus/Helpers.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ internal enum PropertyType {
3333
Vector2Int,
3434
Vector3Int,
3535
RectInt,
36+
Type,
3637
}
3738

3839
internal enum MethodMode {
@@ -85,6 +86,8 @@ public static class Helper {
8586

8687
private static readonly Hashtable storedState = new Hashtable();
8788

89+
internal static readonly Type[] EmptyTypes = new Type[0];
90+
8891
static Helper() {
8992
AddPropertyTypeMap<string>(PropertyType.String);
9093
AddPropertyTypeMap<bool>(PropertyType.Bool);
@@ -113,6 +116,7 @@ static Helper() {
113116
AddPropertyTypeMap<Vector2Int>(PropertyType.Vector2Int);
114117
AddPropertyTypeMap<Vector3Int>(PropertyType.Vector3Int);
115118
AddPropertyTypeMap<RectInt>(PropertyType.RectInt);
119+
AddPropertyTypeMap<Type>(PropertyType.Type);
116120

117121
// Danger properties! Do not use them or they will instanate junks
118122
AddBlacklistedType<MeshFilter>(nameof(MeshFilter.mesh));
@@ -475,22 +479,22 @@ internal static GUIStyle GetGUIStyle(string styleName) => GUI.skin.FindStyle(sty
475479
EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle(styleName);
476480

477481
internal static T GetOrDefault<T>(object value, T defaultValue = default) {
478-
if (value == null) return defaultValue;
482+
if(value == null) return defaultValue;
479483
try {
480484
return (T)Convert.ChangeType(value, typeof(T));
481-
} catch {}
485+
} catch { }
482486
try {
483487
return (T)value;
484-
} catch {}
488+
} catch { }
485489
return defaultValue;
486490
}
487491

488492
internal static T GetOrConstruct<T>(object value) where T : new() => value == null ? new T() : (T)value;
489493

490494
internal static TValue GetOrConstruct<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) where TValue : new() {
491-
if (!dict.TryGetValue(key, out var value)) {
495+
if(!dict.TryGetValue(key, out var value)) {
492496
value = new TValue();
493-
if (!dict.IsReadOnly) dict.Add(key, value);
497+
if(!dict.IsReadOnly) dict.Add(key, value);
494498
}
495499
return value;
496500
}

Editor/UInspectorPlus/InspectorChildWindow.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ private void OnInspectorUpdate() {
5858
UpdateValues();
5959
}
6060

61-
private void UpdateValues() => drawer.UpdateValues(updateProps);
61+
private void UpdateValues() {
62+
if (drawer == null) {
63+
Close();
64+
return;
65+
}
66+
drawer.UpdateValues(updateProps);
67+
}
6268
}
6369
}

Editor/UInspectorPlus/InspectorPlus.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@ private void OnEnable() {
3434
Initialize();
3535
OnFocus();
3636
typeMatcher.OnRequestRedraw += Repaint;
37+
typeMatcher.OnSelected += TypeSelected;
3738
}
3839

3940
private void OnDisable() => typeMatcher.OnRequestRedraw -= Repaint;
4041

4142
private void OnDestroy() => typeMatcher.Dispose();
4243

44+
private static void TypeSelected(Type type) => InspectorChildWindow.OpenStatic(type, true, true, true, true, false, null);
45+
4346
private void Initialize() {
4447
if(initialized) return;
4548
autoUpdateValues = EditorPrefs.GetBool("inspectorplus_autoupdate", true);
@@ -286,10 +289,10 @@ private void DestroyAll() {
286289
case 0: deleteThis = true; break;
287290
case 1: deleteThis = false; break;
288291
case 2: {
289-
deleteAll = true;
290-
deleteThis = true;
291-
break;
292-
}
292+
deleteAll = true;
293+
deleteThis = true;
294+
break;
295+
}
293296
}
294297
if(deleteThis) {
295298
DestroyImmediate(obj);

Editor/UInspectorPlus/ListInspectorDrawer.cs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public ListInspectorDrawer(object target, Type targetType, bool shown, bool show
2121
}
2222

2323
protected override void Draw(bool readOnly) {
24-
if(showListEdit = EditorGUILayout.Foldout(showListEdit, $"Edit List [{target.Count} Items]")) {
24+
if(target != null && (showListEdit = EditorGUILayout.Foldout(showListEdit, $"Edit List [{target.Count} Items]"))) {
2525
if(arrayHandler == null) {
2626
if(arrayContentDrawer == null) {
2727
arrayContentDrawer = new List<MethodPropertyDrawer>();
@@ -66,4 +66,66 @@ private void ListAddItem(object value = null) {
6666
arrayContentDrawer.Add(drawer);
6767
}
6868
}
69-
}
69+
70+
internal class ArrayConstructorDrawer: IDisposable {
71+
const float listItemPadding = 2;
72+
private readonly Type elementType;
73+
private readonly List<MethodPropertyDrawer> drawers = new List<MethodPropertyDrawer>();
74+
private readonly ReorderableList arrayHandler;
75+
public event Action OnRequireRedraw;
76+
77+
public ArrayConstructorDrawer(Type elementType) {
78+
if(elementType == null) throw new ArgumentNullException(nameof(elementType));
79+
this.elementType = elementType;
80+
arrayHandler = new ReorderableList(drawers, typeof(MethodPropertyDrawer)) {
81+
headerHeight = EditorGUIUtility.singleLineHeight,
82+
elementHeightCallback = GetElementHeight,
83+
drawElementCallback = DrawElement,
84+
drawHeaderCallback = DrawTitle,
85+
onAddCallback = AddItem,
86+
onRemoveCallback = RemoveItem,
87+
};
88+
}
89+
90+
private void DrawElement(Rect rect, int index, bool isChecked, bool isDisabled) =>
91+
drawers[index].Draw(isDisabled, Helper.ScaleRect(rect, offsetHeight: -listItemPadding));
92+
93+
private void DrawTitle(Rect rect) =>
94+
GUI.Label(rect, $"{this.elementType.FullName}[]", EditorStyles.miniBoldLabel);
95+
96+
private void AddItem(ReorderableList list) {
97+
var drawer = new MethodPropertyDrawer(elementType, "", null, true, false);
98+
drawer.OnRequireRedraw += RequireRedraw;
99+
drawers.Add(drawer);
100+
}
101+
102+
private float GetElementHeight(int index) {
103+
return EditorGUIUtility.singleLineHeight + listItemPadding;
104+
}
105+
106+
private void RemoveItem(ReorderableList list) {
107+
int selectedIndex = list.index;
108+
if(selectedIndex < 0) selectedIndex = drawers.Count - 1;
109+
drawers[selectedIndex].Dispose();
110+
drawers.RemoveAt(selectedIndex);
111+
}
112+
113+
public Array ToArray() {
114+
int count = drawers.Count;
115+
var array = Array.CreateInstance(elementType, drawers.Count);
116+
for (int i = 0; i < count; i++)
117+
array.SetValue(drawers[i].Value, i);
118+
return array;
119+
}
120+
121+
protected void RequireRedraw() => OnRequireRedraw?.Invoke();
122+
123+
public void Dispose() {
124+
foreach(var entry in drawers)
125+
entry?.Dispose();
126+
drawers.Clear();
127+
}
128+
129+
public void Draw() => arrayHandler.DoLayoutList();
130+
}
131+
}

Editor/UInspectorPlus/MethodPropertyDrawer.cs

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class MethodPropertyDrawer: IReflectorDrawer, IDisposable {
1919
private object rawValue;
2020
private bool referenceMode;
2121
private int grabValueMode;
22+
private ArrayConstructorDrawer arrayConstructorDrawer;
2223

2324
private UnityObject component;
2425
private readonly List<ComponentFields> fields;
@@ -34,6 +35,7 @@ public class MethodPropertyDrawer: IReflectorDrawer, IDisposable {
3435
private bool obsolete = true;
3536
private bool masked;
3637
private bool isInfoReadonly;
38+
private bool hasGetValue;
3739
private readonly bool isStatic;
3840
private readonly bool isPrivate;
3941
public event Action OnRequireRedraw;
@@ -149,6 +151,7 @@ public object Value {
149151
}
150152
set {
151153
rawValue = value;
154+
hasGetValue = true;
152155
Changed = false;
153156
}
154157
}
@@ -182,6 +185,7 @@ public MethodPropertyDrawer(FieldInfo field, object target, bool allowPrivate, b
182185
name = field.GetMemberName(true);
183186
nameContent = new GUIContent(name, field.GetMemberName());
184187
rawValue = field.GetValue(target);
188+
hasGetValue = true;
185189
this.target = target;
186190
isStatic = field.IsStatic;
187191
isPrivate = field.IsPrivate;
@@ -202,6 +206,7 @@ public MethodPropertyDrawer(PropertyInfo property, object target, bool allowPriv
202206
name = property.GetMemberName(true);
203207
nameContent = new GUIContent(name, property.GetMemberName());
204208
}
209+
hasGetValue = initValue;
205210
if(initValue) rawValue = property.GetValue(target, indexParams);
206211
this.target = target;
207212
var getMethod = property.GetGetMethod();
@@ -215,6 +220,7 @@ public MethodPropertyDrawer(ParameterInfo parameter, bool allowPrivate, bool all
215220
requiredType = parameter.ParameterType;
216221
name = parameter.Name;
217222
nameContent = new GUIContent(name, name);
223+
hasGetValue = true;
218224
if(parameter.HasDefaultValue)
219225
rawValue = parameter.DefaultValue;
220226
InitType();
@@ -225,6 +231,7 @@ public MethodPropertyDrawer(Type type, string name, object defaultValue, bool al
225231
requiredType = type;
226232
this.name = name;
227233
nameContent = new GUIContent(name, name);
234+
hasGetValue = true;
228235
rawValue = defaultValue;
229236
InitType();
230237
}
@@ -270,6 +277,22 @@ private void InitType() {
270277
public void Draw(bool readOnly, Rect? rect = null) {
271278
if(target.IsInvalid() && memberInfo.IsInstanceMember())
272279
return;
280+
if(requiredType != null && requiredType.ContainsGenericParameters) {
281+
Rect sRect = rect.HasValue ? rect.Value : EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, GUI.skin.button);
282+
sRect = EditorGUI.PrefixLabel(sRect, nameContent);
283+
GUI.Label(sRect, "Unresolved Generic Type");
284+
return;
285+
}
286+
if(!hasGetValue) {
287+
const string labelText = "Fetch Value...";
288+
Rect sRect = rect.HasValue ? rect.Value : EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, GUI.skin.button);
289+
sRect = EditorGUI.PrefixLabel(sRect, nameContent);
290+
if(GUI.Button(sRect, labelText, GUI.skin.button)) {
291+
hasGetValue = true;
292+
rawValue = (memberInfo as PropertyInfo).GetValue(target);
293+
}
294+
return;
295+
}
273296
readOnly |= isInfoReadonly;
274297
var referenceModeBtn = (!allowReferenceMode && (
275298
currentType == PropertyType.Unknown ||
@@ -283,6 +306,8 @@ public void Draw(bool readOnly, Rect? rect = null) {
283306
Rect sRect = referenceModeBtn ? Helper.ScaleRect(rect.Value, offsetWidth: -EditorGUIUtility.singleLineHeight) : rect.Value;
284307
if(referenceMode || grabValueMode == 1)
285308
DrawReferencedField(sRect);
309+
else if(grabValueMode == 4)
310+
DrawArrayCtorField(sRect);
286311
else if(grabValueMode == 3)
287312
DrawRequestReferenceField(sRect);
288313
else
@@ -297,6 +322,8 @@ public void Draw(bool readOnly, Rect? rect = null) {
297322
EditorGUILayout.LabelField(GUIContent.none, GUILayout.Width(EditorGUIUtility.singleLineHeight));
298323
if(referenceMode || grabValueMode == 1)
299324
DrawReferencedField(null);
325+
else if(grabValueMode == 4)
326+
DrawArrayCtorField(null);
300327
else if(grabValueMode == 3)
301328
DrawRequestReferenceField(null);
302329
else
@@ -324,11 +351,11 @@ public void Draw(bool readOnly, Rect? rect = null) {
324351
var sb = new System.Text.StringBuilder();
325352
var exception = getException;
326353
do {
327-
if (!exceptions.Add(exception)) break;
328-
if (sb.Length > 0) sb.AppendLine();
354+
if(!exceptions.Add(exception)) break;
355+
if(sb.Length > 0) sb.AppendLine();
329356
sb.Append('>', exceptions.Count - 1);
330357
sb.Append($"{exception.GetType().Name}: {exception.Message}");
331-
} while ((exception = exception.InnerException) != null);
358+
} while((exception = exception.InnerException) != null);
332359
EditorGUILayout.HelpBox(sb.ToString(), MessageType.Error);
333360
}
334361
}
@@ -344,6 +371,7 @@ public bool UpdateIfChanged() {
344371
}
345372

346373
public bool UpdateValue() {
374+
hasGetValue = true;
347375
if(memberInfo.FetchValue(target, out var value, indexParams)) {
348376
rawValue = value;
349377
GetException = null;
@@ -559,7 +587,7 @@ private void DrawDirectField(bool readOnly, Rect? rect) {
559587
value = EditorGUILayout.Vector4Field(name, Helper.GetOrDefault<Vector4>(value));
560588
break;
561589
case PropertyType.Quaterion:
562-
if (masked) {
590+
if(masked) {
563591
if(rect.HasValue)
564592
value = Helper.EulerField(rect.Value, name, Helper.GetOrDefault(value, Quaternion.identity));
565593
else
@@ -619,8 +647,29 @@ private void DrawDirectField(bool readOnly, Rect? rect) {
619647
else
620648
value = Helper.StringField(nameContent, (string)value, readOnly);
621649
break;
650+
case PropertyType.Type:
651+
EditorGUI.BeginDisabledGroup(readOnly);
652+
var rect2 = rect.HasValue ? rect.Value : EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, EditorStyles.textField);
653+
rect2 = EditorGUI.PrefixLabel(rect2, nameContent);
654+
Rect buttonRect;
655+
if(rect.HasValue) {
656+
buttonRect = Helper.ScaleRect(rect2, 1, 0, 0, 1, -34, 0, 32);
657+
rect2 = Helper.ScaleRect(rect2, 0, 0, 1, 1, 0, 0, -36);
658+
} else
659+
buttonRect = Rect.zero;
660+
if(GUI.Button(rect2, value is Type t ? $"T: {t.FullName}" : "<Null>", EditorStyles.textField) && !readOnly) {
661+
var typeMatcherPopup = new TypeMatcherPopup(null);
662+
typeMatcherPopup.OnSelected += type => rawValue = type;
663+
PopupWindow.Show(rect2, typeMatcherPopup);
664+
}
665+
EditorGUI.EndDisabledGroup();
666+
if(rect.HasValue)
667+
DrawUnknownField(readOnly, value, buttonRect);
668+
else
669+
DrawUnknownField(readOnly, value);
670+
break;
622671
default:
623-
var stringValue = value != null ? value.ToString() : "Null";
672+
var stringValue = value != null ? value.ToString() : "<Null>";
624673
if(rect.HasValue) {
625674
Helper.StringField(Helper.ScaleRect(rect.Value, 0, 0, 1, 1, 0, 0, -36), nameContent, stringValue, true);
626675
DrawUnknownField(readOnly, value, Helper.ScaleRect(rect.Value, 1, 0, 0, 1, -34, 0, 32));
@@ -656,6 +705,26 @@ private void DrawUnknownField(bool readOnly, object target, Rect? position = nul
656705
InspectorChildWindow.Open(target, true, privateFields, obsolete, true, false, this);
657706
}
658707

708+
private void DrawArrayCtorField(Rect? position = null) {
709+
if(!position.HasValue) EditorGUILayout.BeginVertical();
710+
if(requiredType.IsGenericType) {
711+
if(position.HasValue)
712+
EditorGUI.HelpBox(position.Value, "Type is not resolved.", MessageType.Error);
713+
else
714+
EditorGUILayout.HelpBox("Type is not resolved.", MessageType.Error);
715+
return;
716+
}
717+
if(arrayConstructorDrawer == null) arrayConstructorDrawer = new ArrayConstructorDrawer(requiredType.GetElementType());
718+
arrayConstructorDrawer.Draw();
719+
if(position.HasValue ? GUI.Button(position.Value, "Create Array") : GUILayout.Button("Create Array")) {
720+
Value = arrayConstructorDrawer.ToArray();
721+
arrayConstructorDrawer.Dispose();
722+
arrayConstructorDrawer = null;
723+
grabValueMode = 0;
724+
}
725+
if(!position.HasValue) EditorGUILayout.EndVertical();
726+
}
727+
659728
private void ShowMenu(Rect position) {
660729
var menu = new GenericMenu();
661730
if(castableTypes.Count > 1)
@@ -669,9 +738,14 @@ private void ShowMenu(Rect position) {
669738
if(!allowReferenceMode)
670739
menu.AddItem(new GUIContent("Mode/By Value"), grabValueMode == 0, GrabValueMode, 0);
671740
menu.AddItem(new GUIContent("Mode/From Component"), grabValueMode == 1, GrabValueMode, 1);
672-
if(currentType == PropertyType.Unknown) {
673-
menu.AddItem(new GUIContent("Mode/Construct"), grabValueMode == 2, GrabValueMode, 2);
674-
menu.AddItem(new GUIContent("Mode/From Opened Inspectors"), grabValueMode == 3, GrabValueMode, 3);
741+
switch(currentType) {
742+
case PropertyType.Array:
743+
menu.AddItem(new GUIContent("Mode/Construct"), grabValueMode == 4, GrabValueMode, 4);
744+
break;
745+
case PropertyType.Unknown:
746+
menu.AddItem(new GUIContent("Mode/Construct"), grabValueMode == 2, GrabValueMode, 2);
747+
menu.AddItem(new GUIContent("Mode/From Opened Inspectors"), grabValueMode == 3, GrabValueMode, 3);
748+
break;
675749
}
676750
}
677751
if(currentType == PropertyType.Enum)

Editor/UInspectorPlus/TypeInspectorDrawer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public TypeInspectorDrawer(object target, Type targetType, bool shown, bool show
99
}
1010

1111
protected override void Draw(bool readOnly) {
12-
if(GUILayout.Button(string.Format("Inspect Static Members of {0}...", target)))
12+
if(target != null && GUILayout.Button(string.Format("Inspect Static Members of {0}...", target)))
1313
InspectorChildWindow.OpenStatic(target as Type, true, allowPrivate, false, true, false, null);
1414
base.Draw(readOnly);
1515
}

0 commit comments

Comments
 (0)