Ejemplo n.º 1
0
        private void EnterChild(FuzzyOptionNode node)
        {
            if (node == null || node.hasChildren == false || node.option is FuzzySeparator)
            {
                return;
            }

            ExecuteTask(() =>
            {
                Populate(node, tree.Children(node.option));
            });

            lastRepaintTime = DateTime.UtcNow;

            query        = string.Empty;
            delayedQuery = null;
            GUIUtility.keyboardControl = 0;
            letQueryClear = true;

            if (animTarget == 0)
            {
                animTarget   = 1;
                animAncestor = null;
            }
            else if (anim == 1)
            {
                anim     = 0;
                prevAnim = 0;
                stack.Add(node);
            }
        }
Ejemplo n.º 2
0
        private void OnLevelGUI(float anim)
        {
            var parent = stack[stack.Count - 1];

            anim = Mathf.Floor(anim) + Mathf.SmoothStep(0, 1, Mathf.Repeat(anim, 1));

            if (stack.Count > 1 || !string.IsNullOrEmpty(parent.option.headerLabel))
            {
                OnHeaderGUI();
            }

            if (e.type == EventType.Layout || e.type == EventType.Repaint)
            {
                minOptionWidth = 0;
            }

            OnOptionsGUI(anim, parent);

            if (anim < 1)
            {
                FuzzyOptionNode grandparent = null;

                if (animTarget == 0 && animAncestor != null)
                {
                    grandparent = animAncestor;
                }
                else if (stack.Count > 1)
                {
                    grandparent = stack[stack.Count - 2];
                }

                OnOptionsGUI(anim + 1, grandparent);
            }
        }
Ejemplo n.º 3
0
        public override void OnFooterGUI(FuzzyOptionNode node, Rect position)
        {
            if (editorTarget != value)
            {
                editorTarget = value;
                UEditor.CreateCachedEditor(editorTarget, null, ref editor);
            }

            if (editor != null)
            {
                editor.DrawPreview(position);
            }
        }
Ejemplo n.º 4
0
        private void SelectAncestor(FuzzyOptionNode node)
        {
            if (stack.Contains(node))
            {
                animTarget      = 0;
                animAncestor    = node;
                lastRepaintTime = DateTime.UtcNow;

                query        = node.option is SearchOption searchOption ? searchOption.query : string.Empty;
                delayedQuery = null;
                GUIUtility.keyboardControl = 0;
                letQueryClear = true;
            }
        }
