Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- name: Setup Dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x
dotnet-version: 9.x
source-url: https://nuget.pkg.github.com/ResoniteModdingGroup/index.json

- name: Add MonkeyLoader NuGet Source
Expand Down Expand Up @@ -98,7 +98,7 @@ jobs:
- name: Setup Dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x
dotnet-version: 9.x
source-url: https://nuget.pkg.github.com/ResoniteModdingGroup/index.json

- name: Add MonkeyLoader NuGet Source
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
- name: Setup Dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x
dotnet-version: 9.x
source-url: https://nuget.pkg.github.com/ResoniteModdingGroup/index.json

- name: Add MonkeyLoader NuGet Source
Expand Down
2 changes: 1 addition & 1 deletion ComponentSelectorAdditions/ComponentResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public ComponentResult(CategoryNode<Type>? category, Type type, string? group)
}

/// <inheritdoc/>
public override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj is ComponentResult otherResult && otherResult.Type == Type;

/// <inheritdoc/>
Expand Down
12 changes: 6 additions & 6 deletions ComponentSelectorAdditions/ComponentSelectorAdditions.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyTitle>ComponentSelectorAdditions</AssemblyTitle>
<AssemblyFileName>$(AssemblyTitle).dll</AssemblyFileName>
<RootNamespace>ComponentSelectorAdditions</RootNamespace>
Expand All @@ -11,11 +10,12 @@
<PackageId>ComponentSelectorAdditions</PackageId>
<Title>Component Selector Additions</Title>
<Authors>Banane9</Authors>
<Version>0.9.0-beta</Version>
<Version>0.10.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>
<PackageProjectUrl>https://github.com/ResoniteModdingGroup/ComponentSelectorAdditions</PackageProjectUrl>
<RepositoryUrl>$(PackageProjectUrl).git</RepositoryUrl>
<PackageTags>mod; mods; monkeyloader; resonite; component; attacher; selector; protoflux; node; picker; search; favorites</PackageTags>
</PropertyGroup>

