/// <summary> /// Adds the GUI header line which contains the label and add buttons. /// </summary> /// <param name="label">The visible label in the GUI</param> /// <param name="list">Needed to add a new item if count is 0</param> /// <param name="expanded"></param> /// <param name="lastIndent"></param> private static bool AddFoldOutListHeader <T>(string label, List <T> list, bool expanded, int lastIndent) { int buttonSpacer = 6; EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); expanded = PGEditorUtils.Foldout(expanded, label); if (!expanded) { // Don't add the '+' button when the contents are collapsed. Just quit. EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel = lastIndent; // Return to the last indent return(expanded); } EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(50)); // 1/2 the item button width GUILayout.Space(buttonSpacer); // Master add at end button. List items will insert if (GUILayout.Button(new GUIContent("+", "Click to add"), EditorStyles.toolbarButton)) { list.Add(default(T)); } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); return(expanded); }
public override void OnInspectorGUI() { var script = (SpawnPool)target; EditorGUI.indentLevel = 0; PGEditorUtils.LookLikeControls(); script.poolName = EditorGUILayout.TextField("Pool Name", script.poolName); script.matchPoolScale = EditorGUILayout.Toggle("Match Pool Scale", script.matchPoolScale); script.matchPoolLayer = EditorGUILayout.Toggle("Match Pool Layer", script.matchPoolLayer); script.dontReparent = EditorGUILayout.Toggle("Don't Reparent", script.dontReparent); script._dontDestroyOnLoad = EditorGUILayout.Toggle("Don't Destroy On Load", script._dontDestroyOnLoad); script.logMessages = EditorGUILayout.Toggle("Log Messages", script.logMessages); this.expandPrefabs = PGEditorUtils.SerializedObjFoldOutList <PrefabPool> ( "Per-Prefab Pool Options", script._perPrefabPoolOptions, this.expandPrefabs, ref script._editorListItemStates, true ); // Flag Unity to save the changes to to the prefab to disk if (GUI.changed) { EditorUtility.SetDirty(target); } }
public override void OnInspectorGUI() { var script = (PreRuntimePoolItem)target; EditorGUI.indentLevel = 0; PGEditorUtils.LookLikeControls(); script.poolName = EditorGUILayout.TextField("Pool Name", script.poolName); script.prefabName = EditorGUILayout.TextField("Prefab Name", script.prefabName); script.despawnOnStart = EditorGUILayout.Toggle("Despawn On Start", script.despawnOnStart); script.doNotReparent = EditorGUILayout.Toggle("Do Not Reparent", script.doNotReparent); // Flag Unity to save the changes to to the prefab to disk if (GUI.changed) { EditorUtility.SetDirty(target); } }
/// <summary> /// Adds a fold-out list GUI from a generic list of any serialized object type. /// Uses System.Reflection to add all fields for a passed serialized object /// instance. Handles most basic types including automatic naming like the /// inspector does by default /// /// Adds collapseBools (see docs below) /// </summary> /// <param name="label"> The field label</param> /// <param name="list">A generic List</param> /// <param name="expanded">A bool to determine the state of the primary fold-out</param> /// <param name="foldOutStates">Dictionary<object, bool> used to track list item states</param> /// <param name="collapseBools"> /// If true, bools on list items will collapse fields which follow them /// </param> /// <returns>The new foldout state from user input. Just like Unity's foldout</returns> public static bool SerializedObjFoldOutList <T>(string label, List <T> list, bool expanded, ref Dictionary <object, bool> foldOutStates, bool collapseBools) where T : new() { // Store the previous indent and return the flow to it at the end int indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; int buttonSpacer = 6; #region Header Foldout // Use a Horizanal space or the toolbar will extend to the left no matter what EditorGUILayout.BeginHorizontal(); EditorGUI.indentLevel = 0; // Space will handle this for the header GUILayout.Space(indent * 6); // Matches the content indent EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); expanded = Foldout(expanded, label); if (!expanded) { // Don't add the '+' button when the contents are collapsed. Just quit. EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel = indent; // Return to the last indent return(expanded); } // BUTTONS... EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(100)); // Add expand/collapse buttons if there are items in the list bool masterCollapse = false; bool masterExpand = false; if (list.Count > 0) { GUIContent content; var collapseIcon = '\u2261'.ToString(); content = new GUIContent(collapseIcon, "Click to collapse all"); masterCollapse = GUILayout.Button(content, EditorStyles.toolbarButton); var expandIcon = '\u25A1'.ToString(); content = new GUIContent(expandIcon, "Click to expand all"); masterExpand = GUILayout.Button(content, EditorStyles.toolbarButton); } else { GUILayout.FlexibleSpace(); } EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(50)); // A little space between button groups GUILayout.Space(buttonSpacer); // Main Add button if (GUILayout.Button(new GUIContent("+", "Click to add"), EditorStyles.toolbarButton)) { list.Add(new T()); } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); #endregion Header Foldout #region List Items // Use a for, instead of foreach, to avoid the iterator since we will be // be changing the loop in place when buttons are pressed. Even legal // changes can throw an error when changes are detected for (int i = 0; i < list.Count; i++) { T item = list[i]; #region Section Header // If there is a field with the name 'name' use it for our label string itemLabel = PGEditorUtils.GetSerializedObjFieldName <T>(item); if (itemLabel == "") { itemLabel = string.Format("Element {0}", i); } // Get the foldout state. // If this item is new, add it too (singleton) // Singleton works better than multiple Add() calls because we can do // it all at once, and in one place. bool foldOutState; if (!foldOutStates.TryGetValue(item, out foldOutState)) { foldOutStates[item] = true; foldOutState = true; } // Force states if master buttons were pressed if (masterCollapse) { foldOutState = false; } if (masterExpand) { foldOutState = true; } // Use a Horizanal space or the toolbar will extend to the start no matter what EditorGUILayout.BeginHorizontal(); EditorGUI.indentLevel = 0; // Space will handle this for the header GUILayout.Space((indent + 3) * 6); // Matches the content indent EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); // Display foldout with current state foldOutState = Foldout(foldOutState, itemLabel); foldOutStates[item] = foldOutState; // Used again below LIST_BUTTONS listButtonPressed = AddFoldOutListItemButtons(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); #endregion Section Header // If folded out, display all serialized fields if (foldOutState == true) { EditorGUI.indentLevel = indent + 3; // Display Fields for the list instance PGEditorUtils.SerializedObjectFields <T>(item, collapseBools); GUILayout.Space(2); } #region Process List Changes // Don't allow 'up' presses for the first list item switch (listButtonPressed) { case LIST_BUTTONS.None: // Nothing was pressed, do nothing break; case LIST_BUTTONS.Up: if (i > 0) { T shiftItem = list[i]; list.RemoveAt(i); list.Insert(i - 1, shiftItem); } break; case LIST_BUTTONS.Down: // Don't allow 'down' presses for the last list item if (i + 1 < list.Count) { T shiftItem = list[i]; list.RemoveAt(i); list.Insert(i + 1, shiftItem); } break; case LIST_BUTTONS.Remove: list.RemoveAt(i); foldOutStates.Remove(item); // Clean-up break; case LIST_BUTTONS.Add: list.Insert(i, new T()); break; } #endregion Process List Changes } #endregion List Items EditorGUI.indentLevel = indent; return(expanded); }