diff --git a/ComponentSelectorAdditions/ComponentResult.cs b/ComponentSelectorAdditions/ComponentResult.cs index 33af9a2..1497059 100644 --- a/ComponentSelectorAdditions/ComponentResult.cs +++ b/ComponentSelectorAdditions/ComponentResult.cs @@ -10,22 +10,52 @@ namespace ComponentSelectorAdditions { + /// <summary> + /// Represents a component or node returned by the <see cref="Events.EnumerateComponentsEvent"/>. + /// </summary> public sealed class ComponentResult { + /// <summary> + /// Gets the category that should be shown as the <see cref="Type">Type's</see> parent. + /// </summary> public CategoryNode<Type> Category { get; } - public string FullName => Type.FullName; + + /// <summary> + /// Gets the <see cref="Type">Type's</see> group identifier, if present. + /// </summary> public string? Group { get; } + /// <summary> + /// Gets the <see cref="Type">Type's</see> group name, if present. + /// </summary> public string? GroupName { get; } + /// <summary> + /// Gets whether the <see cref="Type">Type</see> is part of a group. + /// </summary> [MemberNotNullWhen(true, nameof(Group), nameof(GroupName))] public bool HasGroup => Group is not null; + /// <summary> + /// Gets whether this <see cref="Type">Type</see> is a generic type definition. + /// </summary> public bool IsGeneric => Type.IsGenericTypeDefinition; + /// <summary> + /// Gets the <see cref="Type">Type's</see> nice name. + /// </summary> public string NiceName => Type.GetNiceName(); + + /// <summary> + /// Gets the component / node <see cref="System.Type"/> result. + /// </summary> public Type Type { get; } + /// <summary> + /// Creates a new component / node <see cref="System.Type"/> result with the given category. + /// </summary> + /// <param name="category">The category that should be shown as the <see cref="Type">Type's</see> parent.</param> + /// <param name="type">The component / node <see cref="System.Type"/>.</param> public ComponentResult(CategoryNode<Type> category, Type type) { Type = type; diff --git a/ComponentSelectorAdditions/ComponentSelectorAdditions.csproj b/ComponentSelectorAdditions/ComponentSelectorAdditions.csproj index 378edc3..a496715 100644 --- a/ComponentSelectorAdditions/ComponentSelectorAdditions.csproj +++ b/ComponentSelectorAdditions/ComponentSelectorAdditions.csproj @@ -11,7 +11,7 @@ <PackageId>ComponentSelectorAdditions</PackageId> <Title>Component Selector Additions</Title> <Authors>Banane9</Authors> - <Version>0.2.0-beta</Version> + <Version>0.3.0-beta</Version> <Description>This MonkeyLoader mod for Resonite overhauls the Component Selector / Protoflux Node Selector to have a search, as well as favorites and recents categories.</Description> <PackageReadmeFile>README.md</PackageReadmeFile> <PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression> @@ -30,17 +30,13 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="MonkeyLoader" Version="0.18.0-beta" /> - <PackageReference Include="MonkeyLoader.GamePacks.Resonite" Version="0.16.5-beta" /> + <PackageReference Include="MonkeyLoader" Version="0.19.1-beta" /> + <PackageReference Include="MonkeyLoader.GamePacks.Resonite" Version="0.17.0-beta" /> <PackageReference Include="PolySharp" Version="1.14.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Resonite.Elements.Core" Version="1.0.2" /> - <PackageReference Include="Resonite.FrooxEngine" Version="2024.6.11.74" /> - <PackageReference Include="System.Text.Json" Version="8.0.2"> - <PrivateAssets>all</PrivateAssets> - <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> - </PackageReference> + <PackageReference Include="Resonite.Elements.Core" Version="1.1.0" /> + <PackageReference Include="Resonite.FrooxEngine" Version="2024.7.11.1293" /> </ItemGroup> </Project> diff --git a/ComponentSelectorAdditions/Events/BuildCustomGenericBuilder.cs b/ComponentSelectorAdditions/Events/BuildCustomGenericBuilder.cs index 20d2b2d..f4077bd 100644 --- a/ComponentSelectorAdditions/Events/BuildCustomGenericBuilder.cs +++ b/ComponentSelectorAdditions/Events/BuildCustomGenericBuilder.cs @@ -38,7 +38,7 @@ public sealed class BuildCustomGenericBuilder : BuildUIEvent public IEnumerable<Button> OtherAddedButtons => OtherAddedButtonsSet.AsSafeEnumerable(); public ComponentSelector Selector { get; } - public BuildCustomGenericBuilder(ComponentSelector selector, UIBuilder ui, Type component) : base(ui) + internal BuildCustomGenericBuilder(ComponentSelector selector, UIBuilder ui, Type component) : base(ui) { Selector = selector; Component = component; diff --git a/ComponentSelectorAdditions/Events/BuildSelectorFooterEvent.cs b/ComponentSelectorAdditions/Events/BuildSelectorFooterEvent.cs index 7d8d75b..f2b4a93 100644 --- a/ComponentSelectorAdditions/Events/BuildSelectorFooterEvent.cs +++ b/ComponentSelectorAdditions/Events/BuildSelectorFooterEvent.cs @@ -12,7 +12,7 @@ public sealed class BuildSelectorFooterEvent : BuildSelectorEvent public bool HasCancelButton { get; } - public BuildSelectorFooterEvent(ComponentSelector selector, UIBuilder ui, SelectorSearchBar? searchBar, bool hasBackButton, bool hasCancelButton) + internal BuildSelectorFooterEvent(ComponentSelector selector, UIBuilder ui, SelectorSearchBar? searchBar, bool hasBackButton, bool hasCancelButton) : base(selector, ui) { HasBackButton = hasBackButton; diff --git a/ComponentSelectorAdditions/Events/BuildSelectorHeaderEvent.cs b/ComponentSelectorAdditions/Events/BuildSelectorHeaderEvent.cs index 3637cdf..0ad8f70 100644 --- a/ComponentSelectorAdditions/Events/BuildSelectorHeaderEvent.cs +++ b/ComponentSelectorAdditions/Events/BuildSelectorHeaderEvent.cs @@ -6,7 +6,7 @@ namespace ComponentSelectorAdditions.Events public sealed class BuildSelectorHeaderEvent : BuildSelectorEvent { /// <inheritdoc/> - public BuildSelectorHeaderEvent(ComponentSelector selector, UIBuilder ui) : base(selector, ui) + internal BuildSelectorHeaderEvent(ComponentSelector selector, UIBuilder ui) : base(selector, ui) { } } } \ No newline at end of file diff --git a/ComponentSelectorAdditions/Events/EnumerateCategoriesEvent.cs b/ComponentSelectorAdditions/Events/EnumerateCategoriesEvent.cs index 38eb0a8..0dc1188 100644 --- a/ComponentSelectorAdditions/Events/EnumerateCategoriesEvent.cs +++ b/ComponentSelectorAdditions/Events/EnumerateCategoriesEvent.cs @@ -19,7 +19,7 @@ public override IEnumerable<CategoryNode<Type>> Items public ComponentSelector Selector { get; } /// <inheritdoc/> - public EnumerateCategoriesEvent(ComponentSelector selector, SelectorPath path, CategoryNode<Type> rootCategory) + internal EnumerateCategoriesEvent(ComponentSelector selector, SelectorPath path, CategoryNode<Type> rootCategory) { Selector = selector; Path = path; diff --git a/ComponentSelectorAdditions/Events/EnumerateComponentsEvent.cs b/ComponentSelectorAdditions/Events/EnumerateComponentsEvent.cs index 5bd5422..82b08d8 100644 --- a/ComponentSelectorAdditions/Events/EnumerateComponentsEvent.cs +++ b/ComponentSelectorAdditions/Events/EnumerateComponentsEvent.cs @@ -14,6 +14,7 @@ public sealed class EnumerateComponentsEvent : CancelableSortedItemsEvent<Compon public override IEnumerable<ComponentResult> Items => sortableItems .Where(entry => ComponentFilter(entry.Key.Type)) + .Where(entry => Selector.World.Types.IsSupported(entry.Key.Type)) .OrderBy(entry => entry.Value) .ThenBy(entry => entry.Key.GroupName ?? entry.Key.Type.Name) .Select(entry => entry.Key); @@ -24,7 +25,7 @@ public override IEnumerable<ComponentResult> Items public ComponentSelector Selector { get; } /// <inheritdoc/> - public EnumerateComponentsEvent(ComponentSelector selector, SelectorPath path, CategoryNode<Type> rootCategory, Predicate<Type> componentFilter) + internal EnumerateComponentsEvent(ComponentSelector selector, SelectorPath path, CategoryNode<Type> rootCategory, Predicate<Type> componentFilter) { Selector = selector; Path = path; diff --git a/ComponentSelectorAdditions/Events/EnumerateConcreteGenericsEvent.cs b/ComponentSelectorAdditions/Events/EnumerateConcreteGenericsEvent.cs index 2e1db44..f47686f 100644 --- a/ComponentSelectorAdditions/Events/EnumerateConcreteGenericsEvent.cs +++ b/ComponentSelectorAdditions/Events/EnumerateConcreteGenericsEvent.cs @@ -1,6 +1,8 @@ using FrooxEngine; using MonkeyLoader.Resonite.Events; using System; +using System.Collections.Generic; +using System.Linq; namespace ComponentSelectorAdditions.Events { @@ -12,9 +14,16 @@ public class EnumerateConcreteGenericsEvent : SortedItemsEvent<Type> /// </summary> public Type Component { get; } + /// <inheritdoc/> + public override IEnumerable<Type> Items + => sortableItems + .Where(entry => Selector.World.Types.IsSupported(entry.Key)) + .OrderBy(entry => entry.Value) + .Select(entry => entry.Key); + public ComponentSelector Selector { get; } - public EnumerateConcreteGenericsEvent(ComponentSelector selector, Type component) + internal EnumerateConcreteGenericsEvent(ComponentSelector selector, Type component) { Selector = selector; Component = component; diff --git a/ComponentSelectorAdditions/FavoritesCategories.cs b/ComponentSelectorAdditions/FavoritesCategories.cs index f7b02a1..61c0926 100644 --- a/ComponentSelectorAdditions/FavoritesCategories.cs +++ b/ComponentSelectorAdditions/FavoritesCategories.cs @@ -120,9 +120,10 @@ public void Handle(PostProcessButtonsEvent eventData) foreach (var addButton in eventData.AddButtons.Concat(eventData.GenericButtons)) { - AddFavoriteButton(eventData.UI, addButton, true, - isProtoFlux ? IsFavoriteProtoFluxNode : IsFavoriteComponent, - isProtoFlux ? ToggleFavoriteProtoFluxNode : ToggleFavoriteComponent); + Func<TypeManager, string, bool> isFavorite = isProtoFlux ? IsFavoriteProtoFluxNode : IsFavoriteComponent; + Func<TypeManager, string, bool> toggleFavorite = isProtoFlux ? ToggleFavoriteProtoFluxNode : ToggleFavoriteComponent; + + AddFavoriteButton(eventData.UI, addButton, true, isFavorite, toggleFavorite); } } @@ -175,8 +176,10 @@ protected override bool OnShutdown(bool applicationExiting) return base.OnShutdown(applicationExiting); } - private static void AddFavoriteButton(UIBuilder builder, Button button, bool isComponent, Predicate<string> isFavorite, Func<string, bool> toggleFavorite) + private static void AddFavoriteButton(UIBuilder builder, Button button, bool isComponent, + Func<TypeManager, string, bool> isFavorite, Func<TypeManager, string, bool> toggleFavorite) { + var types = button.World.Types; builder.NestInto(button.Slot.Parent); var height = button.Slot.GetComponent<LayoutElement>().MinHeight; @@ -199,14 +202,14 @@ private static void AddFavoriteButton(UIBuilder builder, Button button, bool isC name = name.Substring(lastSlashIndex + 1); } - var favColor = isFavorite(name) ? RadiantUI_Constants.Hero.YELLOW : RadiantUI_Constants.Neutrals.DARKLIGHT; + var favColor = isFavorite(types, name) ? RadiantUI_Constants.Hero.YELLOW : RadiantUI_Constants.Neutrals.DARKLIGHT; var favoriteButton = builder.Button(OfficialAssets.Graphics.Icons.World_Categories.FeaturedRibbon, RadiantUI_Constants.BUTTON_COLOR, favColor); var icon = favoriteButton.Slot.GetComponentsInChildren<Image>().Last(); favoriteButton.LocalPressed += (btn, btnEvent) => { - icon.Tint.Value = toggleFavorite(name) ? + icon.Tint.Value = toggleFavorite(types, name) ? RadiantUI_Constants.Hero.YELLOW : RadiantUI_Constants.Neutrals.DARKLIGHT; Config.Save(); @@ -231,16 +234,16 @@ private void AddCategories() SearchConfig.Instance.AddExcludedCategory(ProtoFluxFavoritesPath); } - private bool IsFavoriteCategory(string name) + private bool IsFavoriteCategory(TypeManager types, string name) => ConfigSection.Categories.Contains(name); - private bool IsFavoriteComponent(string name) - => ConfigSection.Components.Contains(WorkerManager.ParseNiceType(name)); + private bool IsFavoriteComponent(TypeManager types, string name) + => ConfigSection.Components.Contains(types.DecodeType(name)); - private bool IsFavoriteProtoFluxNode(string name) - => ConfigSection.ProtoFluxNodes.Contains(WorkerManager.ParseNiceType(name)); + private bool IsFavoriteProtoFluxNode(TypeManager types, string name) + => ConfigSection.ProtoFluxNodes.Contains(types.DecodeType(name)); - private bool IsProtoFluxFavoriteCategory(string name) + private bool IsProtoFluxFavoriteCategory(TypeManager types, string name) => ConfigSection.ProtoFluxCategories.Contains(name); private void RemoveCategories() @@ -252,16 +255,16 @@ private void RemoveCategories() SearchConfig.Instance.RemoveExcludedCategory(ProtoFluxFavoritesPath); } - private bool ToggleFavoriteCategory(string name) + private bool ToggleFavoriteCategory(TypeManager types, string name) => ToggleHashSetContains(ConfigSection.Categories, name); - private bool ToggleFavoriteComponent(string name) - => ToggleHashSetContains(ConfigSection.Components, WorkerManager.ParseNiceType(name)); + private bool ToggleFavoriteComponent(TypeManager types, string name) + => ToggleHashSetContains(ConfigSection.Components, types.DecodeType(name)); - private bool ToggleFavoriteProtoFluxNode(string name) - => ToggleHashSetContains(ConfigSection.ProtoFluxNodes, WorkerManager.ParseNiceType(name)); + private bool ToggleFavoriteProtoFluxNode(TypeManager types, string name) + => ToggleHashSetContains(ConfigSection.ProtoFluxNodes, types.DecodeType(name)); - private bool ToggleProtoFluxFavoriteCategory(string name) + private bool ToggleProtoFluxFavoriteCategory(TypeManager types, string name) => ToggleHashSetContains(ConfigSection.ProtoFluxCategories, name); } } \ No newline at end of file diff --git a/ComponentSelectorAdditions/FavoritesConfig.cs b/ComponentSelectorAdditions/FavoritesConfig.cs index 45d5256..060faf8 100644 --- a/ComponentSelectorAdditions/FavoritesConfig.cs +++ b/ComponentSelectorAdditions/FavoritesConfig.cs @@ -17,16 +17,25 @@ internal sealed class FavoritesConfig : ConfigSection private static readonly DefiningConfigKey<bool> _sortFavoriteCategoriesToTop = new("SortFavoriteCategoriesToTop", "Sort favorited Categories above unfavorited ones.", () => false); private static readonly DefiningConfigKey<bool> _sortFavoriteComponentsToTop = new("SortFavoriteComponentsToTop", "Sort favorited Components / Nodes above unfavorited ones.", () => true); private static readonly DefiningConfigKey<bool> _sortFavoriteConcreteGenericsToTop = new("SortFavoriteConcreteGenericsToTop", "Sort favorited concrete generic Components / Nodes above unfavorited ones.", () => true); + public HashSet<string> Categories => _categoriesKey.GetValue()!; public HashSet<Type> Components => _componentsKey.GetValue()!; + public override string Description => "Contains the favorited categories and components."; + public override string Id => "Favorites"; + public HashSet<string> ProtoFluxCategories => _protoFluxCategoriesKey.GetValue()!; + public HashSet<Type> ProtoFluxNodes => _protoFluxNodesKey.GetValue()!; + public bool SortFavoriteCategoriesToTop => _sortFavoriteCategoriesToTop.GetValue(); + public bool SortFavoriteComponentsToTop => _sortFavoriteComponentsToTop.GetValue(); + public bool SortFavoriteConcreteGenericsToTop => _sortFavoriteConcreteGenericsToTop.GetValue(); + public override Version Version { get; } = new(1, 1, 0); } } \ No newline at end of file diff --git a/ComponentSelectorAdditions/Injector.cs b/ComponentSelectorAdditions/Injector.cs index 076a8c8..f7b3d67 100644 --- a/ComponentSelectorAdditions/Injector.cs +++ b/ComponentSelectorAdditions/Injector.cs @@ -163,7 +163,7 @@ private static void BuildGenericTypeUI(ComponentSelector selector, UIBuilder ui, { backButton = null; - var type = WorkerManager.GetType(PathUtility.GetFileName(path.PathSegments[^1])); + var type = Type.GetType(path.PathSegments[^1]); selector._genericType.Value = type; if (!doNotGenerateBack) @@ -358,7 +358,7 @@ private static void OnBuildComponentButton(ComponentSelector selector, UIBuilder var category = GetPrettyPath(component.Category, rootCategory); var tint = component.IsGeneric ? RadiantUI_Constants.Sub.GREEN : RadiantUI_Constants.Sub.CYAN; ButtonEventHandler<string> callback = component.IsGeneric ? selector.OpenGenericTypesPressed : selector.OnAddComponentPressed; - var argument = $"{(component.IsGeneric ? $"{path.Path}/" : "")}{component.FullName}{(component.IsGeneric && path.HasGroup ? $"?{path.Group}" : "")}"; + var argument = $"{(component.IsGeneric ? $"{path.Path}/" : "")}{selector.World.Types.EncodeType(component.Type)}{(component.IsGeneric && path.HasGroup ? $"?{path.Group}" : "")}"; MakePermanentButton(ui, category, component.NiceName, tint, callback, argument); } diff --git a/ComponentSelectorAdditions/RecentsCategories.cs b/ComponentSelectorAdditions/RecentsCategories.cs index d5d3579..bdaea38 100644 --- a/ComponentSelectorAdditions/RecentsCategories.cs +++ b/ComponentSelectorAdditions/RecentsCategories.cs @@ -125,7 +125,7 @@ private static void OnAddComponentPressedPostfix(ComponentSelector __instance, s if (!Enabled) return; - var type = WorkerManager.ParseNiceType(typename); + var type = __instance.World.Types.DecodeType(typename); if (type is null || type.IsGenericTypeDefinition) return; diff --git a/ComponentSelectorAdditions/SearchBar.cs b/ComponentSelectorAdditions/SearchBar.cs index 4aaecbc..0da84e6 100644 --- a/ComponentSelectorAdditions/SearchBar.cs +++ b/ComponentSelectorAdditions/SearchBar.cs @@ -40,7 +40,7 @@ public void Handle(BuildSelectorHeaderEvent eventData) ui.Style.FlexibleWidth = 1; var textField = ui.TextField(null, parseRTF: false); - var details = new SelectorSearchBar(searchLayout, textField.Editor.Target, ConfigSection.SearchRefreshDelay); + var details = new SelectorSearchBar(searchLayout, textField.Editor.Target, () => ConfigSection.SearchRefreshDelay); eventData.SearchBar = details; details.Text.NullContent.AssignLocaleString(Mod.GetLocaleString("Search")); diff --git a/ComponentSelectorAdditions/SearchConfig.cs b/ComponentSelectorAdditions/SearchConfig.cs index 641025f..d3dc4c0 100644 --- a/ComponentSelectorAdditions/SearchConfig.cs +++ b/ComponentSelectorAdditions/SearchConfig.cs @@ -13,6 +13,11 @@ namespace ComponentSelectorAdditions { + /// <summary> + /// Represents the configuration for the search functionality.<br/> + /// Use the <see cref="AddExcludedCategory(string)"/> and <see cref="RemoveExcludedCategory(string)"/> + /// methods to add categories which shouldn't be searched into because they're added. + /// </summary> public sealed class SearchConfig : ConfigSection { private static readonly Dictionary<string, bool> _excludedCategories = new(StringComparer.OrdinalIgnoreCase); @@ -29,10 +34,21 @@ public sealed class SearchConfig : ConfigSection private static readonly DefiningConfigKey<string> _userExcludedCategoriesKey = new("UserExcludedCategories", "Excludes specific categories from being searched into by path (case sensitive). Separate entries by semicolon. Search will work when started inside them.", () => "/ProtoFlux"); private static readonly char[] _userExclusionSeparator = new[] { ';' }; - public static SearchConfig Instance { get; private set; } + + /// <summary> + /// Gets this config's instance. + /// </summary> + public static SearchConfig Instance { get; private set; } = null!; + + /// <inheritdoc/> public override string Description => "Contains settings for the Component Selector Search."; + + /// <inheritdoc/> public override string Id => "Search"; + + /// <inheritdoc/> public override Version Version { get; } = new(1, 0, 0); + internal int MaxResultCount => _maxResultCountKey.GetValue(); internal int SearchRefreshDelay => (int)_searchRefreshDelayKey.GetValue(); @@ -41,6 +57,10 @@ static SearchConfig() _userExcludedCategoriesKey.Changed += UserExcludedCategoriesChanged; } + /// <summary> + /// Creates an instance of this config once. + /// </summary> + /// <exception cref="InvalidOperationException"></exception> public SearchConfig() { if (Instance is not null) @@ -87,6 +107,7 @@ public bool RemoveExcludedCategory(string category) return true; } + /// <inheritdoc/> protected override void OnLoad(JObject source, JsonSerializer jsonSerializer) { base.OnLoad(source, jsonSerializer); diff --git a/ComponentSelectorAdditions/SelectorPath.cs b/ComponentSelectorAdditions/SelectorPath.cs index b2f7980..d789197 100644 --- a/ComponentSelectorAdditions/SelectorPath.cs +++ b/ComponentSelectorAdditions/SelectorPath.cs @@ -8,25 +8,68 @@ namespace ComponentSelectorAdditions { + /// <summary> + /// Represents the currently opened path in a <see cref="FrooxEngine.ComponentSelector"/>. + /// </summary> public sealed class SelectorPath { + /// <summary> + /// The path segment after which the search string begins. + /// </summary> public const string SearchSegment = "Search"; + private static readonly char[] _pathSeparators = { '/', '\\' }; + + /// <summary> + /// Gets whether this path targets a generic type. + /// </summary> public bool GenericType { get; } + + /// <summary> + /// Gets the group targeted by the path, if present. + /// </summary> public string? Group { get; } + /// <summary> + /// Gets whether this path targets a group. + /// </summary> [MemberNotNullWhen(true, nameof(Group))] public bool HasGroup => !string.IsNullOrWhiteSpace(Group); + /// <summary> + /// Gets whether this path has a search string. + /// </summary> [MemberNotNullWhen(true, nameof(Search))] public bool HasSearch => !string.IsNullOrWhiteSpace(Search); + /// <summary> + /// Gets whether this path targets the root category. + /// </summary> public bool IsRootCategory => PathSegments.Length == 0; + + /// <summary> + /// Gets whether this path targets whatever the root category of its <see cref="FrooxEngine.ComponentSelector"/> is. + /// </summary> public bool IsSelectorRoot { get; } + + /// <summary> + /// Gets the path to open the current path's target's parent. + /// </summary> public string OpenParentCategoryPath => $"/{PathSegments.Take(PathSegments.Length - (GenericType || !HasGroup ? 1 : 0)).Join(delimiter: "/")}{(GenericType && HasGroup ? $"?{Group}" : "")}"; + /// <summary> + /// Gets this path as a string. + /// </summary> public string Path { get; } + + /// <summary> + /// Gets this path's individual segments. + /// </summary> public string[] PathSegments { get; } + + /// <summary> + /// Gets this path's search string, if present. + /// </summary> public string? Search { get; } internal SelectorPath(string? rawPath, string? search, bool genericType, string? group, bool isSelectorRoot) diff --git a/ComponentSelectorAdditions/SelectorSearchBar.cs b/ComponentSelectorAdditions/SelectorSearchBar.cs index d2f4dcd..69f2e8a 100644 --- a/ComponentSelectorAdditions/SelectorSearchBar.cs +++ b/ComponentSelectorAdditions/SelectorSearchBar.cs @@ -9,35 +9,70 @@ namespace ComponentSelectorAdditions { + /// <summary> + /// Contains details about a <see cref="ComponentSelector"/>'s <see cref="SearchBar"/>. + /// </summary> public sealed class SelectorSearchBar { + private readonly Func<int> _getSearchRefreshDelay; private CancellationTokenSource _lastResultUpdate = new(); + /// <summary> + /// Gets or sets whether the search bar is currently shown. + /// </summary> public bool Active { get => Root.ActiveSelf; set => Root.ActiveSelf = value; } + /// <summary> + /// Gets or sets the search bar's current content. + /// <c>null</c> when inactive. + /// </summary> public string? Content { get => Active ? Text.Content.Value : null; set => Text.Content.Value = value; } + /// <summary> + /// Gets the search bar's <see cref="TextEditor"/>. + /// </summary> public TextEditor Editor { get; } + + /// <summary> + /// Gets the search bar's root <see cref="Slot"/>. + /// </summary> public Slot Root { get; } - public int SearchRefreshDelay { get; } + /// <summary> + /// Gets the search bar's delay before updating when its content changes. + /// </summary> + public int SearchRefreshDelay => _getSearchRefreshDelay(); + + /// <summary> + /// Gets the search bar's <see cref="Text"/> element. + /// </summary> public Text Text => (Text)Editor.Text.Target; - public SelectorSearchBar(Slot root, TextEditor editor, int searchRefreshDelay) + /// <summary> + /// Creates a new search bar with the given details. + /// </summary> + /// <param name="root">The search bar's root slot.</param> + /// <param name="editor">The search bar's text editor.</param> + /// <param name="getSearchRefreshDelay">The search bar's delay before updating when its content changes.</param> + public SelectorSearchBar(Slot root, TextEditor editor, Func<int> getSearchRefreshDelay) { Root = root; Editor = editor; - SearchRefreshDelay = searchRefreshDelay; + _getSearchRefreshDelay = getSearchRefreshDelay ?? (() => 0); } + /// <summary> + /// Cancels the last triggered search and creates a new cancellation token for the new one. + /// </summary> + /// <returns>The newly created <see cref="CancellationToken"/> for the new search.</returns> public CancellationToken UpdateSearch() { _lastResultUpdate.Cancel();