Expand All @@ -30,18 +30,18 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="MicroUtils.HarmonyAnalyzers" Version="1.4.0">
<PackageReference Include="MicroUtils.HarmonyAnalyzers" Version="1.6.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MonkeyLoader.GamePacks.Resonite" Version="0.22.1-beta" />
<PackageReference Include="MonkeyLoader.GamePacks.Resonite" Version="0.24.1-beta" />
<PackageReference Include="PolySharp" Version="1.15.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Resonite.Elements.Assets" Version="1.3.3" />
<PackageReference Include="Resonite.Elements.Core" Version="1.4.3" />
<PackageReference Include="Resonite.Elements.Core" Version="1.4.9.4" />
<PackageReference Include="Resonite.Elements.Quantity" Version="1.2.3" />
<PackageReference Include="Resonite.FrooxEngine" Version="2025.3.21.23" />
<PackageReference Include="Resonite.FrooxEngine" Version="2025.8.25.222" />
</ItemGroup>
</Project>
36 changes: 36 additions & 0 deletions ComponentSelectorAdditions/Events/BuildButtonEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,49 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Abstract base class for button generation events.
/// </summary>
public abstract class BuildButtonEvent : CancelableBuildUIEvent
{
/// <summary>
/// Gets whether the target of the button being generated is
/// a direct <see cref="CategoryNode{T}.Elements">element</see>
/// of the current <see cref="RootCategory">root category</see>.
/// </summary>
public bool IsDirectItem { get; }

/// <summary>
/// Gets the category that the target of the button belongs to, if available.
/// </summary>
public CategoryNode<Type>? ItemCategory { get; }

/// <summary>
/// Gets the current root category of the <see cref="ComponentSelector">selector</see>
/// that the button is being generated for, if available.
/// </summary>
public CategoryNode<Type>? RootCategory { get; }

/// <summary>
/// Gets the selector that the button is being generated for.
/// </summary>
public ComponentSelector Selector { get; }

/// <summary>
/// Creates a new button generation event with the given data.
/// </summary>
/// <param name="selector">The selector that the button is being generated for.</param>
/// <param name="ui">The <see cref="UIBuilder"/> to use while generating extra UI elements.</param>
/// <param name="rootCategory">
/// The current root category of the <see cref="ComponentSelector">selector</see>
/// that the button is being generated for, if available.
/// </param>
/// <param name="itemCategory">The category that the target of the button belongs to, if available.</param>
/// <param name="isDirectItem">
/// Whether the target of the button being generated is
/// a direct <see cref="CategoryNode{T}.Elements">element</see>
/// of the current <see cref="RootCategory">root category</see>.
/// </param>
protected BuildButtonEvent(ComponentSelector selector, UIBuilder ui, CategoryNode<Type>? rootCategory, CategoryNode<Type>? itemCategory, bool isDirectItem) : base(ui)
{
Selector = selector;
Expand Down
7 changes: 7 additions & 0 deletions ComponentSelectorAdditions/Events/BuildCategoryButtonEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event data for the Build Category Button Event.
/// </summary>
/// <remarks>
/// This is used to generate the button for opening a nested
/// <see cref="CategoryNode{T}">category</see> in a <see cref="ComponentSelector">selector</see>.
/// </remarks>
public sealed class BuildCategoryButtonEvent : BuildButtonEvent
{
/// <inheritdoc/>
Expand Down
13 changes: 13 additions & 0 deletions ComponentSelectorAdditions/Events/BuildComponentButtonEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,23 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event data for the Build Component Button Event.
/// </summary>
/// <remarks>
/// This is used to generate the button to attach a concrete component,
/// or to open the custom generic selection page for open generics.
/// </remarks>
public sealed class BuildComponentButtonEvent : BuildButtonEvent
{
/// <summary>
/// Gets the component result that the button targets.
/// </summary>
public ComponentResult Component { get; }

/// <summary>
/// Gets the current selector path.
/// </summary>
public SelectorPath Path { get; }

/// <inheritdoc/>
Expand Down
40 changes: 40 additions & 0 deletions ComponentSelectorAdditions/Events/BuildCustomGenericBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,27 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event data for the Build Custom Generic Builder Event.
/// </summary>
/// <remarks>
/// This is used to generate the UI for picking custom generic arguments for generic components.
/// </remarks>
public sealed class BuildCustomGenericBuilder : BuildUIEvent
{
internal readonly HashSet<Button> OtherAddedButtonsSet = new();

/// <summary>
/// Gets or sets whether a create custom type button has been added already during this event.
/// </summary>
/// <value><see langword="true"/> if a create custom type button has been added; otherwise, <see langword="false"/>.</value>
[MemberNotNullWhen(true, nameof(CreateCustomTypeButton))]
public bool AddsCreateCustomTypeButton => CreateCustomTypeButton is not null;

/// <summary>
/// Gets or sets whether the inputs for generic arguments have been added already during this event.
/// </summary>
/// <value><see langword="true"/> if the inputs for generic arguments have been added; otherwise, <see langword="false"/>.</value>
public bool AddsGenericArgumentInputs { get; set; }

/// <summary>
Expand All @@ -34,8 +48,19 @@ public sealed class BuildCustomGenericBuilder : BuildUIEvent
/// </summary>
public Button? CreateCustomTypeButton { get; set; }

/// <summary>
/// Gets the generic arguments that inputs need to be generated for.
/// </summary>
public Type[] GenericArguments { get; }

/// <summary>
/// Gets the other buttons that have been added to the custom generic builder.
/// </summary>
public IEnumerable<Button> OtherAddedButtons => OtherAddedButtonsSet.AsSafeEnumerable();

/// <summary>
/// Gets the selector that the custom generic builder is being build for.
/// </summary>
public ComponentSelector Selector { get; }

internal BuildCustomGenericBuilder(ComponentSelector selector, UIBuilder ui, Type component) : base(ui)
Expand All @@ -45,12 +70,27 @@ internal BuildCustomGenericBuilder(ComponentSelector selector, UIBuilder ui, Typ
GenericArguments = component.GetGenericArguments();
}

/// <summary>
/// Adds <see cref="OtherAddedButtons">another</see> button to the custom generic builder.
/// </summary>
/// <param name="button">The button to add.</param>
/// <returns><see langword="true"/> if it was newly added; otherwise, <see langword="false"/>.</returns>
public bool AddOtherButton(Button button)
=> OtherAddedButtonsSet.Add(button);

/// <summary>
/// Determines whether <see cref="OtherAddedButtons">another</see> button is already part of the custom generic builder.
/// </summary>
/// <param name="button">The button to check for.</param>
/// <returns><see langword="true"/> if it was found; otherwise, <see langword="false"/>.</returns>
public bool HasOtherButton(Button button)
=> OtherAddedButtonsSet.Contains(button);

/// <summary>
/// Removes <see cref="OtherAddedButtons">another</see> button from the custom generic builder.
/// </summary>
/// <param name="button">The button to remove.</param>
/// <returns><see langword="true"/> if it was found and removed; otherwise, <see langword="false"/>.</returns>
public bool RemoveOtherButton(Button button)
=> OtherAddedButtonsSet.Remove(button);
}
Expand Down
13 changes: 13 additions & 0 deletions ComponentSelectorAdditions/Events/BuildGroupButtonEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,22 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event data for the Build Group Button Event.
/// </summary>
/// <remarks>
/// This is used to generate the button to open a group of components.
/// </remarks>
public sealed class BuildGroupButtonEvent : BuildButtonEvent
{
/// <summary>
/// Gets the group identifier that the button targets.
/// </summary>
public string Group { get; }

/// <summary>
/// Gets the group name that the button should show.
/// </summary>
public string GroupName { get; }

/// <inheritdoc/>
Expand Down
31 changes: 31 additions & 0 deletions ComponentSelectorAdditions/Events/BuildSelectorEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,54 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Abstract base class for Build Selector Events.
/// </summary>
public abstract class BuildSelectorEvent : BuildUIEvent
{
/// <summary>
/// Gets or sets whether a back button has been added already during this event.
/// </summary>
/// <value><see langword="true"/> if a back button has been added; otherwise, <see langword="false"/>.</value>
public bool AddsBackButton { get; set; }

/// <summary>
/// Gets or sets whether a cancel button has been added already during this event.
/// </summary>
/// <value><see langword="true"/> if a cancel button has been added; otherwise, <see langword="false"/>.</value>
public bool AddsCancelButton { get; set; }

/// <summary>
/// Gets or sets whether a <see cref="SearchBar">search bar</see> has been added already during this event.
/// </summary>
/// <value><see langword="true"/> if a search bar has been added; otherwise, <see langword="false"/>.</value>
[MemberNotNullWhen(true, nameof(SearchBar))]
public bool AddsSearchBar => SearchBar is not null;

/// <summary>
/// Gets or sets the search bar that has been added.
/// </summary>
public SelectorSearchBar? SearchBar { get; set; }

/// <summary>
/// Gets the selector that is being build.
/// </summary>
public ComponentSelector Selector { get; }

internal Action<SelectorPath, bool>? SelectorUIChangedHandlers => SelectorUIChanged;

internal BuildSelectorEvent(ComponentSelector selector, UIBuilder ui) : base(ui)
{
Selector = selector;
}

/// <summary>
/// Fired when the selector UI is changed.<br/>
/// The <see langword="bool"/> determines, whether the back button should be shown.
/// </summary>
/// <remarks>
/// This allows UI generated from this event to respond to changes in the path or back button state.
/// </remarks>
public event Action<SelectorPath, bool>? SelectorUIChanged;
}
}
13 changes: 12 additions & 1 deletion ComponentSelectorAdditions/Events/BuildSelectorFooterEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@
namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event fired when a <see cref="ComponentSelector"/>'s footer is constructed.
/// Represents the event data for the Build Selector Footer Event.
/// </summary>
/// <remarks>
/// Fired when a <see cref="ComponentSelector"/>'s footer is constructed.
/// </remarks>
public sealed class BuildSelectorFooterEvent : BuildSelectorEvent
{
/// <summary>
/// Gets whether a back button was already added in
/// the <see cref="BuildSelectorHeaderEvent">header</see>.
/// </summary>
public bool HasBackButton { get; }

/// <summary>
/// Gets whether a cancel button was already added in
/// the <see cref="BuildSelectorHeaderEvent">header</see>.
/// </summary>
public bool HasCancelButton { get; }

internal BuildSelectorFooterEvent(ComponentSelector selector, UIBuilder ui, SelectorSearchBar? searchBar, bool hasBackButton, bool hasCancelButton)
Expand Down
6 changes: 6 additions & 0 deletions ComponentSelectorAdditions/Events/BuildSelectorHeaderEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event data for the Build Selector Footer Event.
/// </summary>
/// <remarks>
/// Fired when a <see cref="ComponentSelector"/>'s header is constructed.
/// </remarks>
public sealed class BuildSelectorHeaderEvent : BuildSelectorEvent
{
/// <inheritdoc/>
Expand Down
13 changes: 12 additions & 1 deletion ComponentSelectorAdditions/Events/EnumerateCategoriesEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,31 @@

namespace ComponentSelectorAdditions.Events
{
/// <summary>
/// Represents the event data for the Enumerate Categories Event.
/// </summary>
/// <remarks>
/// Fired to enumerate the categories to show in the <see cref="ComponentSelector">selector</see>.
/// </remarks>
public sealed class EnumerateCategoriesEvent : CancelableSortedItemsEvent<CategoryNode<Type>>, IEnumerateSelectorResultEvent
{
/// <summary>
/// Gets the sorted categories that should be shown in the <see cref="ComponentSelector">selector</see>.
/// </summary>
public override IEnumerable<CategoryNode<Type>> Items
=> sortableItems.OrderBy(entry => entry.Value)
.ThenBy(entry => entry.Key.Name)
.Select(entry => entry.Key);

/// <inheritdoc/>
public SelectorPath Path { get; }

/// <inheritdoc/>
public CategoryNode<Type> RootCategory { get; }

/// <inheritdoc/>
public ComponentSelector Selector { get; }

/// <inheritdoc/>
internal EnumerateCategoriesEvent(ComponentSelector selector, SelectorPath path, CategoryNode<Type> rootCategory)
{
Selector = selector;
Expand Down
Loading
Loading