Ejemplo n.º 5
0
        private void Search()
        {
            while (stack.Count > 0 && stack[stack.Count - 1].option is SearchOption)
            {
                stack.RemoveAt(stack.Count - 1);
            }

            if (hasSearch)
            {
                searchCancellationTokenSource?.Cancel();

                var query = this.query;

                var parent     = (stack.Count > 1 ? stack[stack.Count - 1] : null);
                var searchNode = new FuzzyOptionNode(new SearchOption(query));

                searchCancellationTokenSource = new CancellationTokenSource();
                var searchCancellationToken = searchCancellationTokenSource.Token;

                ExecuteTask(() =>
                {
                    DisplayProgressBar($"Searching for \"{query}\"...", 0);

                    if (searchCancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    lock (guiLock)
                    {
                        searchNode.children.Clear();
                        searchNode.isPopulated = false;
                    }

                    Populate(searchNode, tree.OrderedSearchResults(query, parent?.option, searchCancellationToken).Take(LudiqCore.Configuration.maxSearchResults));
                    activeSelectedIndex = activeNodes.Count >= 1 ? 0 : -1;
                });

                stack.Add(searchNode);
            }
            else
            {
                animTarget      = 1;
                animAncestor    = null;
                lastRepaintTime = DateTime.UtcNow;
            }
        }
Ejemplo n.º 6
0
        public override float GetFooterHeight(FuzzyOptionNode node, float width)
        {
            if (ZoomIcon(node))
            {
                width -= Styles.zoomSize + Styles.zoomSpacing;
            }

            var height = 0f;

            width -= 2;

            if (documentation.summary != null)
            {
                height += GetSummaryHeight(width);
            }

            foreach (var parameter in documentation.parameters)
            {
                height += GetParameterHeight(parameter, width);
            }

            if (documentation.returns != null)
            {
                height += GetReturnsHeight(width);
            }

            if (documentation.remarks != null)
            {
                height += GetRemarksHeight(width);
            }

            if (ZoomIcon(node))
            {
                return(Mathf.Max(Styles.zoomSize + 2 * Styles.zoomSpacing, height));
            }

            return(height);
        }
Ejemplo n.º 7
0
        private void SelectChild(FuzzyOptionNode node)
        {
            if (node == null || node.option is FuzzySeparator)
            {
                return;
            }

            if (node.option.mode == FuzzyOptionMode.Branch)
            {
                if (node.EvaluateHasChildren(tree))
                {
                    EnterChild(node);
                }
            }
            else if (node.option.mode == FuzzyOptionMode.Leaf)
            {
                if (node == activeNode)
                {
                    node.option.OnFocusLeave(node);
                }

                callback?.Invoke(node.option);
            }
        }
Ejemplo n.º 8
0
 private bool ZoomIcon(FuzzyOptionNode node) => zoom && node.icon != null && (!string.IsNullOrWhiteSpace(documentation.summary) || !string.IsNullOrWhiteSpace(documentation.remarks));
Ejemplo n.º 9
0
        private void OnGUI()
        {
            if (!isValid)
            {
                Close();
                return;
            }

            try
            {
                lock (guiLock)
                {
                    if (alpha < 1 && e.type == EventType.Repaint)
                    {
                        ReadTransparentBackground();
                        var innerPosition = new Rect(0, 0, position.width, position.height);
                        GUI.DrawTexture(innerPosition, transparentBackground);
                        GUI.DrawTexture(innerPosition, ColorPalette.unityBackgroundDark.WithAlpha(alpha).GetPixel());
                    }

                    LudiqGUI.color.BeginOverride(Color.white.WithAlpha(alpha));

                    GUI.Label(new Rect(0, 0, position.width, position.height), GUIContent.none, Styles.background);

                    HandleKeyboard();

                    if (tree.searchable)
                    {
                        LudiqGUI.Space(7);

                        if (letQueryClear)
                        {
                            letQueryClear = false;
                        }
                        else
                        {
                            EditorGUI.FocusTextInControl(searchFieldName);
                        }

                        var searchFieldPosition = GUILayoutUtility.GetRect(10, LudiqStyles.searchFieldInnerHeight);
                        searchFieldPosition.x     += 8;
                        searchFieldPosition.width -= 16;

                        var newQuery = OnSearchGUI(searchFieldPosition, delayedQuery ?? query);

                        if (newQuery != query || delayedQuery != null)
                        {
                            if (!isAnimating)
                            {
                                query = delayedQuery ?? newQuery;
                                Search();
                                delayedQuery = null;
                            }
                            else
                            {
                                delayedQuery = newQuery;
                            }
                        }

                        LudiqGUI.Space(5);
                    }

                    OnLevelGUI(anim);

                    prevAnim = anim;

                    if (isAnimating && e.type == EventType.Repaint)
                    {
                        anim = Mathf.MoveTowards(anim, animTarget, repaintDeltaTime * animationSpeed);

                        if (animTarget == 0 && anim == 0 && animAncestor != null)
                        {
                            while (stack.Count > 1 && stack[stack.Count - 1] != animAncestor)
                            {
                                stack.RemoveAt(stack.Count - 1);
                            }

                            anim         = 1;
                            prevAnim     = 1;
                            animTarget   = 1;
                            animAncestor = null;
                        }

                        Repaint();
                    }

                    if (e.type == EventType.Repaint)
                    {
                        lastRepaintTime = DateTime.UtcNow;
                    }

                    if (!activeParent.isLoading)
                    {
                        if (tree.searchable && hasSearch && activeParent.hasChildren == false)
                        {
                            var searchNotFoundLabel = new GUIContent(string.Format(searchNotFoundFormat, query));

                            minOptionWidth = Styles.searchNotFound.CalcSize(searchNotFoundLabel).x;

                            EditorGUI.LabelField
                            (
                                GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)),
                                searchNotFoundLabel,
                                Styles.searchNotFound
                            );
                        }

                        if (activeNode != null && activeNode.option.hasFooter)
                        {
                            OnFooterGUI();
                        }
                    }

                    LudiqGUI.color.EndOverride();

                    if (previousActiveNode != activeNode)
                    {
                        previousActiveNode?.option.OnFocusLeave(previousActiveNode);
                        activeNode?.option?.OnFocusEnter(activeNode);
                    }

                    previousActiveNode = activeNode;

                    OnPositioning();
                }
            }
            catch (ArgumentException ex)
            {
                if (tree.multithreaded && ex.Message.StartsWith("Getting control "))
                {
                    // A bunch of happens that might affect the GUI could happen on a
                    // secondary thread, leading to Unity complaining about the amount
                    // of controls changing between the draw call and the layout call.
                    // Because these are hamless and last just one frame, we can safely
                    // ignore them and repaint right away.
                    requireRepaint = true;
                }
                else
                {
                    throw;
                }
            }

            if (requireRepaint)
            {
                Repaint();
                requireRepaint = false;
            }
        }
 public virtual void OnFooterGUI(FuzzyOptionNode node, Rect position)
 {
 }
