using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using Avalonia.Media;
using Godosa.Core.Input;
namespace Godosa.Desktop;
/// Gamepad control of an open window: D-pad moves a highlight through its enabled
/// buttons (wrapping), A presses (the game decides B/Start).
public sealed class PadNavigator
{
private static readonly Thickness HighlightThickness = new(2);
private readonly MenuCursor _cursor = new();
private readonly List _buttons = new();
private Control? _container;
private Button? _highlighted;
private readonly IBrush _highlight;
public PadNavigator(IBrush highlight) => _highlight = highlight;
/// The window pad input should drive now, or null (pad drives the character).
public Control? Active { get; private set; }
/// Highlight only while the gamepad is the device in use (keyboard/mouse users
/// get no stray gold border).
public bool ShowHighlight { get; set; }
public void Refresh(Control? active)
{
Active = active;
if (!ReferenceEquals(active, _container))
{
_container = active;
_cursor.Clamp(0);
}
Collect();
_cursor.Clamp(_buttons.Count);
Highlight();
}
public void Move(int delta)
{
Collect();
_cursor.Clamp(_buttons.Count);
_cursor.Move(delta, _buttons.Count);
Highlight();
}
public void Press()
{
Collect();
_cursor.Clamp(_buttons.Count);
if (_cursor.Index >= 0) Buttons.Press(_buttons[_cursor.Index]);
}
private void Collect()
{
_buttons.Clear();
if (_container is null) return;
_buttons.AddRange(_container.GetVisualDescendants().OfType()
.Where(b => b.IsEffectivelyVisible && b.IsEffectivelyEnabled));
}
private void Highlight()
{
var target = ShowHighlight && _cursor.Index >= 0 && _cursor.Index < _buttons.Count ? _buttons[_cursor.Index] : null;
if (ReferenceEquals(target, _highlighted)) return;
if (_highlighted is not null)
{
_highlighted.ClearValue(Button.BorderBrushProperty);
_highlighted.ClearValue(Button.BorderThicknessProperty);
}
_highlighted = target;
if (target is not null)
{
target.BorderBrush = _highlight;
target.BorderThickness = HighlightThickness;
target.BringIntoView(); // long option pages scroll
}
}
}