feat(controls): redefinició de tecles i botons del mando des del menú de servei

This commit is contained in:
JailDesigner committed 2026-04-29 19:54:47 +02:00
1 parent 4739354875
commit 37fdcb4751
15 files changed
+1169 -80

No files matched your search

+126
View File
@@ -0,0 +1,126 @@
#pragma once
#include <SDL3/SDL.h>
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
#include "core/input/gamepad_bindings.hpp"
#include "core/rendering/surface.hpp" // Palette
class Text;
// Sub-mòdul de captura seqüencial de botons per a un mando concret.
// Replica `DefineButtons` de coffee_crisis_arcade_edition: l'usuari obre el
// menú de servei, escull "Definir botons P1" / "P2", i el sub-mòdul li
// demana un per un els botons per a cada acció (JUMP → ATTACK → SERVICE).
//
// Cicle de vida:
// 1. `enable(pad, name, path)`: arrenca la seqüència. `index_` = 0.
// 2. Cada SDL_EVENT_GAMEPAD_BUTTON_DOWN (o transició de L2/R2 via
// AXIS_MOTION) que NO duplique cap botó ja assignat dins la sessió
// avança `index_`. Si `index_` arriba a la mida de la seqüència,
// `finished_` es posa a true i, al pròxim BUTTON_UP, escrivim el mapeig
// complet a `GamepadBindings`, mostrem "Configuració completa" durant
// `MESSAGE_DISPLAY_DURATION_MS`, i posem `closing_`. Quan tot l'overlay
// ja no és visible, `isReadyToClose()` torna `true` i el caller ens
// fa `disable()`.
//
// El layer runtime de l'aplicació viu a `GamepadBindings`: aquesta classe
// només decideix què s'escriu i quan.
class DefineButtons {
public:
DefineButtons() = default;
~DefineButtons() = default;
DefineButtons(const DefineButtons&) = delete;
DefineButtons(DefineButtons&&) = delete;
auto operator=(const DefineButtons&) -> DefineButtons& = delete;
auto operator=(DefineButtons&&) -> DefineButtons& = delete;
// Injecta les fonts i la paleta UI; cridat des de `ServiceMenu::init`
// perquè comparteixin tipografia i colors de tema.
void init(std::shared_ptr<Text> title_font,
std::shared_ptr<Text> items_font,
const Palette& ui_palette);
// Arranca la sessió per al mando indicat. `pad` ha de ser un handle
// viu obtingut de `GamepadManager`. Retorna false si `pad` és nullptr.
auto enable(SDL_Gamepad* pad, std::string name, std::string path) -> bool;
// Atura la sessió (sense persistir) i neteja l'estat.
void disable();
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
[[nodiscard]] auto isReadyToClose() const -> bool;
// Avança el timer de tancament (ms) — replica el `update` de
// coffee_crisis_arcade_edition. No fa res si no està actiu.
void update(int delta_ms);
// Pinta l'overlay sobre el canvas actual (centrat). No fa res si no
// està actiu.
void render() const;
// Punt d'entrada d'events: BUTTON_DOWN / BUTTON_UP / AXIS_MOTION del
// mando objectiu. La resta s'ignoren.
void handleEvent(const SDL_Event& ev);
private:
static constexpr int MESSAGE_DISPLAY_DURATION_MS = 2000;
struct ButtonAssignment {
std::string label_key;
GamepadBindings::Action action;
int button; // SDL_GamepadButton o trigger virtual; INVALID = sense assignar.
};
// Reinicialitza la seqüència ordenada (JUMP → ATTACK → SERVICE) amb
// tots els botons sense assignar. Cridat a `enable`.
void resetSequence();
// Comprova si un botó ja ha estat assignat dins de la sessió actual.
// Replica `checkButtonNotInUse` / `checkTriggerNotInUse`.
[[nodiscard]] auto isInUse(int button) const -> bool;
void handleButtonDown(const SDL_GamepadButtonEvent& ev);
void handleAxisMotion(const SDL_GamepadAxisEvent& ev);
// Helper de la lògica comuna a button-down i als triggers L2/R2:
// assigna `button` a l'acció pendent i avança l'índex (o marca
// finished_ si era l'última). No fa res si `button` ja està en ús.
void assignAndAdvance(int button);
// Tracta una transició de trigger (L2 o R2) com a botó virtual amb
// edge-detect. `virtual_button` és `TRIGGER_L?_AS_BUTTON`,
// `was_pressed` és l'estat anterior (mutat per referència).
void processTrigger(int virtual_button, bool& was_pressed, bool now);
// Crida `onSequenceEnd()` quan l'usuari deixa anar el botó després
// d'haver completat la seqüència — replica la branca de
// `SDL_EVENT_GAMEPAD_BUTTON_UP` a `DefineButtons::handleEvents`.
void onButtonUp();
// Persistix les assignacions a `GamepadBindings` i posa `message_shown_`.
void persistAndShowComplete();
SDL_Gamepad* pad_{nullptr};
std::string pad_name_;
std::string pad_path_;
std::shared_ptr<Text> title_font_;
std::shared_ptr<Text> items_font_;
Palette ui_palette_{};
std::vector<ButtonAssignment> sequence_;
std::size_t index_{0};
int message_timer_ms_{0};
bool enabled_{false};
bool finished_{false};
bool closing_{false};
bool message_shown_{false};
bool l2_was_pressed_{false};
bool r2_was_pressed_{false};
};