private void DrawSearch()
        {
            EditorGUI.BeginChangeCheck();
            using (new GUILayout.HorizontalScope())
            {
                GUI.SetNextControlName(CONTROL_NAME_SEARCH);
                m_SearchText = GUILayout.TextField(m_SearchText, "ToolbarSeachTextField");

                if (GUILayout.Button("", string.IsNullOrEmpty(m_SearchText) ? "ToolbarSeachCancelButtonEmpty" : "ToolbarSeachCancelButton"))
                {
                    m_SearchText = "";
                }
            }

            if (!EditorGUI.EndChangeCheck())
            {
                return;
            }

            // If searching for nothing, the Root Item will be the Current Item
            if (string.IsNullOrEmpty(m_SearchText))
            {
                m_CurrentItem     = m_RootItem;
                m_CurrentSelected = -1;
            }
            // Else we're searching and the Current Item is the Search Item
            else
            {
                m_CurrentItem     = m_SearchItem;
                m_CurrentSelected = 0;
            }

            // Save the Search Text (Unity does this for Add Component so we'll do the same)
            EditorPrefs.SetString(target.GetType().ToString() + CONTROL_NAME_SEARCH, m_SearchText);
        }
        private bool CanShow(ScriptableObjectCreatorItem item)
        {
            if (m_CurrentItem == m_SearchItem)
            {
                if ((item.m_Script != null && item.m_Name.ToLower().Contains(m_SearchText.ToLower())) || item == m_CreateItem)
                {
                    return(true);
                }
            }
            else if (item.m_Parent == m_CurrentItem || item == m_CreateItem)
            {
                return(true);
            }

            return(false);
        }
        private void DrawDropdown()
        {
            DrawSearch();

            bool headerFocused = m_CurrentItem.DrawAsHeader();

            if (headerFocused)
            {
                m_CurrentSelected = -1;
            }

            using (GUILayout.ScrollViewScope scope = new GUILayout.ScrollViewScope(m_Scroll))
            {
                if (m_CurrentItem == m_CreateItem)
                {
                    DrawCreate();
                }
                else
                {
                    for (int i = 0; i < m_Items.Count; i++)
                    {
                        ScriptableObjectCreatorItem item = m_Items[i];
                        if (!CanShow(item))
                        {
                            continue;
                        }

                        bool focused = item.DrawItem(m_CurrentSelected == i);
                        if (focused)
                        {
                            m_CurrentSelected = i;
                        }
                    }
                }

                m_Scroll = scope.scrollPosition;
            }
        }
        private void CreateAllItems()
        {
            // Get all classes that inherit ScriptableObject from the Unity Assemblies, we will ignore our own classes that inherit from those
            List <Type> inheritTypes =
                AppDomain.CurrentDomain.GetAssemblies()
                .Select(x =>
            {
                return(x
                       .GetTypes()
                       .Where(t =>
                              !string.IsNullOrEmpty(t.Namespace) &&
                              t.Namespace.StartsWith("Unity") &&
                              t.IsSubclassOf(typeof(ScriptableObject)) &&
                              !t.IsSubclassOf(typeof(UnityEditor.Editor))
                              ));
            })
                .SelectMany(x => x)
                .ToList();


            // Find all scripts in the project, each script found will be associated with a ScriptableObjectCreatorItem
            List <MonoScript> scripts = AssetDatabase.FindAssets("t:MonoScript")
                                        .Select(x => AssetDatabase.LoadAssetAtPath <MonoScript>(AssetDatabase.GUIDToAssetPath(x)))
                                        .Where(t =>
                                               t.GetClass() != null &&
                                               !t.GetClass().IsAbstract&&
                                               t.GetClass().IsSubclassOf(typeof(ScriptableObject)) &&
                                               !inheritTypes.Any(x => t.GetClass().IsSubclassOf(x))
                                               )
                                        .ToList();

            m_Items.Clear();

            // Create the Root Item, it will be the first Item selected
            m_RootItem = new ScriptableObjectCreatorItem
            {
                m_Name = "Scriptable Object"
            };

            m_Items.Add(m_RootItem);

            foreach (MonoScript script in scripts)
            {
                ScriptableObjectCreatorItem lastFolder = null;
                string[] hierarchy = GetFolderHierarchy(script.GetClass());
                if (hierarchy == null)
                {
                    continue;
                }

                for (int i = 0; i < hierarchy.Length; i++)
                {
                    // Check if it already exists, if it does exist just keep going
                    ScriptableObjectCreatorItem folder = m_Items.FirstOrDefault(x => x.m_Name == hierarchy[i]);
                    if (folder == null)
                    {
                        // Use the Namespace info to create Folders
                        folder = new ScriptableObjectCreatorItem
                        {
                            m_Name   = hierarchy[i],
                            m_Parent = i == 0 ? m_RootItem : lastFolder
                        };

                        folder.m_Clicked         = () => { m_CurrentItem = folder; };
                        folder.m_ClickedAsHeader = () => { m_CurrentItem = folder.m_Parent; };

                        m_Items.Add(folder);
                    }

                    lastFolder = folder;
                }

                // Create a Script Item
                ScriptableObjectCreatorItem item = new ScriptableObjectCreatorItem
                {
                    m_Name   = script.GetClass().Name,
                    m_Script = script,
                    m_Parent = lastFolder ?? m_RootItem
                };

                item.m_Clicked = () => { AddScript(item.m_Script); };

                m_Items.Add(item);
            }

            // Sort all items by Name
            m_Items.Sort((a, b) => a.m_Name.CompareTo(b.m_Name));

            // Create Item that will allow the user to create their own scripts. It will always be at the bottom of the list.
            m_CreateItem = new ScriptableObjectCreatorItem
            {
                m_Name   = "New Script",
                m_Parent = m_RootItem
            };

            m_CreateItem.m_Clicked = () =>
            {
                m_CreateItem.m_Parent = m_CurrentItem;
                m_CurrentItem         = m_CreateItem;
                m_CreateText          = string.IsNullOrEmpty(m_SearchText) ? "NewScriptableObject" : m_SearchText;
                m_SearchText          = string.Empty;
            };

            m_CreateItem.m_ClickedAsHeader = () => { m_CurrentItem = m_CurrentItem.m_Parent; };
            m_Items.Add(m_CreateItem);

            // Create Item that will show that the user is currently searching. It doesn't need to be in the items list.
            m_SearchItem = new ScriptableObjectCreatorItem
            {
                m_Name            = "Search",
                m_Parent          = m_RootItem,
                m_ClickedAsHeader = () =>
                {
                    m_SearchText  = string.Empty;
                    m_CurrentItem = m_RootItem;
                    EditorGUI.FocusTextInControl(null);
                }
            };

            if (string.IsNullOrEmpty(m_SearchText))
            {
                m_CurrentItem = m_RootItem;
            }
            else
            {
                m_CurrentItem     = m_SearchItem;
                m_CurrentSelected = 0;
            }
        }