Ejemplo n.º 11
0
        private void Initialize(Rect activatorPosition, IFuzzyOptionTree optionTree, Action <IFuzzyOption> callback)
        {
            tree = optionTree;

            // Activator position is assumed to be in screen space, not GUI space
            // This lets us properly position fuzzy windows from context menus where no GUI context is available

            this.activatorPosition = activatorPosition;

            // Create the hierarchy

            stack         = new List <FuzzyOptionNode>();
            root          = new FuzzyOptionNode(new Root(optionTree.header));
            favoritesRoot = new FuzzyOptionNode(new FavoritesRoot());
            stack.Add(root);

            Styles.Initialize();

            ExecuteTask(() =>
            {
                if (!optionTree.prewarmed)
                {
                    optionTree.Prewarm();
                    optionTree.prewarmed = true;
                }
                else
                {
                    optionTree.Rewarm();
                }

                Populate(root, optionTree.Root());

                UpdateFavorites();

                // Fit height to children if there is no depth and no search

                var hasSubChildren = root.children.Any(option => option.hasChildren != false);

                if (!optionTree.searchable && !hasSubChildren)
                {
                    var height = 0f;

                    if (!string.IsNullOrEmpty(root.option.headerLabel))
                    {
                        height += Styles.headerHeight;
                    }

                    foreach (var child in root.children)
                    {
                        if (child.option is FuzzySeparator)
                        {
                            height += Styles.separatorHeight;
                        }
                        else
                        {
                            height += Styles.optionHeight;
                        }
                    }

                    this.height = height + 1;
                }
            });


            // Setup the search

            Search();

            // Assign the callback

            this.callback = callback;

            // Show and focus the window

            wantsMouseMove = true;
            var initialSize = new Vector2(activatorPosition.width, height);

            this.ShowAsDropDown(activatorPosition, initialSize);
            Focus();
        }
