This repository has been archived on 2026-10-29. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
EveUnity/packages/org.gamecult.eve.unity-uitoolkit/Runtime/EveInputBindingMapElement.cs
2026-07-11 03:19:50 +01:00

111 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using GameCult.Eve.Surface;
using UnityEngine;
using UnityEngine.UIElements;
namespace GameCult.Eve.UnityUIToolkit
{
public sealed class EveInputBindingMapElement : VisualElement
{
private readonly VisualElement _device = new VisualElement();
private readonly Label _sequence = new Label();
private readonly List<string> _pendingSequence = new List<string>();
private EveInputDeviceLayout _layout = new EveInputDeviceLayout();
private IReadOnlyList<EveInputBinding> _bindings = Array.Empty<EveInputBinding>();
private string _draggedActionId = "";
public EveInputBindingMapElement()
{
style.position = Position.Relative;
style.flexGrow = 1;
_device.style.position = Position.Relative;
_device.style.minHeight = 360;
_device.style.flexGrow = 1;
_sequence.style.unityTextAlign = TextAnchor.MiddleCenter;
_sequence.style.minHeight = 32;
Add(_device);
Add(_sequence);
}
public event Action<string, EveInputGesture>? BindingRequested;
public void SetState(EveInputDeviceLayout layout, IReadOnlyList<EveInputBinding> bindings)
{
_layout = layout ?? new EveInputDeviceLayout();
_bindings = bindings ?? Array.Empty<EveInputBinding>();
Render();
}
public void BeginActionDrag(string actionId)
{
_draggedActionId = actionId ?? "";
}
public void CancelActionDrag()
{
_draggedActionId = "";
_pendingSequence.Clear();
RenderSequence();
}
public void RecordDirectionalStep(string control)
{
if (!_layout.SupportsDirectionalStrings || string.IsNullOrWhiteSpace(_draggedActionId)) return;
if (!control.StartsWith("gamepad.dpad.", StringComparison.Ordinal)) return;
_pendingSequence.Add(control);
RenderSequence();
}
public void CommitDirectionalString()
{
if (string.IsNullOrWhiteSpace(_draggedActionId) || _pendingSequence.Count == 0) return;
BindingRequested?.Invoke(_draggedActionId, new EveInputGesture { Kind = "sequence", Controls = _pendingSequence.ToArray(), MaxStepIntervalMs = 650 });
CancelActionDrag();
}
private void Render()
{
_device.Clear();
foreach (var control in _layout.Controls)
{
var button = new Button(() => BindDirect(control.Control));
button.text = BindingLabel(control.Control, control.Label);
button.style.position = Position.Absolute;
button.style.left = control.X * 54;
button.style.top = control.Y * 54;
button.style.width = control.Width * 50;
button.style.height = control.Height * 46;
button.tooltip = control.Control;
_device.Add(button);
}
RenderSequence();
}
private void BindDirect(string control)
{
if (string.IsNullOrWhiteSpace(_draggedActionId)) return;
if (_layout.SupportsDirectionalStrings && control.StartsWith("gamepad.dpad.", StringComparison.Ordinal))
{
RecordDirectionalStep(control);
return;
}
BindingRequested?.Invoke(_draggedActionId, new EveInputGesture { Kind = "direct", Controls = new[] { control } });
CancelActionDrag();
}
private string BindingLabel(string control, string fallback)
{
var actions = _bindings.Where(binding => binding.Gesture.Controls.Contains(control)).Select(binding => binding.ActionId).ToArray();
return actions.Length == 0 ? fallback : fallback + "\n" + string.Join(" + ", actions);
}
private void RenderSequence()
{
_sequence.text = _pendingSequence.Count == 0 ? "" : string.Join(" ", _pendingSequence.Select(DirectionGlyph));
}
private static string DirectionGlyph(string control) => control.EndsWith(".up") ? "UP" : control.EndsWith(".down") ? "DOWN" : control.EndsWith(".left") ? "LEFT" : "RIGHT";
}
}