using System; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; using BaseGames.Input; using BaseGames.Localization; namespace BaseGames.UI.Settings { /// /// 单行按键重绑定 UI(架构 04_InputModule §6)。 /// 显示 Action 名称 + 当前绑定路径;点击按钮触发交互式重绑定。 /// 由 RebindPanel.Initialize() 批量配置;不直接加载任何资产。 /// public class RebindActionRow : MonoBehaviour { [Tooltip("对应 Input Action 的名称(与 InputActions 资产中 Gameplay Map 内的名称一致)")] [SerializeField] private string _actionName; [Tooltip("绑定索引:0 = 主绑定,1 = 副绑定(视 Action 定义而定)")] [SerializeField] private int _bindingIndex; [Header("UI 引用")] [SerializeField] private TMP_Text _actionLabel; // 显示 Action 可读名(固定) [SerializeField] private TMP_Text _currentBindingText; // 显示当前绑定路径 [SerializeField] private Button _bindButton; // 点击启动重绑定 private InputReaderSO _inputReader; private ConflictDetector _conflictDetector; private Action _onRebindRequested; // ── 初始化(由 RebindPanel 调用)────────────────────────────────── public void Initialize( InputReaderSO reader, ConflictDetector detector, Action onRequest) { _inputReader = reader; _conflictDetector = detector; _onRebindRequested = onRequest; if (_actionLabel != null) _actionLabel.text = _actionName; _bindButton.onClick.AddListener(() => _onRebindRequested?.Invoke(this)); RefreshDisplay(); } // ── 重绑定流程 ──────────────────────────────────────────────────── /// 启动交互式重绑定;完成或取消后调用 onFinished。 public void StartRebind(Action onFinished) { _currentBindingText.text = LocalizationManager.Get("REBIND_WAITING_PROMPT", LocalizationTable.UI); _inputReader.StartRebinding( _actionName, _bindingIndex, onComplete: () => { RefreshDisplay(); RefreshConflicts(); onFinished?.Invoke(); }, onCancel: () => { RefreshDisplay(); onFinished?.Invoke(); }); } // ── 显示刷新 ────────────────────────────────────────────────────── /// 从 InputReaderSO 读取当前绑定路径并更新文字。 public void RefreshDisplay() { if (_inputReader == null) return; var action = _inputReader.FindAction(_actionName); if (action == null || _bindingIndex >= action.bindings.Count) { _currentBindingText.text = "—"; return; } var path = action.bindings[_bindingIndex].effectivePath; _currentBindingText.text = string.IsNullOrEmpty(path) ? "—" : InputControlPath.ToHumanReadableString( path, InputControlPath.HumanReadableStringOptions.OmitDevice); } /// 冲突状态着色:红色 = 与其他 Action 路径冲突,白色 = 正常。 public void SetConflictHighlight(bool conflict) => _currentBindingText.color = conflict ? Color.red : Color.white; /// 是否允许用户点击此行的绑定按钮。 public void SetInteractable(bool interactable) => _bindButton.interactable = interactable; // ── 内部 ────────────────────────────────────────────────────────── /// 重绑定完成后扫描 Panel 内所有行,更新冲突高亮。 private void RefreshConflicts() { if (_conflictDetector == null || _inputReader == null) return; var conflicts = _conflictDetector.FindConflicts(_inputReader.GetAllActionMap()); foreach (var row in GetComponentsInParent(includeInactive: true) [0]?.GetRows() ?? Array.Empty()) { row.SetConflictHighlight(conflicts.Contains(row._actionName)); } } } }