53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
from engine.config import DEFAULT_KEYBINDINGS, KeyBindings
|
|
|
|
# Keys a rebind capture should never accept - they're the menu's own navigation/escape keys,
|
|
# so binding a game action to one of them would make the controls menu itself unusable.
|
|
RESERVED_CAPTURE_KEYS = {"Escape", "ArrowUp", "ArrowDown", "Enter"}
|
|
|
|
|
|
@dataclass
|
|
class ControlsMenu:
|
|
"""Pure interaction state for the "configure controls" screen: list every bindable action,
|
|
navigate up/down, and rebind the highlighted action's primary key to whatever key is
|
|
pressed next. Reads/writes through the same KeyBindings the game itself uses (engine/
|
|
config.py) - a rebind takes effect immediately (live) and can be written back to disk via
|
|
save(). No rendering here - same boundary as the rest of engine/ui.py.
|
|
"""
|
|
|
|
keybindings: KeyBindings
|
|
actions: list[str] = field(default_factory=lambda: list(DEFAULT_KEYBINDINGS))
|
|
selected_index: int = 0
|
|
awaiting_key: bool = False
|
|
|
|
def move(self, delta: int) -> None:
|
|
self.selected_index = (self.selected_index + delta) % len(self.actions)
|
|
|
|
def selected_action(self) -> str:
|
|
return self.actions[self.selected_index]
|
|
|
|
def begin_rebind(self) -> None:
|
|
self.awaiting_key = True
|
|
|
|
def cancel_rebind(self) -> None:
|
|
self.awaiting_key = False
|
|
|
|
def capture_key(self, key: str) -> bool:
|
|
"""Feeds the next raw keypress into the pending rebind, if one is in progress (see
|
|
begin_rebind). Returns whether it was actually applied - a reserved menu key is ignored
|
|
(capture mode stays open so the player can try again) rather than rebinding onto it.
|
|
"""
|
|
if not self.awaiting_key:
|
|
return False
|
|
if key in RESERVED_CAPTURE_KEYS:
|
|
return False
|
|
self.keybindings.rebind(self.selected_action(), key)
|
|
self.awaiting_key = False
|
|
return True
|
|
|
|
def save(self, path) -> None:
|
|
self.keybindings.save(path)
|