From aeaea6d80624777590150a2fe5c01afb5335e6f2 Mon Sep 17 00:00:00 2001 From: kaycodes13 Date: Mon, 4 May 2026 16:19:43 -0400 Subject: [PATCH 1/6] inter-group navigation now considers multiple selectables' positions --- Silksong.ModMenu/Elements/AbstractGroup.cs | 9 +- Silksong.ModMenu/Elements/FreeGroup.cs | 6 +- Silksong.ModMenu/Elements/GridGroup.cs | 43 ++++----- Silksong.ModMenu/Elements/INavigable.cs | 18 ++-- .../Elements/INavigableExtensions.cs | 95 +++++++++++++------ Silksong.ModMenu/Elements/ScrollingPane.cs | 12 +-- .../Elements/SelectableElement.cs | 11 ++- Silksong.ModMenu/Elements/VerticalGroup.cs | 24 +++-- .../Internal/SelectableWrapper.cs | 60 ++++++++++-- Silksong.ModMenu/Screens/BasicMenuScreen.cs | 8 +- .../Screens/PaginatedMenuScreen.cs | 4 +- .../Tests/ScrollingPaneTests.cs | 42 ++++---- 12 files changed, 205 insertions(+), 127 deletions(-) diff --git a/Silksong.ModMenu/Elements/AbstractGroup.cs b/Silksong.ModMenu/Elements/AbstractGroup.cs index 915b891..952b13a 100644 --- a/Silksong.ModMenu/Elements/AbstractGroup.cs +++ b/Silksong.ModMenu/Elements/AbstractGroup.cs @@ -85,9 +85,9 @@ public virtual void ClearNeighbors() .FirstOrDefault(); /// - public abstract bool GetSelectable( + public abstract bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectable ); private GameObject? gameObjectParent; @@ -113,7 +113,10 @@ public virtual void ClearGameObjectParent() } /// - public virtual void SetNeighbor(NavigationDirection direction, Selectable selectable) + public virtual void SetNeighbor( + NavigationDirection direction, + IEnumerable selectable + ) { foreach (var navigable in GetNavigables(direction)) navigable.SetNeighbor(direction, selectable); diff --git a/Silksong.ModMenu/Elements/FreeGroup.cs b/Silksong.ModMenu/Elements/FreeGroup.cs index bac9da0..9e8aa4a 100644 --- a/Silksong.ModMenu/Elements/FreeGroup.cs +++ b/Silksong.ModMenu/Elements/FreeGroup.cs @@ -88,13 +88,13 @@ private static float SortKey(NavigationDirection direction, Vector2 pos) => }; /// - public override bool GetSelectable( + public override bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectable ) { selectable = GetNavigables(direction) - .Select(n => n.GetSelectable(direction, out var s) ? s : null) + .Select(n => n.GetSelectables(direction, out var s) ? s : null) .FirstOrDefault(); return selectable != null; } diff --git a/Silksong.ModMenu/Elements/GridGroup.cs b/Silksong.ModMenu/Elements/GridGroup.cs index b08b7f6..824b632 100644 --- a/Silksong.ModMenu/Elements/GridGroup.cs +++ b/Silksong.ModMenu/Elements/GridGroup.cs @@ -150,36 +150,27 @@ public override void Clear() } /// - public override bool GetSelectable( + public override bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ) { - var navigable = direction switch + var navigables = direction switch { - // Last element. - NavigationDirection.Up => AllEntities() - .Where(e => e.VisibleSelf) - .OfType() - .LastOrDefault(), - // Rightmost element. - NavigationDirection.Left => GetColumns() - .SelectMany(col => col.WhereNonNull(e => e.VisibleSelf).OfType()) - .LastOrDefault(), - // Leftmost element. - NavigationDirection.Right => GetColumns() - .SelectMany(col => col.WhereNonNull(e => e.VisibleSelf).OfType()) - .FirstOrDefault(), - // First element. - NavigationDirection.Down => AllEntities() - .Where(e => e.VisibleSelf) - .OfType() - .FirstOrDefault(), + // Bottom row. + NavigationDirection.Up => GetNavigables(NavigationDirection.Down), + // Rightmost element of every row. + NavigationDirection.Left => GetNavigables(NavigationDirection.Right), + // Leftmost element of every row. + NavigationDirection.Right => GetNavigables(NavigationDirection.Left), + // Top row. + NavigationDirection.Down => GetNavigables(NavigationDirection.Up), _ => throw new ArgumentException($"{direction}"), }; - selectable = default; - return navigable != null && navigable.GetSelectable(direction, out selectable); + selectables = + navigables?.SelectMany(x => x.GetSelectables(direction, out var s) ? s : []) ?? []; + return navigables != null && selectables.Any(); } /// @@ -216,7 +207,7 @@ static bool ClosestColumn( INavigable?[] row, NavigationDirection dir, int column, - [MaybeNullWhen(false)] out Selectable target + [MaybeNullWhen(false)] out IEnumerable targets ) { int offset = 0; @@ -235,12 +226,12 @@ static bool ClosestColumn( if ( idx >= 0 && idx < row.Length - && (row[idx]?.GetSelectable(dir, out target) ?? false) + && (row[idx]?.GetSelectables(dir, out targets) ?? false) ) return true; } - target = default; + targets = default; return false; } diff --git a/Silksong.ModMenu/Elements/INavigable.cs b/Silksong.ModMenu/Elements/INavigable.cs index 05134db..84c0a98 100644 --- a/Silksong.ModMenu/Elements/INavigable.cs +++ b/Silksong.ModMenu/Elements/INavigable.cs @@ -1,4 +1,6 @@ -using System.Diagnostics.CodeAnalysis; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using UnityEngine.UI; namespace Silksong.ModMenu.Elements; @@ -14,10 +16,10 @@ public interface INavigable void ClearNeighbors(); /// - /// Set the directional neighbor of this entity. + /// Set the directional neighbor of this entity to one of the given choices. /// /// False if this entity has no navigation to connect. - void SetNeighbor(NavigationDirection direction, Selectable selectable); + void SetNeighbor(NavigationDirection direction, IEnumerable selectables); /// /// Unset the given directional neighbor of this entity. @@ -25,14 +27,14 @@ public interface INavigable void ClearNeighbor(NavigationDirection direction); /// - /// Get the Selectable to target if navigating to this element along 'direction'. + /// Get a set of choices for the Selectable to target if navigating to this element along 'direction'. /// /// In other words, typical usage would entail: - /// if (foo.GetSelectable(dir, out var selectable)) - /// bar.SetNeighbor(dir, selectable); + /// if (foo.GetSelectables(dir, out var selectables)) + /// bar.SetNeighbor(dir, selectables); /// - bool GetSelectable( + bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ); } diff --git a/Silksong.ModMenu/Elements/INavigableExtensions.cs b/Silksong.ModMenu/Elements/INavigableExtensions.cs index 8e73dd5..78a0561 100644 --- a/Silksong.ModMenu/Elements/INavigableExtensions.cs +++ b/Silksong.ModMenu/Elements/INavigableExtensions.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using UnityEngine.UI; namespace Silksong.ModMenu.Elements; @@ -17,13 +18,22 @@ public static class INavigableExtensions /// Set the upwards neighbor of this navigable. /// public void SetNeighborUp(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Up, selectable); + self.SetNeighbor(NavigationDirection.Up, [selectable]); + + /// + /// Set the upwards neighbor of this navigable to one of the given options. + /// + public void SetNeighborUp(IEnumerable selectables) => + self.SetNeighbor(NavigationDirection.Up, selectables); /// /// Set the upwards neighbor of this navigable. /// - public void SetNeighborUp(SelectableElement selectableElement) => - self.SetNeighborUp(selectableElement.SelectableComponent); + public void SetNeighborUp(SelectableElement selectableElement) + { + if (selectableElement.GetSelectables(NavigationDirection.Up, out var selectables)) + self.SetNeighborDown(selectables); + } /// /// Declare that this navigable has no upwards neighbor. @@ -31,22 +41,32 @@ public void SetNeighborUp(SelectableElement selectableElement) => public void ClearNeighborUp() => self.ClearNeighbor(NavigationDirection.Up); /// - /// Get the most eligible selectable within this navigable when navigating upwards into it. + /// Get the most eligible selectables within this navigable when navigating upwards into it. /// - public bool GetNeighborUp([MaybeNullWhen(false)] out Selectable selectable) => - self.GetSelectable(NavigationDirection.Up, out selectable); + public bool GetNeighborsUp( + [MaybeNullWhen(false)] out IEnumerable selectables + ) => self.GetSelectables(NavigationDirection.Up, out selectables); /// /// Set the leftwards neighbor of this navigable. /// public void SetNeighborLeft(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Left, selectable); + self.SetNeighbor(NavigationDirection.Left, [selectable]); + + /// + /// Set the leftwards neighbor of this navigable to one of the given options. + /// + public void SetNeighborLeft(IEnumerable selectables) => + self.SetNeighbor(NavigationDirection.Left, selectables); /// /// Set the leftwards neighbor of this navigable. /// - public void SetNeighborLeft(SelectableElement selectableElement) => - self.SetNeighborLeft(selectableElement.SelectableComponent); + public void SetNeighborLeft(SelectableElement selectableElement) + { + if (selectableElement.GetSelectables(NavigationDirection.Left, out var selectables)) + self.SetNeighborDown(selectables); + } /// /// Declare that this navigable has no upwards neighbor. @@ -54,28 +74,39 @@ public void SetNeighborLeft(SelectableElement selectableElement) => public void ClearNeighborLeft() => self.ClearNeighbor(NavigationDirection.Left); /// - /// Get the most eligible selectable within this navigable when navigating leftwards into it. + /// Get the most eligible selectables within this navigable when navigating leftwards into it. /// - public bool GetNeighborLeft([MaybeNullWhen(false)] out Selectable selectable) => - self.GetSelectable(NavigationDirection.Left, out selectable); + public bool GetNeighborsLeft( + [MaybeNullWhen(false)] out IEnumerable selectable + ) => self.GetSelectables(NavigationDirection.Left, out selectable); /// /// Set the rightwards neighbor of this navigable. /// public void SetNeighborRight(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Right, selectable); + self.SetNeighbor(NavigationDirection.Right, [selectable]); + + /// + /// Set the rightwards neighbor of this navigable to one of the given options. + /// + public void SetNeighborRight(IEnumerable selectables) => + self.SetNeighbor(NavigationDirection.Right, selectables); /// /// Set the rightwards neighbor of this navigable. /// - public void SetNeighborRight(SelectableElement selectableElement) => - self.SetNeighborRight(selectableElement.SelectableComponent); + public void SetNeighborRight(SelectableElement selectableElement) + { + if (selectableElement.GetSelectables(NavigationDirection.Right, out var selectables)) + self.SetNeighborDown(selectables); + } /// - /// Get the most eligible selectable within this navigable when navigating rightwards into it. + /// Get the most eligible selectables within this navigable when navigating rightwards into it. /// - public bool GetNeighborRight([MaybeNullWhen(false)] out Selectable selectable) => - self.GetSelectable(NavigationDirection.Right, out selectable); + public bool GetNeighborsRight( + [MaybeNullWhen(false)] out IEnumerable selectables + ) => self.GetSelectables(NavigationDirection.Right, out selectables); /// /// Declare that this navigable has no upwards neighbor. @@ -86,13 +117,22 @@ public bool GetNeighborRight([MaybeNullWhen(false)] out Selectable selectable) = /// Set the downwards neighbor of this navigable. /// public void SetNeighborDown(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Down, selectable); + self.SetNeighbor(NavigationDirection.Down, [selectable]); + + /// + /// Set the downwards neighbor of this navigable to one of the given options. + /// + public void SetNeighborDown(IEnumerable selectables) => + self.SetNeighbor(NavigationDirection.Down, selectables); /// /// Set the downwards neighbor of this navigable. /// - public void SetNeighborDown(SelectableElement selectableElement) => - self.SetNeighborDown(selectableElement.SelectableComponent); + public void SetNeighborDown(SelectableElement selectableElement) + { + if (selectableElement.GetSelectables(NavigationDirection.Down, out var selectables)) + self.SetNeighborDown(selectables); + } /// /// Declare that this navigable has no upwards neighbor. @@ -100,19 +140,20 @@ public void SetNeighborDown(SelectableElement selectableElement) => public void ClearNeighborDown() => self.ClearNeighbor(NavigationDirection.Down); /// - /// Get the most eligible selectable within this navigable when navigating downwards into it. + /// Get the most eligible selectables within this navigable when navigating downwards into it. /// - public bool GetNeighborDown([MaybeNullWhen(false)] out Selectable selectable) => - self.GetSelectable(NavigationDirection.Down, out selectable); + public bool GetNeighborsDown( + [MaybeNullWhen(false)] out IEnumerable selectables + ) => self.GetSelectables(NavigationDirection.Down, out selectables); /// /// Symmetrically connect two INavigables. /// public void ConnectSymmetric(INavigable dest, NavigationDirection direction) { - if (dest.GetSelectable(direction, out var s)) + if (dest.GetSelectables(direction, out var s)) self.SetNeighbor(direction, s); - if (self.GetSelectable(direction.Opposite(), out s)) + if (self.GetSelectables(direction.Opposite(), out s)) dest.SetNeighbor(direction.Opposite(), s); } } diff --git a/Silksong.ModMenu/Elements/ScrollingPane.cs b/Silksong.ModMenu/Elements/ScrollingPane.cs index d1b1051..9f0f5d3 100644 --- a/Silksong.ModMenu/Elements/ScrollingPane.cs +++ b/Silksong.ModMenu/Elements/ScrollingPane.cs @@ -288,20 +288,20 @@ Func shouldSkip public void ClearNeighbors() => Content?.ClearNeighbors(); /// - public void SetNeighbor(NavigationDirection direction, Selectable selectable) => - Content?.SetNeighbor(direction, selectable); + public void SetNeighbor(NavigationDirection direction, IEnumerable selectables) => + Content?.SetNeighbor(direction, selectables); /// public void ClearNeighbor(NavigationDirection direction) => Content?.ClearNeighbor(direction); /// - public bool GetSelectable( + public bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ) { - selectable = default; - return Content?.GetSelectable(direction, out selectable) ?? false; + selectables = default; + return Content?.GetSelectables(direction, out selectables) ?? false; } #endregion diff --git a/Silksong.ModMenu/Elements/SelectableElement.cs b/Silksong.ModMenu/Elements/SelectableElement.cs index b49d9b3..9209673 100644 --- a/Silksong.ModMenu/Elements/SelectableElement.cs +++ b/Silksong.ModMenu/Elements/SelectableElement.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Silksong.ModMenu.Internal; using Silksong.ModMenu.Util; @@ -75,16 +76,16 @@ public void ClearNeighbor(NavigationDirection direction) => new SelectableWrapper(SelectableComponent).ClearNeighbor(direction); /// - public void SetNeighbor(NavigationDirection direction, Selectable selectable) => - new SelectableWrapper(SelectableComponent).SetNeighbor(direction, selectable); + public void SetNeighbor(NavigationDirection direction, IEnumerable selectables) => + new SelectableWrapper(SelectableComponent).SetNeighbor(direction, selectables); /// - public bool GetSelectable( + public bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ) { - selectable = SelectableComponent; + selectables = [SelectableComponent]; return true; } diff --git a/Silksong.ModMenu/Elements/VerticalGroup.cs b/Silksong.ModMenu/Elements/VerticalGroup.cs index c756f93..3c9af31 100644 --- a/Silksong.ModMenu/Elements/VerticalGroup.cs +++ b/Silksong.ModMenu/Elements/VerticalGroup.cs @@ -89,33 +89,31 @@ public override void Clear() } /// - public override bool GetSelectable( + public override bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ) { switch (direction) { case NavigationDirection.Left: case NavigationDirection.Right: - selectable = NonHiddenEntities() - .MedianOutwards() + selectables = NonHiddenEntities() .OfType() - .Select(n => n.GetSelectable(direction, out var s) ? s : null) - .FirstOrDefault(); - return selectable != null; + .SelectMany(n => n.GetSelectables(direction, out var s) ? s : null); + return selectables != null; case NavigationDirection.Up: - selectable = NonHiddenEntities() + selectables = NonHiddenEntities() .OfType() - .Select(n => n.GetSelectable(direction, out var s) ? s : null) + .Select(n => n.GetSelectables(direction, out var s) ? s : null) .LastOrDefault(); - return selectable != null; + return selectables != null; case NavigationDirection.Down: - selectable = NonHiddenEntities() + selectables = NonHiddenEntities() .OfType() - .Select(n => n.GetSelectable(direction, out var s) ? s : null) + .Select(n => n.GetSelectables(direction, out var s) ? s : null) .FirstOrDefault(); - return selectable != null; + return selectables != null; default: throw direction.UnsupportedEnum(); } diff --git a/Silksong.ModMenu/Internal/SelectableWrapper.cs b/Silksong.ModMenu/Internal/SelectableWrapper.cs index 597fdc3..01a12fa 100644 --- a/Silksong.ModMenu/Internal/SelectableWrapper.cs +++ b/Silksong.ModMenu/Internal/SelectableWrapper.cs @@ -1,5 +1,9 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using Silksong.ModMenu.Elements; +using UnityEngine; using UnityEngine.UI; namespace Silksong.ModMenu.Internal; @@ -31,22 +35,60 @@ public void ClearNeighbor(NavigationDirection direction) => public void ClearNeighbors() => Nav = new(); - public bool GetSelectable( + public bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out Selectable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ) { - selectable = this.selectable; + selectables = [selectable]; return true; } - public void SetNeighbor(NavigationDirection direction, Selectable selectable) => + public void SetNeighbor(NavigationDirection direction, IEnumerable selectables) + { + if (!selectables.Any()) + throw new ArgumentException( + "At least one selectable is required.", + nameof(selectables) + ); + + Vector2 position = selectable.transform.position; + Vector2 directionVector = direction switch + { + NavigationDirection.Up => Vector2.up, + NavigationDirection.Left => Vector2.left, + NavigationDirection.Right => Vector2.right, + NavigationDirection.Down => Vector2.down, + _ => throw direction.UnsupportedEnum(), + }; + + Selectable bestOption = selectables + .Select(selectable => + { + Vector2 otherPos = selectable.transform.position, + interAngle = otherPos - position; + float directionalAngle = Vector2.Angle(directionVector, interAngle); + return ( + selectable, + directionalAngle, + angle: Mathf.Min(directionalAngle, Vector2.Angle(-directionVector, interAngle)), + position: otherPos + ); + }) + // Rough shallowness of the angle between selectables, then favour selectables on the correct side of this one + .OrderBy(x => (int)Mathf.RoundToMultipleOf(x.angle, 20)) + .ThenBy(x => (int)Mathf.RoundToMultipleOf(x.directionalAngle, 90)) + .ThenBy(x => Vector2.Distance(position, x.position)) + .First() + .selectable; + Nav = direction switch { - NavigationDirection.Up => Nav with { selectOnUp = selectable }, - NavigationDirection.Left => Nav with { selectOnLeft = selectable }, - NavigationDirection.Right => Nav with { selectOnRight = selectable }, - NavigationDirection.Down => Nav with { selectOnDown = selectable }, + NavigationDirection.Up => Nav with { selectOnUp = bestOption }, + NavigationDirection.Left => Nav with { selectOnLeft = bestOption }, + NavigationDirection.Right => Nav with { selectOnRight = bestOption }, + NavigationDirection.Down => Nav with { selectOnDown = bestOption }, _ => throw direction.UnsupportedEnum(), }; + } } diff --git a/Silksong.ModMenu/Screens/BasicMenuScreen.cs b/Silksong.ModMenu/Screens/BasicMenuScreen.cs index 4a3bcf0..025850e 100644 --- a/Silksong.ModMenu/Screens/BasicMenuScreen.cs +++ b/Silksong.ModMenu/Screens/BasicMenuScreen.cs @@ -63,9 +63,9 @@ protected override void UpdateLayout() Content.SetNeighborDown(BackButton); Content.SetNeighborUp(BackButton); - if (Content.GetNeighborDown(out var selectable)) - wrapper.SetNeighborDown(selectable); - if (Content.GetNeighborUp(out selectable)) - wrapper.SetNeighborUp(selectable); + if (Content.GetNeighborsDown(out var selectables)) + wrapper.SetNeighborDown(selectables); + if (Content.GetNeighborsUp(out selectables)) + wrapper.SetNeighborUp(selectables); } } diff --git a/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs b/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs index cd37588..3b7680f 100644 --- a/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs +++ b/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs @@ -140,9 +140,9 @@ protected override void UpdateLayout() s.ClearNeighbors(); foreach (var (top, bot) in column.CircularPairs()) { - if (top.GetNeighborUp(out var s)) + if (top.GetNeighborsUp(out var s)) bot.SetNeighborUp(s); - if (bot.GetNeighborDown(out s)) + if (bot.GetNeighborsDown(out s)) top.SetNeighborDown(s); } } diff --git a/Silksong.ModMenuTesting/Tests/ScrollingPaneTests.cs b/Silksong.ModMenuTesting/Tests/ScrollingPaneTests.cs index e8bb103..b471b9d 100644 --- a/Silksong.ModMenuTesting/Tests/ScrollingPaneTests.cs +++ b/Silksong.ModMenuTesting/Tests/ScrollingPaneTests.cs @@ -32,33 +32,33 @@ internal override AbstractMenuScreen BuildMenuScreen() /// static GridGroup ScrollPaneSiblings() { - VerticalGroup innerContentOne = new(), - innerContentTwo = new(); + VerticalGroup contentOne = new() { VerticalSpacing = SpacingConstants.VSPACE_LARGE }, + contentTwo = new() { VerticalSpacing = SpacingConstants.VSPACE_MEDIUM }, + contentFour = new() { VerticalSpacing = SpacingConstants.VSPACE_SMALL }; - for (int i = 1; i <= 15; i++) + GridGroup contentThree = new(2) { HorizontalSpacing = 240 }; + + for (int i = 1; i <= 6; i++) { - innerContentOne.Add(new TextButton($"Hollow {i}")); - innerContentTwo.Add(new TextButton($"Knight {i}")); + contentOne.Add(new TextButton($"Hollow {i}")); + contentFour.Add(new TextButton($"Silksong {i}")); + } + for (int i = 1; i <= 12; i++) + { + contentTwo.Add(new TextButton($"Knight {i}")); + contentThree.Add(new TextButton($"Yay {i}")); } - ScrollingPane innerScrollOne = - new(innerContentOne) - { - ViewportSize = new Vector2(500, 875), - SmoothScrollTime = 0.5f, - }, - innerScrollTwo = - new(innerContentTwo) - { - ViewportSize = new Vector2(500, 875), - SmoothScrollTime = 0.5f, - }; + ScrollingPane scrollOne = new(contentOne) { ViewportSize = new Vector2(500, 675) }, + scrollTwo = new(contentTwo) { ViewportSize = new Vector2(500, 675) }; - GridGroup outerContent = new(2) { HorizontalSpacing = 600 }; - outerContent.Add(innerScrollOne); - outerContent.Add(innerScrollTwo); + GridGroup outer = new(4) { HorizontalSpacing = SpacingConstants.HSPACE_SMALL }; + outer.Add(scrollOne); + outer.Add(scrollTwo); + outer.Add(contentThree); + outer.Add(contentFour); - return outerContent; + return outer; } /// From f8470c400a96344de7a7194d8633b62d3e5029c0 Mon Sep 17 00:00:00 2001 From: kaycodes13 Date: Mon, 4 May 2026 17:00:03 -0400 Subject: [PATCH 2/6] adjust logic for up/down nav into GridGroup --- Silksong.ModMenu/Elements/GridGroup.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Silksong.ModMenu/Elements/GridGroup.cs b/Silksong.ModMenu/Elements/GridGroup.cs index 824b632..58564be 100644 --- a/Silksong.ModMenu/Elements/GridGroup.cs +++ b/Silksong.ModMenu/Elements/GridGroup.cs @@ -157,14 +157,18 @@ public override bool GetSelectables( { var navigables = direction switch { - // Bottom row. - NavigationDirection.Up => GetNavigables(NavigationDirection.Down), + // Bottommost element of every column. + NavigationDirection.Up => GetColumns() + .Select(x => (INavigable?)x.LastOrDefault(e => e is INavigable && e.VisibleSelf)) + .WhereNonNull(), // Rightmost element of every row. NavigationDirection.Left => GetNavigables(NavigationDirection.Right), // Leftmost element of every row. NavigationDirection.Right => GetNavigables(NavigationDirection.Left), - // Top row. - NavigationDirection.Down => GetNavigables(NavigationDirection.Up), + // Topmost element of every column. + NavigationDirection.Down => GetColumns() + .Select(x => (INavigable?)x.FirstOrDefault(e => e is INavigable && e.VisibleSelf)) + .WhereNonNull(), _ => throw new ArgumentException($"{direction}"), }; From 2cafe9ead5e70fe2b00b1ae5b2c69a2037534fb1 Mon Sep 17 00:00:00 2001 From: kaycodes13 Date: Mon, 4 May 2026 23:57:55 -0400 Subject: [PATCH 3/6] more consistent pluralization, fix SetNeighbors sort priority --- Silksong.ModMenu/Elements/AbstractGroup.cs | 20 ++-- Silksong.ModMenu/Elements/FreeGroup.cs | 9 +- Silksong.ModMenu/Elements/GridGroup.cs | 9 +- Silksong.ModMenu/Elements/INavigable.cs | 10 +- .../Elements/INavigableExtensions.cs | 94 +++++++++---------- Silksong.ModMenu/Elements/ScrollingPane.cs | 6 +- .../Elements/SelectableElement.cs | 8 +- Silksong.ModMenu/Elements/TextButton.cs | 1 + .../Internal/SelectableWrapper.cs | 38 +++++--- Silksong.ModMenu/Screens/BasicMenuScreen.cs | 6 +- .../Screens/PaginatedMenuScreen.cs | 4 +- 11 files changed, 108 insertions(+), 97 deletions(-) diff --git a/Silksong.ModMenu/Elements/AbstractGroup.cs b/Silksong.ModMenu/Elements/AbstractGroup.cs index 952b13a..b87891d 100644 --- a/Silksong.ModMenu/Elements/AbstractGroup.cs +++ b/Silksong.ModMenu/Elements/AbstractGroup.cs @@ -60,19 +60,19 @@ protected AbstractGroup() protected abstract IEnumerable GetNavigables(NavigationDirection direction); /// - public virtual void ClearNeighbor(NavigationDirection direction) + public virtual void ClearNeighbors(NavigationDirection direction) { foreach (var navigable in GetNavigables(direction)) - navigable.ClearNeighbor(direction); + navigable.ClearNeighbors(direction); } /// public virtual void ClearNeighbors() { - ClearNeighbor(NavigationDirection.Up); - ClearNeighbor(NavigationDirection.Left); - ClearNeighbor(NavigationDirection.Right); - ClearNeighbor(NavigationDirection.Down); + ClearNeighbors(NavigationDirection.Up); + ClearNeighbors(NavigationDirection.Left); + ClearNeighbors(NavigationDirection.Right); + ClearNeighbors(NavigationDirection.Down); } /// @@ -87,7 +87,7 @@ public virtual void ClearNeighbors() /// public abstract bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out IEnumerable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ); private GameObject? gameObjectParent; @@ -113,13 +113,13 @@ public virtual void ClearGameObjectParent() } /// - public virtual void SetNeighbor( + public virtual void SetNeighbors( NavigationDirection direction, - IEnumerable selectable + IEnumerable selectables ) { foreach (var navigable in GetNavigables(direction)) - navigable.SetNeighbor(direction, selectable); + navigable.SetNeighbors(direction, selectables); } /// diff --git a/Silksong.ModMenu/Elements/FreeGroup.cs b/Silksong.ModMenu/Elements/FreeGroup.cs index 9e8aa4a..556ec8a 100644 --- a/Silksong.ModMenu/Elements/FreeGroup.cs +++ b/Silksong.ModMenu/Elements/FreeGroup.cs @@ -90,13 +90,12 @@ private static float SortKey(NavigationDirection direction, Vector2 pos) => /// public override bool GetSelectables( NavigationDirection direction, - [MaybeNullWhen(false)] out IEnumerable selectable + [MaybeNullWhen(false)] out IEnumerable selectables ) { - selectable = GetNavigables(direction) - .Select(n => n.GetSelectables(direction, out var s) ? s : null) - .FirstOrDefault(); - return selectable != null; + selectables = GetNavigables(direction) + .SelectMany(n => n.GetSelectables(direction, out var s) ? s : null); + return selectables != null; } /// diff --git a/Silksong.ModMenu/Elements/GridGroup.cs b/Silksong.ModMenu/Elements/GridGroup.cs index 58564be..e06bcf2 100644 --- a/Silksong.ModMenu/Elements/GridGroup.cs +++ b/Silksong.ModMenu/Elements/GridGroup.cs @@ -172,9 +172,8 @@ public override bool GetSelectables( _ => throw new ArgumentException($"{direction}"), }; - selectables = - navigables?.SelectMany(x => x.GetSelectables(direction, out var s) ? s : []) ?? []; - return navigables != null && selectables.Any(); + selectables = navigables.SelectMany(x => x.GetSelectables(direction, out var s) ? s : []); + return selectables.Any(); } /// @@ -245,12 +244,12 @@ static bool ClosestColumn( prevRow[i] != null && ClosestColumn(nextRow, NavigationDirection.Down, i, out var s) ) - prevRow[i]!.SetNeighborDown(s); + prevRow[i]!.SetNeighborsDown(s); if ( nextRow[i] != null && ClosestColumn(prevRow, NavigationDirection.Up, i, out s) ) - nextRow[i]!.SetNeighborUp(s); + nextRow[i]!.SetNeighborsUp(s); } } prevRow = nextRow; diff --git a/Silksong.ModMenu/Elements/INavigable.cs b/Silksong.ModMenu/Elements/INavigable.cs index 84c0a98..e38ae18 100644 --- a/Silksong.ModMenu/Elements/INavigable.cs +++ b/Silksong.ModMenu/Elements/INavigable.cs @@ -16,22 +16,22 @@ public interface INavigable void ClearNeighbors(); /// - /// Set the directional neighbor of this entity to one of the given choices. + /// Set the directional neighbors of this entity to one or more of the given choices. /// /// False if this entity has no navigation to connect. - void SetNeighbor(NavigationDirection direction, IEnumerable selectables); + void SetNeighbors(NavigationDirection direction, IEnumerable selectables); /// /// Unset the given directional neighbor of this entity. /// - void ClearNeighbor(NavigationDirection direction); + void ClearNeighbors(NavigationDirection direction); /// - /// Get a set of choices for the Selectable to target if navigating to this element along 'direction'. + /// Get a set of choices for the Selectables to target if navigating to this element along 'direction'. /// /// In other words, typical usage would entail: /// if (foo.GetSelectables(dir, out var selectables)) - /// bar.SetNeighbor(dir, selectables); + /// bar.SetNeighbors(dir, selectables); /// bool GetSelectables( NavigationDirection direction, diff --git a/Silksong.ModMenu/Elements/INavigableExtensions.cs b/Silksong.ModMenu/Elements/INavigableExtensions.cs index 78a0561..83b54a7 100644 --- a/Silksong.ModMenu/Elements/INavigableExtensions.cs +++ b/Silksong.ModMenu/Elements/INavigableExtensions.cs @@ -15,30 +15,30 @@ public static class INavigableExtensions extension(INavigable self) { /// - /// Set the upwards neighbor of this navigable. + /// Set the upwards neighbors of this navigable. /// - public void SetNeighborUp(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Up, [selectable]); + public void SetNeighborsUp(Selectable selectable) => + self.SetNeighbors(NavigationDirection.Up, [selectable]); /// - /// Set the upwards neighbor of this navigable to one of the given options. + /// Set the upwards neighbors of this navigable to one or more of the given options. /// - public void SetNeighborUp(IEnumerable selectables) => - self.SetNeighbor(NavigationDirection.Up, selectables); + public void SetNeighborsUp(IEnumerable selectables) => + self.SetNeighbors(NavigationDirection.Up, selectables); /// - /// Set the upwards neighbor of this navigable. + /// Set the upwards neighbors of this navigable. /// - public void SetNeighborUp(SelectableElement selectableElement) + public void SetNeighborsUp(SelectableElement selectableElement) { if (selectableElement.GetSelectables(NavigationDirection.Up, out var selectables)) - self.SetNeighborDown(selectables); + self.SetNeighborsUp(selectables); } /// - /// Declare that this navigable has no upwards neighbor. + /// Declare that this navigable has no upwards neighbors. /// - public void ClearNeighborUp() => self.ClearNeighbor(NavigationDirection.Up); + public void ClearNeighborsUp() => self.ClearNeighbors(NavigationDirection.Up); /// /// Get the most eligible selectables within this navigable when navigating upwards into it. @@ -48,57 +48,57 @@ public bool GetNeighborsUp( ) => self.GetSelectables(NavigationDirection.Up, out selectables); /// - /// Set the leftwards neighbor of this navigable. + /// Set the leftwards neighbors of this navigable. /// - public void SetNeighborLeft(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Left, [selectable]); + public void SetNeighborsLeft(Selectable selectable) => + self.SetNeighbors(NavigationDirection.Left, [selectable]); /// - /// Set the leftwards neighbor of this navigable to one of the given options. + /// Set the leftwards neighbors of this navigable to one or more of the given options. /// - public void SetNeighborLeft(IEnumerable selectables) => - self.SetNeighbor(NavigationDirection.Left, selectables); + public void SetNeighborsLeft(IEnumerable selectables) => + self.SetNeighbors(NavigationDirection.Left, selectables); /// - /// Set the leftwards neighbor of this navigable. + /// Set the leftwards neighbors of this navigable. /// - public void SetNeighborLeft(SelectableElement selectableElement) + public void SetNeighborsLeft(SelectableElement selectableElement) { if (selectableElement.GetSelectables(NavigationDirection.Left, out var selectables)) - self.SetNeighborDown(selectables); + self.SetNeighborsLeft(selectables); } /// - /// Declare that this navigable has no upwards neighbor. + /// Declare that this navigable has no upwards neighbors. /// - public void ClearNeighborLeft() => self.ClearNeighbor(NavigationDirection.Left); + public void ClearNeighborsLeft() => self.ClearNeighbors(NavigationDirection.Left); /// /// Get the most eligible selectables within this navigable when navigating leftwards into it. /// public bool GetNeighborsLeft( - [MaybeNullWhen(false)] out IEnumerable selectable - ) => self.GetSelectables(NavigationDirection.Left, out selectable); + [MaybeNullWhen(false)] out IEnumerable selectables + ) => self.GetSelectables(NavigationDirection.Left, out selectables); /// - /// Set the rightwards neighbor of this navigable. + /// Set the rightwards neighbors of this navigable. /// - public void SetNeighborRight(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Right, [selectable]); + public void SetNeighborsRight(Selectable selectable) => + self.SetNeighbors(NavigationDirection.Right, [selectable]); /// - /// Set the rightwards neighbor of this navigable to one of the given options. + /// Set the rightwards neighbors of this navigable to one or more of the given options. /// - public void SetNeighborRight(IEnumerable selectables) => - self.SetNeighbor(NavigationDirection.Right, selectables); + public void SetNeighborsRight(IEnumerable selectables) => + self.SetNeighbors(NavigationDirection.Right, selectables); /// - /// Set the rightwards neighbor of this navigable. + /// Set the rightwards neighbors of this navigable. /// - public void SetNeighborRight(SelectableElement selectableElement) + public void SetNeighborsRight(SelectableElement selectableElement) { if (selectableElement.GetSelectables(NavigationDirection.Right, out var selectables)) - self.SetNeighborDown(selectables); + self.SetNeighborsRight(selectables); } /// @@ -109,35 +109,35 @@ public bool GetNeighborsRight( ) => self.GetSelectables(NavigationDirection.Right, out selectables); /// - /// Declare that this navigable has no upwards neighbor. + /// Declare that this navigable has no upwards neighbors. /// - public void ClearNeighborRight() => self.ClearNeighbor(NavigationDirection.Right); + public void ClearNeighborsRight() => self.ClearNeighbors(NavigationDirection.Right); /// - /// Set the downwards neighbor of this navigable. + /// Set the downwards neighbors of this navigable. /// public void SetNeighborDown(Selectable selectable) => - self.SetNeighbor(NavigationDirection.Down, [selectable]); + self.SetNeighbors(NavigationDirection.Down, [selectable]); /// - /// Set the downwards neighbor of this navigable to one of the given options. + /// Set the downwards neighbors of this navigable to one or more of the given options. /// - public void SetNeighborDown(IEnumerable selectables) => - self.SetNeighbor(NavigationDirection.Down, selectables); + public void SetNeighborsDown(IEnumerable selectables) => + self.SetNeighbors(NavigationDirection.Down, selectables); /// - /// Set the downwards neighbor of this navigable. + /// Set the downwards neighbors of this navigable. /// - public void SetNeighborDown(SelectableElement selectableElement) + public void SetNeighborsDown(SelectableElement selectableElement) { if (selectableElement.GetSelectables(NavigationDirection.Down, out var selectables)) - self.SetNeighborDown(selectables); + self.SetNeighborsDown(selectables); } /// - /// Declare that this navigable has no upwards neighbor. + /// Declare that this navigable has no upwards neighbors. /// - public void ClearNeighborDown() => self.ClearNeighbor(NavigationDirection.Down); + public void ClearNeighborsDown() => self.ClearNeighbors(NavigationDirection.Down); /// /// Get the most eligible selectables within this navigable when navigating downwards into it. @@ -152,9 +152,9 @@ public bool GetNeighborsDown( public void ConnectSymmetric(INavigable dest, NavigationDirection direction) { if (dest.GetSelectables(direction, out var s)) - self.SetNeighbor(direction, s); + self.SetNeighbors(direction, s); if (self.GetSelectables(direction.Opposite(), out s)) - dest.SetNeighbor(direction.Opposite(), s); + dest.SetNeighbors(direction.Opposite(), s); } } } diff --git a/Silksong.ModMenu/Elements/ScrollingPane.cs b/Silksong.ModMenu/Elements/ScrollingPane.cs index 9f0f5d3..14fa9ac 100644 --- a/Silksong.ModMenu/Elements/ScrollingPane.cs +++ b/Silksong.ModMenu/Elements/ScrollingPane.cs @@ -288,11 +288,11 @@ Func shouldSkip public void ClearNeighbors() => Content?.ClearNeighbors(); /// - public void SetNeighbor(NavigationDirection direction, IEnumerable selectables) => - Content?.SetNeighbor(direction, selectables); + public void SetNeighbors(NavigationDirection direction, IEnumerable selectables) => + Content?.SetNeighbors(direction, selectables); /// - public void ClearNeighbor(NavigationDirection direction) => Content?.ClearNeighbor(direction); + public void ClearNeighbors(NavigationDirection direction) => Content?.ClearNeighbors(direction); /// public bool GetSelectables( diff --git a/Silksong.ModMenu/Elements/SelectableElement.cs b/Silksong.ModMenu/Elements/SelectableElement.cs index 9209673..7e4c705 100644 --- a/Silksong.ModMenu/Elements/SelectableElement.cs +++ b/Silksong.ModMenu/Elements/SelectableElement.cs @@ -72,12 +72,12 @@ public bool Interactable public void ClearNeighbors() => new SelectableWrapper(SelectableComponent).ClearNeighbors(); /// - public void ClearNeighbor(NavigationDirection direction) => - new SelectableWrapper(SelectableComponent).ClearNeighbor(direction); + public void ClearNeighbors(NavigationDirection direction) => + new SelectableWrapper(SelectableComponent).ClearNeighbors(direction); /// - public void SetNeighbor(NavigationDirection direction, IEnumerable selectables) => - new SelectableWrapper(SelectableComponent).SetNeighbor(direction, selectables); + public void SetNeighbors(NavigationDirection direction, IEnumerable selectables) => + new SelectableWrapper(SelectableComponent).SetNeighbors(direction, selectables); /// public bool GetSelectables( diff --git a/Silksong.ModMenu/Elements/TextButton.cs b/Silksong.ModMenu/Elements/TextButton.cs index c9379a3..e32cfbf 100644 --- a/Silksong.ModMenu/Elements/TextButton.cs +++ b/Silksong.ModMenu/Elements/TextButton.cs @@ -20,6 +20,7 @@ public TextButton(LocalizedText text, LocalizedText description) : base(MenuPrefabs.Get().NewTextButtonContainer(out var menuButton), menuButton) { Container.name = text.Text; + SelectableComponent.name = text.Canonical; MenuButton = menuButton; MenuButton diff --git a/Silksong.ModMenu/Internal/SelectableWrapper.cs b/Silksong.ModMenu/Internal/SelectableWrapper.cs index 01a12fa..36f690d 100644 --- a/Silksong.ModMenu/Internal/SelectableWrapper.cs +++ b/Silksong.ModMenu/Internal/SelectableWrapper.cs @@ -23,7 +23,7 @@ private Navigation Nav }; } - public void ClearNeighbor(NavigationDirection direction) => + public void ClearNeighbors(NavigationDirection direction) => Nav = direction switch { NavigationDirection.Up => Nav with { selectOnUp = null }, @@ -44,7 +44,7 @@ public bool GetSelectables( return true; } - public void SetNeighbor(NavigationDirection direction, IEnumerable selectables) + public void SetNeighbors(NavigationDirection direction, IEnumerable selectables) { if (!selectables.Any()) throw new ArgumentException( @@ -52,7 +52,7 @@ public void SetNeighbor(NavigationDirection direction, IEnumerable s nameof(selectables) ); - Vector2 position = selectable.transform.position; + Vector2 thisPosition = selectable.transform.position; Vector2 directionVector = direction switch { NavigationDirection.Up => Vector2.up, @@ -65,20 +65,32 @@ public void SetNeighbor(NavigationDirection direction, IEnumerable s Selectable bestOption = selectables .Select(selectable => { - Vector2 otherPos = selectable.transform.position, - interAngle = otherPos - position; - float directionalAngle = Vector2.Angle(directionVector, interAngle); + Vector2 otherPosition = selectable.transform.position, + angleBetweenSelectables = otherPosition - thisPosition; + + float angleRelativeToDirection = Vector2.Angle( + directionVector, + angleBetweenSelectables + ), + angleRelativeToOpposite = Vector2.Angle( + -directionVector, + angleBetweenSelectables + ); + return ( selectable, - directionalAngle, - angle: Mathf.Min(directionalAngle, Vector2.Angle(-directionVector, interAngle)), - position: otherPos + angleRelativeToDirection, + angleRelativeToAxis: Mathf.Min( + angleRelativeToDirection, + angleRelativeToOpposite + ), + position: otherPosition ); }) - // Rough shallowness of the angle between selectables, then favour selectables on the correct side of this one - .OrderBy(x => (int)Mathf.RoundToMultipleOf(x.angle, 20)) - .ThenBy(x => (int)Mathf.RoundToMultipleOf(x.directionalAngle, 90)) - .ThenBy(x => Vector2.Distance(position, x.position)) + // Favour selectables on the correct side of this one, narrow down by how well aligned they are with the current selectable + .OrderBy(other => (int)Mathf.RoundToMultipleOf(other.angleRelativeToDirection, 180)) + .ThenBy(other => (int)Mathf.RoundToMultipleOf(other.angleRelativeToAxis, 20)) + .ThenBy(other => Vector2.Distance(thisPosition, other.position)) .First() .selectable; diff --git a/Silksong.ModMenu/Screens/BasicMenuScreen.cs b/Silksong.ModMenu/Screens/BasicMenuScreen.cs index 025850e..be90e2e 100644 --- a/Silksong.ModMenu/Screens/BasicMenuScreen.cs +++ b/Silksong.ModMenu/Screens/BasicMenuScreen.cs @@ -62,10 +62,10 @@ protected override void UpdateLayout() wrapper.ClearNeighbors(); Content.SetNeighborDown(BackButton); - Content.SetNeighborUp(BackButton); + Content.SetNeighborsUp(BackButton); if (Content.GetNeighborsDown(out var selectables)) - wrapper.SetNeighborDown(selectables); + wrapper.SetNeighborsDown(selectables); if (Content.GetNeighborsUp(out selectables)) - wrapper.SetNeighborUp(selectables); + wrapper.SetNeighborsUp(selectables); } } diff --git a/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs b/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs index 3b7680f..e08f251 100644 --- a/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs +++ b/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs @@ -141,9 +141,9 @@ protected override void UpdateLayout() foreach (var (top, bot) in column.CircularPairs()) { if (top.GetNeighborsUp(out var s)) - bot.SetNeighborUp(s); + bot.SetNeighborsUp(s); if (bot.GetNeighborsDown(out s)) - top.SetNeighborDown(s); + top.SetNeighborsDown(s); } } } From f444a44158669643758a9461e789749b548ff2e5 Mon Sep 17 00:00:00 2001 From: kaycodes13 Date: Tue, 5 May 2026 00:35:19 -0400 Subject: [PATCH 4/6] fix minor issue with navigating into FreeGroups --- Silksong.ModMenu/Elements/FreeGroup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Silksong.ModMenu/Elements/FreeGroup.cs b/Silksong.ModMenu/Elements/FreeGroup.cs index 556ec8a..a525dd4 100644 --- a/Silksong.ModMenu/Elements/FreeGroup.cs +++ b/Silksong.ModMenu/Elements/FreeGroup.cs @@ -93,7 +93,7 @@ public override bool GetSelectables( [MaybeNullWhen(false)] out IEnumerable selectables ) { - selectables = GetNavigables(direction) + selectables = GetNavigables(direction.Opposite()) .SelectMany(n => n.GetSelectables(direction, out var s) ? s : null); return selectables != null; } From 0f7912d03c6b9b2118eefc3e521185964198cce1 Mon Sep 17 00:00:00 2001 From: kaycodes13 Date: Tue, 5 May 2026 00:47:17 -0400 Subject: [PATCH 5/6] fix an always-true condition in FreeGroup + revert an accidentally-committed test line --- Silksong.ModMenu/Elements/FreeGroup.cs | 4 ++-- Silksong.ModMenu/Elements/TextButton.cs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Silksong.ModMenu/Elements/FreeGroup.cs b/Silksong.ModMenu/Elements/FreeGroup.cs index a525dd4..2eec70e 100644 --- a/Silksong.ModMenu/Elements/FreeGroup.cs +++ b/Silksong.ModMenu/Elements/FreeGroup.cs @@ -94,8 +94,8 @@ public override bool GetSelectables( ) { selectables = GetNavigables(direction.Opposite()) - .SelectMany(n => n.GetSelectables(direction, out var s) ? s : null); - return selectables != null; + .SelectMany(n => n.GetSelectables(direction, out var s) ? s : []); + return selectables.Any(); } /// diff --git a/Silksong.ModMenu/Elements/TextButton.cs b/Silksong.ModMenu/Elements/TextButton.cs index e32cfbf..c9379a3 100644 --- a/Silksong.ModMenu/Elements/TextButton.cs +++ b/Silksong.ModMenu/Elements/TextButton.cs @@ -20,7 +20,6 @@ public TextButton(LocalizedText text, LocalizedText description) : base(MenuPrefabs.Get().NewTextButtonContainer(out var menuButton), menuButton) { Container.name = text.Text; - SelectableComponent.name = text.Canonical; MenuButton = menuButton; MenuButton From b3118c3ad1febca805539b5197b1f1c5f97f8094 Mon Sep 17 00:00:00 2001 From: kaycodes13 Date: Tue, 19 May 2026 14:21:01 -0400 Subject: [PATCH 6/6] bump version to v0.8.0 --- Silksong.ModMenu/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Silksong.ModMenu/Directory.Build.props b/Silksong.ModMenu/Directory.Build.props index 1340085..8fe9e05 100644 --- a/Silksong.ModMenu/Directory.Build.props +++ b/Silksong.ModMenu/Directory.Build.props @@ -11,6 +11,6 @@ It should follow the format major.minor.patch (semantic versioning). If you publish your mod as a library to NuGet, this version will also be used as the package version. --> - 0.7.4 + 0.8.0