///Return a string hex color for a type.
 public static string GetTypeHexColor(System.Type type)
 {
     return(TypePrefs.GetTypeHexColor(type));
 }
 ///Save changes
 void Save()
 {
     TypePrefs.SetPreferedTypesList(typeList);
 }
示例#3
0
        //...
        void OnGUI()
        {
            GUI.skin.label.richText = true;
            EditorGUILayout.HelpBox("Here you can specify frequently used types for your project and for easier access wherever you need to select a type, like for example when you create a new blackboard variable or using any refelection based actions. Furthermore, it is essential when working with AOT platforms like iOS or WebGL, that you generate an AOT Classes and link.xml files with the relevant button bellow. To add types in the list quicker, you can also Drag&Drop an object, or a Script file in this editor window.\n\nIf you save a preset in your 'Editor Default Resources/" + TypePrefs.SYNC_FILE_NAME + "' it will automatically sync with the list. Useful when working with others on source control.", MessageType.Info);

            if (GUILayout.Button("Add New Type", EditorStyles.miniButton))
            {
                GenericMenu.MenuFunction2 Selected = delegate(object o)
                {
                    if (o is System.Type)
                    {
                        AddType((System.Type)o);
                    }
                    if (o is string)     //namespace
                    {
                        foreach (var type in alltypes)
                        {
                            if (type.Namespace == (string)o)
                            {
                                AddType(type);
                            }
                        }
                    }
                };

                var menu       = new GenericMenu();
                var namespaces = new List <string>();
                menu.AddItem(new GUIContent("Classes/System/Object"), false, Selected, typeof(object));
                foreach (var t in alltypes)
                {
                    var a            = (string.IsNullOrEmpty(t.Namespace) ? "No Namespace/" : t.Namespace.Replace(".", "/") + "/") + t.FriendlyName();
                    var b            = string.IsNullOrEmpty(t.Namespace) ? string.Empty : " (" + t.Namespace + ")";
                    var friendlyName = a + b;
                    var category     = "Classes/";
                    if (t.IsValueType)
                    {
                        category = "Structs/";
                    }
                    if (t.IsInterface)
                    {
                        category = "Interfaces/";
                    }
                    if (t.IsEnum)
                    {
                        category = "Enumerations/";
                    }
                    menu.AddItem(new GUIContent(category + friendlyName), typeList.Contains(t), Selected, t);
                    if (t.Namespace != null && !namespaces.Contains(t.Namespace))
                    {
                        namespaces.Add(t.Namespace);
                    }
                }

                menu.AddSeparator("/");
                foreach (var ns in namespaces)
                {
                    var path = "Whole Namespaces/" + ns.Replace(".", "/") + "/Add " + ns;
                    menu.AddItem(new GUIContent(path), false, Selected, ns);
                }

                menu.ShowAsBrowser("Add Preferred Type");
            }


            if (GUILayout.Button("Generate AOTClasses.cs and link.xml Files", EditorStyles.miniButton))
            {
                if (EditorUtility.DisplayDialog("Generate AOT Classes", "A script relevant to AOT compatibility for certain platforms will now be generated.", "OK"))
                {
                    var path = EditorUtility.SaveFilePanelInProject("AOT Classes File", "AOTClasses", "cs", "");
                    if (!string.IsNullOrEmpty(path))
                    {
                        AOTClassesGenerator.GenerateAOTClasses(path, TypePrefs.GetPreferedTypesList(true).ToArray());
                    }
                }

                if (EditorUtility.DisplayDialog("Generate link.xml File", "A file relevant to 'code stripping' for platforms that have code stripping enabled will now be generated.", "OK"))
                {
                    var path = EditorUtility.SaveFilePanelInProject("AOT link.xml", "link", "xml", "");
                    if (!string.IsNullOrEmpty(path))
                    {
                        AOTClassesGenerator.GenerateLinkXML(path, TypePrefs.GetPreferedTypesList().ToArray());
                    }
                }

                AssetDatabase.Refresh();
            }

            GUILayout.BeginHorizontal();

            if (GUILayout.Button("Reset Defaults", EditorStyles.miniButtonLeft))
            {
                if (EditorUtility.DisplayDialog("Reset Preferred Types", "Are you sure?", "Yes", "NO!"))
                {
                    TypePrefs.ResetTypeConfiguration();
                    typeList = TypePrefs.GetPreferedTypesList();
                    Save();
                }
            }

            if (GUILayout.Button("Save Preset", EditorStyles.miniButtonMid))
            {
                var path = EditorUtility.SaveFilePanelInProject("Save Types Preset", "PreferredTypes", "typePrefs", "");
                if (!string.IsNullOrEmpty(path))
                {
                    System.IO.File.WriteAllText(path, JSONSerializer.Serialize(typeof(List <System.Type>), typeList, null, true));
                    AssetDatabase.Refresh();
                }
            }

            if (GUILayout.Button("Load Preset", EditorStyles.miniButtonRight))
            {
                var path = EditorUtility.OpenFilePanel("Load Types Preset", "Assets", "typePrefs");
                if (!string.IsNullOrEmpty(path))
                {
                    var json = System.IO.File.ReadAllText(path);
                    typeList = JSONSerializer.Deserialize <List <System.Type> >(json);
                    Save();
                }
            }

            GUILayout.EndHorizontal();
            GUILayout.Space(5);
            var syncPath = TypePrefs.SyncFilePath();

            EditorGUILayout.HelpBox(syncPath != null ? "List synced with file: " + syncPath.Replace(Application.dataPath, ".../Assets") : "No sync file found in '.../Assets/Editor Default Resources'. Types are currently saved in Unity EditorPrefs only.", MessageType.None);
            GUILayout.Space(5);

            scrollPos = GUILayout.BeginScrollView(scrollPos);
            for (int i = 0; i < typeList.Count; i++)
            {
                if (EditorGUIUtility.isProSkin)
                {
                    GUI.color = Color.black.WithAlpha(i % 2 == 0 ? 0.3f : 0);
                }
                if (!EditorGUIUtility.isProSkin)
                {
                    GUI.color = Color.white.WithAlpha(i % 2 == 0 ? 0.3f : 0);
                }
                GUILayout.BeginHorizontal("box");
                GUI.color = Color.white;
                var type = typeList[i];
                if (type == null)
                {
                    GUILayout.Label("MISSING TYPE", GUILayout.Width(300));
                    GUILayout.Label("---");
                }
                else
                {
                    var name = type.FriendlyName();
                    var icon = TypePrefs.GetTypeIcon(type);
                    GUILayout.Label(icon, GUILayout.Width(16), GUILayout.Height(16));
                    GUILayout.Label(name, GUILayout.Width(300));
                    GUILayout.Label(type.Namespace);
                }
                if (GUILayout.Button("X", GUILayout.Width(18)))
                {
                    RemoveType(type);
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.EndScrollView();

            AcceptDrops();
            Repaint();
        }
        ///----------------------------------------------------------------------------------------------

        ///Return a color for a type.
        public static Color GetTypeColor(System.Type type)
        {
            return(TypePrefs.GetTypeColor(type));
        }
        public static List <ScriptInfo> GetScriptInfosOfType(Type baseType)
        {
            if (cachedInfos == null)
            {
                cachedInfos = new Dictionary <Type, List <ScriptInfo> >();
            }

            List <ScriptInfo> infosResult;

            if (cachedInfos.TryGetValue(baseType, out infosResult))
            {
                return(infosResult.ToList());
            }

            infosResult = new List <ScriptInfo>();

            var subTypes = ReflectionTools.GetImplementationsOf(baseType);

            if (baseType.IsGenericTypeDefinition)
            {
                subTypes = new Type[] { baseType };
            }

            foreach (var subType in subTypes)
            {
                if (subType.IsAbstract || subType.IsDefined(typeof(DoNotListAttribute), true) || subType.IsDefined(typeof(ObsoleteAttribute), true))
                {
                    continue;
                }

                var isGeneric      = subType.IsGenericTypeDefinition && subType.GetGenericArguments().Length == 1;
                var scriptName     = subType.FriendlyName().SplitCamelCase();
                var scriptCategory = string.Empty;
                var scriptPriority = 0;

                var nameAttribute = subType.RTGetAttribute <NameAttribute>(true);
                if (nameAttribute != null)
                {
                    scriptPriority = nameAttribute.priority;
                    scriptName     = nameAttribute.name;
                    if (isGeneric && !scriptName.EndsWith("<T>"))
                    {
                        scriptName += " (T)";
                    }
                }

                var categoryAttribute = subType.RTGetAttribute <CategoryAttribute>(true);
                if (categoryAttribute != null)
                {
                    scriptCategory = categoryAttribute.category;
                }

                var info = new ScriptInfo(subType, scriptName, scriptCategory, scriptPriority);
                info.originalType     = subType;
                info.originalName     = scriptName;
                info.originalCategory = scriptCategory;

                //add the generic types based on constrains and prefered types list
                if (isGeneric)
                {
                    var exposeAsBaseDefinition = subType.RTIsDefined <ExposeAsDefinitionAttribute>(true);
                    if (!exposeAsBaseDefinition)
                    {
                        var typesToWrap = TypePrefs.GetPreferedTypesList(true);
                        foreach (var t in typesToWrap)
                        {
                            infosResult.Add(info.MakeGenericInfo(t, string.Format("/{0}/{1}", info.name, t.NamespaceToPath())));
                            infosResult.Add(info.MakeGenericInfo(typeof(List <>).MakeGenericType(t), string.Format("/{0}/{1}{2}", info.name, TypePrefs.LIST_MENU_STRING, t.NamespaceToPath()), -1));
                            infosResult.Add(info.MakeGenericInfo(typeof(Dictionary <,>).MakeGenericType(typeof(string), t), string.Format("/{0}/{1}{2}", info.name, TypePrefs.DICT_MENU_STRING, t.NamespaceToPath()), -2));
                        }
                        continue;
                    }
                }

                infosResult.Add(info);
            }

            infosResult = infosResult
                          .Where(s => s != null)
                          .OrderBy(s => s.GetBaseInfo().name)
                          .OrderBy(s => s.GetBaseInfo().priority * -1)
                          .OrderBy(s => s.GetBaseInfo().category)
                          .ToList();
            cachedInfos[baseType] = infosResult;
            return(infosResult);
        }
示例#6
0
 //...
 void OnEnable()
 {
     titleContent = new GUIContent("Preferred Types");
     typeList     = TypePrefs.GetPreferedTypesList();
     alltypes     = ReflectionTools.GetAllTypes(true).Where(t => !t.IsGenericType && !t.IsGenericTypeDefinition).ToList();
 }
        //...
        public static object DirectFieldControl(GUIContent content, object value, Type t, UnityEngine.Object unityObjectContext, object[] attributes, out bool handled, params GUILayoutOption[] options)
        {
            handled = true;

            //Check scene object type for UnityObjects. Consider Interfaces as scene object type. Assume that user uses interfaces with UnityObjects
            if (typeof(UnityObject).IsAssignableFrom(t) || t.IsInterface)
            {
                var isSceneObjectType = (typeof(Component).IsAssignableFrom(t) || t == typeof(GameObject) || t.IsInterface);
                if (value == null || value is UnityObject)     //check this to avoid case of interface but no unityobject
                {
                    var newValue = EditorGUILayout.ObjectField(content, (UnityObject)value, t, isSceneObjectType, options);
                    if (unityObjectContext != null && newValue != null)
                    {
                        if (!Application.isPlaying && EditorUtility.IsPersistent(unityObjectContext) && !EditorUtility.IsPersistent(newValue as UnityEngine.Object))
                        {
                            ParadoxNotion.Services.Logger.LogWarning("Assets can not have scene object references", "Editor", unityObjectContext);
                            newValue = value as UnityObject;
                        }
                    }
                    return(newValue);
                }
            }

            //Check Type second
            if (t == typeof(Type))
            {
                return(Popup <Type>(content, (Type)value, TypePrefs.GetPreferedTypesList(true), options));
            }

            //get real current type
            t = value != null?value.GetType() : t;

            //for these just show type information
            if (t.IsAbstract || t == typeof(object) || typeof(Delegate).IsAssignableFrom(t) || typeof(UnityEngine.Events.UnityEventBase).IsAssignableFrom(t))
            {
                EditorGUILayout.LabelField(content, new GUIContent(string.Format("({0})", t.FriendlyName())), options);
                return(value);
            }

            //create instance for value types
            if (value == null && t.RTIsValueType())
            {
                value = System.Activator.CreateInstance(t);
            }

            //create new instance with button for non value types
            if (value == null && !t.IsAbstract && !t.IsInterface && (t.IsArray || t.GetConstructor(Type.EmptyTypes) != null))
            {
                if (content != GUIContent.none)
                {
                    GUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel(content, GUI.skin.button);
                }
                if (GUILayout.Button("(null) Create", options))
                {
                    value = t.IsArray ? Array.CreateInstance(t.GetElementType(), 0) : Activator.CreateInstance(t);
                }
                if (content != GUIContent.none)
                {
                    GUILayout.EndHorizontal();
                }
                return(value);
            }


            ///----------------------------------------------------------------------------------------------


            if (t == typeof(string))
            {
                return(EditorGUILayout.TextField(content, (string)value, options));
            }

            if (t == typeof(char))
            {
                var c = (char)value;
                var s = c.ToString();
                s = EditorGUILayout.TextField(content, s, options);
                return(string.IsNullOrEmpty(s) ? (char)c : (char)s[0]);
            }

            if (t == typeof(bool))
            {
                return(EditorGUILayout.Toggle(content, (bool)value, options));
            }

            if (t == typeof(int))
            {
                return(EditorGUILayout.IntField(content, (int)value, options));
            }

            if (t == typeof(float))
            {
                return(EditorGUILayout.FloatField(content, (float)value, options));
            }

            if (t == typeof(byte))
            {
                return(Convert.ToByte(Mathf.Clamp(EditorGUILayout.IntField(content, (byte)value, options), 0, 255)));
            }

            if (t == typeof(long))
            {
                return(EditorGUILayout.LongField(content, (long)value, options));
            }

            if (t == typeof(double))
            {
                return(EditorGUILayout.DoubleField(content, (double)value, options));
            }

            if (t == typeof(Vector2))
            {
                return(EditorGUILayout.Vector2Field(content, (Vector2)value, options));
            }

            if (t == typeof(Vector2Int))
            {
                return(EditorGUILayout.Vector2IntField(content, (Vector2Int)value, options));
            }

            if (t == typeof(Vector3))
            {
                return(EditorGUILayout.Vector3Field(content, (Vector3)value, options));
            }

            if (t == typeof(Vector3Int))
            {
                return(EditorGUILayout.Vector3IntField(content, (Vector3Int)value, options));
            }

            if (t == typeof(Vector4))
            {
                return(EditorGUILayout.Vector4Field(content, (Vector4)value, options));
            }

            if (t == typeof(Quaternion))
            {
                var quat = (Quaternion)value;
                var vec4 = new Vector4(quat.x, quat.y, quat.z, quat.w);
                vec4 = EditorGUILayout.Vector4Field(content, vec4, options);
                return(new Quaternion(vec4.x, vec4.y, vec4.z, vec4.w));
            }

            if (t == typeof(Color))
            {
                var att       = attributes?.FirstOrDefault(a => a is ColorUsageAttribute) as ColorUsageAttribute;
                var hdr       = att != null? att.hdr : false;
                var showAlpha = att != null? att.showAlpha : true;
                return(EditorGUILayout.ColorField(content, (Color)value, true, showAlpha, hdr, options));
            }

            if (t == typeof(Gradient))
            {
                return(EditorGUILayout.GradientField(content, (Gradient)value, options));
            }

            if (t == typeof(Rect))
            {
                return(EditorGUILayout.RectField(content, (Rect)value, options));
            }

            if (t == typeof(AnimationCurve))
            {
                return(EditorGUILayout.CurveField(content, (AnimationCurve)value, options));
            }

            if (t == typeof(Bounds))
            {
                return(EditorGUILayout.BoundsField(content, (Bounds)value, options));
            }

            if (t == typeof(LayerMask))
            {
                return(LayerMaskField(content, (LayerMask)value, options));
            }

            if (t.IsSubclassOf(typeof(System.Enum)))
            {
                if (t.RTIsDefined(typeof(FlagsAttribute), true))
                {
#if UNITY_2017_3_OR_NEWER
                    return(EditorGUILayout.EnumFlagsField(content, (System.Enum)value, options));
#else
                    return(EditorGUILayout.EnumMaskPopup(content, (System.Enum)value, options));
#endif
                }
                return(EditorGUILayout.EnumPopup(content, (System.Enum)value, options));
            }

            handled = false;
            return(value);
        }
        ///----------------------------------------------------------------------------------------------

        ///Returns a type icon
        public static Texture GetTypeIcon(System.Type type)
        {
            return(TypePrefs.GetTypeIcon(type));
        }
        ///Draws an Editor field for object of type directly
        public static object DrawEditorFieldDirect(GUIContent content, object value, Type t, FieldInfo field = null, object context = null, object[] attributes = null)
        {
            if (typeof(UnityObject).IsAssignableFrom(t) == false && t != typeof(Type))
            {
                //Check abstract
                if ((value != null && value.GetType().IsAbstract) || (value == null && t.IsAbstract))
                {
                    EditorGUILayout.LabelField(content, new GUIContent(string.Format("Abstract ({0})", t.FriendlyName())));
                    return(value);
                }

                //Auto create instance for some types
                if (value == null && t != typeof(object) && !t.IsAbstract && !t.IsInterface)
                {
                    if (t.GetConstructor(Type.EmptyTypes) != null || t.IsArray)
                    {
                        if (t.IsArray)
                        {
                            value = Array.CreateInstance(t.GetElementType(), 0);
                        }
                        else
                        {
                            value = Activator.CreateInstance(t);
                        }
                    }
                }
            }

            //Check the type
            if (typeof(UnityObject).IsAssignableFrom(t))
            {
                if (t == typeof(Component) && (value is Component))
                {
                    return(ComponentField(content, (Component)value, typeof(Component)));
                }
                return(EditorGUILayout.ObjectField(content, (UnityObject)value, t, true));
            }

            if (t == typeof(Type))
            {
                return(Popup <Type>(content, (Type)value, TypePrefs.GetPreferedTypesList(true)));
            }

            if (t == typeof(string))
            {
                return(EditorGUILayout.TextField(content, (string)value));
            }

            if (t == typeof(char))
            {
                var c = (char)value;
                var s = c.ToString();
                s = EditorGUILayout.TextField(content, s);
                return(string.IsNullOrEmpty(s) ? (char)c : (char)s[0]);
            }

            if (t == typeof(bool))
            {
                return(EditorGUILayout.Toggle(content, (bool)value));
            }

            if (t == typeof(int))
            {
                return(EditorGUILayout.IntField(content, (int)value));
            }

            if (t == typeof(float))
            {
                return(EditorGUILayout.FloatField(content, (float)value));
            }

            if (t == typeof(byte))
            {
                return(Convert.ToByte(Mathf.Clamp(EditorGUILayout.IntField(content, (byte)value), 0, 255)));
            }

            if (t == typeof(long))
            {
                return(EditorGUILayout.LongField(content, (long)value));
            }

            if (t == typeof(double))
            {
                return(EditorGUILayout.DoubleField(content, (double)value));
            }

            if (t == typeof(Vector2))
            {
                return(EditorGUILayout.Vector2Field(content, (Vector2)value));
            }

            if (t == typeof(Vector3))
            {
                return(EditorGUILayout.Vector3Field(content, (Vector3)value));
            }

            if (t == typeof(Vector4))
            {
                return(EditorGUILayout.Vector4Field(content, (Vector4)value));
            }

            if (t == typeof(Quaternion))
            {
                var quat = (Quaternion)value;
                var vec4 = new Vector4(quat.x, quat.y, quat.z, quat.w);
                vec4 = EditorGUILayout.Vector4Field(content, vec4);
                return(new Quaternion(vec4.x, vec4.y, vec4.z, vec4.w));
            }

            if (t == typeof(Color))
            {
                return(EditorGUILayout.ColorField(content, (Color)value));
            }

            if (t == typeof(Rect))
            {
                return(EditorGUILayout.RectField(content, (Rect)value));
            }

            if (t == typeof(AnimationCurve))
            {
                return(EditorGUILayout.CurveField(content, (AnimationCurve)value));
            }

            if (t == typeof(Bounds))
            {
                return(EditorGUILayout.BoundsField(content, (Bounds)value));
            }

            if (t == typeof(LayerMask))
            {
                return(LayerMaskField(content, (LayerMask)value));
            }

            if (t.IsSubclassOf(typeof(System.Enum)))
            {
                if (t.IsDefined(typeof(FlagsAttribute), true))
                {
#if UNITY_2017_3_OR_NEWER
                    return(EditorGUILayout.EnumFlagsField(content, (System.Enum)value));
#else
                    return(EditorGUILayout.EnumMaskPopup(content, (System.Enum)value));
#endif
                }
                return(EditorGUILayout.EnumPopup(content, (System.Enum)value));
            }

            if (typeof(IList).IsAssignableFrom(t))
            {
                return(ListEditor(content, (IList)value, t, field, context, attributes));
            }

            if (typeof(IDictionary).IsAssignableFrom(t))
            {
                return(DictionaryEditor(content, (IDictionary)value, t, field, context, attributes));
            }

            //show nested class members recursively
            if (value != null && (t.IsClass || t.IsValueType))
            {
                if (EditorGUI.indentLevel <= 8)
                {
                    GUILayout.BeginVertical();
                    EditorGUILayout.LabelField(content, new GUIContent(string.Format("({0})", t.FriendlyName())));
                    EditorGUI.indentLevel++;
                    ReflectedObjectInspector(value);
                    EditorGUI.indentLevel--;
                    GUILayout.EndVertical();
                }
            }
            else
            {
                EditorGUILayout.LabelField(content, new GUIContent(string.Format("NonInspectable ({0})", t.FriendlyName())));
            }

            return(value);
        }
示例#10
0
        ///<summary> !* Providing an open GenericTypeDefinition for 'baseType', wraps the Preferred Types wihin the 1st Generic Argument of that Definition *!</summary>
        public static GenericMenu GetPreferedTypesSelectionMenu(Type baseType, Action <Type> callback, GenericMenu menu = null, string subCategory = null, bool showAddTypeOption = false)
        {
            if (menu == null)
            {
                menu = new GenericMenu();
            }

            if (subCategory != null)
            {
                subCategory = subCategory + "/";
            }

            var constrainType         = baseType;
            var isGenericDefinition   = baseType.IsGenericTypeDefinition && baseType.RTGetGenericArguments().Length == 1;
            var genericDefinitionType = isGenericDefinition ? baseType : null;

            if (isGenericDefinition)
            {
                constrainType = genericDefinitionType.GetFirstGenericParameterConstraintType();
            }

            GenericMenu.MenuFunction2 Selected = (object t) => { callback((Type)t); };

            var listTypes = new Dictionary <Type, string>();
            var dictTypes = new Dictionary <Type, string>();

            foreach (var t in TypePrefs.GetPreferedTypesList(constrainType, true))
            {
                var nsString = t.NamespaceToPath() + "/";

                var finalType   = isGenericDefinition && genericDefinitionType.TryMakeGeneric(t, out Type genericType) ? genericType : t;
                var finalString = nsString + finalType.FriendlyName();
                menu.AddItem(new GUIContent(subCategory + finalString), false, Selected, finalType);

                var listType      = typeof(List <>).MakeGenericType(t);
                var finalListType = isGenericDefinition && genericDefinitionType.TryMakeGeneric(listType, out Type genericListType) ? genericListType : listType;
                if (constrainType.IsAssignableFrom(finalListType))
                {
                    listTypes[finalListType] = nsString;
                }

                var dictType      = typeof(Dictionary <,>).MakeGenericType(typeof(string), t);
                var finalDictType = isGenericDefinition && genericDefinitionType.TryMakeGeneric(dictType, out Type genericDictType) ? genericDictType : dictType;
                if (constrainType.IsAssignableFrom(finalDictType))
                {
                    dictTypes[finalDictType] = nsString;
                }
            }

            foreach (var pair in listTypes)
            {
                menu.AddItem(new GUIContent(subCategory + TypePrefs.LIST_MENU_STRING + pair.Value + pair.Key.FriendlyName()), false, Selected, pair.Key);
            }

            foreach (var pair in dictTypes)
            {
                menu.AddItem(new GUIContent(subCategory + TypePrefs.DICT_MENU_STRING + pair.Value + pair.Key.FriendlyName()), false, Selected, pair.Key);
            }

            if (showAddTypeOption)
            {
                menu.AddItem(new GUIContent(subCategory + "Add Type..."), false, () => { TypePrefsEditorWindow.ShowWindow(); });
            }

            if (menu.GetItemCount() == 0)
            {
                menu.AddDisabledItem(new GUIContent(string.Format("No {0} derived types found in Preferred Types List", baseType.Name)));
            }

            return(menu);
        }
        //THE TREE
        void DoTree(Rect treeRect, Event e)
        {
            GUILayout.BeginArea(treeRect);

            scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false);
            GUILayout.BeginVertical();

            if (search != lastSearch)
            {
                hoveringIndex = 0;
                if (!string.IsNullOrEmpty(search))
                {
                    var results = new List <Node>();
                    foreach (var node in leafNodes)
                    {
                        if (filterFavorites && !node.isFavorite)
                        {
                            continue;
                        }
                        if (StringUtils.SearchMatch(search, node.name, node.category))
                        {
                            results.Add(node);
                        }
                    }
                    var searchRootNode = new Node()
                    {
                        name = "Search Root"
                    };
                    //Remark: scoring is done on category name instead of leaf name
                    searchRootNode.children = results
                                              .OrderBy(r => StringUtils.ScoreSearchMatch(search, r.category, r.category) * (r.isFavorite ? 0.5f : 1))
                                              .ToDictionary(r => r.fullPath, r => r);
                    currentNode = searchRootNode;
                }
                else
                {
                    currentNode = rootNode;
                }
                lastSearch = search;
            }

            ///----------------------------------------------------------------------------------------------

            var    i                  = 0;
            var    itemAdded          = false;
            string lastSearchCategory = null;

            foreach (var childPair in currentNode.children)
            {
                var isSearch = !string.IsNullOrEmpty(search);

                if (isSearch && i >= 200)
                {
                    EditorGUILayout.HelpBox("There are more than 200 results. Please try refine your search input.", MessageType.Info);
                    break;
                }

                var node       = childPair.Value;
                var leafItem   = node.item;
                var memberInfo = leafItem != null ? leafItem.userData as MemberInfo : null;
                var isDisabled = leafItem != null && leafItem.func == null && leafItem.func2 == null;
                var icon       = leafItem != null ? leafItem.content.image : Icons.folderIcon;
                if (icon == null && memberInfo != null)
                {
                    icon = TypePrefs.GetTypeIcon(memberInfo);
                }

                //when within search, show category on top
                if (isSearch)
                {
                    var searchCategory = lastSearchCategory;
                    if (memberInfo == null || memberInfo is System.Type)
                    {
                        searchCategory = node.parent.fullPath != null?node.parent.fullPath.Split(new char[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries).FirstOrDefault() : null;
                    }
                    else
                    {
                        searchCategory = memberInfo.ReflectedType.FriendlyName();
                    }

                    if (searchCategory != lastSearchCategory)
                    {
                        lastSearchCategory = searchCategory;
                        GUI.color          = EditorGUIUtility.isProSkin ? Color.black : Color.white;
                        GUILayout.BeginHorizontal("box");
                        GUI.color = Color.white;
                        GUILayout.Label(searchCategory, Styles.leftLabel, GUILayout.Height(16));
                        GUILayout.EndHorizontal();
                    }
                }
                //


                if (filterFavorites && !node.isFavorite && !node.HasAnyFavoriteChild())
                {
                    continue;
                }

                if (leafItem != null && leafItem.separator)
                {
                    if (itemAdded)
                    {
                        EditorUtils.Separator();
                    }
                    continue;
                }

                itemAdded = true;

                GUI.color = EditorGUIUtility.isProSkin ? Color.white : new Color(0.8f, 0.8f, 0.8f, 1);
                GUILayout.BeginHorizontal("box");

                //Prefix icon
                GUI.color = Color.white;
                GUILayout.Label(icon, GUILayout.Width(32), GUILayout.Height(16));
                GUI.enabled = !isDisabled;

                //Favorite
                if (currentKeyType != null)
                {
                    GUI.color = node.isFavorite ? Color.white : (node.HasAnyFavoriteChild() ? new Color(1, 1, 1, 0.2f) : new Color(0f, 0f, 0f, 0.4f));
                    if (GUILayout.Button(Icons.favoriteIcon, GUIStyle.none, GUILayout.Width(16), GUILayout.Height(16)))
                    {
                        node.ToggleFavorite();
                    }
                    GUI.color = Color.white;
                }

                //Content
                var label = node.name;
                var text  = string.Format("<size=9>{0}</size>", (leafItem == null ? string.Format("<b>{0}</b>", label) : label));
                GUILayout.Box(text, (GUIStyle)"label", GUILayout.Width(0), GUILayout.ExpandWidth(true));
                GUILayout.Label(leafItem != null ? "●" : "►", GUILayout.Width(20));
                GUILayout.EndHorizontal();

                var elementRect = GUILayoutUtility.GetLastRect();
                if (e.type == EventType.MouseDown && e.button == 0 && elementRect.Contains(e.mousePosition))
                {
                    e.Use();
                    if (leafItem != null)
                    {
                        ExecuteItemFunc(leafItem);
                        break;
                    }
                    else
                    {
                        currentNode   = node;
                        hoveringIndex = 0;
                        break;
                    }
                }

                if (e.type == EventType.MouseMove && elementRect.Contains(e.mousePosition))
                {
                    hoveringIndex = i;
                }

                if (hoveringIndex == i)
                {
                    GUI.color = hoverColor;
                    GUI.DrawTexture(elementRect, EditorGUIUtility.whiteTexture);
                    GUI.color = Color.white;
                }

                i++;
                GUI.enabled = true;
            }

            if (hoveringIndex != lastHoveringIndex)
            {
                base.editorWindow.Repaint();
                lastHoveringIndex = hoveringIndex;
            }

            if (!itemAdded)
            {
                GUILayout.Label("No results to display with current search and filter combination");
            }

            GUILayout.EndVertical();
            EditorGUILayout.EndScrollView();
            GUILayout.EndArea();
        }