title: How do I display a list or array pullout in a Unity Editor Window?
body: <p>I am making an inventory and crafting system based off of this Unity Scriptable Objects Tutorial: <a href="https://learn.unity.com/tutorial/introduction-to-scriptable-objects#5cf187b7edbc2a31a3b9b123" rel="nofollow noreferrer">https://learn.unity.com/tutorial/introduction-to-scriptable-objects#5cf187b7edbc2a31a3b9b123</a></p>
  
  <p>Presently I have all of that working but I am trying to extend it to add the ability for a used potion to create a temporary buff or an equipped item to increase your armor / weapon damage (as they are supposed to).  So my Item class has a list of class type ItemEffect.  But I am not sure how to get that to display in my item database editor window.</p>
  
  <p>I have already done some searching around on the web and found some pretty old solutions for making this work, although I must admit I am having trouble getting them to work myself.  I've also tried approaching it from the approach of using an array as opposed to a list (I don't mind either one) since arrays are faster, I don't need to change the item dataset at runtime, and because it seems Unity doesn't suppose showing lists in an editor window by default.</p>
  
  <p><strong>Item.cs</strong></p>
  
  <pre class="lang-cs prettyprint-override"><code>using System.Collections.Generic;
  using UnityEngine;
  
  namespace PixelsoftGames.Inventory
  {
      public enum ItemType { Weapon, Armor, Food, Material }
      public enum EquipSlot { None, Head, Chest, Hands, Legs, Feet, Accessory1, Accessory2, Weapon, Shield }
      public enum EffectType { RestoreHP, IncreaseArmor, IncreaseDamage }
  
      [System.Serializable]
      public class Item
      {
          public string name = "New Item";
          public string description = "Item Description";
          public Sprite icon = null;
          public int basePrice = 0;
          public int useValue = 0;
          public ItemType type = ItemType.Material;
          public EquipSlot equipSlot = EquipSlot.None;
          public List&lt;ItemEffect&gt; itemEffects;
          public bool isEquippable = false;
          public bool isUseable = false;
          public bool isSellable = false;
          public bool canDestroy = false;
      }
  
      [System.Serializable]
      public class ItemEffect
      {
          public EffectType effectType;
          public float effectDuration;
          public int effectMagnitude;
      }
  }
  </code></pre>
  
  <p><strong>ItemEditor.cs</strong></p>
  
  <pre class="lang-cs prettyprint-override"><code>using UnityEngine;
  using UnityEditor;
  using System.Collections.Generic;
  
  namespace PixelsoftGames.Inventory
  {
      public class ItemEditor : EditorWindow
      {
          public ItemDatabase itemDatabase;
          private int viewIndex = 1;
          Vector2 scroll;
  
          [MenuItem("Window/Item Editor %#e")]
          static void Init()
          {
              EditorWindow.GetWindow(typeof(ItemEditor));
          }
  
          void OnEnable()
          {
              if (EditorPrefs.HasKey("ObjectPath"))
              {
                  string objectPath = EditorPrefs.GetString("ObjectPath");
                  itemDatabase = AssetDatabase.LoadAssetAtPath(objectPath, typeof(ItemDatabase)) as ItemDatabase;
              }
  
          }
  
          void OnGUI()
          {
              GUILayout.BeginHorizontal();
              GUILayout.Label("Item Editor", EditorStyles.boldLabel);
              if (itemDatabase != null)
              {
                  if (GUILayout.Button("Show Item Database"))
                  {
                      EditorUtility.FocusProjectWindow();
                      Selection.activeObject = itemDatabase;
                  }
              }
              if (GUILayout.Button("Open Item Database"))
              {
                  OpenItemDatabase();
              }
              if (GUILayout.Button("New Item Database"))
              {
                  EditorUtility.FocusProjectWindow();
                  Selection.activeObject = itemDatabase;
              }
              GUILayout.EndHorizontal();
  
              if (itemDatabase == null)
              {
                  GUILayout.BeginHorizontal();
                  GUILayout.Space(10);
                  if (GUILayout.Button("Create New Item Database", GUILayout.ExpandWidth(false)))
                  {
                      CreateItemDatabase();
                  }
                  if (GUILayout.Button("Open Existing Item Database", GUILayout.ExpandWidth(false)))
                  {
                      OpenItemDatabase();
                  }
                  GUILayout.EndHorizontal();
              }
  
              GUILayout.Space(20);
  
              if (itemDatabase != null)
              {
                  GUILayout.BeginHorizontal();
  
                  GUILayout.Space(10);
  
                  if (GUILayout.Button("Prev", GUILayout.ExpandWidth(false)))
                  {
                      if (viewIndex &gt; 1)
                          viewIndex--;
                  }
                  GUILayout.Space(5);
                  if (GUILayout.Button("Next", GUILayout.ExpandWidth(false)))
                  {
                      if (viewIndex &lt; itemDatabase.Items.Count)
                      {
                          viewIndex++;
                      }
                  }
  
                  GUILayout.Space(60);
  
                  if (GUILayout.Button("Add Item", GUILayout.ExpandWidth(false)))
                  {
                      AddItem();
                  }
                  if (GUILayout.Button("Delete Item", GUILayout.ExpandWidth(false)))
                  {
                      DeleteItem(viewIndex - 1);
                  }
  
                  GUILayout.EndHorizontal();
                  if (itemDatabase.Items == null)
                      Debug.Log("wtf");
                  if (itemDatabase.Items.Count &gt; 0)
                  {
                      GUILayout.BeginHorizontal();
                      viewIndex = Mathf.Clamp(EditorGUILayout.IntField("Current Item", viewIndex, GUILayout.ExpandWidth(false)), 1, itemDatabase.Items.Count);
                      //Mathf.Clamp (viewIndex, 1, inventoryItemList.itemList.Count);
                      EditorGUILayout.LabelField("of   " + itemDatabase.Items.Count.ToString() + "  items", "", GUILayout.ExpandWidth(false));
                      GUILayout.EndHorizontal();
  
                      itemDatabase.Items[viewIndex - 1].name = EditorGUILayout.TextField("Item Name", itemDatabase.Items[viewIndex - 1].name as string);
                      scroll = EditorGUILayout.BeginScrollView(scroll);
                      itemDatabase.Items[viewIndex - 1].description = EditorGUILayout.TextArea(itemDatabase.Items[viewIndex - 1].description, GUILayout.Height(position.height - 30));
                      EditorGUILayout.EndScrollView();
                      itemDatabase.Items[viewIndex - 1].icon = EditorGUILayout.ObjectField("Item Icon", itemDatabase.Items[viewIndex - 1].icon, typeof(Sprite), false) as Sprite;
  
                      GUILayout.Space(10);
  
                      GUILayout.BeginHorizontal();
                      itemDatabase.Items[viewIndex - 1].basePrice = EditorGUILayout.IntField("Base Price", itemDatabase.Items[viewIndex - 1].basePrice, GUILayout.ExpandWidth(false));
                      itemDatabase.Items[viewIndex - 1].useValue = EditorGUILayout.IntField("Use Value", itemDatabase.Items[viewIndex - 1].useValue, GUILayout.ExpandWidth(false));
                      itemDatabase.Items[viewIndex - 1].type = (ItemType)EditorGUILayout.EnumPopup("Item Type", itemDatabase.Items[viewIndex - 1].type);
                      itemDatabase.Items[viewIndex - 1].equipSlot = (EquipSlot)EditorGUILayout.EnumPopup("Equip Slot", itemDatabase.Items[viewIndex - 1].equipSlot);
                      GUILayout.EndHorizontal();
  
                      GUILayout.Space(10);
  
                      GUILayout.BeginHorizontal();
                      itemDatabase.Items[viewIndex - 1].isEquippable = (bool)EditorGUILayout.Toggle("Is Equippable ", itemDatabase.Items[viewIndex - 1].isEquippable, GUILayout.ExpandWidth(false));
                      itemDatabase.Items[viewIndex - 1].isUseable = (bool)EditorGUILayout.Toggle("Is Useable ", itemDatabase.Items[viewIndex - 1].isUseable, GUILayout.ExpandWidth(false));
                      itemDatabase.Items[viewIndex - 1].isSellable = (bool)EditorGUILayout.Toggle("Is Sellable ", itemDatabase.Items[viewIndex - 1].isSellable, GUILayout.ExpandWidth(false));
                      itemDatabase.Items[viewIndex - 1].canDestroy = (bool)EditorGUILayout.Toggle("Can Destroy ", itemDatabase.Items[viewIndex - 1].canDestroy, GUILayout.ExpandWidth(false));
                      GUILayout.EndHorizontal();
  
                      GUILayout.Space(10);
                  }
                  else
                  {
                      GUILayout.Label("This item database is empty.");
                  }
              }
              if (GUI.changed)
              {
                  EditorUtility.SetDirty(itemDatabase);
              }
          }
  
          void CreateItemDatabase()
          {
              // There is no overwrite protection here!
              // There is No "Are you sure you want to overwrite your existing object?" if it exists.
              // This should probably get a string from the user to create a new name and pass it ...
              viewIndex = 1;
              itemDatabase = PixelsoftGames.Inventory.CreateItemDatabase.Create();
              if (itemDatabase)
              {
                  itemDatabase.Items = new List&lt;Item&gt;();
                  string relPath = AssetDatabase.GetAssetPath(itemDatabase);
                  EditorPrefs.SetString("ObjectPath", relPath);
              }
          }
  
          void OpenItemDatabase()
          {
              string absPath = EditorUtility.OpenFilePanel("Select Item Database", "", "");
              if (absPath.StartsWith(Application.dataPath))
              {
                  string relPath = absPath.Substring(Application.dataPath.Length - "Assets".Length);
                  itemDatabase = AssetDatabase.LoadAssetAtPath(relPath, typeof(ItemDatabase)) as ItemDatabase;
                  if (itemDatabase.Items == null)
                      itemDatabase.Items = new List&lt;Item&gt;();
                  if (itemDatabase)
                  {
                      EditorPrefs.SetString("ObjectPath", relPath);
                  }
              }
          }
  
          void AddItem()
          {
              Item newItem = new Item();
              newItem.name = "New Item";
              itemDatabase.Items.Add(newItem);
              viewIndex = itemDatabase.Items.Count;
          }
  
          void DeleteItem(int index)
          {
              itemDatabase.Items.RemoveAt(index);
          }
      }
  }
  </code></pre>
  
  <p>Code is error free right now, I just don't know how to display the ItemEffect pullout in the editor window.  This is what it looks like right now:</p>
  
  <p><img src="https://i.imgur.com/7CYqIFT.jpg" alt="item editor"></p>