/// <summary> /// Draws the specified object. /// </summary> /// <param name="guiContent">The GUIContent to draw with the associated object.</param> /// <param name="type">The type of object to draw.</param> /// <param name="value">The value of the object.</param> /// <param name="name">The name of the object being drawn.</param> /// <param name="hashPrefix">The prefix of the hash from the parent class. This value will prevent collisions with similarly named objects.</param> /// <param name="valuePositionMap">A map between the value hash and the position within the positions array.</param> /// <param name="serialization">The serialized data.</param> /// <param name="fieldProperty">A reference to the field or property that is being drawn.</param> /// <param name="drawFields">Should the fields be drawn? If false the properties will be drawn.</param> /// <returns>The drawn object.</returns> private static object DrawSingleObject(GUIContent guiContent, Type type, object value, string name, int hashPrefix, Dictionary <int, int> valuePositionMap, Serialization serialization, object fieldProperty, bool drawFields) { if (type == typeof(int)) { return(EditorGUILayout.IntField(guiContent, (int)value)); } if (type == typeof(float)) { // The range attribute may be used instead. if (drawFields) { var field = (System.Reflection.FieldInfo)fieldProperty; var rangeAttribute = field.GetCustomAttributes(typeof(RangeAttribute), false) as RangeAttribute[]; if (rangeAttribute != null && rangeAttribute.Length > 0) { return(EditorGUILayout.Slider(guiContent, (float)value, rangeAttribute[0].min, rangeAttribute[0].max)); } } return(EditorGUILayout.FloatField(guiContent, (float)value)); } if (type == typeof(double)) { return(EditorGUILayout.FloatField(guiContent, Convert.ToSingle((double)value))); } if (type == typeof(long)) { return((long)EditorGUILayout.IntField(guiContent, Convert.ToInt32((long)value))); } if (type == typeof(bool)) { return(EditorGUILayout.Toggle(guiContent, (bool)value)); } if (type == typeof(string)) { return(EditorGUILayout.TextField(guiContent, (string)value)); } if (type == typeof(byte)) { return(Convert.ToByte(EditorGUILayout.IntField(guiContent, Convert.ToInt32(value)))); } if (type == typeof(Vector2)) { return(EditorGUILayout.Vector2Field(guiContent, (Vector2)value)); } if (type == typeof(Vector3)) { return(EditorGUILayout.Vector3Field(guiContent, (Vector3)value)); } if (type == typeof(Vector4)) { return(EditorGUILayout.Vector4Field(guiContent, (Vector4)value)); } if (type == typeof(Quaternion)) { var quaternion = (Quaternion)value; var vectorValue = Vector4.zero; vectorValue.Set(quaternion.x, quaternion.y, quaternion.z, quaternion.w); vectorValue = EditorGUILayout.Vector4Field(name, vectorValue); quaternion.Set(vectorValue.x, vectorValue.y, vectorValue.z, vectorValue.w); return(quaternion); } if (type == typeof(Color)) { return(EditorGUILayout.ColorField(guiContent, (Color)value)); } if (type == typeof(Rect)) { return(EditorGUILayout.RectField(guiContent, (Rect)value)); } if (type == typeof(Matrix4x4)) { var matrix = (Matrix4x4)value; if (InspectorUtility.Foldout(value, guiContent)) { EditorGUI.indentLevel++; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { matrix[i, j] = EditorGUILayout.FloatField("E" + i.ToString() + j.ToString(), matrix[i, j]); } } EditorGUI.indentLevel--; } return(matrix); } if (type == typeof(AnimationCurve)) { if (value == null) { value = AnimationCurve.EaseInOut(0, 0, 1, 1); GUI.changed = true; } return(EditorGUILayout.CurveField(guiContent, (AnimationCurve)value)); } if (type == typeof(LayerMask)) { return(DrawLayerMask(guiContent, (LayerMask)value)); } if (type.IsEnum) { if (type.IsDefined(typeof(FlagsAttribute), true)) { return(EditorGUILayout.MaskField(guiContent, (int)value, Enum.GetNames(type))); } return(EditorGUILayout.EnumPopup(guiContent, (Enum)Enum.ToObject(type, value))); } if (typeof(UnityEngine.Object).IsAssignableFrom(type)) { return(EditorGUILayout.ObjectField(guiContent, (UnityEngine.Object)value, type, true)); } if (type.IsClass || (type.IsValueType && !type.IsPrimitive)) // Classes and structs. { if (typeof(Delegate).IsAssignableFrom(type)) // Delegates are not supported. { return(null); } if (s_DrawnObjects == null) { s_DrawnObjects = new HashSet <int>(); } // Do not endlessly loop on objects that have already been drawn. var hash = name.GetHashCode(); if (s_DrawnObjects.Contains(hash)) { return(null); } else { try { // Unity may throw an exception so catch it to clean up. s_DrawnObjects.Add(hash); GUILayout.BeginVertical(); if (value == null) { value = Activator.CreateInstance(type); GUI.changed = true; } if (InspectorUtility.Foldout(value, guiContent)) { EditorGUI.indentLevel++; var inspectorDrawer = InspectorDrawerUtility.InspectorDrawerForType(type); if (inspectorDrawer != null) { inspectorDrawer.OnInspectorGUI(value, null); } else if (drawFields) { value = DrawFields(value, true, hashPrefix + Serialization.StringHash(type.FullName) + Serialization.StringHash(name)); } else { value = DrawProperties(type, value, hashPrefix + Serialization.StringHash(type.FullName) + Serialization.StringHash(name), valuePositionMap, serialization, MemberVisibility.Public, null, null); } EditorGUI.indentLevel--; } GUILayout.EndVertical(); s_DrawnObjects.Remove(hash); return(value); } catch (Exception /*e*/) { // Clean up any exceptions. EditorGUI.indentLevel--; GUILayout.EndVertical(); s_DrawnObjects.Remove(hash); return(null); } } } Debug.LogWarning("Warning: unsupported value type: " + type); return(null); }
/// <summary> /// Draws the specified array object. /// </summary> /// <param name="guiContent">The GUIContent to draw with the associated object.</param> /// <param name="type">The type of object to draw.</param> /// <param name="parent">The parent of the value.</param> /// <param name="value">The value of the object.</param> /// <param name="name">The name of the object being drawn.</param> /// <param name="hashPrefix">The prefix of the hash from the parent class. This value will prevent collisions with similarly named objects.</param> /// <param name="valuePositionMap">A map between the value hash and the position within the positions array.</param> /// <param name="serialization">The serialized data.</param> /// <param name="fieldProperty">A reference to the field or property that is being drawn.</param> /// <param name="drawFields">Should the fields be drawn? If false the properties will be drawn.</param> /// <returns>The drawn object.</returns> private static object DrawArrayObject(GUIContent guiContent, Type type, object parent, object value, string name, int hashPrefix, Dictionary <int, int> valuePositionMap, Serialization serialization, object fieldProperty, bool drawFields) { // Arrays and lists operate differently when retrieving the element type. Type elementType; if (type.IsArray) { elementType = type.GetElementType(); } else { var baseFieldType = type; while (!baseFieldType.IsGenericType) { baseFieldType = baseFieldType.BaseType; } elementType = baseFieldType.GetGenericArguments()[0]; } // Create the list value if it is null. The list cannot be null. IList list; if (value == null) { if (type.IsGenericType || type.IsArray) { list = Activator.CreateInstance(typeof(List <>).MakeGenericType(elementType), true) as IList; } else { list = Activator.CreateInstance(type, true) as IList; } if (type.IsArray) { // Copy to an array so SetValue will accept the new value. var array = Array.CreateInstance(elementType, list.Count); list.CopyTo(array, 0); list = array; } } else { list = (IList)value; } EditorGUILayout.BeginVertical(); if (InspectorUtility.Foldout(list, guiContent)) { EditorGUI.indentLevel++; var hash = hashPrefix + (parent != null ? parent.GetHashCode() : 0) + Serialization.StringHash(type.FullName) + Serialization.StringHash(name); // s_EditingArray is static so s_FocusHash is necessary so the array that is being modified can be identified. if (s_EditingArray && s_FocusHash == hash && (s_KeybordControl != GUIUtility.keyboardControl || Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)) { s_EditingArray = false; var newArray = Array.CreateInstance(elementType, s_ArraySize); var origElement = -1; // Copy all of the old values to the new array. for (int i = 0; i < s_ArraySize; ++i) { if (i < list.Count) { origElement = i; } if (origElement == -1) { break; } var listValue = list[origElement]; if (i >= list.Count && !typeof(UnityEngine.Object).IsAssignableFrom(elementType) && !typeof(string).IsAssignableFrom(elementType)) { // Do not copy by reference. listValue = Activator.CreateInstance(list[origElement].GetType(), true); } newArray.SetValue(listValue, i); } if (type.IsArray) { list = (IList)newArray; } else { if (type.IsGenericType) { list = Activator.CreateInstance(typeof(List <>).MakeGenericType(elementType), true) as IList; } else { list = Activator.CreateInstance(type, true) as IList; } for (int i = 0; i < newArray.Length; ++i) { list.Add(newArray.GetValue(i)); } } // Mark the GUI as changed so the object will be serialized. GUI.changed = true; } var size = EditorGUILayout.IntField("Size", list.Count); if (size != list.Count) { if (!s_EditingArray) { s_EditingArray = true; s_KeybordControl = GUIUtility.keyboardControl; s_FocusHash = hash; } s_ArraySize = size; } hash = hashPrefix + Serialization.StringHash(type.FullName) + Serialization.StringHash(name); for (int i = 0; i < list.Count; ++i) { GUILayout.BeginHorizontal(); if (list[i] == null && !typeof(UnityEngine.Object).IsAssignableFrom(elementType) && elementType != typeof(string)) { list[i] = Activator.CreateInstance(elementType); } guiContent.text = "Element " + i; list[i] = DrawObject(guiContent, elementType, parent, list[i], name, hash / (i + 2), valuePositionMap, serialization, fieldProperty, drawFields); GUILayout.Space(6); GUILayout.EndHorizontal(); } EditorGUI.indentLevel--; } EditorGUILayout.EndVertical(); return(list); }