Nested Selection Grid?

I want to make a GUI list that I can expand and contract, like this: Nested List.

I can’t think of how to go about it, though. I have an array for the first level, and arrays for the sub-columns, and arrays for a sub-sub-column, but I can’t figure out how to accept a random number of each and expand and contract. Any suggestions?

The Editor GUI has a Foldout control; you’d have to replicate it in-game with a clickable icon+label.

Expandable GUI is easiest to accomplish with GUILayout:

[pseudocode]

GUILayout.BeginVertical();
foreach button {
  button.open = GUIUtils.Foldout(button.name);
  if ( button.open ) {
    GUIUtils.BeginIndent(); // see below snippet
    // display contents of the button
    GUIUtils.EndIndent();
  }
} 
GUILayout.EndVertical();

I actually wrote a fully-clickable foldout control because I hate clicking the triangle:

(This is from my GUIUtils.cs file, comment out the (FontStyle)1 bit if you don’t want bold text)

	/* These functions begin and end a horizontal indentation */
	public static void BeginIndent(string style) { GUILayout.BeginHorizontal(); GUILayout.Space(20); GUILayout.BeginVertical(style); }
	public static void BeginIndent() { BeginIndent(""); }
	public static void EndIndent() { GUILayout.EndVertical(); GUILayout.EndHorizontal(); }

/////////////////////////////////////////////////////////////////////////////
	/*
	* This section makes an EditorGUILayout.Foldout, except you can actually click anywhere on the word to open it
	* instead of having to click on the teeny-tiny triangle.
	* 
	* ... what the bananas, Unity
	*/ 
	private static GUIStyle openFoldoutStyle;
	private static GUIStyle closedFoldoutStyle;
	private static bool initted;
	
	private static void Init() {
		openFoldoutStyle = new GUIStyle( GUI.skin.FindStyle("Foldout") );
		openFoldoutStyle.fontStyle = (FontStyle)1;
		openFoldoutStyle.stretchHeight = true;
		closedFoldoutStyle = new GUIStyle( openFoldoutStyle );
		openFoldoutStyle.normal = openFoldoutStyle.onNormal;
		openFoldoutStyle.active = openFoldoutStyle.onActive;
		initted = true;
	}
	
	public static bool Foldout(bool open, string text ) { return Foldout(open, new GUIContent(text)); }
	public static bool Foldout(bool open, GUIContent text ) {
		if ( !initted ) Init();
		
		if ( open ) { 
			if ( GUILayout.Button( text, openFoldoutStyle, GUILayout.Height(20) ) ) {
				GUI.FocusControl ("");
				GUI.changed = false; // force change-checking group to take notice
				GUI.changed = true;
				return false;
			}
		} else {
			if ( GUILayout.Button( text, closedFoldoutStyle, GUILayout.Height(20) ) ) { 
				GUI.FocusControl ("");
				GUI.changed = false; // force change-checking to take notice
				GUI.changed = true;
				return true;
			}
		}
		return open;
	}