Compare commits

...

3 Commits

12 changed files with 319 additions and 132 deletions

View File

@@ -2,7 +2,7 @@
"[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMAT I DISSENYAT PER", "[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMAT I DISSENYAT PER",
"[CREDITS] PIXELART_DRAWN_BY": "GRAFICS DIBUIXATS PER", "[CREDITS] PIXELART_DRAWN_BY": "GRAFICS DIBUIXATS PER",
"[CREDITS] MUSIC_COMPOSED_BY": "MUSICA COMPOSADA PER", "[CREDITS] MUSIC_COMPOSED_BY": "MUSICA COMPOSADA PER",
"[CREDITS] SOUND_EFFECTS": "EFECTES DE SO", "[CREDITS] SOUND_EFFECTS": "EFECTES DE SO PER",
"[DEFINE_BUTTONS] TITLE": "define buttons title", "[DEFINE_BUTTONS] TITLE": "define buttons title",
"[DEFINE_BUTTONS] FIRE_LEFT": "Disparar cap a l'esquerra", "[DEFINE_BUTTONS] FIRE_LEFT": "Disparar cap a l'esquerra",
@@ -17,8 +17,9 @@
"[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Prem un boto per a", "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Prem un boto per a",
"[DEFINE_BUTTONS] CONFIGURED" : "configurat", "[DEFINE_BUTTONS] CONFIGURED" : "configurat",
"[GAME_TEXT] 1": "Felicitats!!", "[GAME_TEXT] 1": "Felicitats!",
"[GAME_TEXT] 2": " fases mes!", "[GAME_TEXT] 2": "Queden ",
"[GAME_TEXT] 2A": " fases mes!",
"[GAME_TEXT] 3": "Ultima fase!", "[GAME_TEXT] 3": "Ultima fase!",
"[GAME_TEXT] 4": "SuperPoder!", "[GAME_TEXT] 4": "SuperPoder!",
"[GAME_TEXT] 5": "+1 Colp", "[GAME_TEXT] 5": "+1 Colp",
@@ -29,11 +30,11 @@
"[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions", "[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions",
"[INSTRUCTIONS] 01": "Objectiu", "[INSTRUCTIONS] 01": "Objectiu",
"[INSTRUCTIONS] 02": "HAS D'EXPLOTAR", "[INSTRUCTIONS] 02": "HAS D'EXPLOTAR TANTS",
"[INSTRUCTIONS] 03": "TANTS GLOBUS COM PUGUES", "[INSTRUCTIONS] 03": "GLOBOS COM PUGUES",
"[INSTRUCTIONS] 04": "LA DIFICULTAT AUGMENTA", "[INSTRUCTIONS] 04": "LA DIFICULTAT AUGMENTA",
"[INSTRUCTIONS] 05": "A MESURA QUE VAS PUNTUANT", "[INSTRUCTIONS] 05": "A MESURA QUE VAS PUNTUANT",
"[INSTRUCTIONS] 06": "Objectes", "[INSTRUCTIONS] 06": "Objectes de bonus",
"[INSTRUCTIONS] 07": "1.000 PUNTS", "[INSTRUCTIONS] 07": "1.000 PUNTS",
"[INSTRUCTIONS] 08": "2.500 PUNTS", "[INSTRUCTIONS] 08": "2.500 PUNTS",
"[INSTRUCTIONS] 09": "5.000 PUNTS", "[INSTRUCTIONS] 09": "5.000 PUNTS",
@@ -65,6 +66,8 @@
"[NOTIFICATIONS] 13": "Filtre", "[NOTIFICATIONS] 13": "Filtre",
"[NOTIFICATIONS] 14": "Sincronisme vertical", "[NOTIFICATIONS] 14": "Sincronisme vertical",
"[NOTIFICATIONS] 15": "Reiniciar", "[NOTIFICATIONS] 15": "Reiniciar",
"[NOTIFICATIONS] CONNECTED": "conectat",
"[NOTIFICATIONS] DISCONNECTED": "desconectat",
"[RESOURCE] LOADING": "Carregant", "[RESOURCE] LOADING": "Carregant",

View File

