feat(controls): redefinició de tecles i botons del mando des del menú de servei
This commit is contained in:
1 parent
4739354875
commit
37fdcb4751
15 files changed
+1169
-80
No files matched your search
@@ -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};
|
||||
};
|
||||
Reference in new issue
Block a user