Esempio n. 1
0
        public static OdinMenuItem AddThumbnailIcon(this OdinMenuItem item, bool preferAssetPreviewAsIcon)
        {
            var unityObject = item.ObjectInstance as UnityEngine.Object;
            var assetPath   = item.ObjectInstance as string;
            var type        = item.ObjectInstance as Type;

            if (unityObject)
            {
                item.Icon = GUIHelper.GetAssetThumbnail(unityObject, item.GetType(), preferAssetPreviewAsIcon);
            }
            else if (item.ObjectInstance == null)
            {
                item.Icon = EditorIcons.UnityFolderIcon;
            }
            else if (type != null)
            {
                item.Icon = GUIHelper.GetAssetThumbnail(null, type, preferAssetPreviewAsIcon);
            }
            else if (assetPath != null)
            {
                if (assetPath != null)
                {
                    item.Icon = InternalEditorUtility.GetIconForFile(assetPath);
                }
            }

            return(item);
        }
Esempio n. 2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OdinMenuTree"/> class.
 /// </summary>
 public OdinMenuTree(bool supportsMultiSelect, OdinMenuTreeDrawingConfig config)
 {
     this.Config    = config;
     this.selection = new OdinMenuTreeSelection(supportsMultiSelect);
     this.root      = new OdinMenuItem(this, "root", null);
     this.SetupAutoScroll();
 }
Esempio n. 3
0
        /// <summary>
        /// Scrolls to the specified menu item.
        /// </summary>
        public void ScrollToMenuItem(OdinMenuItem menuItem, bool centerMenuItem = false)
        {
            if (menuItem != null)
            {
                var config = this.Config;
                var rect   = menuItem.Rect;

                float a, b;

                if (centerMenuItem)
                {
                    var r = this.outerScrollViewRect.AlignCenterY(rect.height);

                    a = rect.yMin - (this.innerScrollViewYTop + config.ScrollPos.y - r.y);
                    b = (rect.yMax - r.height + this.innerScrollViewYTop) - (config.ScrollPos.y + r.y);
                }
                else
                {
                    a = rect.yMin - (this.innerScrollViewYTop + config.ScrollPos.y - this.outerScrollViewRect.y);
                    b = (rect.yMax - this.outerScrollViewRect.height + this.innerScrollViewYTop) - (config.ScrollPos.y + this.outerScrollViewRect.y);
                }


                if (a < 0)
                {
                    config.ScrollPos.y += a;
                }

                if (b > 0)
                {
                    config.ScrollPos.y += b;
                }
            }
        }
Esempio n. 4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OdinMenuTree"/> class.
 /// </summary>
 /// <param name="supportsMultiSelect">if set to <c>true</c> [supports multi select].</param>
 /// <param name="defaultMenuStyle">The default menu item style.</param>
 public OdinMenuTree(bool supportsMultiSelect, OdinMenuStyle defaultMenuStyle)
 {
     this.DefaultMenuStyle = defaultMenuStyle;
     this.selection        = new OdinMenuTreeSelection(supportsMultiSelect);
     this.root             = new OdinMenuItem(this, "root", null);
     this.SetupAutoScroll();
 }
Esempio n. 5
0
        private void DrawEnumInfo(OdinMenuItem obj)
        {
            var member = obj.Value as EnumMember;

            if (member == null)
            {
                return;
            }


            var hasMessage = !string.IsNullOrEmpty(member.message);

            if (member.isObsolete)
            {
                var rect = obj.Rect.Padding(5, 3).AlignRight(16).AlignCenterY(16);
                GUI.DrawTexture(rect, EditorIcons.TestInconclusive);
            }
            else if (hasMessage)
            {
                var rect = obj.Rect.Padding(5, 3).AlignRight(16).AlignCenterY(16);
                GUI.DrawTexture(rect, EditorIcons.ConsoleInfoIcon);
            }

            if (hasMessage)
            {
                GUI.Label(obj.Rect, new GUIContent("", member.message));
            }
        }
Esempio n. 6
0
        private void DrawEnumItem(OdinMenuItem obj)
        {
            if (Event.current.type == EventType.MouseDown && obj.Rect.Contains(Event.current.mousePosition))
            {
                obj.Select();
                Event.current.Use();
                wasMouseDown = true;
            }

            if (wasMouseDown)
            {
                GUIHelper.RequestRepaint();
            }

            if (wasMouseDown == true && Event.current.type == EventType.MouseDrag && obj.Rect.Contains(Event.current.mousePosition))
            {
                obj.Select();
            }

            if (Event.current.type == EventType.MouseUp)
            {
                wasMouseDown = false;
                if (obj.IsSelected && obj.Rect.Contains(Event.current.mousePosition))
                {
                    obj.MenuTree.Selection.ConfirmSelection();
                }
            }
        }
        private void EnableSingleClickToSelect(OdinMenuItem obj)
        {
            var t = Event.current.type;

            if (t == EventType.Layout)
            {
                return;
            }

            if (obj.Rect.Contains(Event.current.mousePosition) == false)
            {
                return;
            }

            GUIHelper.RequestRepaint();

            if (Event.current.type == EventType.MouseDrag)
            {
                if (obj is T)
                {
                    if (this.IsValidSelection(Enumerable.Repeat((T)obj.Value, 1)))
                    {
                        obj.Select();
                    }
                }
            }

            bool confirm = t == EventType.MouseUp && (obj.ChildMenuItems.Count == 0);

            if (confirm)
            {
                obj.MenuTree.Selection.ConfirmSelection();
                Event.current.Use();
            }
        }
