Feature Request: dynamic TabGroup for lists or customizable page size in ListDrawerSettings

Issue #55 resolved
Ivan Wang
created an issue

I like tabs, but I'd like them even better if you could dynamically create one tab for each element of a list.

Alternatively, you could add an extra option to ListDrawerSettings for the number of elements per page. This way, I could fake the effect by setting the page size to 1 (functionally giving me a "tabbed" list).

Comments (4)

  1. Bjarke Elias Clauson-Kaas ├śrrild

    Haha, Never thought of that before, clever. I'll add that to the list drawer settings.

    We actually have a [TabList] attribute in our prototyping folder which we used internally for some time. But I would much rather want a general solution that solves it for all group drawers. Just haven't thought of one yet ­čśÇ

    For now though, you could also create your own tab list drawer which could look something like this:

    _oJqEcwVEUwON482HGh8ix3w9qgJTyliAgGjqOcRfpRjs_0NI7NDTvwQlQAm1Y4PaDpuzwgAuaBzNpO7td3txd0Iq-_ZMIwlJNqsu6s4bO0F1kR3dMUjedqC16uBUu85.png

    public class MyComponent : MonoBehaviour
    {
        public MyType[] MyTypeList;
    }
    
    [Serializable]
    public class MyType
    {
        public string TabTitle;
        public string SomeField1;
        public string SomeField2;
        public string SomeField3;
    }
    
    [OdinDrawer]
    [DrawerPriority(0, 0, 2)]
    public class MyTypeDrawer<TList> : OdinValueDrawer<TList> where TList : IList<MyType>
    {
        protected override void DrawPropertyLayout(IPropertyValueEntry<TList> entry, GUIContent label)
        {
            var list = entry.SmartValue;
    
            if (list == null)
            {
                this.CallNextDrawer(entry, label);
                return;
            }
    
            // Draws a foldout to toggle the list in order to add, edit or remove tabs.
            var showList = entry.Property.Context.Get(this, "showList", false);
            showList.Value = SirenixEditorGUI.Foldout(showList.Value, "Edit List");
            if (SirenixEditorGUI.BeginFadeGroup(showList, showList.Value))
            {
                this.CallNextDrawer(entry, label);
            }
            SirenixEditorGUI.EndFadeGroup();
    
            // Draws the tabs
            var smallestSelectedListLength = entry.Property.Children.Count;
            var tabGroup = SirenixEditorGUI.CreateAnimatedTabGroup(UniqueDrawerKey.Create(entry, this));
    
            for (int i = 0; i < smallestSelectedListLength; i++)
            {
                tabGroup.RegisterTab(list[i].TabTitle ?? "Empty");
            }
    
            tabGroup.BeginGroup();
            for (int i = 0; i < smallestSelectedListLength; i++)
            {
                var tab = tabGroup.RegisterTab(list[i].TabTitle ?? "Empty");
                if (tab.BeginPage())
                {
                    entry.Property.Children[i].Draw(null);
    
                    // If you want to hide the MyType.TabTitle field. You can do something like this:
                    // var listElementProperty = entry.Property.Children[i];
                    // if (listElementProperty.ValueEntry.WeakSmartValue == null)
                    // {
                    //     listElementProperty.Draw(null);
                    // }
                    // else
                    // {
                    //     for (int j = 0; j < listElementProperty.Children.Count; j++)
                    //     {
                    //         if (listElementProperty.Children[j].Name != "TabTitle")
                    //         {
                    //             listElementProperty.Children[j].Draw();
                    //         }
                    //     }
                    // }
                }
                tab.EndPage();
            }
            tabGroup.EndGroup();
        }
    }
    
  2. Ivan Wang reporter

    Thanks for the detailed solution :) Is there a way to have add and remove buttons (just like the list header) instead of re-rendering the entire list in the foldout? I'd consult the documentation but it seems like it's still under construction...

  3. Bjarke Elias Clauson-Kaas ├śrrild

    You have access to insert and add via the entry.GetListValueEntryChanger() it will handle multi-selection, and resolve references and all that.

    Note that entry.GetListValueEntryChanger().AddListElement() takes an array of objects in order to make it work with multi-selection.

    So you would need to do something like:

    entry.GetListValueEntryChanger()
         .AddListElement(Enumerable.Repeat(valueToAdd, this.ListChanger.ValueCount).ToArray(), "Added values to the list");
    
  4. Log in to comment