Ejemplo n.º 12
0
        public void Populate(FuzzyOptionNode node, IEnumerable <IFuzzyOption> children, CancellationToken?cancellation = null)
        {
            if (node.isPopulated)
            {
                return;
            }

            if (node.option.mode == FuzzyOptionMode.Branch)
            {
                var i = 0;

                var _children = children.ToArray();

                lock (guiLock)
                {
                    if (node.hasChildren == null)
                    {
                        node.hasChildren = _children.Length > 0;
                    }
                }

                var childNodes = new List <FuzzyOptionNode>();

                foreach (var child in _children)
                {
                    if (child == null)
                    {
                        continue;
                    }

                    try
                    {
                        child.OnPopulate();
                    }
                    catch (Exception ex)
                    {
                        Debug.LogWarning($"Failed to display {child.GetType()}: \n{ex}");
                        continue;
                    }

                    string label;

                    if (node.option is SearchOption)
                    {
                        label = tree.SearchResultLabel(child, query);
                    }
                    else if (node == favoritesRoot || tree.UseExplicitLabel(node.option, child))
                    {
                        label = tree.ExplicitLabel(child) ?? child.label;
                    }
                    else
                    {
                        label = child.label;
                    }

                    FuzzyOptionNode childNode;

                    try
                    {
                        childNode = new FuzzyOptionNode(child, label);
                    }
                    catch (Exception ex)
                    {
                        Debug.LogWarning($"Failed to create option node for {child.GetType()} (value = {child.value}): \n{ex}");
                        continue;
                    }

                    DisplayProgressBar($"{child.label}... ({++i} / {_children.Length})", (float)i / _children.Length);

                    var evaluateBranchesEarly = false;

                    if (child.mode == FuzzyOptionMode.Leaf)
                    {
                        childNode.hasChildren = false;
                        childNodes.Add(childNode);
                    }
                    else if (child.mode == FuzzyOptionMode.Branch)
                    {
                        if (evaluateBranchesEarly)
                        {
                            if (childNode.EvaluateHasChildren(tree))
                            {
                                childNodes.Add(childNode);
                            }
                        }
                        else
                        {
                            childNodes.Add(childNode);
                        }
                    }

                    cancellation?.ThrowIfCancellationRequested();
                }

                lock (guiLock)
                {
                    node.children.AddRange(childNodes);
                }
            }

            lock (guiLock)
            {
                node.isPopulated = true;
            }
        }