Esempio n. 8
0
        internal void UpdateMenuTreeRecursive(bool isRoot = false)
        {
            this.isInitialized = true;
            OdinMenuItem prev = null;

            foreach (var child in this.ChildMenuItems)
            {
                child.parentMenuItem       = null;
                child.nextMenuItem         = null;
                child.previousMenuItemFlat = null;
                child.nextMenuItemFlat     = null;
                child.previousMenuItem     = null;

                if (!isRoot)
                {
                    child.parentMenuItem = this;
                }

                if (prev != null)
                {
                    prev.nextMenuItem      = child;
                    child.previousMenuItem = prev;
                }

                prev = child;

                child.UpdateMenuTreeRecursive();
            }
        }
Esempio n. 9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OdinMenuTree"/> class.
 /// </summary>
 /// <param name="supportsMultiSelect">if set to <c>true</c> [supports multi select].</param>
 /// <param name="defaultMenuStyle">The default menu item style.</param>
 public OdinMenuTree(bool supportsMultiSelect, OdinMenuStyle defaultMenuStyle)
 {
     this.DefaultMenuStyle = defaultMenuStyle;
     this.selection        = new OdinMenuTreeSelection(supportsMultiSelect);
     this.root             = new OdinMenuItem(this, "root", null);
     this.SetupAutoScroll();
     this.searchFieldControlName = Guid.NewGuid().ToString();
 }
Esempio n. 10
0
        private static object GetMenuItemEnumValue(OdinMenuItem item)
        {
            var memmebr = item.Value as EnumMember;

            if (memmebr != null && memmebr.value != null)
            {
                return(memmebr.value);
            }
            return(0);
        }
