// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using FlaxEditor.Surface.Elements; using FlaxEditor.Utilities; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Surface.ContextMenu { /// /// Drop panel for group of . It represents . /// /// [HideInEditor] public sealed class VisjectCMGroup : DropPanel { /// /// The context menu. /// public readonly VisjectCM ContextMenu; /// /// The archetypes (one or more). /// public readonly List Archetypes = new List(); /// /// A computed score for the context menu order. /// public float SortScore; /// /// The group name. /// public string Name; /// /// Initializes a new instance of the class. /// /// The context menu. /// The group archetype. public VisjectCMGroup(VisjectCM cm, GroupArchetype archetype) { Pivot = Float2.Zero; ContextMenu = cm; Archetypes.Add(archetype); Name = archetype.Name; EnableDropDownIcon = true; HeaderColor = Style.Current.Background; ArrowImageOpened = new SpriteBrush(Style.Current.ArrowDown); ArrowImageClosed = new SpriteBrush(Style.Current.ArrowRight); CloseAnimationTime = 0; } /// /// Resets the view. /// public void ResetView() { Profiler.BeginEvent("VisjectCMGroup.ResetView"); // Remove filter SortScore = 0; for (int i = 0; i < _children.Count; i++) { if (_children[i] is VisjectCMItem item) { item.UpdateFilter(null, null); item.UpdateScore(null); } } SortChildren(); if (ContextMenu.ShowExpanded) Open(false); else Close(false); Visible = true; Profiler.EndEvent(); } /// /// Updates the filter. /// /// The filter text. /// The optionally selected box to show hints for it. public void UpdateFilter(string filterText, Box selectedBox) { Profiler.BeginEvent("VisjectCMGroup.UpdateFilter"); // Check if a dot is inside the filter text and split the string accordingly. // Everything in front of the dot is for specifying a class/group name. And everything afterward is the actual item filter text if (!string.IsNullOrEmpty(filterText)) { int dotIndex = filterText.IndexOf('.'); if (dotIndex != -1) { string filterGroupName = filterText.Substring(0, dotIndex); // If the string in front of the dot has the length of 0 or doesn't start with a letter we skip the filtering to make spawning floats work if (filterGroupName.Length > 0 && char.IsLetter(filterGroupName[0])) { // Early out and make the group invisible if it doesn't start with the specified string if (!Name.StartsWith(filterGroupName, StringComparison.InvariantCultureIgnoreCase)) { Visible = false; Profiler.EndEvent(); return; } filterText = filterText.Substring(dotIndex + 1); } } } // Update items bool isAnyVisible = false; bool groupHeaderMatches = QueryFilterHelper.Match(filterText, HeaderText); for (int i = 0; i < _children.Count; i++) { if (_children[i] is VisjectCMItem item) { item.UpdateFilter(filterText, selectedBox, groupHeaderMatches); isAnyVisible |= item.Visible; } } // Update itself if (isAnyVisible) { if (!string.IsNullOrEmpty(filterText)) Open(false); Visible = true; } else { // Hide group if none of the items matched the filter Visible = false; } Profiler.EndEvent(); } internal void EvaluateVisibilityWithBox(Box selectedBox) { if (selectedBox == null) { for (int i = 0; i < _children.Count; i++) { if (_children[i] is VisjectCMItem item) { item.Visible = true; } } Visible = true; return; } Profiler.BeginEvent("VisjectCMGroup.EvaluateVisibilityWithBox"); bool isAnyVisible = false; for (int i = 0; i < _children.Count; i++) { if (_children[i] is VisjectCMItem item) { item.Visible = item.CanConnectTo(selectedBox); isAnyVisible |= item.Visible; } } // Update itself if (isAnyVisible) { Visible = true; } else { // Hide group if none of the items matched the filter Visible = false; } Profiler.EndEvent(); } /// /// Updates the sorting of the s of this /// Also updates the /// /// The currently user-selected box public void UpdateItemSort(Box selectedBox) { Profiler.BeginEvent("VisjectCMGroup.UpdateItemSort"); SortScore = 0; for (int i = 0; i < _children.Count; i++) { if (_children[i] is VisjectCMItem item) { item.UpdateScore(selectedBox); if (item.SortScore > SortScore) SortScore = item.SortScore; } } if (selectedBox != null) { if (string.Equals(Name, selectedBox.CurrentType.Name, StringComparison.InvariantCultureIgnoreCase)) SortScore += 10; } SortChildren(); Profiler.EndEvent(); } /// public override int Compare(Control other) { if (other is VisjectCMGroup otherGroup) { int order = -1 * SortScore.CompareTo(otherGroup.SortScore); if (order == 0) { order = string.Compare(Name, otherGroup.Name, StringComparison.InvariantCulture); } return order; } return base.Compare(other); } } }