Ejemplo n.º 13
0
        private void OnOptionsGUI(float anim, FuzzyOptionNode parent)
        {
            var hasHeader         = !string.IsNullOrEmpty(parent.option.headerLabel);
            var headerHeight      = hasHeader ? Styles.headerHeight : 0;
            var searchFieldHeight = tree.searchable ? LudiqStyles.searchFieldOuterHeight : 0;

            var levelPosition = new Rect
                                (
                position.width * (1 - anim) + 1,
                searchFieldHeight + headerHeight,
                position.width - 2,
                height - (searchFieldHeight + 1) - headerHeight
                                );

            if (e.type == EventType.MouseDown && e.button == (int)MouseButton.Right && levelPosition.Contains(e.mousePosition))
            {
                SelectParent();
                e.Use();
            }

            GUILayout.BeginArea(levelPosition);

            if (parent.isLoading)
            {
                LudiqGUI.BeginVertical();
                LudiqGUI.FlexibleSpace();

                LudiqGUI.BeginHorizontal();
                LudiqGUI.FlexibleSpace();
                LudiqGUI.LoaderLayout();
                LudiqGUI.FlexibleSpace();
                LudiqGUI.EndHorizontal();

                LudiqGUI.Space(16);

                LudiqGUI.BeginHorizontal();
                LudiqGUI.Space(10);
                var progressBarPosition = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.Height(19), GUILayout.ExpandWidth(true));
                if (showProgress)
                {
                    EditorGUI.ProgressBar(progressBarPosition, progress, progressText);
                }

                LudiqGUI.Space(10);
                LudiqGUI.EndHorizontal();
                LudiqGUI.Space(LudiqGUI.loaderSize * 1.5f);

                LudiqGUI.FlexibleSpace();
                LudiqGUI.EndVertical();
                Repaint();
            }
            else
            {
                parent.scroll = GUILayout.BeginScrollView(parent.scroll);

                EditorGUIUtility.SetIconSize(new Vector2(IconSize.Small, IconSize.Small));

                var selectedOptionPosition = default(Rect);

                foreach (var node in parent.children)
                {
                    node.EnsurePositionable();

                    if (e.type == EventType.Layout || e.type == EventType.Repaint)
                    {
                        minOptionWidth = Mathf.Max(minOptionWidth, Mathf.Min(node.width, Styles.maxOptionWidth));
                    }
                }

                for (var i = 0; i < parent.children.Count; i++)
                {
                    var node        = parent.children[i];
                    var isSeparator = node.option is FuzzySeparator;

                    var optionPosition = GUILayoutUtility.GetRect(IconSize.Small, isSeparator ? Styles.separator.fixedHeight : Styles.optionHeight, GUILayout.ExpandWidth(true));

                    if (((e.type == EventType.MouseMove && GUIUtility.GUIToScreenPoint(e.mousePosition) != lastMouseMovePosition) || e.type == EventType.MouseDown) &&
                        parent.selectedIndex != i &&
                        optionPosition.Contains(e.mousePosition))
                    {
                        parent.selectedIndex = i;
                        Repaint();
                        lastMouseMovePosition = GUIUtility.GUIToScreenPoint(e.mousePosition);
                    }

                    var optionIsSelected = false;

                    if (i == parent.selectedIndex)
                    {
                        optionIsSelected       = true;
                        selectedOptionPosition = optionPosition;
                    }

                    // Clipping
                    if (optionPosition.yMax < parent.scroll.y || optionPosition.yMin > parent.scroll.y + levelPosition.height)
                    {
                        continue;
                    }

                    EditorGUI.BeginDisabledGroup(node.option.mode == FuzzyOptionMode.Branch && node.hasChildren == false);

                    node.EnsureDrawable();

                    if (e.type == EventType.Repaint)
                    {
                        using (LudiqGUI.color.Override(node.dim ? LudiqGUI.color.value.WithAlphaMultiplied(0.66f) : LudiqGUI.color.value))
                        {
                            if (node.option is FuzzySeparator)
                            {
                                Styles.separator.Draw(optionPosition, node.label, false, false, false, false);

                                var linePosition = new Rect(optionPosition.x, optionPosition.yMax - 1, optionPosition.width, 1);

                                Styles.separatorLine.Draw(linePosition, GUIContent.none, false, false, false, false);
                            }
                            else
                            {
                                Styles.optionBackground.Draw(optionPosition, GUIContent.none, false, false, optionIsSelected, optionIsSelected);

                                float x = Styles.optionBackground.padding.left;

                                var spaced = false;

                                foreach (var icon in node.icons)
                                {
                                    if (icon == null)
                                    {
                                        continue;
                                    }

                                    var iconPosition = new Rect
                                                       (
                                        optionPosition.x + x,
                                        optionPosition.y + Styles.optionBackground.padding.top,
                                        IconSize.Small,
                                        IconSize.Small
                                                       );

                                    GUI.DrawTexture(iconPosition, icon[IconSize.Small]);

                                    x     += IconSize.Small;
                                    x     += Styles.spaceBetweenIcons;
                                    spaced = true;
                                }

                                if (spaced)
                                {
                                    x -= Styles.spaceBetweenIcons;
                                    x += Styles.spaceAfterIcons;
                                }

                                var foregroundPosition = optionPosition;
                                foregroundPosition.x     += x;
                                foregroundPosition.width -= x;

                                Styles.optionForeground.Draw(foregroundPosition, node.label, false, false, optionIsSelected, optionIsSelected);
                            }
                        }
                    }

                    var right = optionPosition.xMax;

                    if (node.option.mode == FuzzyOptionMode.Branch)
                    {
                        right -= 13;
                        var rightArrowPosition = new Rect(right, optionPosition.y + 4, 13, 13);

                        if (e.type == EventType.Repaint)
                        {
                            Styles.rightArrow.Draw(rightArrowPosition, false, false, false, false);
                        }
                    }

                    if (node.option.mode == FuzzyOptionMode.Leaf && tree.selected.Contains(node.option.value) && !isSeparator)
                    {
                        right -= 16;
                        var checkPosition = new Rect(right, optionPosition.y + 4, 12, 12);

                        if (e.type == EventType.Repaint)
                        {
                            Styles.check.Draw(checkPosition, false, false, false, false);
                        }
                    }

                    EditorGUI.EndDisabledGroup();

                    if (tree.favorites != null && tree.CanFavorite(node.option) && (optionIsSelected || tree.favorites.Contains(node.option)))
                    {
                        right -= 19;
                        var starPosition = new Rect(right, optionPosition.y + 2, IconSize.Small, IconSize.Small);

                        EditorGUI.BeginChangeCheck();

                        var isFavorite = tree.favorites.Contains(node.option);

                        isFavorite = GUI.Toggle(starPosition, isFavorite, GUIContent.none, Styles.star);

                        if (EditorGUI.EndChangeCheck())
                        {
                            if (isFavorite)
                            {
                                tree.favorites.Add(node.option);
                            }
                            else
                            {
                                tree.favorites.Remove(node.option);
                            }

                            tree.OnFavoritesChange();

                            ExecuteTask(() => UpdateFavorites());
                        }
                    }

                    if (e.type == EventType.MouseUp && e.button == (int)MouseButton.Left && optionPosition.Contains(e.mousePosition))
                    {
                        e.Use();
                        parent.selectedIndex = i;
                        SelectChild(node);
                    }
                }

                EditorGUIUtility.SetIconSize(default(Vector2));

                GUILayout.EndScrollView();

                if (scrollToSelected && e.type == EventType.Repaint)
                {
                    scrollToSelected = false;

                    var lastRect = GUILayoutUtility.GetLastRect();

                    if (selectedOptionPosition.yMax - lastRect.height > parent.scroll.y)
                    {
                        var scroll = parent.scroll;
                        scroll.y      = selectedOptionPosition.yMax - lastRect.height;
                        parent.scroll = scroll;
                        Repaint();
                    }

                    if (selectedOptionPosition.y < parent.scroll.y)
                    {
                        var scroll = parent.scroll;
                        scroll.y      = selectedOptionPosition.y;
                        parent.scroll = scroll;
                        Repaint();
                    }
                }
            }

            GUILayout.EndArea();
        }
