Files
crtr/Assets/Cryville/Crtr/Config/UI/InputDialog.cs

135 lines
4.4 KiB
C#

using Cryville.Crtr.Ruleset;
using Cryville.Input;
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
namespace Cryville.Crtr.Config.UI {
internal class InputDialog : MonoBehaviour {
static InputDialog _instance;
[SerializeField] CanvasGroup m_group;
[SerializeField] AnimationCurve m_fadeCurve;
[SerializeField] TextMeshProUGUI m_msgText;
[SerializeField] Transform m_deviceList;
[SerializeField] GameObject m_deviceItemPrefab;
float _fadeDuration;
void Awake() {
_instance = this;
_fadeDuration = m_fadeCurve[m_fadeCurve.length - 1].time;
_consumer = new SimpleInputConsumer(Game.InputManager);
_d_HandleInputEvent = HandleInputEvent;
}
float _timer;
bool _active;
Action<InputSource?> _callback;
InputProxy _proxy;
int _applicableEntries;
int _targetDim;
PhysicalDimension? _targetPDim;
bool _targetNotNull;
readonly Dictionary<InputSource, InputDialogEntry> _recvsrcs = new();
void ShowInternal(Action<InputSource?> callback, string message, InputDefinition def, InputProxy proxy) {
_active = true;
_callback = callback;
m_group.gameObject.SetActive(true);
m_msgText.text = message;
_proxy = proxy;
_targetDim = def.dim;
if (def.pdim != null) _targetPDim = ParsePhysicalDimension(def.pdim);
else _targetPDim = null;
_targetNotNull = def.notnull;
foreach (Transform i in m_deviceList) Destroy(i.gameObject);
_consumer.EnumerateEvents(ev => { });
_recvsrcs.Clear();
_applicableEntries = 1;
AddSourceItem(null).transform.SetSiblingIndex(0);
}
public static void Show(Action<InputSource?> callback, string message, InputDefinition def, InputProxy proxy) {
_instance.ShowInternal(callback, message, def, proxy);
}
static PhysicalDimension ParsePhysicalDimension(string str) {
var comps = str.Split(' ', StringSplitOptions.RemoveEmptyEntries);
var result = new PhysicalDimension();
foreach (var comp in comps) {
int dim = 1;
if (comp.Length > 1) dim = int.Parse(comp[1..]);
switch (comp[0]) {
case 'T': result.Time += dim; break;
case 'L': result.Length += dim; break;
case 'M': result.Mass += dim; break;
case 'I': result.ElectricCurrent += dim; break;
case '\x0398':
case 'H': result.ThermodynamicTemperature += dim; break;
case 'N': result.AmountOfSubstance += dim; break;
case 'J': result.LuminousIntensity += dim; break;
default: throw new ArgumentException(string.Format("Invalid dimension symbol {0}", comp[0]));
}
}
return result;
}
void Update() {
if (_active) {
_consumer.EnumerateEvents(_d_HandleInputEvent);
if (_timer >= _fadeDuration) return;
_timer += Time.deltaTime;
if (_timer > _fadeDuration) _timer = _fadeDuration;
m_group.alpha = m_fadeCurve.Evaluate(_timer);
}
else {
if (_timer <= 0) return;
_timer -= Time.deltaTime;
if (_timer < 0) {
_timer = 0;
m_group.gameObject.SetActive(false);
}
m_group.alpha = m_fadeCurve.Evaluate(_timer);
}
}
SimpleInputConsumer _consumer;
void OnEnable() { _consumer.Activate(); }
void OnDisable() { _consumer.Deactivate(); }
Action<InputEvent> _d_HandleInputEvent;
void HandleInputEvent(InputEvent ev) {
InputSource src = ev.Identifier.Source;
if (!_recvsrcs.TryGetValue(src, out InputDialogEntry entry)) {
_recvsrcs.Add(src, entry = AddSourceItem(src));
if (_proxy.IsUsed(src)) {
entry.Status |= InputDeviceStatus.Used;
}
if (src.Handler.Dimension < _targetDim) {
entry.Status |= InputDeviceStatus.InsufficientDimension;
}
if (_targetPDim != null && src.Handler.ReferenceCue.PhysicalDimension != _targetPDim) {
entry.Status |= InputDeviceStatus.IncompatiblePhysicalDimension;
}
if (!_targetNotNull && !src.Handler.IsNullable) {
entry.Status |= InputDeviceStatus.IncompatibleNullable;
}
entry.transform.SetSiblingIndex(entry.Status == InputDeviceStatus.Default ? _applicableEntries++ : m_deviceList.childCount - 1);
}
entry.OnInputEvent(ev);
}
InputDialogEntry AddSourceItem(InputSource? src) {
var entry = Instantiate(m_deviceItemPrefab, m_deviceList, false).GetComponent<InputDialogEntry>();
entry.Init(src);
entry.Clicked += () => OnItemSelected(src);
return entry;
}
void OnItemSelected(InputSource? src) {
if (!_active) return;
_active = false;
_callback(src);
}
public void Close() {
_active = false;
}
}
}