Draw inspector of array elements?

Hello community.

The short version is I wish to draw custom inspectors for array elements within the Unity editor. The long version is this:

I am playing around with PropertyDrawer and CustomEditor classes for improving my inspectors in the editor.

I have created custom .asset files from ScriptableObjects as I want to use the .asset files as configurations files as in this post:
http://www.jacobpennock.com/Blog/?p=670

First I create the code for the ScriptableObject:

/** Base class */
using UnityEngine;
using System.Collections;

public abstract class Decorator : ScriptableObject 
{
}

/** Derived class (value object) */
using UnityEngine;
using System.Collections;

[System.Serializable]
public class DcRigidBody : Decorator
{
	public bool freezeVertical		= false;
	public bool freezeHorizontal	= false;
	public bool freezeRotation	= false;
	public float mass			= 1.0f;
	public float drag			= 0.0f;
	public float angularDrag		= 0.0f;
	[Compact]
	public Vector3 constantForce	= Vector3.zero;
	public PhysicMaterial material	= null;
}

I turn the script into an .asset file and name the .asset file “RigidBody (falling)”. It shows up in the inspector like this:

Inspector A

alt text

I then create a second ScriptableObject .asset that contains an array of of the first type of assets:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Decorated : ScriptableObject 
{
	public List<Decorator> decorators;
}

I name the .asset file "Matter (falling) and it shows up in the inspector like this:

Inspector B

alt text

What I wish to do is to create an custom inspector for the array elements, so the inspector for asset A shows up when I expand the array in asset B. This is a mock-up of what I wish to achieve:

Inspector C (combines inspector A and inspector B - mock-up)

alt text

So far I have tried to create a custom editor for the ScriptableObject that contains the array. It look like this:

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(Decorated))]
public class DecoratedEditor : Editor 
{
    override public void OnInspectorGUI () 
    {
	    Decorated decorated = target as Decorated;
	
	    EditorGUIUtility.LookLikeControls();
   	    DrawDefaultInspector();
	
	    foreach( Decorator d in decorated.decorators )
   	    {
		    Debug.Log( d.ToString() );
	    }
    }
}

This draws Inspector A and then output the array elements to the console. What I want to do is call something like DrawDefaultInspector() for each array element and let it all render in the same inspector so i end up with the mocked-up Inspector C, but I can’t figure out how to do it?

Any advices?

Hi.

I came up with a solution using reflection to inspect the array / List<> elements and draw an appropriate GUI. This is my initial (untested version) - screenshot below:

alt text

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.Reflection;

[CustomEditor(typeof(Decorated))]
public class DecoratedEditor : Editor 
{
	// properties
	Object of = null;
	
    override public void OnInspectorGUI () 
	{
		// DrawDefaultInspector();

		// helper vars
		Decorated decorated = target as Decorated;
		List<Decorator> decorators = decorated.decorators;
		
		// create add button
		EditorGUILayout.BeginHorizontal();
		bool addButton = GUILayout.Button("Add", GUILayout.Width(70.0f));
		if(addButton)
		{
			if(of != null)
			{
				decorators.Add(of as Decorator);
				of = null;
			}
		}
		of = EditorGUILayout.ObjectField(of, typeof(Decorator), false);
		EditorGUILayout.EndHorizontal();		
		EditorGUILayout.Separator();
		
		// draw inspectors for each element
		foreach( Decorator decorator in decorators )
		{
			// title bar for decorator
			EditorGUIUtility.LookLikeControls();
			EditorGUILayout.Separator();
			EditorGUILayout.BeginHorizontal();

			// create remove button
			bool removeButton = GUILayout.Button("Remove", GUILayout.Width(70.0f));
			if(removeButton)
			{
				decorators.Remove(decorator);
				return;
			}
			
			// object selector
			object df = EditorGUILayout.ObjectField(decorator, typeof(Decorator), false);
			if(df != decorator)
			{
				int index = decorators.IndexOf(decorator);
				decorators[index] = df as Decorator;
			}
			
			EditorGUILayout.EndHorizontal();
			EditorGUIUtility.LookLikeInspector();

			// parse fields using reflection
			FieldInfo[] info = decorator.GetType().GetFields();
			
			foreach(FieldInfo field in info )
			{
				// handle bool
				if(field.FieldType == typeof(System.Boolean))
				{
					bool b = (bool)field.GetValue(decorator);
					bool bf = EditorGUILayout.Toggle(field.Name, b);
					field.SetValue(decorator, bf);
				}
				
				// handle float
				if(field.FieldType == typeof(System.Single))
				{
					float f = (float)field.GetValue(decorator);
					float ff = EditorGUILayout.FloatField(field.Name, f);
					field.SetValue(decorator, ff);
				}
				
				// handle Vector3
				if(field.FieldType == typeof(UnityEngine.Vector3))
				{
					Vector3 v = (Vector3)field.GetValue(decorator);
					Vector3 vf = EditorGUILayout.Vector3Field(field.Name, v);
					field.SetValue(decorator, vf);
				}
			}
			
			// store changes
			if(GUI.changed)
			{
				EditorUtility.SetDirty(decorator);
			}
			
    	}
	}
}