using UnityEngine; using UnityEditor; namespace NaughtyAttributes.Editor { [CustomPropertyDrawer(typeof(ExpandableAttribute))] public class ExpandablePropertyDrawer : PropertyDrawerBase { protected override float GetPropertyHeight_Internal(SerializedProperty property, GUIContent label) { if (property.objectReferenceValue == null) { return GetPropertyHeight(property); } System.Type propertyType = PropertyUtility.GetPropertyType(property); if (typeof(ScriptableObject).IsAssignableFrom(propertyType)) { ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject; if (scriptableObject == null) { return GetPropertyHeight(property); } if (property.isExpanded) { using (SerializedObject serializedObject = new SerializedObject(scriptableObject)) { float totalHeight = EditorGUIUtility.singleLineHeight; using (var iterator = serializedObject.GetIterator()) { if (iterator.NextVisible(true)) { do { SerializedProperty childProperty = serializedObject.FindProperty(iterator.name); if (childProperty.name.Equals("m_Script", System.StringComparison.Ordinal)) { continue; } bool visible = PropertyUtility.IsVisible(childProperty); if (!visible) { continue; } float height = GetPropertyHeight(childProperty); totalHeight += height; } while (iterator.NextVisible(false)); } } totalHeight += EditorGUIUtility.standardVerticalSpacing; return totalHeight; } } else { return GetPropertyHeight(property); } } else { return GetPropertyHeight(property) + GetHelpBoxHeight(); } } protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(rect, label, property); if (property.objectReferenceValue == null) { EditorGUI.PropertyField(rect, property, label, false); } else { System.Type propertyType = PropertyUtility.GetPropertyType(property); if (typeof(ScriptableObject).IsAssignableFrom(propertyType)) { ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject; if (scriptableObject == null) { EditorGUI.PropertyField(rect, property, label, false); } else { // Draw a foldout Rect foldoutRect = new Rect() { x = rect.x, y = rect.y, width = EditorGUIUtility.labelWidth, height = EditorGUIUtility.singleLineHeight }; property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label, toggleOnLabelClick: true); // Draw the scriptable object field Rect propertyRect = new Rect() { x = rect.x, y = rect.y, width = rect.width, height = EditorGUIUtility.singleLineHeight }; EditorGUI.PropertyField(propertyRect, property, label, false); property.serializedObject.ApplyModifiedProperties(); // Draw the child properties if (property.isExpanded) { DrawChildProperties(rect, property); } } } else { string message = $"{typeof(ExpandableAttribute).Name} can only be used on scriptable objects"; DrawDefaultPropertyAndHelpBox(rect, property, message, MessageType.Warning); } } EditorGUI.EndProperty(); } private void DrawChildProperties(Rect rect, SerializedProperty property) { ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject; if (scriptableObject == null) { return; } Rect boxRect = new Rect() { x = 0.0f, y = rect.y + EditorGUIUtility.singleLineHeight, width = rect.width * 2.0f, height = rect.height - EditorGUIUtility.singleLineHeight }; GUI.Box(boxRect, GUIContent.none); using (new EditorGUI.IndentLevelScope()) { SerializedObject serializedObject = new SerializedObject(scriptableObject); using (var iterator = serializedObject.GetIterator()) { float yOffset = EditorGUIUtility.singleLineHeight; if (iterator.NextVisible(true)) { do { SerializedProperty childProperty = serializedObject.FindProperty(iterator.name); if (childProperty.name.Equals("m_Script", System.StringComparison.Ordinal)) { continue; } bool visible = PropertyUtility.IsVisible(childProperty); if (!visible) { continue; } float childHeight = GetPropertyHeight(childProperty); Rect childRect = new Rect() { x = rect.x, y = rect.y + yOffset, width = rect.width, height = childHeight }; NaughtyEditorGUI.PropertyField(childRect, childProperty, true); yOffset += childHeight; } while (iterator.NextVisible(false)); } } serializedObject.ApplyModifiedProperties(); } } } }