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
diff --git a/Silksong.ModMenu/Elements/AbstractGroup.cs b/Silksong.ModMenu/Elements/AbstractGroup.cs
index 915b891..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);
}
///
@@ -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 selectables
);
private GameObject? gameObjectParent;
@@ -113,10 +113,13 @@ public virtual void ClearGameObjectParent()
}
///
- public virtual void SetNeighbor(NavigationDirection direction, Selectable selectable)
+ public virtual void SetNeighbors(
+ NavigationDirection direction,
+ 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 bac9da0..2eec70e 100644
--- a/Silksong.ModMenu/Elements/FreeGroup.cs
+++ b/Silksong.ModMenu/Elements/FreeGroup.cs
@@ -88,15 +88,14 @@ 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 selectables
)
{
- selectable = GetNavigables(direction)
- .Select(n => n.GetSelectable(direction, out var s) ? s : null)
- .FirstOrDefault();
- return selectable != null;
+ selectables = GetNavigables(direction.Opposite())
+ .SelectMany(n => n.GetSelectables(direction, out var s) ? s : []);
+ return selectables.Any();
}
///
diff --git a/Silksong.ModMenu/Elements/GridGroup.cs b/Silksong.ModMenu/Elements/GridGroup.cs
index b08b7f6..e06bcf2 100644
--- a/Silksong.ModMenu/Elements/GridGroup.cs
+++ b/Silksong.ModMenu/Elements/GridGroup.cs
@@ -150,36 +150,30 @@ 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(),
+ // 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),
+ // Topmost element of every column.
+ NavigationDirection.Down => GetColumns()
+ .Select(x => (INavigable?)x.FirstOrDefault(e => e is INavigable && e.VisibleSelf))
+ .WhereNonNull(),
_ => 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 selectables.Any();
}
///
@@ -216,7 +210,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 +229,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;
}
@@ -250,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 05134db..e38ae18 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,25 +16,25 @@ public interface INavigable
void ClearNeighbors();
///
- /// Set the directional neighbor of this entity.
+ /// 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, Selectable selectable);
+ void SetNeighbors(NavigationDirection direction, IEnumerable selectables);
///
/// Unset the given directional neighbor of this entity.
///
- void ClearNeighbor(NavigationDirection direction);
+ void ClearNeighbors(NavigationDirection direction);
///
- /// Get 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.GetSelectable(dir, out var selectable))
- /// bar.SetNeighbor(dir, selectable);
+ /// if (foo.GetSelectables(dir, out var selectables))
+ /// bar.SetNeighbors(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..83b54a7 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;
@@ -14,106 +15,146 @@ 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.
+ /// Set the upwards neighbors of this navigable to one or more of the given options.
///
- public void SetNeighborUp(SelectableElement selectableElement) =>
- self.SetNeighborUp(selectableElement.SelectableComponent);
+ public void SetNeighborsUp(IEnumerable selectables) =>
+ self.SetNeighbors(NavigationDirection.Up, selectables);
///
- /// Declare that this navigable has no upwards neighbor.
+ /// Set the upwards neighbors of this navigable.
///
- public void ClearNeighborUp() => self.ClearNeighbor(NavigationDirection.Up);
+ public void SetNeighborsUp(SelectableElement selectableElement)
+ {
+ if (selectableElement.GetSelectables(NavigationDirection.Up, out var selectables))
+ self.SetNeighborsUp(selectables);
+ }
+
+ ///
+ /// Declare that this navigable has no upwards neighbors.
+ ///
+ public void ClearNeighborsUp() => self.ClearNeighbors(NavigationDirection.Up);
+
+ ///
+ /// Get the most eligible selectables within this navigable when navigating upwards into it.
+ ///
+ public bool GetNeighborsUp(
+ [MaybeNullWhen(false)] out IEnumerable selectables
+ ) => self.GetSelectables(NavigationDirection.Up, out selectables);
+
+ ///
+ /// Set the leftwards neighbors of this navigable.
+ ///
+ public void SetNeighborsLeft(Selectable selectable) =>
+ self.SetNeighbors(NavigationDirection.Left, [selectable]);
///
- /// Get the most eligible selectable within this navigable when navigating upwards into it.
+ /// Set the leftwards neighbors of this navigable to one or more of the given options.
///
- public bool GetNeighborUp([MaybeNullWhen(false)] out Selectable selectable) =>
- self.GetSelectable(NavigationDirection.Up, out selectable);
+ 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(Selectable selectable) =>
- self.SetNeighbor(NavigationDirection.Left, selectable);
+ public void SetNeighborsLeft(SelectableElement selectableElement)
+ {
+ if (selectableElement.GetSelectables(NavigationDirection.Left, out var selectables))
+ self.SetNeighborsLeft(selectables);
+ }
///
- /// Set the leftwards neighbor of this navigable.
+ /// Declare that this navigable has no upwards neighbors.
///
- public void SetNeighborLeft(SelectableElement selectableElement) =>
- self.SetNeighborLeft(selectableElement.SelectableComponent);
+ public void ClearNeighborsLeft() => self.ClearNeighbors(NavigationDirection.Left);
///
- /// Declare that this navigable has no upwards neighbor.
+ /// Get the most eligible selectables within this navigable when navigating leftwards into it.
///
- public void ClearNeighborLeft() => self.ClearNeighbor(NavigationDirection.Left);
+ public bool GetNeighborsLeft(
+ [MaybeNullWhen(false)] out IEnumerable selectables
+ ) => self.GetSelectables(NavigationDirection.Left, out selectables);
///
- /// Get the most eligible selectable within this navigable when navigating leftwards into it.
+ /// Set the rightwards neighbors of this navigable.
///
- public bool GetNeighborLeft([MaybeNullWhen(false)] out Selectable selectable) =>
- self.GetSelectable(NavigationDirection.Left, out selectable);
+ public void SetNeighborsRight(Selectable selectable) =>
+ self.SetNeighbors(NavigationDirection.Right, [selectable]);
///
- /// Set the rightwards neighbor of this navigable.
+ /// Set the rightwards neighbors of this navigable to one or more of the given options.
///
- public void SetNeighborRight(Selectable selectable) =>
- self.SetNeighbor(NavigationDirection.Right, selectable);
+ 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) =>
- self.SetNeighborRight(selectableElement.SelectableComponent);
+ public void SetNeighborsRight(SelectableElement selectableElement)
+ {
+ if (selectableElement.GetSelectables(NavigationDirection.Right, out var selectables))
+ self.SetNeighborsRight(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.
+ /// 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.
+ /// Set the downwards neighbors of this navigable to one or more of the given options.
///
- public void SetNeighborDown(SelectableElement selectableElement) =>
- self.SetNeighborDown(selectableElement.SelectableComponent);
+ public void SetNeighborsDown(IEnumerable selectables) =>
+ self.SetNeighbors(NavigationDirection.Down, selectables);
+
+ ///
+ /// Set the downwards neighbors of this navigable.
+ ///
+ public void SetNeighborsDown(SelectableElement selectableElement)
+ {
+ if (selectableElement.GetSelectables(NavigationDirection.Down, out var 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 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))
- self.SetNeighbor(direction, s);
- if (self.GetSelectable(direction.Opposite(), out s))
- dest.SetNeighbor(direction.Opposite(), s);
+ if (dest.GetSelectables(direction, out var s))
+ self.SetNeighbors(direction, s);
+ if (self.GetSelectables(direction.Opposite(), out s))
+ dest.SetNeighbors(direction.Opposite(), s);
}
}
}
diff --git a/Silksong.ModMenu/Elements/ScrollingPane.cs b/Silksong.ModMenu/Elements/ScrollingPane.cs
index d1b1051..14fa9ac 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 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 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..7e4c705 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;
@@ -71,20 +72,20 @@ 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, Selectable selectable) =>
- new SelectableWrapper(SelectableComponent).SetNeighbor(direction, selectable);
+ public void SetNeighbors(NavigationDirection direction, IEnumerable selectables) =>
+ new SelectableWrapper(SelectableComponent).SetNeighbors(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..36f690d 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;
@@ -19,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 },
@@ -31,22 +35,72 @@ 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 SetNeighbors(NavigationDirection direction, IEnumerable selectables)
+ {
+ if (!selectables.Any())
+ throw new ArgumentException(
+ "At least one selectable is required.",
+ nameof(selectables)
+ );
+
+ Vector2 thisPosition = 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 otherPosition = selectable.transform.position,
+ angleBetweenSelectables = otherPosition - thisPosition;
+
+ float angleRelativeToDirection = Vector2.Angle(
+ directionVector,
+ angleBetweenSelectables
+ ),
+ angleRelativeToOpposite = Vector2.Angle(
+ -directionVector,
+ angleBetweenSelectables
+ );
+
+ return (
+ selectable,
+ angleRelativeToDirection,
+ angleRelativeToAxis: Mathf.Min(
+ angleRelativeToDirection,
+ angleRelativeToOpposite
+ ),
+ position: otherPosition
+ );
+ })
+ // 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;
+
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..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);
- if (Content.GetNeighborDown(out var selectable))
- wrapper.SetNeighborDown(selectable);
- if (Content.GetNeighborUp(out selectable))
- wrapper.SetNeighborUp(selectable);
+ Content.SetNeighborsUp(BackButton);
+ if (Content.GetNeighborsDown(out var selectables))
+ wrapper.SetNeighborsDown(selectables);
+ if (Content.GetNeighborsUp(out selectables))
+ wrapper.SetNeighborsUp(selectables);
}
}
diff --git a/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs b/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs
index cd37588..e08f251 100644
--- a/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs
+++ b/Silksong.ModMenu/Screens/PaginatedMenuScreen.cs
@@ -140,10 +140,10 @@ protected override void UpdateLayout()
s.ClearNeighbors();
foreach (var (top, bot) in column.CircularPairs())
{
- if (top.GetNeighborUp(out var s))
- bot.SetNeighborUp(s);
- if (bot.GetNeighborDown(out s))
- top.SetNeighborDown(s);
+ if (top.GetNeighborsUp(out var s))
+ bot.SetNeighborsUp(s);
+ if (bot.GetNeighborsDown(out s))
+ top.SetNeighborsDown(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;
}
///