@@ -1,8 +1,8 @@
{ {
"[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMMED AND DESIGNED BY", "[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMMED AND DESIGNED BY",
"[CREDITS] PIXELART_DRAWN_BY" : "PIXELART DRAWN BY", "[CREDITS] PIXELART_DRAWN_BY" : "PIXELART BY",
"[CREDITS] MUSIC_COMPOSED_BY" : "MUSIC COMPOSED BY", "[CREDITS] MUSIC_COMPOSED_BY" : "MUSIC COMPOSED BY",
"[CREDITS] SOUND_EFFECTS" : "SOUND EFFECTS", "[CREDITS] SOUND_EFFECTS" : "SOUND EFFECTS BY",
"[DEFINE_BUTTONS] FIRE_LEFT" : "Fire left", "[DEFINE_BUTTONS] FIRE_LEFT" : "Fire left",
"[DEFINE_BUTTONS] FIRE_UP" : "Fire up", "[DEFINE_BUTTONS] FIRE_UP" : "Fire up",
@@ -13,30 +13,31 @@
"[DEFINE_BUTTONS] KEYBOARD" : "Keyboard", "[DEFINE_BUTTONS] KEYBOARD" : "Keyboard",
"[DEFINE_BUTTONS] CONFIGURATION_COMPLETE": "Configuration complete", "[DEFINE_BUTTONS] CONFIGURATION_COMPLETE": "Configuration complete",
"[DEFINE_BUTTONS] CONFIGURING" : "Configuring", "[DEFINE_BUTTONS] CONFIGURING" : "Configuring",
"[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Press button for", "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Press a button for",
"[DEFINE_BUTTONS] CONFIGURED" : "Configured", "[DEFINE_BUTTONS] CONFIGURED" : "Configured",
"[GAME_TEXT] 1": "Congratulations!!", "[GAME_TEXT] 1": "Congratulations!",
"[GAME_TEXT] 2": " stages left!", "[GAME_TEXT] 2": "",
"[GAME_TEXT] 2A": " stages left!",
"[GAME_TEXT] 3": "Last stage!", "[GAME_TEXT] 3": "Last stage!",
"[GAME_TEXT] 4": "PowerUp", "[GAME_TEXT] 4": "PowerUp",
"[GAME_TEXT] 5": "+1 Hit", "[GAME_TEXT] 5": "+1 Hit",
"[GAME_TEXT] 6": "Stop!", "[GAME_TEXT] 6": "Stop!",
"[GAME_TEXT] 7": "Get Ready!", "[GAME_TEXT] 7": "Get Ready!",
"[GAME_TEXT] 8": "1.000.000 points!", "[GAME_TEXT] 8": "1,000,000 points!",
"[HIGHSCORE_TABLE] CAPTION": "Best scores", "[HIGHSCORE_TABLE] CAPTION": "Best scores",
"[INSTRUCTIONS] 01": "OBJECTIVE", "[INSTRUCTIONS] 01": "OBJECTIVE",
"[INSTRUCTIONS] 02": "YOU HAVE TO POP AS MANY", "[INSTRUCTIONS] 02": "POP AS MANY BALLOONS",
"[INSTRUCTIONS] 03": "BALLOONS AS YOU CAN", "[INSTRUCTIONS] 03": "AS YOU CAN",
"[INSTRUCTIONS] 04": "DIFFICULTY WILL BE INCREASED", "[INSTRUCTIONS] 04": "DIFFICULTY INCREASES",
"[INSTRUCTIONS] 05": "AS YOU SCORE POINTS", "[INSTRUCTIONS] 05": "AS YOU EARN POINTS",
"[INSTRUCTIONS] 06": "ITEMS", "[INSTRUCTIONS] 06": "BONUS ITEMS",
"[INSTRUCTIONS] 07": "1.000 POINTS", "[INSTRUCTIONS] 07": "1.000 POINTS",
"[INSTRUCTIONS] 08": "2.500 POINTS", "[INSTRUCTIONS] 08": "2.500 POINTS",
"[INSTRUCTIONS] 09": "5.000 POINTS", "[INSTRUCTIONS] 09": "5.000 POINTS",
"[INSTRUCTIONS] 10": "TIME STOPPER", "[INSTRUCTIONS] 10": "TTIME FREEZE",
"[INSTRUCTIONS] 11": "EXTRA HIT", "[INSTRUCTIONS] 11": "EXTRA HIT",
"[INTRO] 1": "Any day of the year 2000", "[INTRO] 1": "Any day of the year 2000",
@@ -50,29 +51,31 @@
"[INTRO] 9": "Blop... blop... blop...", "[INTRO] 9": "Blop... blop... blop...",
"[NOTIFICATIONS] 01": "Press again to quit", "[NOTIFICATIONS] 01": "Press again to quit",
"[NOTIFICATIONS] 02": "Press again to shutdown system", "[NOTIFICATIONS] 02": "Press again to shut down the system",
"[NOTIFICATIONS] 03": "Press again to reset", "[NOTIFICATIONS] 03": "Press again to reset",
"[NOTIFICATIONS] 04": "Press again to change language to", "[NOTIFICATIONS] 04": "Press again to change language to",
"[NOTIFICATIONS] 05": "Language set to", "[NOTIFICATIONS] 05": "Language changed to",
"[NOTIFICATIONS] 06": "on", "[NOTIFICATIONS] 06": "on",
"[NOTIFICATIONS] 07": "off", "[NOTIFICATIONS] 07": "off",
"[NOTIFICATIONS] 08": "Autofire", "[NOTIFICATIONS] 08": "Autofire",
"[NOTIFICATIONS] 09": "Window zoom", "[NOTIFICATIONS] 09": "Window zoom",
"[NOTIFICATIONS] 10": "Window mode", "[NOTIFICATIONS] 10": "Window mode",
"[NOTIFICATIONS] 11": "Fullscreen mode", "[NOTIFICATIONS] 11": "Fullscreen mode",
"[NOTIFICATIONS] 12": "Integer scale", "[NOTIFICATIONS] 12": "Pixel-perfect scale",
"[NOTIFICATIONS] 13": "Filter", "[NOTIFICATIONS] 13": "Filter",
"[NOTIFICATIONS] 14": "Vertical Sync", "[NOTIFICATIONS] 14": "Vertical Sync",
"[NOTIFICATIONS] 15": "Reset", "[NOTIFICATIONS] 15": "Reset",
"[NOTIFICATIONS] CONNECTED": "connected",
"[NOTIFICATIONS] DISCONNECTED": "disconnected",
"[RESOURCE] LOADING": "Loading", "[RESOURCE] LOADING": "Loading",
"[SERVICE_MENU] TITLE": "Service Menu", "[SERVICE_MENU] TITLE": "Service Menu",
"[SERVICE_MENU] RESET": "Reset", "[SERVICE_MENU] RESET": "Reset",
"[SERVICE_MENU] QUIT": "Quit Game", "[SERVICE_MENU] QUIT": "Exit Game",
"[SERVICE_MENU] SHUTDOWN": "Shutdown System", "[SERVICE_MENU] SHUTDOWN": "Shutdown System",
"[SERVICE_MENU] FULLSCREEN": "Fullscreen", "[SERVICE_MENU] FULLSCREEN": "Fullscreen",
"[SERVICE_MENU] WINDOW_SIZE": "Window Size", "[SERVICE_MENU] WINDOW_SIZE": "Window Zoom",
"[SERVICE_MENU] SHADERS": "Shaders", "[SERVICE_MENU] SHADERS": "Shaders",
"[SERVICE_MENU] VSYNC": "V-Sync", "[SERVICE_MENU] VSYNC": "V-Sync",
"[SERVICE_MENU] INTEGER_SCALE": "Integer Scale", "[SERVICE_MENU] INTEGER_SCALE": "Integer Scale",
@@ -95,7 +98,7 @@
"[SERVICE_MENU] NORMAL": "Normal", "[SERVICE_MENU] NORMAL": "Normal",
"[SERVICE_MENU] HARD": "Hard", "[SERVICE_MENU] HARD": "Hard",
"[SERVICE_MENU] NEED_RESTART_MESSAGE": "Restart to apply changes", "[SERVICE_MENU] NEED_RESTART_MESSAGE": "Restart to apply changes",
"[SERVICE_MENU] ENABLE_SHUTDOWN": "Enable shutdown", "[SERVICE_MENU] ENABLE_SHUTDOWN": "Allow system shutdown",
"[SERVICE_MENU] CONTROLS": "Controls", "[SERVICE_MENU] CONTROLS": "Controls",
"[SERVICE_MENU] KEYBOARD": "Keyboard", "[SERVICE_MENU] KEYBOARD": "Keyboard",
"[SERVICE_MENU] PLAYER1": "Player 1", "[SERVICE_MENU] PLAYER1": "Player 1",
@@ -104,7 +107,7 @@
"[SERVICE_MENU] CONTROLLER2": "Controller 2", "[SERVICE_MENU] CONTROLLER2": "Controller 2",
"[SERVICE_MENU] CONFIGURE1": "Configure Controller 1", "[SERVICE_MENU] CONFIGURE1": "Configure Controller 1",
"[SERVICE_MENU] CONFIGURE2": "Configure Controller 2", "[SERVICE_MENU] CONFIGURE2": "Configure Controller 2",
"[SERVICE_MENU] NO_CONTROLLER": "[No controller]", "[SERVICE_MENU] NO_CONTROLLER": "[ No controller ]",
"[SERVICE_MENU] SWAP_CONTROLLERS": "Swap Controllers", "[SERVICE_MENU] SWAP_CONTROLLERS": "Swap Controllers",
"[SCOREBOARD] 1" : "Player 1", "[SCOREBOARD] 1" : "Player 1",

View File

@@ -2,7 +2,7 @@
"[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMADO Y DISENADO POR", "[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMADO Y DISENADO POR",
"[CREDITS] PIXELART_DRAWN_BY" : "GRAFICOS DIBUJADOS POR", "[CREDITS] PIXELART_DRAWN_BY" : "GRAFICOS DIBUJADOS POR",
"[CREDITS] MUSIC_COMPOSED_BY" : "MUSICA COMPUESTA POR", "[CREDITS] MUSIC_COMPOSED_BY" : "MUSICA COMPUESTA POR",
"[CREDITS] SOUND_EFFECTS" : "EFECTOS DE SONIDO", "[CREDITS] SOUND_EFFECTS" : "EFECTOS DE SONIDO POR",
"[DEFINE_BUTTONS] FIRE_LEFT" : "Disparar a la izquierda", "[DEFINE_BUTTONS] FIRE_LEFT" : "Disparar a la izquierda",
"[DEFINE_BUTTONS] FIRE_UP" : "Disparar hacia arriba", "[DEFINE_BUTTONS] FIRE_UP" : "Disparar hacia arriba",
@@ -16,8 +16,9 @@
"[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Pulsa un boton para", "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Pulsa un boton para",
"[DEFINE_BUTTONS] CONFIGURED" : "Configurado", "[DEFINE_BUTTONS] CONFIGURED" : "Configurado",
"[GAME_TEXT] 1": "Felicidades!!", "[GAME_TEXT] 1": "Felicidades!",
"[GAME_TEXT] 2": " fases mas!", "[GAME_TEXT] 2": "!Quedan ",
"[GAME_TEXT] 2A": " fases!",
"[GAME_TEXT] 3": "Ultima fase!", "[GAME_TEXT] 3": "Ultima fase!",
"[GAME_TEXT] 4": "Potenciador", "[GAME_TEXT] 4": "Potenciador",
"[GAME_TEXT] 5": "+1 Golpe", "[GAME_TEXT] 5": "+1 Golpe",
@@ -32,7 +33,7 @@
"[INSTRUCTIONS] 03": "TANTOS GLOBOS COMO PUEDAS", "[INSTRUCTIONS] 03": "TANTOS GLOBOS COMO PUEDAS",
"[INSTRUCTIONS] 04": "LA DIFICULTAD SE INCREMENTA", "[INSTRUCTIONS] 04": "LA DIFICULTAD SE INCREMENTA",
"[INSTRUCTIONS] 05": "A MEDIDA QUE VAS PUNTUANDO", "[INSTRUCTIONS] 05": "A MEDIDA QUE VAS PUNTUANDO",
"[INSTRUCTIONS] 06": "OBJETOS", "[INSTRUCTIONS] 06": "OBJETOS DE BONUS",
"[INSTRUCTIONS] 07": "1.000 PUNTOS", "[INSTRUCTIONS] 07": "1.000 PUNTOS",
"[INSTRUCTIONS] 08": "2.500 PUNTOS", "[INSTRUCTIONS] 08": "2.500 PUNTOS",
"[INSTRUCTIONS] 09": "5.000 PUNTOS", "[INSTRUCTIONS] 09": "5.000 PUNTOS",
@@ -64,6 +65,8 @@
"[NOTIFICATIONS] 13": "Filtro", "[NOTIFICATIONS] 13": "Filtro",
"[NOTIFICATIONS] 14": "Sincronismo vertical", "[NOTIFICATIONS] 14": "Sincronismo vertical",
"[NOTIFICATIONS] 15": "Reiniciar", "[NOTIFICATIONS] 15": "Reiniciar",
"[NOTIFICATIONS] CONNECTED": "conectado",
"[NOTIFICATIONS] DISCONNECTED": "desconectado",
"[RESOURCE] LOADING": "Cargando", "[RESOURCE] LOADING": "Cargando",
@@ -73,9 +76,9 @@
"[SERVICE_MENU] SHUTDOWN": "Apagar el sistema", "[SERVICE_MENU] SHUTDOWN": "Apagar el sistema",
"[SERVICE_MENU] FULLSCREEN": "Pantalla completa", "[SERVICE_MENU] FULLSCREEN": "Pantalla completa",
"[SERVICE_MENU] WINDOW_SIZE": "Zoom de ventana", "[SERVICE_MENU] WINDOW_SIZE": "Zoom de ventana",
"[SERVICE_MENU] SHADERS": "Filtro", "[SERVICE_MENU] SHADERS": "Filtro grafico",
"[SERVICE_MENU] VSYNC": "Sincronismo vertical", "[SERVICE_MENU] VSYNC": "Sincronismo vertical",
"[SERVICE_MENU] INTEGER_SCALE": "Escalado entero", "[SERVICE_MENU] INTEGER_SCALE": "Escalado proporcional",
"[SERVICE_MENU] MAIN_VOLUME": "Volumen general", "[SERVICE_MENU] MAIN_VOLUME": "Volumen general",
"[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica", "[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica",
"[SERVICE_MENU] SFX_VOLUME": "Volumen de los efectos", "[SERVICE_MENU] SFX_VOLUME": "Volumen de los efectos",
@@ -104,8 +107,8 @@
"[SERVICE_MENU] CONTROLLER2": "Mando 2", "[SERVICE_MENU] CONTROLLER2": "Mando 2",
"[SERVICE_MENU] CONFIGURE1": "Configurar Mando 1", "[SERVICE_MENU] CONFIGURE1": "Configurar Mando 1",
"[SERVICE_MENU] CONFIGURE2": "Configurar Mando 2", "[SERVICE_MENU] CONFIGURE2": "Configurar Mando 2",
"[SERVICE_MENU] NO_CONTROLLER": "[Desconectat]", "[SERVICE_MENU] NO_CONTROLLER": "[ Desconectado ]",
"[SERVICE_MENU] SWAP_CONTROLLERS": "Intercambia mandos", "[SERVICE_MENU] SWAP_CONTROLLERS": "Intercambiar mandos",
"[SCOREBOARD] 1": "Jugador 1", "[SCOREBOARD] 1": "Jugador 1",
"[SCOREBOARD] 2": "Jugador 2", "[SCOREBOARD] 2": "Jugador 2",

View File

@@ -3,13 +3,37 @@
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory #include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory
#include "input.h" // Para Input #include "input.h" // Para Input
#include "lang.h" // Para Lang
#include "mouse.h" // Para handleEvent #include "mouse.h" // Para handleEvent
#include "options.h" // Para Options #include "options.h" // Para Options
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.hpp" // Para Name, Options, name, options #include "section.hpp" // Para Name, Options, name, options
#include "ui/notifier.h" // Para Notifier
#include "ui/service_menu.h" // Para ServiceMenu #include "ui/service_menu.h" // Para ServiceMenu
namespace GlobalEvents { namespace GlobalEvents {
// Comprueba los eventos de Input y muestra notificaciones
void handleInputEvents(const SDL_Event &event) {
static auto *input_ = Input::get();
auto message = input_->handleEvent(event);
if (message.empty()) return;
// Reemplazo de palabras clave por texto localizado
size_t pos;
while ((pos = message.find(" CONNECTED")) != std::string::npos) {
message.replace(pos, std::string(" CONNECTED").length(), " " + Lang::getText("[NOTIFICATIONS] CONNECTED"));
}
while ((pos = message.find(" DISCONNECTED")) != std::string::npos) {
message.replace(pos, std::string(" DISCONNECTED").length(), " " + Lang::getText("[NOTIFICATIONS] DISCONNECTED"));
}
Options::gamepad_manager.assignAndLinkGamepads();
Options::gamepad_manager.resyncGamepadsWithPlayers();
Notifier::get()->show({message});
ServiceMenu::get()->refresh();
}
// Comprueba los eventos que se pueden producir en cualquier sección del juego // Comprueba los eventos que se pueden producir en cualquier sección del juego
void check(const SDL_Event &event) { void check(const SDL_Event &event) {
switch (event.type) { switch (event.type) {
@@ -33,10 +57,6 @@ void check(const SDL_Event &event) {
ServiceMenu::get()->handleEvent(event); ServiceMenu::get()->handleEvent(event);
Mouse::handleEvent(event); Mouse::handleEvent(event);
handleInputEvents(event);
static auto *input_ = Input::get();
if (input_->handleEvent(event)) {
Options::gamepad_manager.assignAndLinkGamepads();
}
} }
} // namespace GlobalEvents } // namespace GlobalEvents

View File

@@ -308,42 +308,45 @@ void Input::update() {
} }
} }
auto Input::handleEvent(const SDL_Event &event) -> bool { auto Input::handleEvent(const SDL_Event &event) -> std::string {
switch (event.type) { switch (event.type) {
case SDL_EVENT_GAMEPAD_ADDED: case SDL_EVENT_GAMEPAD_ADDED:
addGamepad(event.gdevice.which); return addGamepad(event.gdevice.which);
return true;
case SDL_EVENT_GAMEPAD_REMOVED: case SDL_EVENT_GAMEPAD_REMOVED:
removeGamepad(event.gdevice.which); return removeGamepad(event.gdevice.which);
return true;
} }
return false; return std::string();
} }
void Input::addGamepad(int device_index) { auto Input::addGamepad(int device_index) -> std::string {
SDL_Gamepad *pad = SDL_OpenGamepad(device_index); SDL_Gamepad *pad = SDL_OpenGamepad(device_index);
if (pad == nullptr) { if (pad == nullptr) {
std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << std::endl; std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << std::endl;
return; return std::string();
} }
auto gamepad = std::make_shared<Gamepad>(pad); auto gamepad = std::make_shared<Gamepad>(pad);
std::cout << "Gamepad connected (" << gamepad->name << ")" << std::endl; auto name = gamepad->name;
std::cout << "Gamepad connected (" << name << ")" << std::endl;
applyGamepadConfig(gamepad); applyGamepadConfig(gamepad);
saveGamepadConfigFromGamepad(gamepad); saveGamepadConfigFromGamepad(gamepad);
gamepads_.push_back(std::move(gamepad)); gamepads_.push_back(std::move(gamepad));
return name + " CONNECTED";
} }
void Input::removeGamepad(SDL_JoystickID id) { auto Input::removeGamepad(SDL_JoystickID id) -> std::string {
auto it = std::remove_if(gamepads_.begin(), gamepads_.end(), [id](const std::shared_ptr<Gamepad> &gamepad) { auto it = std::find_if(gamepads_.begin(), gamepads_.end(), [id](const std::shared_ptr<Gamepad> &gamepad) {
return gamepad->instance_id == id; return gamepad->instance_id == id;
}); });
if (it != gamepads_.end()) { if (it != gamepads_.end()) {
std::cout << "Gamepad disconnected (" << (*it)->name << ")" << std::endl; std::string name = (*it)->name;
gamepads_.erase(it, gamepads_.end()); std::cout << "Gamepad disconnected (" << name << ")" << std::endl;
gamepads_.erase(it);
return name + " DISCONNECTED";
} else { } else {
std::cerr << "No se encontró el gamepad con ID " << id << std::endl; std::cerr << "No se encontró el gamepad con ID " << id << std::endl;
return {};
} }
} }

View File

@@ -168,7 +168,7 @@ class Input {
void resetInputStates(); void resetInputStates();
// --- Eventos --- // --- Eventos ---
auto handleEvent(const SDL_Event &event) -> bool; auto handleEvent(const SDL_Event &event) -> std::string;
void printConnectedGamepads() const; void printConnectedGamepads() const;
@@ -190,8 +190,8 @@ class Input {
// --- Métodos internos --- // --- Métodos internos ---
void initSDLGamePad(); void initSDLGamePad();
static auto checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool; static auto checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
void addGamepad(int device_index); auto addGamepad(int device_index) -> std::string;
void removeGamepad(SDL_JoystickID id); auto removeGamepad(SDL_JoystickID id) -> std::string;
void addGamepadMappingsFromFile(); void addGamepadMappingsFromFile();
void discoverGamepads(); void discoverGamepads();

View File

@@ -157,10 +157,12 @@ class GamepadManager {
std::swap(gamepads_[0].name, gamepads_[1].name); std::swap(gamepads_[0].name, gamepads_[1].name);
std::swap(gamepads_[0].path, gamepads_[1].path); std::swap(gamepads_[0].path, gamepads_[1].path);
for (auto player: players) resyncGamepadsWithPlayers();
{ }
switch (player->getId())
{ void resyncGamepadsWithPlayers() {
for (auto player : players) {
switch (player->getId()) {
case Player::Id::PLAYER1: case Player::Id::PLAYER1:
player->setGamepad(gamepads_[0].instance); player->setGamepad(gamepads_[0].instance);
break; break;
@@ -168,7 +170,7 @@ class GamepadManager {
player->setGamepad(gamepads_[1].instance); player->setGamepad(gamepads_[1].instance);
break; break;
default: default:
break; break;
} }
} }
} }
@@ -229,7 +231,6 @@ class GamepadManager {
// Asigna el mando a un jugador // Asigna el mando a un jugador
void assignTo(Input::Gamepad gamepad, Player::Id player_id) { void assignTo(Input::Gamepad gamepad, Player::Id player_id) {
} }
// Asigna los mandos físicos basándose en la configuración actual de nombres. // Asigna los mandos físicos basándose en la configuración actual de nombres.
@@ -246,7 +247,7 @@ class GamepadManager {
private: private:
static constexpr std::string_view UNASSIGNED_TEXT = "---"; static constexpr std::string_view UNASSIGNED_TEXT = "---";
static constexpr size_t MAX_PLAYERS = 2; static constexpr size_t MAX_PLAYERS = 2;
std::array<Gamepad, MAX_PLAYERS> gamepads_; // Punteros a las estructuras de mandos de Options std::array<Gamepad, MAX_PLAYERS> gamepads_; // Punteros a las estructuras de mandos de Options
std::vector<std::shared_ptr<Player>> players; // Punteros a los jugadores std::vector<std::shared_ptr<Player>> players; // Punteros a los jugadores
// Convierte Player::Id a índice del array // Convierte Player::Id a índice del array

129
source/pause_manager.h Normal file
View File

@@ -0,0 +1,129 @@
#pragma once
#include <cstdint>
#include <functional>
#include <string>
// Clase dedicada para manejar el sistema de pausa
class PauseManager {
public:
// Enum encapsulado dentro de la clase
enum class Source : uint8_t {
NONE = 0,
PLAYER = 1 << 0, // 0001
SERVICE_MENU = 1 << 1, // 0010
FOCUS_LOST = 1 << 2 // 0100
};
// Operadores para trabajar con las banderas (funciones friend)
friend Source operator|(Source a, Source b) {
return static_cast<Source>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
}
friend Source operator&(Source a, Source b) {
return static_cast<Source>(static_cast<uint8_t>(a) & static_cast<uint8_t>(b));
}
friend Source operator~(Source a) {
return static_cast<Source>(~static_cast<uint8_t>(a));
}
friend Source& operator|=(Source& a, Source b) {
return a = a | b;
}
friend Source& operator&=(Source& a, Source b) {
return a = a & b;
}
private:
Source flags_ = Source::NONE;
std::function<void(bool)> onPauseChangedCallback_;
bool hasFlag(Source flag) const {
return (flags_ & flag) != Source::NONE;
}
void notifyPauseChanged() {
if (onPauseChangedCallback_) {
onPauseChangedCallback_(isPaused());
}
}
public:
// Constructor con callback opcional
explicit PauseManager(std::function<void(bool)> callback = nullptr)
: onPauseChangedCallback_(callback) {}
// Establece/quita una fuente de pausa específica
void setFlag(Source source, bool enable) {
bool wasPaused = isPaused();
if (enable) {
flags_ |= source;
} else {
flags_ &= ~source;
}
// Solo notifica si cambió el estado general de pausa
if (wasPaused != isPaused()) {
notifyPauseChanged();
}
}
// Métodos específicos para cada fuente
void setPlayerPause(bool enable) { setFlag(Source::PLAYER, enable); }
void setServiceMenuPause(bool enable) { setFlag(Source::SERVICE_MENU, enable); }
void setFocusLossPause(bool enable) { setFlag(Source::FOCUS_LOST, enable); }
// Toggle para el jugador (más común)
void togglePlayerPause() { setPlayerPause(!isPlayerPaused()); }
// Getters
bool isPaused() const { return flags_ != Source::NONE; }
bool isPlayerPaused() const { return hasFlag(Source::PLAYER); }
bool isServiceMenuPaused() const { return hasFlag(Source::SERVICE_MENU); }
bool isFocusLossPaused() const { return hasFlag(Source::FOCUS_LOST); }
// Obtiene las banderas actuales
Source getFlags() const { return flags_; }
// Limpia todas las pausas (útil para reset)
void clearAll() {
if (isPaused()) {
flags_ = Source::NONE;
notifyPauseChanged();
}
}
// Método para debug
std::string getStatusString() const {
if (flags_ == Source::NONE) return "Active";
std::string result = "Paused by: ";
bool first = true;
if (hasFlag(Source::PLAYER)) {
if (!first) result += ", ";
result += "Player";
first = false;
}
if (hasFlag(Source::SERVICE_MENU)) {
if (!first) result += ", ";
result += "ServiceMenu";
first = false;
}
if (hasFlag(Source::FOCUS_LOST)) {
if (!first) result += ", ";
result += "FocusLoss";
first = false;
}
return result;
}
// Permite cambiar el callback en runtime
void setCallback(std::function<void(bool)> callback) {
onPauseChangedCallback_ = callback;
}
};

View File

@@ -30,6 +30,7 @@
#include "manage_hiscore_table.h" // Para HiScoreEntry, ManageHiScoreTable #include "manage_hiscore_table.h" // Para HiScoreEntry, ManageHiScoreTable
#include "param.h" // Para Param, param, ParamGame, ParamScoreboard, ParamFade, ParamBalloon #include "param.h" // Para Param, param, ParamGame, ParamScoreboard, ParamFade, ParamBalloon
#include "path_sprite.h" // Para Path, PathSprite, createPath, PathType #include "path_sprite.h" // Para Path, PathSprite, createPath, PathType
#include "pause_manager.h" // Para PauseManager
#include "player.h" // Para Player #include "player.h" // Para Player
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "scoreboard.h" // Para Scoreboard #include "scoreboard.h" // Para Scoreboard
@@ -50,6 +51,7 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
input_(Input::get()), input_(Input::get()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)),
pause_manager_(std::make_unique<PauseManager>([this](bool isPaused) { onPauseStateChanged(isPaused); })),
fade_in_(std::make_unique<Fade>()), fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>()), fade_out_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()), balloon_manager_(std::make_unique<BalloonManager>()),
@@ -96,6 +98,14 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
initPaths(); initPaths();
setTotalPower(); setTotalPower();
// Registra callbacks
ServiceMenu::get()->setStateChangeCallback([this](bool isActive) {
// Solo aplicar pausa si NO estamos en modo demo
if (!demo_.enabled) {
pause_manager_->setServiceMenuPause(isActive);
}
});
#ifdef _DEBUG #ifdef _DEBUG
// Si se empieza en una fase que no es la primera // Si se empieza en una fase que no es la primera
if (!demo_.enabled) { if (!demo_.enabled) {
@@ -258,7 +268,7 @@ void Game::updateStage() {
createMessage(paths, Resource::get()->getTexture("game_text_last_stage")); createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
} else { } else {
auto text = Resource::get()->getText("04b_25_2x"); auto text = Resource::get()->getText("04b_25_2x");
const std::string CAPTION = std::to_string(10 - Stage::number) + Lang::getText("[GAME_TEXT] 2"); const std::string CAPTION = Lang::getText("[GAME_TEXT] 2") + std::to_string(10 - Stage::number) + Lang::getText("[GAME_TEXT] 2A");
createMessage(paths, text->writeToTexture(CAPTION, 1, -4)); createMessage(paths, text->writeToTexture(CAPTION, 1, -4));
} }
} }
@@ -888,7 +898,6 @@ void Game::update() {
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
screen_->update(); screen_->update();
checkServiceMenu();
updateDemo(); updateDemo();
#ifdef RECORDING #ifdef RECORDING
updateRecording(); updateRecording();
@@ -914,7 +923,7 @@ void Game::render() {
// Actualiza los estados del juego // Actualiza los estados del juego
void Game::updateGameStates() { void Game::updateGameStates() {
if (!paused_) { if (!pause_manager_->isPaused()) {
switch (state_) { switch (state_) {
case State::FADE_IN: case State::FADE_IN:
updateGameStateFadeIn(); updateGameStateFadeIn();
@@ -1121,11 +1130,11 @@ void Game::checkEvents() {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_EVENT_WINDOW_FOCUS_LOST: { case SDL_EVENT_WINDOW_FOCUS_LOST: {
pause(!demo_.enabled); pause_manager_->setFocusLossPause(!demo_.enabled);
break; break;
} }
case SDL_EVENT_WINDOW_FOCUS_GAINED: { case SDL_EVENT_WINDOW_FOCUS_GAINED: {
pause(false); pause_manager_->setFocusLossPause(false);
break; break;
} }
default: default:
@@ -1156,13 +1165,6 @@ void Game::updateScoreboard() {
scoreboard_->update(); scoreboard_->update();
} }
// Pausa el juego
void Game::pause(bool value) {
paused_ = value;
screen_->attenuate(paused_);
tabe_->pauseTimer(paused_);
}
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records
void Game::addScoreToScoreBoard(const std::shared_ptr<Player> &player) { void Game::addScoreToScoreBoard(const std::shared_ptr<Player> &player) {
const auto ENTRY = HiScoreEntry(trim(player->getLastEnterName()), player->getScore(), player->get1CC()); const auto ENTRY = HiScoreEntry(trim(player->getLastEnterName()), player->getScore(), player->get1CC());
@@ -1242,17 +1244,16 @@ void Game::checkInput() {
// Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego. // Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego.
void Game::checkPauseInput() { void Game::checkPauseInput() {
// Comprueba los mandos // Comprueba los mandos
auto gamepads = input_->getGamepads(); for (auto gamepad : input_->getGamepads()) {
for (auto gamepad : gamepads) {
if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) { if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
pause(!paused_); pause_manager_->togglePlayerPause();
return; return;
} }
} }
// Comprueba el teclado // Comprueba el teclado
if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) { if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
pause(!paused_); pause_manager_->togglePlayerPause();
return; return;
} }
} }
@@ -1866,29 +1867,6 @@ void Game::sortPlayersByZOrder() {
} }
} }
// Comprueba si está activo el menu de servicio para poner el juego en pausa
void Game::checkServiceMenu() {
if (demo_.enabled) {
return;
}
static bool was_paused_before_service_menu_ = false;
static bool service_menu_was_active_ = false;
bool service_menu_is_active = ServiceMenu::get()->isEnabled();
if (service_menu_is_active && !service_menu_was_active_) {
// El menú acaba de abrirse
was_paused_before_service_menu_ = paused_;
pause(true);
} else if (!service_menu_is_active && service_menu_was_active_) {
// El menú acaba de cerrarse
pause(was_paused_before_service_menu_);
}
service_menu_was_active_ = service_menu_is_active;
}
// Mueve el jugador para pintarlo al fondo de la lista de jugadores // Mueve el jugador para pintarlo al fondo de la lista de jugadores
void Game::sendPlayerToTheBack(const std::shared_ptr<Player> &player) { void Game::sendPlayerToTheBack(const std::shared_ptr<Player> &player) {
players_to_put_at_back_.push_back(player); players_to_put_at_back_.push_back(player);
@@ -1899,6 +1877,11 @@ void Game::sendPlayerToTheFront(const std::shared_ptr<Player> &player) {
players_to_put_at_front_.push_back(player); players_to_put_at_front_.push_back(player);
} }
void Game::onPauseStateChanged(bool isPaused) {
screen_->attenuate(isPaused);
tabe_->pauseTimer(isPaused);
}
#ifdef _DEBUG #ifdef _DEBUG
// Comprueba los eventos en el modo DEBUG // Comprueba los eventos en el modo DEBUG
void Game::checkDebugEvents(const SDL_Event &event) { void Game::checkDebugEvents(const SDL_Event &event) {

View File

@@ -3,6 +3,7 @@
#include <SDL3/SDL.h> // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64, Uint8 #include <SDL3/SDL.h> // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64, Uint8
#include <memory> // Para shared_ptr, unique_ptr #include <memory> // Para shared_ptr, unique_ptr
#include <set> // Para Set
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
@@ -11,6 +12,7 @@
#include "manage_hiscore_table.h" // Para HiScoreEntry #include "manage_hiscore_table.h" // Para HiScoreEntry
#include "options.h" // Para SettingsOptions, settings #include "options.h" // Para SettingsOptions, settings
#include "path_sprite.h" // Para PathSprite, Path #include "path_sprite.h" // Para PathSprite, Path
#include "pause_manager.h" // Para PauseManager
#include "player.h" // Para Player #include "player.h" // Para Player
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "utils.h" // Para Demo #include "utils.h" // Para Demo
@@ -116,6 +118,7 @@ class Game {
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::unique_ptr<PauseManager> pause_manager_; // Objeto para gestionar la pausa
std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
@@ -133,17 +136,15 @@ class Game {
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego
bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima
bool paused_ = false; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade) float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad
// bool paused_by_service_menu_ = false; int counter_ = 0; // Contador para el juego
float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos
int counter_ = 0; // Contador para el juego int game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida
int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido
int game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido int menace_current_ = 0; // Nivel de amenaza actual
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
int menace_current_ = 0; // Nivel de amenaza actual State state_ = State::FADE_IN; // Estado
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
State state_ = State::FADE_IN; // Estado
std::vector<std::shared_ptr<Player>> players_to_put_at_back_; std::vector<std::shared_ptr<Player>> players_to_put_at_back_;
std::vector<std::shared_ptr<Player>> players_to_put_at_front_; std::vector<std::shared_ptr<Player>> players_to_put_at_front_;
Hit hit_; // Para representar colisiones en pantalla Hit hit_; // Para representar colisiones en pantalla
@@ -158,7 +159,6 @@ class Game {
void checkEvents(); // Procesa los eventos del sistema en cola void checkEvents(); // Procesa los eventos del sistema en cola
void checkState(); // Verifica y actualiza el estado actual del juego void checkState(); // Verifica y actualiza el estado actual del juego
void setState(State state); // Cambia el estado del juego void setState(State state); // Cambia el estado del juego
void pause(bool value); // Pausa o reanuda el juego
void cleanVectors(); // Limpia vectores de elementos deshabilitados void cleanVectors(); // Limpia vectores de elementos deshabilitados
// --- Gestión de estados del juego --- // --- Gestión de estados del juego ---
@@ -289,11 +289,9 @@ class Game {
static void resumeMusic(); // Retoma la música que eestaba pausada static void resumeMusic(); // Retoma la música que eestaba pausada
void playSound(const std::string &name) const; // Reproduce un efecto de sonido específico void playSound(const std::string &name) const; // Reproduce un efecto de sonido específico
// --- Utilidades y servicios ---
void checkServiceMenu(); // Verifica si el menú de servicio está activo
void sendPlayerToTheBack(const std::shared_ptr<Player> &player); // Mueve el jugador para pintarlo al fondo de la lista de jugadores void sendPlayerToTheBack(const std::shared_ptr<Player> &player); // Mueve el jugador para pintarlo al fondo de la lista de jugadores
void sendPlayerToTheFront(const std::shared_ptr<Player> &player); // Mueve el jugador para pintarlo el primero de la lista de jugadores void sendPlayerToTheFront(const std::shared_ptr<Player> &player); // Mueve el jugador para pintarlo el primero de la lista de jugadores
void onPauseStateChanged(bool isPaused);
// SISTEMA DE GRABACIÓN (CONDICIONAL) // SISTEMA DE GRABACIÓN (CONDICIONAL)
#ifdef RECORDING #ifdef RECORDING

View File

@@ -42,20 +42,18 @@ ServiceMenu::ServiceMenu()
void ServiceMenu::toggle() { void ServiceMenu::toggle() {
if (define_buttons_ && define_buttons_->isEnabled()) return; if (define_buttons_ && define_buttons_->isEnabled()) return;
if (isAnimating() && !define_buttons_->isEnabled()) return; // No permitir toggle durante una animación if (isAnimating() && !define_buttons_->isEnabled()) return;
playBackSound(); playBackSound();
enabled_ = !enabled_;
if (!enabled_) { // Si está cerrado, abrir
if (enabled_) { reset();
// Primero resetea el estado y luego muestra la animación
// reset();
Options::gamepad_manager.assignAndLinkGamepads(); Options::gamepad_manager.assignAndLinkGamepads();
renderer_->show(this); renderer_->show(this);
} else { setEnabledInternal(true);
// Al cerrar, solo inicia la animación de ocultar } else { // Si está abierto, cerrar
renderer_->hide(); renderer_->hide();
// NO llames a reset() aquí setEnabledInternal(false);
} }
} }
@@ -614,4 +612,31 @@ auto ServiceMenu::isAnimating() const -> bool {
auto ServiceMenu::isDefiningButtons() const -> bool { auto ServiceMenu::isDefiningButtons() const -> bool {
return define_buttons_ && define_buttons_->isEnabled(); return define_buttons_ && define_buttons_->isEnabled();
}
void ServiceMenu::refresh() {
// Este método está diseñado para ser llamado desde fuera, por ejemplo,
// cuando un mando se conecta o desconecta mientras el menú está abierto.
// La función updateMenu() es la forma más completa de refrescar, ya que
// sincroniza los valores, actualiza la lista de opciones visibles y notifica
// al renderer de cualquier cambio de layout que pueda haber ocurrido.
updateMenu();
}
// Método para registrar callback
void ServiceMenu::setStateChangeCallback(StateChangeCallback callback) {
state_change_callback_ = callback;
}
// Método interno que cambia estado y notifica
void ServiceMenu::setEnabledInternal(bool enabled) {
if (enabled_ != enabled) { // Solo si realmente cambia
enabled_ = enabled;
// Notifica el cambio si hay callback registrado
if (state_change_callback_) {
state_change_callback_(enabled_);
}
}
} }

View File

@@ -1,27 +1,40 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "ui_message.h"
#include "define_buttons.h" #include "define_buttons.h"
#include "ui_message.h"
class MenuOption; class MenuOption;
class MenuRenderer; class MenuRenderer;
class ServiceMenu { class ServiceMenu {
public: public:
// ... (enums y constantes sin cambios) // --- Enums y constantes ---
enum class SettingsGroup { CONTROLS, VIDEO, AUDIO, SETTINGS, SYSTEM, MAIN }; enum class SettingsGroup {
enum class GroupAlignment { CENTERED, LEFT }; CONTROLS,
VIDEO,
AUDIO,
SETTINGS,
SYSTEM,
MAIN
};
enum class GroupAlignment {
CENTERED,
LEFT
};
static constexpr size_t OPTIONS_HORIZONTAL_PADDING = 20; static constexpr size_t OPTIONS_HORIZONTAL_PADDING = 20;
static constexpr size_t MIN_WIDTH = 240; static constexpr size_t MIN_WIDTH = 240;
static constexpr size_t MIN_GAP_OPTION_VALUE = 30; static constexpr size_t MIN_GAP_OPTION_VALUE = 30;
static constexpr size_t SETTINGS_GROUP_SIZE = 6; static constexpr size_t SETTINGS_GROUP_SIZE = 6;
using StateChangeCallback = std::function<void(bool isActive)>;
// --- Métodos de singleton --- // --- Métodos de singleton ---
static void init(); static void init();
static void destroy(); static void destroy();
@@ -45,14 +58,19 @@ class ServiceMenu {
// --- Método para manejar eventos --- // --- Método para manejar eventos ---
void handleEvent(const SDL_Event &event); void handleEvent(const SDL_Event &event);
bool checkInput(); bool checkInput();
// --- Método principal para refresco externo ---
void refresh(); // Refresca los valores y el layout del menú bajo demanda
// --- Método para registrar el callback ---
void setStateChangeCallback(StateChangeCallback callback);
// --- Getters para el estado --- // --- Getters para el estado ---
[[nodiscard]] auto isDefiningButtons() const -> bool; [[nodiscard]] auto isDefiningButtons() const -> bool;
[[nodiscard]] auto isAnimating() const -> bool; // Nuevo getter [[nodiscard]] auto isAnimating() const -> bool; // Nuevo getter
// --- Getters para que el Renderer pueda leer el estado --- // --- Getters para que el Renderer pueda leer el estado ---
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; } [[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
// ... (resto de getters sin cambios)
[[nodiscard]] auto getTitle() const -> const std::string & { return title_; } [[nodiscard]] auto getTitle() const -> const std::string & { return title_; }
[[nodiscard]] auto getCurrentGroup() const -> SettingsGroup { return current_settings_group_; } [[nodiscard]] auto getCurrentGroup() const -> SettingsGroup { return current_settings_group_; }
[[nodiscard]] auto getCurrentGroupAlignment() const -> GroupAlignment; [[nodiscard]] auto getCurrentGroupAlignment() const -> GroupAlignment;
@@ -63,7 +81,6 @@ class ServiceMenu {
[[nodiscard]] auto countOptionsInGroup(SettingsGroup group) const -> size_t; [[nodiscard]] auto countOptionsInGroup(SettingsGroup group) const -> size_t;
private: private:
// ... (resto de miembros privados sin cambios)
bool enabled_ = false; bool enabled_ = false;
std::vector<std::unique_ptr<MenuOption>> options_; std::vector<std::unique_ptr<MenuOption>> options_;
std::vector<MenuOption *> display_options_; std::vector<MenuOption *> display_options_;
@@ -77,6 +94,7 @@ class ServiceMenu {
bool last_pending_changes_ = false; bool last_pending_changes_ = false;
std::unique_ptr<DefineButtons> define_buttons_; std::unique_ptr<DefineButtons> define_buttons_;
std::unique_ptr<MenuRenderer> renderer_; std::unique_ptr<MenuRenderer> renderer_;
StateChangeCallback state_change_callback_;
// --- Métodos de lógica interna --- // --- Métodos de lógica interna ---
void updateDisplayOptions(); void updateDisplayOptions();
@@ -96,6 +114,7 @@ class ServiceMenu {
static void playBackSound(); static void playBackSound();
[[nodiscard]] static auto settingsGroupToString(SettingsGroup group) -> std::string; [[nodiscard]] static auto settingsGroupToString(SettingsGroup group) -> std::string;
void setHiddenOptions(); void setHiddenOptions();
void setEnabledInternal(bool enabled); // Método privado para cambiar estado y notificar
// --- Constructores y destructor privados (singleton) --- // --- Constructores y destructor privados (singleton) ---
ServiceMenu(); ServiceMenu();