private void OnHeaderGUI(FuzzyOptionNode parent, Rect headerPosition) { EditorGUIUtility.SetIconSize(new Vector2(IconSize.Small, IconSize.Small)); var headerContent = new GUIContent(new GUIContent(parent.option.headerLabel, parent.option.showHeaderIcon ? parent.option.icon?[IconSize.Small] : null)); headerWidth = Styles.header.CalcSize(headerContent).x; GUI.Label(headerPosition, headerContent, Styles.header); EditorGUIUtility.SetIconSize(default(Vector2)); }
private void SelectChild(FuzzyOptionNode node) { if (node == null) { return; } if (node.hasChildren) { EnterChild(node); } else if (callback != null) { callback(node.option); } }
private void Initialize(IFuzzyOptionTree optionTree, Action <IFuzzyOption> callback) { tree = optionTree; // Create the hierarchy stack = new Stack <FuzzyOptionNode>(); root = new FuzzyOptionNode(new Root(optionTree.header)); ExecuteTask(delegate { optionTree.Prewarm(); Populate(root, optionTree.Root()); // Fit height to children if there is no depth and no search var hasSubChildren = root.children.Any(option => option.hasChildren); if (!optionTree.searchable && !hasSubChildren) { height = 0; if (!string.IsNullOrEmpty(root.option.headerLabel)) { height += Styles.headerHeight; } height += root.children.Count * Styles.optionHeight + 1; } }); // Add favorites favoritesRoot = new FuzzyOptionNode(new FavoritesRoot()); UpdateFavorites(); // Setup the search searchRoot = new FuzzyOptionNode(new SearchRoot()); Search(); // Assign the callback this.callback = callback; // Show and focus the window }
private void OnLevelGUI(float anim, FuzzyOptionNode parent, FuzzyOptionNode grandParent) { anim = Mathf.Floor(anim) + Mathf.SmoothStep(0, 1, Mathf.Repeat(anim, 1)); var levelPosition = new Rect ( position.width * (1 - anim) + 1, tree.searchable ? 30 : 0, position.width - 2, height - (tree.searchable ? 31 : 1) ); GUILayout.BeginArea(levelPosition); if (grandParent != null || !string.IsNullOrEmpty(parent.option.headerLabel)) { var headerPosition = GUILayoutUtility.GetRect(10, Styles.headerHeight); OnHeaderGUI(parent, headerPosition); if (grandParent != null) { var leftArrowPosition = new Rect(headerPosition.x + 4, headerPosition.y + 7, 13, 13); if (e.type == EventType.Repaint) { Styles.leftArrow.Draw(leftArrowPosition, false, false, false, false); } if (!isAnimating) { if (e.type == EventType.MouseDown && (e.button == (int)MouseButton.Right || headerPosition.Contains(e.mousePosition))) { SelectParent(); e.Use(); GUIUtility.ExitGUI(); } } } } OnOptionsGUI(parent, levelPosition.height - Styles.headerHeight); GUILayout.EndArea(); }
private void EnterChild(FuzzyOptionNode node) { if (node == null || !node.hasChildren) { return; } ExecuteTask(delegate { Populate(node, tree.Children(node.option.value)); }); lastRepaintTime = DateTime.Now; if (animTarget == 0) { animTarget = 1; } else if (anim == 1) { anim = 0; stack.Push(node); } }
private void OnOptionsGUI(FuzzyOptionNode parent, float scrollViewHeight) { if (parent.isLoading || (tree.showBackgroundWorkerProgress && BackgroundWorker.hasProgress)) { 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 (progressBarPosition.width > 0 && progress > 0) { if (tree.showBackgroundWorkerProgress && BackgroundWorker.hasProgress) { EditorGUI.ProgressBar(progressBarPosition, BackgroundWorker.progressProportion, BackgroundWorker.progressLabel); } else if (showProgress) { EditorGUI.ProgressBar(progressBarPosition, progress, progressText); } } LudiqGUI.Space(10); LudiqGUI.EndHorizontal(); LudiqGUI.FlexibleSpace(); LudiqGUI.EndVertical(); return; } parent.scroll = GUILayout.BeginScrollView(parent.scroll); EditorGUIUtility.SetIconSize(new Vector2(IconSize.Small, IconSize.Small)); var selectedOptionPosition = default(Rect); if (e.type == EventType.Repaint) { minOptionWidth = 0; } foreach (var node in parent.children) { node.EnsureDrawable(); 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 optionPosition = GUILayoutUtility.GetRect(IconSize.Small, Styles.optionHeight, GUILayout.ExpandWidth(true)); if (!isAnimating) { if (((e.type == EventType.MouseMove && GUIUtility.GUIToScreenPoint(e.mousePosition) != lastMouseMovePosition) || e.type == EventType.MouseDown) && parent.selectedIndex != i && optionPosition.Contains(e.mousePosition)) { parent.selectedIndex = i; requireRepaint = true; lastMouseMovePosition = GUIUtility.GUIToScreenPoint(e.mousePosition); GUIUtility.ExitGUI(); } } var optionIsSelected = false; if (i == parent.selectedIndex) { optionIsSelected = true; selectedOptionPosition = optionPosition; } // Clipping if (optionPosition.yMax < parent.scroll.y || optionPosition.yMin > parent.scroll.y + scrollViewHeight) { continue; } if (e.type == EventType.Repaint) { node.style.Draw(optionPosition, node.label, false, false, optionIsSelected, optionIsSelected); } var right = optionPosition.xMax; if (node.hasChildren) { 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.hasChildren && tree.selected.Contains(node.option.value)) { 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); } } if (tree.favorites != null && tree.CanFavorite(node.option.value) && (optionIsSelected || tree.favorites.Contains(node.option.value))) { right -= 19; var starPosition = new Rect(right, optionPosition.y + 2, IconSize.Small, IconSize.Small); EditorGUI.BeginChangeCheck(); var isFavorite = tree.favorites.Contains(node.option.value); isFavorite = GUI.Toggle(starPosition, isFavorite, GUIContent.none, Styles.star); if (EditorGUI.EndChangeCheck()) { if (isFavorite) { tree.favorites.Add(node.option.value); } else { tree.favorites.Remove(node.option.value); } tree.OnFavoritesChange(); UpdateFavorites(); } } if (!isAnimating) { if (e.type == EventType.MouseDown && e.button == (int)MouseButton.Left && optionPosition.Contains(e.mousePosition)) { e.Use(); parent.selectedIndex = i; SelectChild(node); GUIUtility.ExitGUI(); } } } 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; requireRepaint = true; } if (selectedOptionPosition.y < parent.scroll.y) { var scroll = parent.scroll; scroll.y = selectedOptionPosition.y; parent.scroll = scroll; requireRepaint = true; } } }
public void Populate(FuzzyOptionNode node, IEnumerable <object> childrenValues, CancellationToken?cancellation = null) { if (node.isPopulated) { return; } var i = 0; var _childrenValues = childrenValues.ToArray(); lock (guiLock) { node.hasChildren = _childrenValues.Length > 0; } foreach (var childValue in _childrenValues) { var childOption = tree.Option(childValue); try { childOption.OnPopulate(); } catch (ThreadAbortException) { throw; } catch (Exception ex) { Debug.LogWarning($"Failed to display {childOption.GetType()}: \n{ex}"); continue; } DisplayProgressBar($"{childOption.label}... ({++i} / {_childrenValues.Length})", (float)i / _childrenValues.Length); var hasChildren = tree.Children(childValue).Any(); var include = !childOption.parentOnly || hasChildren; if (!include) { continue; } string label; if (node == searchRoot) { label = tree.SearchResultLabel(childValue, query); } else if (node == favoritesRoot) { label = tree.FavoritesLabel(childValue); } else { label = childOption.label; } var childNode = new FuzzyOptionNode(childOption, label); childNode.hasChildren = hasChildren; lock (guiLock) { node.children.Add(childNode); } cancellation?.ThrowIfCancellationRequested(); } lock (guiLock) { node.isPopulated = true; } }