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 _callback; InputProxy _proxy; int _applicableEntries; int _targetDim; PhysicalDimension? _targetPDim; bool _targetNotNull; readonly Dictionary _recvsrcs = new(); void ShowInternal(Action 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 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 _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(); 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; } } }