Пример #1
0
    /// <summary>
    /// Adds a fold-out list GUI from a generic list of any serialized object type
    /// </summary>
    /// <param name="list">A generic List</param>
    /// <param name="expanded">A bool to determine the state of the primary fold-out</param>
    public static bool FoldOutTextList(string label, List <string> list, bool expanded)
    {
        // Store the previous indent and return the flow to it at the end
        int indent = EditorGUI.indentLevel;

        EditorGUI.indentLevel = 0;

        // A copy of toolbarButton with left alignment for foldouts
        var foldoutStyle = new GUIStyle(EditorStyles.toolbarButton);

        foldoutStyle.alignment = TextAnchor.MiddleLeft;

        expanded = AddFoldOutListHeader <string>(label, list, expanded, indent);

        // START. Will consist of one row with two columns.
        //        The second column has the content
        EditorGUILayout.BeginHorizontal();

        // SPACER COLUMN / INDENT
        EditorGUILayout.BeginVertical();
        EditorGUILayout.BeginHorizontal(GUILayout.MinWidth((indent + 3) * 9));
        GUILayout.FlexibleSpace();
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.EndVertical();

        // CONTENT COLUMN...
        EditorGUILayout.BeginVertical();

        // 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++)
        {
            string item = list[i];

            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);

            // FIELD...
            if (item == null)
            {
                item = "";
            }
            list[i] = EditorGUILayout.TextField(item);

            LIST_BUTTONS listButtonPressed = AddFoldOutListItemButtons();
            EditorGUILayout.EndHorizontal();
            GUILayout.Space(2);
            UpdateFoldOutListOnButtonPressed <string>(list, i, listButtonPressed);
        }

        EditorGUILayout.EndVertical();

        EditorGUILayout.EndHorizontal();

        EditorGUI.indentLevel = indent;

        return(expanded);
    }
Пример #2
0
    /// <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);
    }
Пример #3
0
    /// <summary>
    /// Adds a fold-out list GUI from a generic list of any serialized object type
    /// </summary>
    /// <param name="list">A generic List</param>
    /// <param name="expanded">A bool to determine the state of the primary fold-out</param>
    public static bool FoldOutObjList <T>(string label, List <T> list, bool expanded) where T : UnityEngine.Object
    {
        // Store the previous indent and return the flow to it at the end
        int indent = EditorGUI.indentLevel;

        EditorGUI.indentLevel = 0;  // Space will handle this for the header

        // A copy of toolbarButton with left alignment for foldouts
        var foldoutStyle = new GUIStyle(EditorStyles.toolbarButton);

        foldoutStyle.alignment = TextAnchor.MiddleLeft;

        if (!AddFoldOutListHeader <T>(label, list, expanded, indent))
        {
            return(false);
        }


        // 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];

            EditorGUILayout.BeginHorizontal();

            GUILayout.Space((indent + 3) * 6); // Matches the content indent

            // OBJECT FIELD...
            // Count is always in sync bec
            T fieldVal = (T)EditorGUILayout.ObjectField(item, typeof(T), true);


            // This is weird but have to replace the item with the new value, can't
            //   find a way to set in-place in a more stable way
            list.RemoveAt(i);
            list.Insert(i, fieldVal);

            LIST_BUTTONS listButtonPressed = AddFoldOutListItemButtons();

            EditorGUILayout.EndHorizontal();

            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);
                break;

            case LIST_BUTTONS.Add:
                list.Insert(i, null);
                break;
            }
            #endregion Process List Changes
        }

        EditorGUI.indentLevel = indent;

        return(true);
    }
Пример #4
0
    /// <summary>
    /// Used by basic foldout lists to process any list item button presses which will alter
    /// the order or members of the ist
    /// </summary>
    /// <param name="listButtonPressed"></param>
    private static void UpdateFoldOutListOnButtonPressed <T>(List <T> list, int currentIndex, LIST_BUTTONS listButtonPressed)
    {
        // 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 (currentIndex > 0)
            {
                T shiftItem = list[currentIndex];
                list.RemoveAt(currentIndex);
                list.Insert(currentIndex - 1, shiftItem);
            }
            break;

        case LIST_BUTTONS.Down:
            // Don't allow 'down' presses for the last list item
            if (currentIndex + 1 < list.Count)
            {
                T shiftItem = list[currentIndex];
                list.RemoveAt(currentIndex);
                list.Insert(currentIndex + 1, shiftItem);
            }
            break;

        case LIST_BUTTONS.Remove:
            list.RemoveAt(currentIndex);
            break;

        case LIST_BUTTONS.Add:
            list.Insert(currentIndex, default(T));
            break;
        }
    }