Skip to content

Commit 60725fd

Browse files
committed
- Nested value editing is supported now
- Search function - Auto update - Minor bug fixes
1 parent b04c4f2 commit 60725fd

File tree

6 files changed

+439
-178
lines changed

6 files changed

+439
-178
lines changed

Assets/Script Tester/Editor/ComponentMethodDrawer.cs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace ScriptTester {
1111
class ComponentMethodDrawer:IReflectorDrawer {
12-
UnityEngine.Object component;
12+
object component;
1313
readonly List<ComponentMethod> methods = new List<ComponentMethod>();
1414
AnimBool showMethodOptions;
1515
AnimBool showMethodSelector;
@@ -21,8 +21,9 @@ class ComponentMethodDrawer:IReflectorDrawer {
2121
MethodPropertyDrawer[] parameters;
2222
MethodPropertyDrawer result;
2323
Exception thrownException;
24+
string filter;
2425
bool titleFolded = true, paramsFolded = true, resultFolded = true,
25-
drawHeader = true, privateFields = true;
26+
drawHeader = true, privateFields = true, obsolete = true;
2627

2728
public event Action OnRequireRedraw;
2829

@@ -49,7 +50,17 @@ public bool AllowPrivateFields {
4950
}
5051
set {
5152
privateFields = value;
52-
InitComponentMethods();
53+
InitComponentMethods(false);
54+
}
55+
}
56+
57+
public bool AllowObsolete {
58+
get {
59+
return obsolete;
60+
}
61+
set {
62+
obsolete = value;
63+
InitComponentMethods(false);
5364
}
5465
}
5566

@@ -70,14 +81,22 @@ public ComponentMethodDrawer() {
7081
showResultSelector.valueChanged.AddListener(RequireRedraw);
7182
}
7283

73-
public ComponentMethodDrawer(UnityEngine.Object target)
84+
public ComponentMethodDrawer(object target)
7485
: this() {
7586
component = target;
7687
drawHeader = false;
7788
showMethodSelector.value = true;
7889
InitComponentMethods();
7990
}
8091

92+
public string Filter {
93+
get { return filter; }
94+
set {
95+
filter = value;
96+
InitComponentMethods(false);
97+
}
98+
}
99+
81100
public void Call() {
82101
if(selectedMethod == null || component == null || parameters == null)
83102
return;
@@ -87,7 +106,7 @@ public void Call() {
87106
var returnData = selectedMethod.Invoke(component, requestData);
88107
result = selectedMethod.ReturnType == typeof(void) ?
89108
null :
90-
new MethodPropertyDrawer(selectedMethod.ReturnType, "Return data", returnData);
109+
new MethodPropertyDrawer(selectedMethod.ReturnType, "Return data", returnData, privateFields, obsolete);
91110
for(int i = 0; i < Math.Min(parameters.Length, requestData.Length); i++) {
92111
parameters[i].Value = requestData[i];
93112
if(parameters[i].ReferenceMode)
@@ -103,15 +122,15 @@ public void Call() {
103122
public void Draw() {
104123
if(drawHeader) {
105124
EditorGUI.BeginDisabledGroup(component == null);
106-
titleFolded = EditorGUILayout.InspectorTitlebar(titleFolded, component) || component == null;
125+
titleFolded = EditorGUILayout.InspectorTitlebar(titleFolded, component as UnityEngine.Object) || component == null;
107126
EditorGUI.EndDisabledGroup();
108127
}
109128
GUI.changed = false;
110129
if(component == null || titleFolded || !drawHeader) {
111130
if(drawHeader) {
112131
EditorGUI.indentLevel++;
113132
EditorGUILayout.BeginVertical();
114-
component = EditorGUILayout.ObjectField("Target", component, typeof(UnityEngine.Object), true);
133+
component = EditorGUILayout.ObjectField("Target", component as UnityEngine.Object, typeof(UnityEngine.Object), true);
115134
}
116135
if(component != null) {
117136
if(GUI.changed) {
@@ -135,17 +154,22 @@ public void Draw() {
135154
}
136155
}
137156

138-
void AddComponentMethod(UnityEngine.Object target) {
157+
void AddComponentMethod(object target) {
139158
BindingFlags flag = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
140159
if(privateFields)
141160
flag |= BindingFlags.NonPublic;
142-
methods.AddRange(component.GetType().GetMethods(flag).Select(m => new ComponentMethod {
143-
method = m,
144-
target = target
145-
}));
161+
methods.AddRange(
162+
target.GetType().GetMethods(flag)
163+
.Where(t => obsolete || !Attribute.IsDefined(t, typeof(ObsoleteAttribute)))
164+
.Where(t => string.IsNullOrEmpty(filter) || t.Name.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0)
165+
.Select(m => new ComponentMethod {
166+
method = m,
167+
target = target
168+
})
169+
);
146170
}
147171

148-
void InitComponentMethods() {
172+
void InitComponentMethods(bool resetIndex = true) {
149173
methods.Clear();
150174
AddComponentMethod(component);
151175
if(drawHeader) {
@@ -156,7 +180,7 @@ void InitComponentMethods() {
156180
methodNames = methods.Select(m => string.Format(
157181
"{0} ({1})/{2} ({3} parameters)",
158182
m.target.GetType().Name,
159-
m.target.GetInstanceID(),
183+
Helper.ObjIdOrHashCode(m.target),
160184
Helper.GetMemberName(m.method as MemberInfo),
161185
m.method.GetParameters().Length
162186
)).ToArray();
@@ -167,6 +191,11 @@ void InitComponentMethods() {
167191
m.method.GetParameters().Length
168192
)).ToArray();
169193
}
194+
if(!resetIndex && selectedMethod != null) {
195+
selectedMethodIndex = methods.FindIndex(m => m.method == selectedMethod);
196+
if(selectedMethodIndex >= 0)
197+
return;
198+
}
170199
selectedMethodIndex = -1;
171200
selectedMethod = null;
172201
parameterInfo = null;
@@ -182,7 +211,7 @@ void InitMethodParams() {
182211
parameters = new MethodPropertyDrawer[parameterInfo.Length];
183212
for(int i = 0; i < parameterInfo.Length; i++) {
184213
var info = parameterInfo[i];
185-
parameters[i] = new MethodPropertyDrawer(info.ParameterType, info.Name, info.IsOptional ? info.DefaultValue : null);
214+
parameters[i] = new MethodPropertyDrawer(info.ParameterType, info.Name, info.IsOptional ? info.DefaultValue : null, privateFields, obsolete);
186215
parameters[i].OnRequireRedraw += RequireRedraw;
187216
}
188217
result = null;

Assets/Script Tester/Editor/Helpers.cs

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,9 @@ enum PropertyType {
2929
Array
3030
}
3131

32-
class InspectorDrawer {
33-
public UnityEngine.Object target;
34-
public List<IReflectorDrawer> drawer;
35-
public bool shown;
36-
public bool isInternalType;
37-
public InspectorDrawer(UnityEngine.Object target) {
38-
this.target = target;
39-
this.drawer = new List<IReflectorDrawer>();
40-
}
41-
}
42-
4332
struct ComponentMethod {
4433
public MethodInfo method;
45-
public UnityEngine.Object target;
34+
public object target;
4635
}
4736

4837
struct ComponentFields {
@@ -54,6 +43,7 @@ struct ComponentFields {
5443
interface IReflectorDrawer {
5544
void Draw();
5645
bool AllowPrivateFields { get; set; }
46+
bool AllowObsolete { get; set; }
5747
bool Changed { get; }
5848
object Value { get; }
5949
MemberInfo Info { get; }
@@ -62,6 +52,7 @@ interface IReflectorDrawer {
6252

6353
public static class Helper {
6454
internal static readonly Dictionary<Type, PropertyType> propertyTypeMapper = new Dictionary<Type, PropertyType>();
55+
static double clickTime;
6556

6657
internal static void InitPropertyTypeMapper() {
6758
if(propertyTypeMapper.Count > 0)
@@ -114,7 +105,7 @@ internal static void ReadOnlyLabelField(string label, string value) {
114105
}
115106

116107
internal static Rect ScaleRect(Rect source,
117-
float xScale, float yScale, float widthScale, float heightScale,
108+
float xScale = 0, float yScale = 0, float widthScale = 1, float heightScale = 1,
118109
float offsetX = 0, float offsetY = 0, float offsetWidth = 0, float offsetHeight = 0) {
119110
return new Rect(
120111
source.x + source.width * xScale + offsetX,
@@ -282,6 +273,103 @@ static int MaskedEnumFieldPostProcess(int[] itemValues, int val, int maskVal, in
282273
return val;
283274
}
284275

276+
internal static string StringField(string label, string value, bool readOnly, params GUILayoutOption[] options) {
277+
int lines = CountLines(value);
278+
if(lines > 1) {
279+
var _opts = options.ToList();
280+
_opts.Add(GUILayout.Height(EditorGUIUtility.singleLineHeight * lines));
281+
_opts.Add(GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth));
282+
EditorGUILayout.BeginVertical();
283+
EditorGUILayout.PrefixLabel(label);
284+
if(readOnly)
285+
EditorGUILayout.SelectableLabel(value, EditorStyles.textArea, _opts.ToArray());
286+
else
287+
value = EditorGUILayout.TextArea(value, _opts.ToArray());
288+
EditorGUILayout.EndVertical();
289+
} else {
290+
if(readOnly) {
291+
var _opts = options.ToList();
292+
_opts.Add(GUILayout.Height(EditorGUIUtility.singleLineHeight));
293+
EditorGUILayout.BeginHorizontal();
294+
EditorGUILayout.PrefixLabel(label);
295+
EditorGUILayout.SelectableLabel(value, EditorStyles.textField, _opts.ToArray());
296+
EditorGUILayout.EndHorizontal();
297+
} else
298+
value = EditorGUILayout.TextField(label, value, options);
299+
}
300+
return value;
301+
}
302+
303+
internal static string StringField(Rect position, string label, string value, bool readOnly) {
304+
if(readOnly) {
305+
EditorGUI.SelectableLabel(position, value);
306+
} else {
307+
int lines = position.height <= EditorGUIUtility.singleLineHeight ? 1 : CountLines(value);
308+
if(lines > 1)
309+
EditorGUI.PrefixLabel(ScaleRect(position, heightScale: 0, offsetHeight: EditorGUIUtility.singleLineHeight), new GUIContent(label));
310+
value = lines > 1 ?
311+
EditorGUI.TextArea(ScaleRect(position, offsetY: EditorGUIUtility.singleLineHeight, offsetHeight: -EditorGUIUtility.singleLineHeight), value) :
312+
EditorGUI.TextField(position, label, value);
313+
}
314+
return value;
315+
}
316+
317+
internal static UnityEngine.Object ObjectField(string label, UnityEngine.Object value, Type objectType, bool allowScreenObjs, bool readOnly, params GUILayoutOption[] options) {
318+
if(!readOnly)
319+
return EditorGUILayout.ObjectField(label, value, objectType, allowScreenObjs, options);
320+
EditorGUILayout.BeginHorizontal();
321+
EditorGUILayout.PrefixLabel(label);
322+
var _opts = options.ToList();
323+
_opts.Add(GUILayout.Height(EditorGUIUtility.singleLineHeight));
324+
if(GUILayout.Button(EditorGUIUtility.ObjectContent(value, objectType), EditorStyles.objectField, _opts.ToArray()))
325+
ClickObject(value);
326+
EditorGUILayout.EndHorizontal();
327+
return value;
328+
}
329+
330+
internal static UnityEngine.Object ObjectField(Rect position, string label, UnityEngine.Object value, Type objectType, bool allowScreenObjs, bool readOnly) {
331+
if(!readOnly)
332+
return EditorGUI.ObjectField(position, label, value, objectType, allowScreenObjs);
333+
EditorGUI.PrefixLabel(ScaleRect(position, widthScale: 0.5F), new GUIContent(label));
334+
if(GUI.Button(ScaleRect(position, 0.5F, widthScale: 0.5F), EditorGUIUtility.ObjectContent(value, objectType), EditorStyles.objectField))
335+
ClickObject(value);
336+
return value;
337+
}
338+
339+
static void ClickObject(UnityEngine.Object obj) {
340+
var newClickTime = EditorApplication.timeSinceStartup;
341+
if(newClickTime - clickTime < 0.3 && obj != null)
342+
Selection.activeObject = obj;
343+
clickTime = newClickTime;
344+
EditorGUIUtility.PingObject(obj);
345+
}
346+
347+
static int CountLines(string str) {
348+
if(string.IsNullOrEmpty(str))
349+
return 1;
350+
int cursor = 0, count = 0, length = str.Length, i = -1;
351+
bool isCR = false;
352+
while(cursor < length) {
353+
i = str.IndexOf('\r', cursor);
354+
if(i >= 0) {
355+
count++;
356+
isCR = true;
357+
cursor = i + 1;
358+
continue;
359+
}
360+
i = str.IndexOf('\n', cursor);
361+
if(i >= 0) {
362+
if(!isCR || i != 0)
363+
count++;
364+
isCR = false;
365+
cursor = i + 1;
366+
continue;
367+
}
368+
break;
369+
}
370+
return Math.Max(1, count);
371+
}
372+
285373
internal static bool AssignValue(MemberInfo info, object target, object value) {
286374
try {
287375
var fieldInfo = info as FieldInfo;
@@ -298,6 +386,16 @@ internal static bool AssignValue(MemberInfo info, object target, object value) {
298386
return true;
299387
}
300388

389+
internal static bool IsReadOnly(MemberInfo info) {
390+
var fieldInfo = info as FieldInfo;
391+
if(fieldInfo != null)
392+
return fieldInfo.IsInitOnly || fieldInfo.IsLiteral;
393+
var propertyInfo = info as PropertyInfo;
394+
if(propertyInfo != null)
395+
return !propertyInfo.CanWrite;
396+
return false;
397+
}
398+
301399
internal static bool FetchValue(MemberInfo info, object target, out object value) {
302400
value = null;
303401
try {
@@ -316,6 +414,19 @@ internal static bool FetchValue(MemberInfo info, object target, out object value
316414
return true;
317415
}
318416

417+
internal static int ObjIdOrHashCode(object obj) {
418+
var unityObj = obj as UnityEngine.Object;
419+
if (unityObj != null)
420+
return unityObj.GetInstanceID();
421+
if (obj != null)
422+
return obj.GetHashCode();
423+
return 0;
424+
}
425+
426+
internal static GUIStyle GetGUIStyle(string styleName) {
427+
return GUI.skin.FindStyle(styleName) ?? EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle(styleName);
428+
}
429+
319430
[MenuItem("Window/Script Tester/Inspector+")]
320431
public static void ShowInspectorPlus() {
321432
EditorWindow.GetWindow(typeof(InspectorPlus));

0 commit comments

Comments
 (0)