blob: b4b59d527d09136c99c373d957fdd5cdfe06e649 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
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;
/// <summary>Gamepad control of an open window: D-pad moves a highlight through its enabled
/// buttons (wrapping), A presses (the game decides B/Start).</summary>
public sealed class PadNavigator
{
private static readonly Thickness HighlightThickness = new(2);
private readonly MenuCursor _cursor = new();
private readonly List<Button> _buttons = new();
private Control? _container;
private Button? _highlighted;
private readonly IBrush _highlight;
public PadNavigator(IBrush highlight) => _highlight = highlight;
/// <summary>The window pad input should drive now, or null (pad drives the character).</summary>
public Control? Active { get; private set; }
/// <summary>Highlight only while the gamepad is the device in use (keyboard/mouse users
/// get no stray gold border).</summary>
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<Button>()
.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
}
}
}
|