1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-26 14:38:34 +01:00

Improved gamepad navigation by employing angles between elements

This commit is contained in:
Ell 2022-03-10 14:25:41 +01:00
parent cb8fed87e5
commit 45955bb5e8
2 changed files with 15 additions and 30 deletions

View file

@ -46,6 +46,7 @@ Improvements
- Allow setting a default color for clickable links in UiStyle - Allow setting a default color for clickable links in UiStyle
- Allow ElementHelper's KeybindButton to query a combination at a given index - Allow ElementHelper's KeybindButton to query a combination at a given index
- Automatically select the first element when a dropdown is opened in auto nav mode - Automatically select the first element when a dropdown is opened in auto nav mode
- Improved gamepad navigation by employing angles between elements
Fixes Fixes
- Fixed paragraph links having incorrect hover locations when using special text alignments - Fixed paragraph links having incorrect hover locations when using special text alignments

View file

@ -1,8 +1,10 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch; using Microsoft.Xna.Framework.Input.Touch;
using MLEM.Extensions;
using MLEM.Input; using MLEM.Input;
using MLEM.Misc; using MLEM.Misc;
using MLEM.Ui.Elements; using MLEM.Ui.Elements;
@ -355,11 +357,11 @@ namespace MLEM.Ui {
} }
/// <summary> /// <summary>
/// Returns the next element that should be selected during gamepad navigation, based on the <see cref="RectangleF"/> that we're looking for elements in. /// Returns the next element that should be selected during gamepad navigation, based on the <see cref="Direction2"/> that we're looking for elements in.
/// </summary> /// </summary>
/// <param name="searchArea">The area that we're looking for next elements in</param> /// <param name="direction">The direction that we're looking for next elements in</param>
/// <returns>The first element found in that area</returns> /// <returns>The first element found in that area</returns>
protected virtual Element GetGamepadNextElement(RectangleF searchArea) { protected virtual Element GetGamepadNextElement(Direction2 direction) {
if (this.ActiveRoot == null) if (this.ActiveRoot == null)
return null; return null;
var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element); var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element);
@ -367,14 +369,17 @@ namespace MLEM.Ui {
return children.FirstOrDefault(c => c.CanBeSelected); return children.FirstOrDefault(c => c.CanBeSelected);
} else { } else {
Element closest = null; Element closest = null;
float closestDist = 0; float closestDistSq = 0;
foreach (var child in children) { foreach (var child in children) {
if (!child.CanBeSelected || child == this.SelectedElement || !searchArea.Intersects(child.Area)) if (!child.CanBeSelected || child == this.SelectedElement)
continue; continue;
var dist = Vector2.Distance(child.Area.Center, this.SelectedElement.Area.Center); var distVec = child.Area.Center - this.SelectedElement.Area.Center;
if (closest == null || dist < closestDist) { if (Math.Abs(direction.Angle() - Math.Atan2(distVec.Y, distVec.X)) >= MathHelper.PiOver2 - Element.Epsilon)
continue;
var distSq = distVec.LengthSquared();
if (closest == null || distSq < closestDistSq) {
closest = child; closest = child;
closestDist = dist; closestDistSq = distSq;
} }
} }
return closest; return closest;
@ -383,28 +388,7 @@ namespace MLEM.Ui {
private void HandleGamepadNextElement(Direction2 dir) { private void HandleGamepadNextElement(Direction2 dir) {
this.IsAutoNavMode = true; this.IsAutoNavMode = true;
RectangleF searchArea = default; var next = this.GetGamepadNextElement(dir);
if (this.SelectedElement?.Root != null) {
searchArea = this.SelectedElement.Area;
var (_, _, width, height) = this.System.Viewport;
switch (dir) {
case Direction2.Down:
searchArea.Height += height;
break;
case Direction2.Left:
searchArea.X -= width;
searchArea.Width += width;
break;
case Direction2.Right:
searchArea.Width += width;
break;
case Direction2.Up:
searchArea.Y -= height;
searchArea.Height += height;
break;
}
}
var next = this.GetGamepadNextElement(searchArea);
if (this.SelectedElement != null) if (this.SelectedElement != null)
next = this.SelectedElement.GetGamepadNextElement(dir, next); next = this.SelectedElement.GetGamepadNextElement(dir, next);
if (next != null) if (next != null)