Ejemplo n.º 14
0
 public override float GetFooterHeight(FuzzyOptionNode node, float width)
 {
     return(128);
 }
 public virtual void OnFocusLeave(FuzzyOptionNode node)
 {
 }
 public virtual void OnFocusEnter(FuzzyOptionNode node)
 {
 }
Ejemplo n.º 17
0
        public override void OnFooterGUI(FuzzyOptionNode node, Rect position)
        {
            if (ZoomIcon(node))
            {
                var zoomPosition = new Rect
                                   (
                    position.x + Styles.zoomSpacing,
                    position.y + Styles.zoomSpacing,
                    Styles.zoomSize,
                    Styles.zoomSize
                                   );

                position.x     += Styles.zoomSize + Styles.zoomSpacing;
                position.width -= Styles.zoomSize + Styles.zoomSpacing;

                GUI.DrawTexture(zoomPosition, Icon()[IconSize.Medium]);
            }

            var y = position.y;

            if (documentation.summary != null)
            {
                var summaryPosition = new Rect
                                      (
                    position.x,
                    y,
                    position.width,
                    GetSummaryHeight(position.width)
                                      );

                OnSummaryGUI(summaryPosition);

                y = summaryPosition.yMax;
            }

            if (documentation.parameters.Any())
            {
                var parameterPosition = new Rect
                                        (
                    position.x,
                    y,
                    position.width,
                    0
                                        );

                foreach (var parameter in documentation.parameters)
                {
                    parameterPosition.height = GetParameterHeight(parameter, position.width);

                    OnParameterGUI(parameterPosition, parameter);

                    parameterPosition.y += parameterPosition.height;

                    y = parameterPosition.y;
                }
            }

            if (documentation.returns != null)
            {
                var returnsPosition = new Rect
                                      (
                    position.x,
                    y,
                    position.width,
                    GetReturnsHeight(position.width)
                                      );

                OnReturnsGUI(returnsPosition);

                y = returnsPosition.yMax;
            }

            if (documentation.remarks != null)
            {
                var remarksPosition = new Rect
                                      (
                    position.x,
                    y,
                    position.width,
                    GetRemarksHeight(position.width)
                                      );

                OnRemarksGUI(remarksPosition);

                y = remarksPosition.yMax;
            }
        }
 public virtual float GetFooterHeight(FuzzyOptionNode node, float width)
 {
     return(0);
 }