//... void OnGUI() { if (targetType == null) { return; } var e = Event.current; if (e.type == EventType.ValidateCommand && e.commandName == "UndoRedoPerformed") { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; e.Use(); return; } GUILayout.Space(10); GUILayout.Label(string.Format("<size=14><b>{0}</b></size>", targetType.FriendlyName()), Styles.centerLabel); EditorUtils.Separator(); GUILayout.Space(10); scrollPos = GUILayout.BeginScrollView(scrollPos); var serializationInfo = new InspectedFieldInfo(unityObjectContext, null, null, null); var oldValue = read(); var newValue = EditorUtils.ReflectedFieldInspector(friendlyTitle, oldValue, targetType, serializationInfo); if (!Equals(oldValue, newValue) || GUI.changed) { write(newValue); } GUILayout.EndScrollView(); willRepaint = true; }
///<summary>Show an automatic editor GUI inspector for target object, taking into account drawer attributes</summary> public static void ReflectedObjectInspector(object target, UnityObject unityObjectContext) { if (target == null) { return; } var fields = target.GetType().RTGetFields(); for (var i = 0; i < fields.Length; i++) { var field = fields[i]; //no statics if (field.IsStatic) { continue; } //hide type altogether? if (field.FieldType.RTIsDefined(typeof(HideInInspector), true)) { continue; } //inspect only public fields or private fields with the [ExposeField] attribute if (field.IsPublic || field.RTIsDefined(typeof(ExposeFieldAttribute), true)) { var attributes = field.RTGetAllAttributes(); //Hide field? if (attributes.Any(a => a is HideInInspector)) { continue; } var serializationInfo = new InspectedFieldInfo(unityObjectContext, field, target, attributes); var currentValue = field.GetValue(target); var newValue = ReflectedFieldInspector(field.Name, currentValue, field.FieldType, serializationInfo); var changed = !object.Equals(newValue, currentValue); if (changed) { UndoUtility.RecordObject(unityObjectContext, field.Name); } if (changed || field.FieldType.IsValueType) { field.SetValue(target, newValue); } if (changed) { UndoUtility.SetDirty(unityObjectContext); } } } }
///Begin GUI object IObjectDrawer.DrawGUI(GUIContent content, object instance, InspectedFieldInfo info) { this.content = content; this.instance = (T)instance; this.info = info; this.attributes = info.attributes != null?info.attributes.OfType <DrawerAttribute>().OrderBy(a => a.priority).ToArray() : null; this.attributeIndex = -1; var result = (this as IObjectDrawer).MoveNextDrawer(); // //flush references this.info = default(InspectedFieldInfo); this.content = null; this.instance = default(T); this.attributes = null; return(result); }
///A IDictionary editor public static IDictionary DictionaryEditor(GUIContent content, IDictionary dict, Type dictType, InspectedFieldInfo info) { var keyType = dictType.RTGetGenericArguments()[0]; var valueType = dictType.RTGetGenericArguments()[1]; if (object.Equals(dict, null)) { GUILayout.Label("Null Dictionary"); return(dict); } if (!CachedFoldout(dictType, content)) { return(dict); } GUILayout.BeginVertical(); var keys = dict.Keys.Cast <object>().ToList(); var values = dict.Values.Cast <object>().ToList(); if (GUILayout.Button("Add Element")) { if (!typeof(UnityObject).IsAssignableFrom(keyType)) { object newKey = null; if (keyType == typeof(string)) { newKey = string.Empty; } else { newKey = Activator.CreateInstance(keyType); } if (dict.Contains(newKey)) { Logger.LogWarning(string.Format("Key '{0}' already exists in Dictionary", newKey.ToString()), "Editor"); return(dict); } keys.Add(newKey); } else { Logger.LogWarning("Can't add a 'null' Dictionary Key", "Editor"); return(dict); } values.Add(valueType.IsValueType ? Activator.CreateInstance(valueType) : null); } //clear before reconstruct dict.Clear(); for (var i = 0; i < keys.Count; i++) { GUILayout.BeginHorizontal("box"); GUILayout.Box("", GUILayout.Width(6), GUILayout.Height(35)); GUILayout.BeginVertical(); keys[i] = ReflectedFieldInspector("K:", keys[i], keyType, info); values[i] = ReflectedFieldInspector("V:", values[i], valueType, info); GUILayout.EndVertical(); if (GUILayout.Button("X", GUILayout.Width(18), GUILayout.Height(34))) { keys.RemoveAt(i); values.RemoveAt(i); } GUILayout.EndHorizontal(); try { dict.Add(keys[i], values[i]); } catch { Logger.Log("Dictionary Key removed due to duplicate found", "Editor"); } } Separator(); GUILayout.EndVertical(); return(dict); }
///An IList editor (List<T> and Arrays) public static IList ListEditor(GUIContent content, IList list, Type listType, InspectedFieldInfo info) { var argType = listType.GetEnumerableElementType(); if (argType == null) { return(list); } if (object.Equals(list, null)) { GUILayout.Label("Null List"); return(list); } if (!CachedFoldout(listType, content)) { return(list); } GUILayout.BeginVertical(); EditorGUI.indentLevel++; var options = new ReorderableListOptions(); options.allowAdd = true; options.allowRemove = true; options.unityObjectContext = info.unityObjectContext; list = EditorUtils.ReorderableList(list, options, (i, r) => { list[i] = ReflectedFieldInspector("Element " + i, list[i], argType, info); }); EditorGUI.indentLevel--; Separator(); GUILayout.EndVertical(); return(list); }
///Begin GUI object IAttributeDrawer.DrawGUI(IObjectDrawer objectDrawer, GUIContent content, object instance, DrawerAttribute attribute, InspectedFieldInfo info) { this.objectDrawer = objectDrawer; this.content = content; this.instance = instance; this.attribute = (T)attribute; this.info = info; var result = OnGUI(content, instance); //flush references this.info = default(InspectedFieldInfo); this.content = null; this.instance = null; this.attribute = null; this.objectDrawer = null; return(result); }
///<summary>Draws an Editor field for object of type directly WITH taking into acount object drawers and drawer attributes</summary> public static object ReflectedFieldInspector(string name, object value, Type t, InspectedFieldInfo info) { var content = GetTempContent(name.SplitCamelCase()); if (info.attributes != null) { //Create proper GUIContent var nameAtt = info.attributes.FirstOrDefault(a => a is NameAttribute) as NameAttribute; if (nameAtt != null) { content.text = nameAtt.name; } var tooltipAtt = info.attributes.FirstOrDefault(a => a is TooltipAttribute) as TooltipAttribute; if (tooltipAtt != null) { content.tooltip = tooltipAtt.tooltip; } } return(ReflectedFieldInspector(content, value, t, info)); }
///<summary>Draws an Editor field for object of type directly WITHOUT taking into acount object drawers and drawer attributes unless provided</summary> public static object DrawEditorFieldDirect(GUIContent content, object value, Type t, InspectedFieldInfo info) { ///---------------------------------------------------------------------------------------------- bool handled; var newValue = DirectFieldControl(content, value, t, info.unityObjectContext, info.attributes, out handled); var changed = !object.Equals(newValue, value); if (changed) { UndoUtility.RecordObjectComplete(info.unityObjectContext, content.text + "Field Change"); } value = newValue; if (changed) { UndoUtility.SetDirty(info.unityObjectContext); } if (handled) { return(value); } ///---------------------------------------------------------------------------------------------- if (typeof(IList).IsAssignableFrom(t)) { return(ListEditor(content, (IList)value, t, info)); } if (typeof(IDictionary).IsAssignableFrom(t)) { return(DictionaryEditor(content, (IDictionary)value, t, info)); } //show nested class members recursively, avoid all collections not handles above manually if (value != null && (t.IsClass || t.IsValueType) && !typeof(ICollection).IsAssignableFrom(t)) { if (EditorGUI.indentLevel <= 8) { if (!CachedFoldout(t, content)) { return(value); } EditorGUI.indentLevel++; ReflectedObjectInspector(value, info.unityObjectContext); EditorGUI.indentLevel--; } } else { EditorGUILayout.LabelField(content, GetTempContent(string.Format("NonInspectable ({0})", t.FriendlyName()))); } return(value); }
///<summary>Draws an Editor field for object of type directly WITH taking into acount object drawers and drawer attributes</summary> public static object ReflectedFieldInspector(GUIContent content, object value, Type t, InspectedFieldInfo info) { if (t == null) { GUILayout.Label("NO TYPE PROVIDED!"); return(value); } //Use drawers var objectDrawer = PropertyDrawerFactory.GetObjectDrawer(t); var newValue = objectDrawer.DrawGUI(content, value, info); var changed = !object.Equals(newValue, value); if (changed) { UndoUtility.RecordObjectComplete(info.unityObjectContext, content.text + "Field Change"); } value = newValue; if (changed) { UndoUtility.SetDirty(info.unityObjectContext); } return(value); }
///<summary>An IList editor (List<T> and Arrays)</summary> public static IList ListEditor(GUIContent content, IList list, Type listType, InspectedFieldInfo info) { var optionsAtt = info.attributes?.FirstOrDefault(x => x is ListInspectorOptionAttribute) as ListInspectorOptionAttribute; var argType = listType.GetEnumerableElementType(); if (argType == null) { return(list); } if (object.Equals(list, null)) { GUILayout.Label("Null List"); return(list); } if (optionsAtt == null || optionsAtt.showFoldout) { if (!CachedFoldout(listType, content)) { return(list); } } else { GUILayout.Label(content.text); } GUILayout.BeginVertical(); EditorGUI.indentLevel++; var options = new ReorderableListOptions(); options.allowAdd = optionsAtt == null || optionsAtt.allowAdd; options.allowRemove = optionsAtt == null || optionsAtt.allowRemove; options.unityObjectContext = info.unityObjectContext; list = EditorUtils.ReorderableList(list, options, (i, r) => { list[i] = ReflectedFieldInspector("Element " + i, list[i], argType, info); }); EditorGUI.indentLevel--; Separator(); GUILayout.EndVertical(); return(list); }