Esempio n. 11
0
        /// <summary>
        /// Not yet documented.
        /// </summary>
        /// <param name="toolbarStyle">Not yet documented.</param>
        public void DrawSearchToolbar(GUIStyle toolbarStyle = null)
        {
            var config = this.Config;

            var searchFieldRect = GUILayoutUtility.GetRect(0, config.SearchToolbarHeight, GUILayoutOptions.ExpandWidth(true));

            if (Event.current.type == EventType.Repaint)
            {
                (toolbarStyle ?? SirenixGUIStyles.ToolbarBackground).Draw(searchFieldRect, GUIContent.none, 0);
            }

            searchFieldRect       = searchFieldRect.HorizontalPadding(5).AlignMiddle(16);
            searchFieldRect.xMin += 3;
            searchFieldRect.y    += 1;

            EditorGUI.BeginChangeCheck();
            config.SearchTerm = this.DrawSearchField(searchFieldRect, config.SearchTerm, config.AutoFocusSearchBar);
            var changed = EditorGUI.EndChangeCheck();

            if (changed && this.hasRepaintedCurrentSearchResult)
            {
                // We want fast visual search feedback. If the user is typing faster than the window can repaint,
                // then no results will be visible while he's typing. this.hasRepaintedCurrentSearchResult fixes that.

                this.hasRepaintedCurrentSearchResult = false;
                bool doSearch = !string.IsNullOrEmpty(config.SearchTerm);
                if (doSearch)
                {
                    this.DrawInSearchMode = true;
                    this.EnumerateTree().ForEach(x => x.IsVisible = config.SearchFunction(x));
                }
                else
                {
                    if (this.DrawInSearchMode)
                    {
                        this.DrawInSearchMode = false;
                        var last = this.selection.LastOrDefault();
                        UnityEditorEventUtility.DelayAction(() => this.scrollToAndCenter = last);
                    }

                    this.EnumerateTree()
                    .ForEach(x => x.IsVisible = true);

                    this.Selection
                    .SelectMany(x => x.GetParentMenuItemsRecursive(false))
                    .ForEach(x => x.Toggled = true);
                }
            }

            if (Event.current.type == EventType.Repaint)
            {
                this.hasRepaintedCurrentSearchResult = true;
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Assigns the asset mini thumbnail as an icon to all menu items in the collection. If the menu items object is null then a Unity folder icon is assigned.
        /// </summary>
        public static OdinMenuItem AddThumbnailIcon(this OdinMenuItem item, bool preferAssetPreviewAsIcon)
        {
            var instance = item.Value;

            var unityObject = instance as UnityEngine.Object;

            if (unityObject)
            {
                if (preferAssetPreviewAsIcon)
                {
                    item.IconGetter = () => GUIHelper.GetAssetThumbnail(unityObject, unityObject.GetType(), preferAssetPreviewAsIcon);
                }
                else
                {
                    item.Icon = GUIHelper.GetAssetThumbnail(unityObject, unityObject.GetType(), preferAssetPreviewAsIcon);
                }
                return(item);
            }

            var type = instance as Type;

            if (type != null)
            {
                if (preferAssetPreviewAsIcon)
                {
                    item.IconGetter = () => GUIHelper.GetAssetThumbnail(null, type, preferAssetPreviewAsIcon);
                }
                else
                {
                    item.Icon = GUIHelper.GetAssetThumbnail(null, type, preferAssetPreviewAsIcon);
                }

                return(item);
            }

            var assetPath = instance as string;

            if (assetPath != null)
            {
                if (assetPath != null)
                {
                    if (File.Exists(assetPath))
                    {
                        item.Icon = InternalEditorUtility.GetIconForFile(assetPath);
                    }
                    else if (Directory.Exists(assetPath))
                    {
                        item.Icon = EditorIcons.UnityFolderIcon;
                    }
                }
            }

            return(item);
        }
Esempio n. 13
0
        void OnRightClickEvent(OdinMenuItem item)
        {
            if (MenuTree.Selection.Count == 0)
            {
                return;
            }

            List <string> paths = new List <string>();

            for (int i = 0; i < MenuTree.Selection.Count; i++)
            {
                paths.Add(MenuTree.Selection[i].Value as string);
            }

            SVNTool.DrawGenericMenu(ref _popMenu, paths);
            _popMenu.DropDown(item.LabelRect);
        }
Esempio n. 14
0
        private static void AddRecursive(OdinMenuTree tree, List <OdinMenuItem> source, List <OdinMenuItem> destination)
        {
            destination.Capacity = source.Count;

            for (int i = 0; i < source.Count; i++)
            {
                var item  = source[i];
                var clone = new OdinMenuItem(tree, item.Name, item.ObjectInstance)
                            .AddThumbnailIcon(false);

                destination.Add(clone);

                if (item.ChildMenuItems.Count > 0)
                {
                    AddRecursive(tree, item.ChildMenuItems, clone.ChildMenuItems);
                }
            }
        }
Esempio n. 15
0
        private void ToggleEnumFlag(OdinMenuItem obj)
        {
            var val = (ulong)Convert.ToInt64(GetMenuItemEnumValue(obj));

            if ((val & this.curentValue) == val)
            {
                this.curentValue = val == 0 ? 0 : (this.curentValue & ~val);
            }
            else
            {
                this.curentValue = this.curentValue | val;
            }

            if (Event.current.clickCount >= 2)
            {
                Event.current.Use();
            }
        }
Esempio n. 16
0
 private void SetupAutoScroll()
 {
     this.selection.SelectionChanged += (x) =>
     {
         if (this.Config.AutoScrollOnSelectionChanged)
         {
             if (this.isFirstFrame)
             {
                 this.scrollToAndCenter = this.selection.LastOrDefault();
             }
             else
             {
                 this.requestRepaint = true;
                 GUIHelper.RequestRepaint();
                 ScrollToMenuItem(this.selection.LastOrDefault());
             }
         }
     };
 }
Esempio n. 17
0
        /// <summary>
        /// Adds the specified object at the specified menu item path and returns all menu items created in order to add in order to end up at the specified menu path.
        /// </summary>
        /// <param name="tree">The tree.</param>
        /// <param name="menuPath">The menu path.</param>
        /// <param name="instance">The object instance.</param>
        /// <param name="forceShowOdinSerializedMembers">Set this to true if you want ODIN serialzied members such as dictionaries and generics to be shown as well.</param>
        /// <returns>Returns all menu items created in order to add the menu item at the specified menu item path.</returns>
        public static IEnumerable <OdinMenuItem> AddObjectAtPath(this OdinMenuTree tree, string menuPath, object instance, bool forceShowOdinSerializedMembers = false, MyEnumColor textColor = MyEnumColor.Blue)
        {
            string name;

            SplitMenuPath(menuPath, out menuPath, out name);

            if (forceShowOdinSerializedMembers && !(instance as UnityEngine.Object))
            {
                OdinMenuItem item = new OdinMenuItem(tree, name, new SerializedValueWrapper(instance));
                item.TextColor = textColor;
                return(tree.AddMenuItemAtPath(menuPath, item));
            }
            else
            {
                OdinMenuItem item = new OdinMenuItem(tree, name, instance);
                item.TextColor = textColor;
                return(tree.AddMenuItemAtPath(menuPath, item));
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Adds the menu item at the specified menu item path and populates the result list with all menu items created in order to add the menuItem at the specified path.
        /// </summary>
        /// <param name="tree">The tree instance.</param>
        /// <param name="result">The result list.</param>
        /// <param name="path">The menu item path.</param>
        /// <param name="menuItem">The menu item.</param>
        public static void AddMenuItemAtPath(this OdinMenuTree tree, List <OdinMenuItem> result, string path, OdinMenuItem menuItem)
        {
            var curr = tree.Root;

            if (!string.IsNullOrEmpty(path))
            {
                path = path.Trim('/') + "/";

                var iFrom = 0;
                var iTo   = 0;

                do
                {
                    iTo = path.IndexOf('/', iFrom);
                    var name  = path.Substring(iFrom, iTo - iFrom);
                    var child = curr.ChildMenuItems.FirstOrDefault(x => x.Name == name);

                    if (child == null)
                    {
                        child = new OdinMenuItem(tree, name, null);
                        curr.ChildMenuItems.Add(child);
                    }

                    result.Add(child);

                    curr = child;

                    iFrom = iTo + 1;
                } while (iTo != path.Length - 1);
            }

            var oldItem = curr.ChildMenuItems.FirstOrDefault(x => x.Name == menuItem.Name);

            if (oldItem != null)
            {
                curr.ChildMenuItems.Remove(oldItem);
                menuItem.ChildMenuItems.AddRange(oldItem.ChildMenuItems);
            }

            curr.ChildMenuItems.Add(menuItem);
            result.Add(menuItem);
        }
Esempio n. 19
0
        internal void UpdateFlatMenuItemNavigation()
        {
            int          i    = 0;
            OdinMenuItem prev = null;
            IEnumerable <OdinMenuItem> query = this.menuTree.DrawInSearchMode ? this.menuTree.FlatMenuTree : this.menuTree.EnumerateTree();

            foreach (var item in query)
            {
                item.flatTreeIndex        = i++;
                item.nextMenuItemFlat     = null;
                item.previousMenuItemFlat = null;

                if (prev != null)
                {
                    item.previousMenuItemFlat = prev;
                    prev.nextMenuItemFlat     = item;
                }

                prev = item;
            }
        }
Esempio n. 20
0
        internal void UpdateMenuTreeRecursive(bool isRoot = false)
        {
            this.isInitialized = true;
            OdinMenuItem prev = null;

            foreach (var child in this.ChildMenuItems)
            {
                if (!isRoot)
                {
                    child.parentMenuItem = this;
                }

                if (prev != null)
                {
                    prev.nextMenuItem      = child;
                    child.previousMenuItem = prev;
                }

                prev = child;

                child.UpdateMenuTreeRecursive();
            }

            if (isRoot)
            {
                int i = 0;
                prev = null;
                foreach (var item in this.menuTree.EnumerateTree())
                {
                    item.flatTreeIndex = i++;
                    if (prev != null)
                    {
                        item.previousMenuItemFlat = prev;
                        prev.nextMenuItemFlat     = item;
                    }
                    prev = item;
                }
            }
        }
Esempio n. 21
0
 /// <summary>
 /// Adds the menu item at specified menu item path, and returns all menu items created in order to add the menuItem at the specified path.
 /// </summary>
 /// <param name="tree">The tree.</param>
 /// <param name="path">The menu item path.</param>
 /// <param name="menuItem">The menu item.</param>
 /// <returns>Returns all menu items created in order to add the menu item at the specified menu item path.</returns>
 public static IEnumerable <OdinMenuItem> AddMenuItemAtPath(this OdinMenuTree tree, string path, OdinMenuItem menuItem)
 {
     cache.Clear();
     AddMenuItemAtPath(tree, cache, path, menuItem);
     return(cache);
 }
Esempio n. 22
0
        private void DrawEnumFlagItem(OdinMenuItem obj)
        {
            if ((Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseUp) && obj.Rect.Contains(Event.current.mousePosition))
            {
                if (Event.current.type == EventType.MouseDown)
                {
                    ToggleEnumFlag(obj);

                    this.TriggerSelectionChanged();
                }
                Event.current.Use();
            }

            if (Event.current.type == EventType.Repaint)
            {
                var val          = (ulong)Convert.ToInt64(GetMenuItemEnumValue(obj));
                var isPowerOfTwo = (val & (val - 1)) == 0;

                if (val != 0 && !isPowerOfTwo)
                {
                    var isMouseOver = obj.Rect.Contains(Event.current.mousePosition);
                    if (isMouseOver)
                    {
                        curentMouseOverValue = val;
                    }
                    else if (val == curentMouseOverValue)
                    {
                        curentMouseOverValue = 0;
                    }
                }

                var chked     = (val & this.curentValue) == val && !((val == 0 && this.curentValue != 0));
                var highlight = val != 0 && isPowerOfTwo && (val & this.curentMouseOverValue) == val && !((val == 0 && this.curentMouseOverValue != 0));

                if (highlight)
                {
                    EditorGUI.DrawRect(obj.Rect.AlignLeft(6).Padding(2), highlightLineColor);
                }

                if (chked || isPowerOfTwo)
                {
                    var rect = obj.Rect.AlignLeft(30).AlignCenter(EditorIcons.TestPassed.width, EditorIcons.TestPassed.height);
                    if (chked)
                    {
                        if (isPowerOfTwo)
                        {
                            if (!EditorGUIUtility.isProSkin)
                            {
                                var tmp = GUI.color;
                                GUI.color = new Color(1, 0.7f, 1, 1);
                                GUI.DrawTexture(rect, EditorIcons.TestPassed);
                                GUI.color = tmp;
                            }
                            else
                            {
                                GUI.DrawTexture(rect, EditorIcons.TestPassed);
                            }
                        }
                        else
                        {
                            EditorGUI.DrawRect(obj.Rect.AlignTop(obj.Rect.height - (EditorGUIUtility.isProSkin ? 1 : 0)), selectedMaskBgColor);
                        }
                    }
                    else
                    {
                        GUI.DrawTexture(rect, EditorIcons.TestNormal);
                    }
                }
            }
        }
Esempio n. 23
0
        /// <summary>
        /// Handles the keybaord menu navigation. Call this at the end of your GUI scope, to prevent the menu tree from stealing input events from other text fields.
        /// </summary>
        /// <returns>Returns true, if anything was changed via the keyboard.</returns>
        public bool HandleKeybaordMenuNavigation()
        {
            if (Event.current.type != EventType.KeyDown)
            {
                return(false);
            }

            if (OdinMenuTree.ActiveMenuTree != this)
            {
                return(false);
            }

            GUIHelper.RequestRepaint();

            var keycode = Event.current.keyCode;

            // Select first or last if no visisble items is slected.
            if (this.Selection.Count == 0 || !this.Selection.Any(x => x._IsVisible()))
            {
                var query = this.DrawInSearchMode ? this.FlatMenuTree : this.EnumerateTree().Where(x => x._IsVisible());

                OdinMenuItem next = null;
                if (keycode == KeyCode.DownArrow)
                {
                    next = query.FirstOrDefault();
                }
                else if (keycode == KeyCode.UpArrow)
                {
                    next = query.LastOrDefault();
                }
                else if (keycode == KeyCode.LeftAlt)
                {
                    next = query.FirstOrDefault();
                }
                else if (keycode == KeyCode.RightAlt)
                {
                    next = query.FirstOrDefault();
                }

                if (next != null)
                {
                    next.Select();
                    Event.current.Use();
                    return(true);
                }
            }
            else
            {
                if (keycode == KeyCode.LeftArrow && !this.DrawInSearchMode)
                {
                    bool goUp = true;
                    foreach (var curr in this.Selection.ToList())
                    {
                        if (curr.Toggled == true && curr.ChildMenuItems.Any())
                        {
                            goUp         = false;
                            curr.Toggled = false;
                        }

                        if ((Event.current.modifiers & EventModifiers.Alt) != 0)
                        {
                            goUp = false;
                            foreach (var item in curr.GetChildMenuItemsRecursive(false))
                            {
                                item.Toggled = curr.Toggled;
                            }
                        }
                    }

                    if (goUp)
                    {
                        keycode = KeyCode.UpArrow;
                    }

                    Event.current.Use();
                }

                if (keycode == KeyCode.RightArrow && !this.DrawInSearchMode)
                {
                    bool goDown = true;
                    foreach (var curr in this.Selection.ToList())
                    {
                        if (curr.Toggled == false && curr.ChildMenuItems.Any())
                        {
                            curr.Toggled = true;
                            goDown       = false;
                        }

                        if ((Event.current.modifiers & EventModifiers.Alt) != 0)
                        {
                            goDown = false;

                            foreach (var item in curr.GetChildMenuItemsRecursive(false))
                            {
                                item.Toggled = curr.Toggled;
                            }
                        }
                    }

                    if (goDown)
                    {
                        keycode = KeyCode.DownArrow;
                    }

                    Event.current.Use();
                }

                if (keycode == KeyCode.UpArrow)
                {
                    if ((Event.current.modifiers & EventModifiers.Shift) != 0)
                    {
                        var last = this.Selection.Last();
                        var prev = last.PrevVisualMenuItem;

                        if (prev != null)
                        {
                            if (prev.IsSelected)
                            {
                                last.Deselect();
                            }
                            else
                            {
                                prev.Select(true);
                            }

                            Event.current.Use();
                            return(true);
                        }
                    }
                    else
                    {
                        var prev = this.Selection.Last().PrevVisualMenuItem;
                        if (prev != null)
                        {
                            prev.Select();
                            Event.current.Use();
                            return(true);
                        }
                    }
                }

                if (keycode == KeyCode.DownArrow)
                {
                    if ((Event.current.modifiers & EventModifiers.Shift) != 0)
                    {
                        var last = this.Selection.Last();
                        var next = last.NextVisualMenuItem;

                        if (next != null)
                        {
                            if (next.IsSelected)
                            {
                                last.Deselect();
                            }
                            else
                            {
                                next.Select(true);
                            }

                            Event.current.Use();
                            return(true);
                        }
                    }
                    else
                    {
                        var next = this.Selection.Last().NextVisualMenuItem;
                        if (next != null)
                        {
                            next.Select();
                            Event.current.Use();
                            return(true);
                        }
                    }
                }

                if (keycode == KeyCode.Return)
                {
                    this.Selection.ConfirmSelection();
                    Event.current.Use();
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 24
0
        /// <summary>
        /// Scrolls to the specified menu item.
        /// </summary>
        public void ScrollToMenuItem(OdinMenuItem menuItem, bool centerMenuItem = false)
        {
            if (menuItem != null)
            {
                this.scollToCenter     = centerMenuItem;
                this.scrollToWhenReady = menuItem;

                if (!menuItem._IsVisible())
                {
                    foreach (var item in menuItem.GetParentMenuItemsRecursive(false))
                    {
                        item.Toggled = true;
                    }
                    return;
                }

                foreach (var item in menuItem.GetParentMenuItemsRecursive(false))
                {
                    item.Toggled = true;
                }

                if (this.outerScrollViewRect.height == 0 || menuItem.Rect.height <= 0.01f)
                {
                    return;
                }

                if (Event.current.type == EventType.Layout)
                {
                    return;
                }

                var config = this.Config;
                var rect   = menuItem.Rect;

                float a, b;

                if (centerMenuItem)
                {
                    var r = this.outerScrollViewRect.AlignCenterY(rect.height);

                    a = rect.yMin - (this.innerScrollViewRect.y + config.ScrollPos.y - r.y);
                    b = (rect.yMax - r.height + this.innerScrollViewRect.y) - (config.ScrollPos.y + r.y);
                }
                else
                {
                    var viewRect = this.outerScrollViewRect;
                    viewRect.y = 0;

                    a  = rect.yMin - (this.innerScrollViewRect.y + config.ScrollPos.y) - 1;
                    b  = (rect.yMax - this.outerScrollViewRect.height + this.innerScrollViewRect.y) - config.ScrollPos.y;
                    a -= rect.height;
                    b += rect.height;
                }

                if (a < 0)
                {
                    config.ScrollPos.y += a;
                }

                if (b > 0)
                {
                    config.ScrollPos.y += b;
                }

                // Some windows takes a while to adjust themselves, where the inner and outer range are subject to change.
                if (this.frameCounter.FrameCount > 6)
                {
                    this.scrollToWhenReady = null;
                }
                else
                {
                    GUIHelper.RequestRepaint();
                }
            }
        }
Esempio n. 25
0
        /// <summary>
        /// Handles the mouse events.
        /// </summary>
        /// <param name="rect">The rect.</param>
        /// <param name="triangleRect">The triangle rect.</param>
        protected void HandleMouseEvents(Rect rect, Rect triangleRect)
        {
            var e = Event.current.type;

            if (e == EventType.Used && this.wasMouseDownEvent)
            {
                this.wasMouseDownEvent    = false;
                handleClickEventOnMouseUp = this;
            }

            bool isMouseClick =
                (e == EventType.MouseDown) ||
                (e == EventType.MouseUp && handleClickEventOnMouseUp == this);

            if (isMouseClick)
            {
                handleClickEventOnMouseUp = null;
                this.wasMouseDownEvent    = false;

                if (!rect.Contains(Event.current.mousePosition))
                {
                    return;
                }

                var hasChildren = this.ChildMenuItems.Any();
                var instance    = this.ObjectInstance;
                var selected    = this.IsSelected;
                var selectable  = !triangleRect.Contains(Event.current.mousePosition);

                bool isUnityObjectInstance = instance as UnityEngine.Object;

                if (selected && isUnityObjectInstance)
                {
                    var unityObject = instance as UnityEngine.Object;
                    var behaviour   = unityObject as Behaviour;
                    if (behaviour)
                    {
                        unityObject = behaviour.gameObject;
                    }
                    EditorGUIUtility.PingObject(unityObject);
                }

                if (Event.current.button == 1)
                {
                    if (this.OnRightClick != null)
                    {
                        this.OnRightClick(this);
                    }
                }

                if (Event.current.button == 0)
                {
                    if (hasChildren && selected && Event.current.modifiers == EventModifiers.None || !selectable)
                    {
                        this.Toggled = !this.Toggled;
                    }

                    if (!selectable && Event.current.modifiers == EventModifiers.Alt)
                    {
                        selectable = true;
                    }

                    if (selectable)
                    {
                        if (Event.current.modifiers == EventModifiers.Alt)
                        {
                            foreach (var item in this.GetChildMenuItemsRecursive(false))
                            {
                                item.Toggled = this.Toggled;
                            }
                        }

                        bool shiftSelect =
                            this.menuTree.Selection.SupportsMultiSelect &&
                            Event.current.modifiers == EventModifiers.Shift &&
                            this.menuTree.Selection.Count > 0;

                        if (shiftSelect)
                        {
                            var curr          = this.menuTree.Selection.First();
                            var maxIterations = Mathf.Abs(curr.FlatTreeIndex - this.FlatTreeIndex) + 1;
                            var down          = curr.FlatTreeIndex < this.FlatTreeIndex;
                            this.menuTree.Selection.Clear();

                            for (int i = 0; i < maxIterations; i++)
                            {
                                if (curr == null)
                                {
                                    break;
                                }

                                curr.Select(true);

                                if (curr == this)
                                {
                                    break;
                                }

                                curr = down ? curr.NextVisualMenuItem : curr.PrevVisualMenuItem;
                            }
                        }
                        else
                        {
                            var ctrl = Event.current.modifiers == EventModifiers.Control;
                            if (ctrl && selected)
                            {
                                this.Deselect();
                            }
                            else
                            {
                                this.Select(ctrl);
                            }

                            if (Event.current.clickCount == 2)
                            {
                                this.MenuTree.Selection.ConfirmSelection();
                            }
                        }
                    }
                }

                GUIHelper.RemoveFocusControl();
                Event.current.Use();
            }
        }
Esempio n. 26
0
        /// <summary>
        /// Draws the menu tree recursively.
        /// </summary>
        public void DrawMenuTree()
        {
            var config = this.Config;

            if (this.requestRepaint)
            {
                GUIHelper.RequestRepaint();
                this.requestRepaint = false;
            }

            if (config.DrawSearchToolbar)
            {
                DrawSearchToolbar();
            }

            if (config.DrawScrollView)
            {
                var r = EditorGUILayout.BeginVertical();
                if (Event.current.type == EventType.Repaint)
                {
                    this.outerScrollViewRect = r;
                }

                // GUIScrollViews doesn't play well with ExpandHeight(false). The scroll wheel will flicker when it expanding or contracting in size.
                // But for popup windows and other stuff, it is important that the ExpandHeight is false during the first couple of frames
                // so we can calculate a good height for the window.

                if (frameCounter.Update().FrameCount < 4)
                {
                    config.ScrollPos = EditorGUILayout.BeginScrollView(config.ScrollPos, GUILayoutOptions.ExpandHeight(false));
                }
                else
                {
                    config.ScrollPos = EditorGUILayout.BeginScrollView(config.ScrollPos);
                }

                if (Event.current.type == EventType.Repaint)
                {
                    this.innerScrollViewYTop = GUIHelper.GetCurrentLayoutRect().y;
                }

                GUILayout.Space(-1);
            }

            foreach (var item in this.MenuItems)
            {
                item.DrawMenuItems(0);
            }

            if (config.DrawScrollView)
            {
                EditorGUILayout.EndScrollView();
                EditorGUILayout.EndVertical();

                if (!this.isFirstFrame)
                {
                    if (this.scrollToAndCenter != null && Event.current.type == EventType.Layout)
                    {
                        this.ScrollToMenuItem(this.Selection.LastOrDefault(), true);
                        this.scrollToAndCenter = null;
                    }

                    if (this.updateScrollView)
                    {
                        this.ScrollToMenuItem(this.Selection.LastOrDefault());
                        this.updateScrollView = false;
                    }
                }
            }

            if (config.AutoHandleKeyboardNavigation)
            {
                this.HandleKeybaordMenuNavigation();
            }

            if (Event.current.type == EventType.Repaint)
            {
                this.isFirstFrame = false;
            }
        }
Esempio n. 27
0
        /// <summary>
        /// Adds the menu item at specified menu item path, and returns all menu items created in order to add the menuItem at the specified path.
        /// </summary>
        /// <param name="tree">The tree.</param>
        /// <param name="path">The menu item path.</param>
        /// <param name="menuItem">The menu item.</param>
        /// <returns>Returns all menu items created in order to add the menu item at the specified menu item path.</returns>
        public static IEnumerable <OdinMenuItem> AddMenuItemAtPath(this OdinMenuTree tree, string path, OdinMenuItem menuItem)
        {
            List <OdinMenuItem> result = new List <OdinMenuItem>(5);

            AddMenuItemAtPath(tree, result, path, menuItem);
            return(result);
        }
Esempio n. 28
0
        /// <summary>
        /// Adds the menu item at the specified menu item path and populates the result list with all menu items created in order to add the menuItem at the specified path.
        /// </summary>
        /// <param name="tree">The tree instance.</param>
        /// <param name="result">The result list.</param>
        /// <param name="path">The menu item path.</param>
        /// <param name="menuItem">The menu item.</param>
        public static void AddMenuItemAtPath(this OdinMenuTree tree, ICollection <OdinMenuItem> result, string path, OdinMenuItem menuItem)
        {
            var curr = tree.Root;

            if (!string.IsNullOrEmpty(path))
            {
                if (path[0] == '/' || path[path.Length - 1] == '/')
                {
                    path = path.Trim();
                }

                var iFrom = 0;
                var iTo   = 0;

                do
                {
                    iTo = path.IndexOf('/', iFrom);

                    string name;

                    if (iTo < 0)
                    {
                        iTo  = path.Length - 1;
                        name = path.Substring(iFrom, iTo - iFrom + 1);
                    }
                    else
                    {
                        name = path.Substring(iFrom, iTo - iFrom);
                    }

                    var childs = curr.ChildMenuItems;

                    // OdinMenuItem child = curr.ChildMenuItems.FirstOrDefault(x => x.Name == name);
                    // If we assume people add menu items in a local order, then starting our search from then end of the list, should be faster.
                    OdinMenuItem child = null;
                    for (int i = childs.Count - 1; i >= 0; i--)
                    {
                        if (childs[i].Name == name)
                        {
                            child = childs[i];
                            break;
                        }
                    }

                    if (child == null)
                    {
                        child = new OdinMenuItem(tree, name, null);
                        curr.ChildMenuItems.Add(child);
                    }

                    result.Add(child);

                    curr = child;

                    iFrom = iTo + 1;
                } while (iTo != path.Length - 1);
            }

            // var oldItem = curr.ChildMenuItems.FirstOrDefault(x => x.Name == menuItem.Name);
            // If we assume people add menu items in a local order, then starting our search from then end of the list, should be faster.
            var          currChilds = curr.ChildMenuItems;
            OdinMenuItem oldItem    = null;

            for (int i = currChilds.Count - 1; i >= 0; i--)
            {
                if (currChilds[i].Name == menuItem.Name)
                {
                    oldItem = currChilds[i];
                    break;
                }
            }

            if (oldItem != null)
            {
                curr.ChildMenuItems.Remove(oldItem);
                menuItem.ChildMenuItems.AddRange(oldItem.ChildMenuItems);
            }

            curr.ChildMenuItems.Add(menuItem);
            result.Add(menuItem);
        }
        private void DrawCheckboxMenuItems(OdinMenuItem xx)
        {
            var allChilds = xx.GetChildMenuItemsRecursive(true)
                            .Select(x => x.Value)
                            .OfType <T>().ToList();

            bool isEmpty      = allChilds.Count == 0;
            bool isSelected   = false;
            bool isMixed      = false;
            int  prevUpdateId = -1;

            Action validate = () =>
            {
                if (isEmpty)
                {
                    return;
                }
                isSelected = this.selection.Contains(allChilds[0]);
                //var a = this.selection.ToList();
                var b = allChilds[0];
                isMixed = false;
                for (int i = 1; i < allChilds.Count; i++)
                {
                    var sel = this.selection.Contains(allChilds[i]);
                    if (sel != isSelected)
                    {
                        isMixed = true;
                        break;
                    }
                }
            };

            xx.OnDrawItem += (menuItem) =>
            {
                if (isEmpty)
                {
                    return;
                }

                var checkboxRect = xx.LabelRect;
                checkboxRect    = checkboxRect.AlignMiddle(18).AlignLeft(16);
                checkboxRect.x -= 16;
                if (xx.IconGetter())
                {
                    checkboxRect.x -= 16;
                }

                if (Event.current.type != EventType.Repaint && xx.ChildMenuItems.Count == 0)
                {
                    checkboxRect = xx.Rect;
                }
                //else if (menuItem.ChildMenuItems.Count > 0)
                //{
                //    rect = xx.Rect;
                //}

                if (prevUpdateId != this.checkboxUpdateId)
                {
                    validate();
                    prevUpdateId = this.checkboxUpdateId;
                }

                EditorGUI.showMixedValue = isMixed;
                EditorGUI.BeginChangeCheck();
                var newSelected = EditorGUI.Toggle(checkboxRect, isSelected);
                if (EditorGUI.EndChangeCheck())
                {
                    for (int i = 0; i < allChilds.Count; i++)
                    {
                        if (newSelected)
                        {
                            this.selection.Add(allChilds[i]);
                        }
                        else
                        {
                            this.selection.Remove(allChilds[i]);
                        }
                    }
                    xx.Select();
                    validate();
                    this.requestCheckboxUpdate = true;
                    GUIHelper.RemoveFocusControl();
                }
                EditorGUI.showMixedValue = false;
            };
        }
Esempio n. 30
0
        /// <summary>
        /// Handles the keybaord menu navigation. Call this at the end of your GUI scope, to prevent the menu tree from stealing input events from text fields and such.
        /// </summary>
        /// <returns>Returns true, if anything was changed via the keyboard.</returns>
        public bool HandleKeybaordMenuNavigation()
        {
            if (Event.current.type != EventType.KeyDown)
            {
                return(false);
            }

            GUIHelper.RequestRepaint();

            if (this.Selection.Count == 0)
            {
                OdinMenuItem next = null;
                if (Event.current.keyCode == KeyCode.DownArrow)
                {
                    next = this.MenuItems.FirstOrDefault();
                }
                else if (Event.current.keyCode == KeyCode.UpArrow)
                {
                    next = this.MenuItems.LastOrDefault();
                }
                else if (Event.current.keyCode == KeyCode.LeftAlt)
                {
                    next = this.MenuItems.FirstOrDefault();
                }
                else if (Event.current.keyCode == KeyCode.RightAlt)
                {
                    next = this.MenuItems.FirstOrDefault();
                }

                if (next != null)
                {
                    Event.current.Use();
                    next.Select();
                    return(true);
                }
            }
            else
            {
                if (Event.current.keyCode == KeyCode.RightArrow)
                {
                    foreach (var curr in this.Selection.ToList())
                    {
                        curr.Toggled = true;

                        if ((Event.current.modifiers & EventModifiers.Alt) != 0)
                        {
                            foreach (var item in curr.GetChildMenuItemsRecursive(false))
                            {
                                item.Toggled = curr.Toggled;
                            }
                        }
                    }

                    Event.current.Use();
                }
                else if (Event.current.keyCode == KeyCode.LeftArrow)
                {
                    foreach (var curr in this.Selection.ToList())
                    {
                        if (curr.Parent != null && (!curr.ChildMenuItems.Any() || curr.Parent.Toggled == false))
                        {
                            curr.Parent.Select();
                            return(true);
                        }
                        else
                        {
                            curr.Toggled = false;

                            if ((Event.current.modifiers & EventModifiers.Alt) != 0)
                            {
                                foreach (var item in curr.GetChildMenuItemsRecursive(false))
                                {
                                    item.Toggled = curr.Toggled;
                                }
                            }
                        }
                    }

                    Event.current.Use();
                }
                else if (Event.current.keyCode == KeyCode.UpArrow)
                {
                    if ((Event.current.modifiers & EventModifiers.Shift) != 0)
                    {
                        var last = this.Selection.Last();
                        var prev = last.PrevVisualMenuItem;

                        if (prev != null)
                        {
                            if (prev.IsSelected)
                            {
                                last.Deselect();
                                return(true);
                            }
                            else
                            {
                                prev.Select(true);
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        var prev = this.Selection.Last().PrevVisualMenuItem;
                        if (prev != null)
                        {
                            prev.Select();
                            return(true);
                        }
                    }

                    Event.current.Use();
                }
                else if (Event.current.keyCode == KeyCode.DownArrow)
                {
                    if ((Event.current.modifiers & EventModifiers.Shift) != 0)
                    {
                        var last = this.Selection.Last();
                        var next = last.NextVisualMenuItem;

                        if (next != null)
                        {
                            if (next.IsSelected)
                            {
                                last.Deselect();
                                return(true);
                            }
                            else
                            {
                                next.Select(true);
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        var next = this.Selection.Last().NextVisualMenuItem;
                        if (next != null)
                        {
                            next.Select();
                            return(true);
                        }
                    }

                    Event.current.Use();
                }
            }

            return(false);
        }