ServiceMenu: afegida opció per a canviar el idioma

This commit is contained in:
2025-06-12 13:50:05 +02:00
parent e6f4e27fbd
commit f9b576ea25
14 changed files with 307 additions and 109 deletions

View File

@@ -74,6 +74,10 @@
"[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica",
"[SERVICE_MENU] SFX_VOLUME": "Volumen dels sons",
"[SERVICE_MENU] AUTOFIRE": "Dispar automatic",
"[SERVICE_MENU] LANGUAGE": "Idioma",
"[SERVICE_MENU] LANG ES": "Castella",
"[SERVICE_MENU] LANG EN": "Angles",
"[SERVICE_MENU] LANG BA": "Balooncia",
"[SERVICE_MENU] VIDEO": "Video",
"[SERVICE_MENU] AUDIO": "Audio",
"[SERVICE_MENU] GAME": "Joc",

View File

@@ -74,6 +74,10 @@
"[SERVICE_MENU] MUSIC_VOLUME": "Music Volume",
"[SERVICE_MENU] SFX_VOLUME": "Sound Volume",
"[SERVICE_MENU] AUTOFIRE": "Autofire",
"[SERVICE_MENU] LANGUAGE": "Language",
"[SERVICE_MENU] LANG ES": "Spanish",
"[SERVICE_MENU] LANG EN": "English",
"[SERVICE_MENU] LANG BA": "Balooncia",
"[SERVICE_MENU] VIDEO": "Video",
"[SERVICE_MENU] AUDIO": "Audio",
"[SERVICE_MENU] GAME": "Game",

View File

@@ -74,6 +74,10 @@
"[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica",
"[SERVICE_MENU] SFX_VOLUME": "Volumen de los efectos",
"[SERVICE_MENU] AUTOFIRE": "Disparo automatico",
"[SERVICE_MENU] LANGUAGE": "Idioma",
"[SERVICE_MENU] LANG ES": "Castellano",
"[SERVICE_MENU] LANG EN": "Ingles",
"[SERVICE_MENU] LANG BA": "Balooncia",
"[SERVICE_MENU] VIDEO": "Video",
"[SERVICE_MENU] AUDIO": "Audio",
"[SERVICE_MENU] GAME": "Juego",

View File

@@ -93,15 +93,15 @@ void Director::init()
loadScoreFile(); // Carga el archivo de puntuaciones
// Inicialización de subsistemas principales
lang::loadFromFile(getLangFile(static_cast<lang::Code>(options.game.language))); // Carga el archivo de idioma
Screen::init(); // Inicializa la pantalla y el sistema de renderizado
Audio::init(); // Activa el sistema de audio
Resource::init(); // Inicializa el sistema de gestión de recursos
Input::init(Asset::get()->get("gamecontrollerdb.txt")); // Carga configuración de controles
bindInputs(); // Asigna los controles a la entrada del sistema
ServiceMenu::init(); // Inicializa el menú de servicio
Notifier::init(std::string(), Resource::get()->getText("8bithud")); // Inicialización del sistema de notificaciones
Screen::get()->getSingletons(); // Obtiene los punteros al resto de singletones
lang::setLanguage(options.game.language); // Carga el archivo de idioma
Screen::init(); // Inicializa la pantalla y el sistema de renderizado
Audio::init(); // Activa el sistema de audio
Resource::init(); // Inicializa el sistema de gestión de recursos
Input::init(Asset::get()->get("gamecontrollerdb.txt")); // Carga configuración de controles
bindInputs(); // Asigna los controles a la entrada del sistema
ServiceMenu::init(); // Inicializa el menú de servicio
Notifier::init(std::string(), Resource::get()->getText("8bithud")); // Inicialización del sistema de notificaciones
Screen::get()->getSingletons(); // Obtiene los punteros al resto de singletones
}
// Cierra todo y libera recursos del sistema y de los singletons
@@ -616,9 +616,12 @@ void Director::runDemoGame()
game->run();
}
// Ejecuta la sección init
void Director::runInit()
// Reinicia objetos y vuelve a la sección inicial
void Director::reset()
{
saveOptionsFile(Asset::get()->get("config.txt"));
loadOptionsFile(Asset::get()->get("config.txt"));
lang::setLanguage(options.game.language);
Audio::get()->stopMusic();
Audio::get()->stopAllSounds();
if (section::options == section::Options::RELOAD || true)
@@ -636,8 +639,8 @@ int Director::run()
{
switch (section::name)
{
case section::Name::INIT:
runInit();
case section::Name::RESET:
reset();
break;
case section::Name::LOGO:
runLogo();
@@ -687,27 +690,6 @@ int Director::run()
return (section::options == section::Options::QUIT_WITH_CONTROLLER) ? 1 : 0;
}
// Obtiene una fichero a partir de un lang::Code
std::string Director::getLangFile(lang::Code code)
{
switch (code)
{
case lang::Code::VALENCIAN:
return Asset::get()->get("ba_BA.json");
break;
case lang::Code::SPANISH:
return Asset::get()->get("es_ES.json");
break;
case lang::Code::ENGLISH:
return Asset::get()->get("en_UK.json");
break;
default:
break;
}
return Asset::get()->get("en_UK.json");
}
#ifdef ARCADE
// Apaga el sistema
void Director::shutdownSystem(bool should_shutdown)

View File

@@ -46,7 +46,7 @@ private:
void runCredits(); // Muestra los créditos del juego
void runHiScoreTable(); // Muestra la tabla de puntuaciones
void runDemoGame(); // Ejecuta el modo demo
void runInit(); // Ejecuta la fase de inicialización
void reset(); // Reinicia objetos y vuelve a la sección inicial
// Gestión de archivos de idioma
std::string getLangFile(lang::Code code); // Obtiene un fichero de idioma según el código

View File

@@ -1724,13 +1724,13 @@ void Game::initDifficultyVars()
void Game::initPlayers(int player_id)
{
// Crea los dos jugadores
const int y = param.game.play_area.rect.h - 30;
players_.emplace_back(std::make_unique<Player>(1, param.game.play_area.first_quarter_x - 15, y, demo_.enabled, param.game.play_area.rect, player_textures_[0], player_animations_));
const int Y = param.game.play_area.rect.h - 30;
players_.emplace_back(std::make_unique<Player>(1, param.game.play_area.first_quarter_x - 15, Y, demo_.enabled, param.game.play_area.rect, player_textures_[0], player_animations_));
players_.back()->setScoreBoardPanel(SCOREBOARD_LEFT_PANEL);
players_.back()->setName(lang::getText("[SCOREBOARD] 1"));
players_.back()->setController(getController(players_.back()->getId()));
players_.emplace_back(std::make_unique<Player>(2, param.game.play_area.third_quarter_x - 15, y, demo_.enabled, param.game.play_area.rect, player_textures_[1], player_animations_));
players_.emplace_back(std::make_unique<Player>(2, param.game.play_area.third_quarter_x - 15, Y, demo_.enabled, param.game.play_area.rect, player_textures_[1], player_animations_));
players_.back()->setScoreBoardPanel(SCOREBOARD_RIGHT_PANEL);
players_.back()->setName(lang::getText("[SCOREBOARD] 2"));
players_.back()->setController(getController(players_.back()->getId()));

View File

@@ -44,7 +44,7 @@ namespace globalInputs
const std::string CODE = "RESET";
if (Notifier::get()->checkCode(CODE))
{
section::name = section::Name::INIT;
section::name = section::Name::RESET;
Notifier::get()->show({lang::getText("[NOTIFICATIONS] 15")});
}
else
@@ -124,7 +124,7 @@ namespace globalInputs
{
options.game.language = lang::getNextLangCode(options.game.language);
lang::loadFromFile(getLangFile(static_cast<lang::Code>(options.game.language)));
section::name = section::Name::INIT;
section::name = section::Name::RESET;
section::options = section::Options::RELOAD;
Notifier::get()->show({lang::getText("[NOTIFICATIONS] 05") + getLangName(options.game.language)});
}

View File

@@ -2,6 +2,8 @@
#include <fstream>
#include <unordered_map>
#include "json.hpp"
#include "options.h"
#include "asset.h"
using json = nlohmann::json;
@@ -9,6 +11,12 @@ namespace lang
{
std::unordered_map<std::string, std::string> texts;
// Vector con los idiomas soportados
std::vector<Language> languages = {
{Code::SPANISH, "Castellano", "es_ES.json"},
{Code::VALENCIAN, "Balooncia", "ba_BA.json"},
{Code::ENGLISH, "Ingles", "en_UK.json"}};
// Inicializa los textos del juego en el idioma seleccionado
bool loadFromFile(const std::string &file_path)
{
@@ -50,8 +58,81 @@ namespace lang
// Obtiene el código del siguiente idioma disponible
Code getNextLangCode(Code lang)
{
auto index = static_cast<int>(lang);
index = (index + 1) % 3;
return static_cast<Code>(index);
for (size_t i = 0; i < languages.size(); ++i)
{
if (languages[i].code == lang)
{
return languages[(i + 1) % languages.size()].code;
}
}
// Si no se encuentra, devuelve el primero por defecto
return languages[0].code;
}
// Obtiene un idioma del vector de idiomas a partir de un código
Language getLanguage(Code code)
{
for (const auto &lang : languages)
{
if (lang.code == code)
return lang;
}
// Si no se encuentra, devuelve el primero por defecto
return languages[0];
}
// Devuelve el código de un idioma a partir de un nombre
Code getCodeFromName(const std::string& name)
{
for (const auto& lang : languages)
{
if (lang.name == name)
return lang.code;
}
// Si no se encuentra, devuelve el primero por defecto
return languages[0].code;
}
// Actualiza los nombres de los idiomas
void updateLanguageNames()
{
for (auto &lang : languages)
{
switch (lang.code)
{
case Code::SPANISH:
lang.name = lang::getText("[SERVICE_MENU] LANG ES");
break;
case Code::VALENCIAN:
lang.name = lang::getText("[SERVICE_MENU] LANG BA");
break;
case Code::ENGLISH:
lang.name = lang::getText("[SERVICE_MENU] LANG EN");
break;
default:
lang.name = "Unknown";
break;
}
}
}
// Obtiene una fichero a partir de un lang::Code
std::string getLanguageFileName(lang::Code code)
{
for (const auto &lang : languages)
{
if (lang.code == code)
return Asset::get()->get(lang.file_name);
}
// Si no se encuentra, devuelve el fichero del primer idioma por defecto
return Asset::get()->get(languages[0].file_name);
}
// Establece el idioma
void setLanguage(Code lang)
{
options.game.language = lang;
loadFromFile(Asset::get()->get(getLanguage(lang).file_name));
updateLanguageNames();
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <vector>
namespace lang
{
@@ -12,12 +13,38 @@ namespace lang
ENGLISH = 2
};
// Estructura que representa un idioma
struct Language
{
Code code; // Código que identifica al idioma
std::string name; // Nombre que identifica el idioma
std::string file_name; // Nombre del fichero con los textos
Language(Code c, const std::string &n, const std::string &fn)
: code(c), name(n), file_name(fn) {}
};
// Carga los textos desde el fichero JSON especificado
bool loadFromFile(const std::string &file_path);
// Obtiene un texto a partir de una clave
// Obtiene el texto por clave
std::string getText(const std::string &key);
// Obtiene el código del siguiente idioma (circular)
Code getNextLangCode(Code lang);
Code getNextLangCode(Code current_lang);
// Obtiene el idioma correspondiente al código proporcionado
Language getLanguage(Code code);
// Devuelve el código de un idioma a partir de un nombre
Code getCodeFromName(const std::string& name);
// Actualiza los nombres de los idiomas
void updateLanguageNames();
// Obtiene el nombre del fichero de textos asociado a un código de idioma
std::string getLanguageFileName(Code code);
// Establece el idioma actual
void setLanguage(Code lang);
}

View File

@@ -47,6 +47,11 @@ void initOptions()
options.controllers.at(0).player_id = 1;
options.controllers.at(1).player_id = 2;
setKeyboardToPlayer(1);
// Opciones pendientes
options.pending_changes.new_language = options.game.language;
options.pending_changes.new_difficulty = options.game.difficulty;
options.pending_changes.has_pending_changes = false;
}
// Carga el fichero de configuración
@@ -115,6 +120,8 @@ bool saveOptionsFile(std::string file_path)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file: %s", getFileName(file_path).c_str());
applyPendingChanges();
// Opciones de video
file << "## VIDEO\n";
file << "## video.scale_mode [" << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_NEAREST) << ": nearest, " << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_LINEAR) << ": lineal]\n";
@@ -237,10 +244,12 @@ bool setOptions(const std::string &var, const std::string &value)
else if (var == "game.language")
{
options.game.language = static_cast<lang::Code>(std::stoi(value));
options.pending_changes.new_language = options.game.language;
}
else if (var == "game.difficulty")
{
options.game.difficulty = static_cast<GameDifficulty>(std::stoi(value));
options.pending_changes.new_difficulty = options.game.difficulty;
}
else if (var == "game.autofire")
{
@@ -366,3 +375,14 @@ int getPlayerWhoUsesKeyboard()
}
return 0;
}
// Aplica los cambios pendientes copiando los valores a sus variables
void applyPendingChanges()
{
if (options.pending_changes.has_pending_changes)
{
options.game.language = options.pending_changes.new_language;
options.game.difficulty = options.pending_changes.new_difficulty;
options.pending_changes.has_pending_changes = false;
}
}

View File

@@ -97,6 +97,14 @@ struct GamepadOptions
buttons{SDL_GAMEPAD_BUTTON_WEST, SDL_GAMEPAD_BUTTON_NORTH, SDL_GAMEPAD_BUTTON_EAST, SDL_GAMEPAD_BUTTON_START, SDL_GAMEPAD_BUTTON_BACK} {}
};
// --- Opciones pendientes de aplicar ---
struct PendingChanges
{
lang::Code new_language; // Idioma en espera de aplicar
GameDifficulty new_difficulty; // Dificultad en espera de aplicar
bool has_pending_changes = false; // Indica si hay cambios pendientes
};
// --- Opciones generales del programa ---
struct Options
{
@@ -105,6 +113,7 @@ struct Options
VideoOptions video; // Opciones de vídeo
AudioOptions audio; // Opciones de audio
std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador
PendingChanges pending_changes; // Opciones que se aplican al cerrar
};
// --- Variables globales ---
@@ -118,3 +127,4 @@ void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador
void swapOptionsKeyboard(); // Intercambia el teclado de jugador
void swapOptionsControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
int getPlayerWhoUsesKeyboard(); // Averigua quién está usando el teclado
void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables

View File

@@ -11,7 +11,7 @@ namespace section
// --- Enumeraciones de secciones del programa ---
enum class Name
{
INIT, // Inicialización
RESET, // Inicialización
LOGO, // Pantalla de logo
INTRO, // Introducción
TITLE, // Pantalla de título/menú principal

View File

@@ -38,7 +38,9 @@ void ServiceMenu::toggle()
{
enabled_ = !enabled_;
if (!enabled_)
{
reset();
}
}
// Dibuja el menú de servicio en pantalla
@@ -135,14 +137,8 @@ void ServiceMenu::setAnchors()
// Establce la posición donde empezar a escribir las opciones del menu
void ServiceMenu::setOptionsPosition()
{
/*
const size_t MAX_ENTRIES = findLargestGroupSize();
const size_t CURRENT_ENTRIES = display_options_.size();
const size_t ADDED_SPACE = ((MAX_ENTRIES - CURRENT_ENTRIES) * (options_height_ + options_padding_)) / 2;
options_y_ = rect_.y + upper_height_ + lower_padding_ + ADDED_SPACE;
*/
resize();
options_y_ = rect_.y + upper_height_ + lower_padding_;
resize();
options_y_ = rect_.y + upper_height_ + lower_padding_;
}
// Cambia el tamaño de la ventana de menu
@@ -222,11 +218,13 @@ void ServiceMenu::setSelectorDown()
void ServiceMenu::adjustOption(bool adjust_up)
{
if (display_options_.empty() || selected_ >= display_options_.size())
return;
if (display_options_.at(selected_).behavior == OptionBehavior::ADJUST)
{
display_options_.at(selected_).adjustValue(adjust_up);
return;
}
if (display_options_.at(selected_)->behavior == OptionBehavior::ADJUST)
{
display_options_.at(selected_)->adjustValue(adjust_up);
option_pairs_ = getOptionPairs(current_settings_group_);
applySettings(current_settings_group_);
playMenuSound();
@@ -237,13 +235,15 @@ void ServiceMenu::adjustOption(bool adjust_up)
void ServiceMenu::selectOption()
{
if (display_options_.empty() || selected_ >= display_options_.size())
{
return;
}
// Carpeta
if (display_options_.at(selected_).type == ValueType::FOLDER)
if (display_options_.at(selected_)->type == ValueType::FOLDER)
{
previous_settings_group_ = current_settings_group_;
current_settings_group_ = display_options_.at(selected_).target_group;
current_settings_group_ = display_options_.at(selected_)->target_group;
updateMenu(current_settings_group_);
selected_ = 0;
setOptionsPosition();
@@ -252,21 +252,21 @@ void ServiceMenu::selectOption()
}
// Opción
if (display_options_.at(selected_).behavior == OptionBehavior::SELECT)
if (display_options_.at(selected_)->behavior == OptionBehavior::SELECT)
{
if (display_options_.at(selected_).caption == lang::getText("[SERVICE_MENU] RESET"))
if (display_options_.at(selected_)->caption == lang::getText("[SERVICE_MENU] RESET"))
{
section::name = section::Name::INIT;
section::name = section::Name::RESET;
toggle();
return;
}
else if (display_options_.at(selected_).caption == lang::getText("[SERVICE_MENU] QUIT"))
else if (display_options_.at(selected_)->caption == lang::getText("[SERVICE_MENU] QUIT"))
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_WITH_KEYBOARD;
return;
}
else if (display_options_.at(selected_).caption == lang::getText("[SERVICE_MENU] SHUTDOWN"))
else if (display_options_.at(selected_)->caption == lang::getText("[SERVICE_MENU] SHUTDOWN"))
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_WITH_CONTROLLER;
@@ -314,6 +314,15 @@ void ServiceMenu::initializeOptions()
// Game
options_.emplace_back(lang::getText("[SERVICE_MENU] AUTOFIRE"), SettingsGroup::GAME, OptionBehavior::ADJUST, &options.game.autofire, ValueType::BOOL);
options_.emplace_back(
lang::getText("[SERVICE_MENU] LANGUAGE"),
SettingsGroup::GAME,
OptionBehavior::ADJUST,
&options.pending_changes.new_language,
std::vector<std::string>{
lang::getText("[SERVICE_MENU] LANG ES"),
lang::getText("[SERVICE_MENU] LANG BA"),
lang::getText("[SERVICE_MENU] LANG EN")});
// System
options_.emplace_back(lang::getText("[SERVICE_MENU] RESET"), SettingsGroup::SYSTEM, OptionBehavior::SELECT, nullptr, ValueType::NONE);
@@ -330,33 +339,31 @@ void ServiceMenu::initializeOptions()
// Devuelve las opciones del grupo como pares (nombre, valor)
ServiceMenu::OptionPairs ServiceMenu::getOptionPairs(ServiceMenu::SettingsGroup group) const
{
OptionPairs optionPairs;
OptionPairs option_pairs;
for (const auto &option : options_)
{
if (option.group == group)
{
optionPairs.emplace_back(option.caption, option.getValueAsString());
option_pairs.emplace_back(option.caption, option.getValueAsString());
}
}
return optionPairs;
return option_pairs;
}
// Devuelve las opciones del grupo como un vector de OptionEntry
std::vector<ServiceMenu::OptionEntry> ServiceMenu::getOptionsByGroup(SettingsGroup group) const
std::vector<ServiceMenu::OptionEntry *> ServiceMenu::getOptionsByGroup(SettingsGroup group)
{
std::vector<OptionEntry> filteredOptions;
for (const auto &option : options_)
std::vector<OptionEntry *> filtered_options;
for (auto &option : options_)
{
if (option.group == group)
{
filteredOptions.push_back(option);
filtered_options.push_back(&option);
}
}
return filteredOptions;
return filtered_options;
}
// Aplica la configuración correspondiente al grupo seleccionado
@@ -367,11 +374,11 @@ void ServiceMenu::applySettings(ServiceMenu::SettingsGroup group)
case SettingsGroup::VIDEO:
Screen::get()->applySettings();
break;
case SettingsGroup::AUDIO:
Audio::get()->applySettings();
break;
case SettingsGroup::GAME:
break;
default:
break;
}
@@ -380,6 +387,7 @@ void ServiceMenu::applySettings(ServiceMenu::SettingsGroup group)
// Actualiza las opciones mostradas según el grupo seleccionado
void ServiceMenu::updateMenu(SettingsGroup group)
{
AdjustListValues();
option_pairs_ = getOptionPairs(group);
display_options_ = getOptionsByGroup(group);
}
@@ -423,8 +431,34 @@ ServiceMenu::GroupAlignment ServiceMenu::getGroupAlignment(SettingsGroup group)
case SettingsGroup::AUDIO:
case SettingsGroup::GAME:
return GroupAlignment::LEFT;
default:
return GroupAlignment::CENTERED;
}
}
// Devuelve un puntero a OptionEntry a partir del caption, o nullptr si no se encuentra
ServiceMenu::OptionEntry *ServiceMenu::getOptionEntryByCaption(const std::string &caption)
{
for (auto &option : options_)
{
if (option.caption == caption)
{
return &option;
}
}
return nullptr;
}
// Ajusta los valores de las opciones tipo lista
void ServiceMenu::AdjustListValues()
{
// Idioma
auto option = getOptionEntryByCaption(lang::getText("[SERVICE_MENU] LANGUAGE"));
for (size_t i = 0; i < option->value_list.size(); ++i)
{
if (lang::getCodeFromName(option->value_list[i]) == options.game.language)
{
option->list_index = i;
}
}
}

View File

@@ -7,6 +7,7 @@
#include <SDL3/SDL.h>
#include "utils.h"
#include "lang.h"
#include "options.h"
class Text;
@@ -68,6 +69,7 @@ private:
{
BOOL, // Valor booleano
INT, // Valor entero
LIST, // Lista de valores
FOLDER, // Referencia a otro grupo
NONE // Sin valor asociado
};
@@ -85,28 +87,35 @@ private:
SettingsGroup group; // Categoría de la opción
OptionBehavior behavior; // Cómo se interactúa con la opción
void *linked_variable; // Puntero a la variable que controla la opción
ValueType type; // Tipo de la variable (bool, int, folder, none)
ValueType type; // Tipo de la variable
int min_value; // Valor mínimo (solo aplicable si type == INT)
int max_value; // Valor máximo (solo aplicable si type == INT)
int step_value; // Incremento al modificar la opción (solo aplicable si type == INT)
int min_value; // Valor mínimo (solo aplicable si type == INT)
int max_value; // Valor máximo (solo aplicable si type == INT)
int step_value; // Incremento al modificar la opción (solo aplicable si type == INT)
std::vector<std::string> value_list; // Lista de valores posibles (solo aplicable si type == LIST)
size_t list_index; // Índice del valor seleccionado dentro de value_list
SettingsGroup target_group; // Grupo al que hace referencia la opción si es de tipo FOLDER
// Constructor para opciones de tipo BOOL, NONE o FOLDER
// Constructor para opciones de tipo BOOL, NONE, FOLDER
OptionEntry(std::string cap, SettingsGroup grp, OptionBehavior beh, void *var, ValueType t)
: caption(cap), group(grp), behavior(beh), linked_variable(var), type(t),
min_value(0), max_value(0), step_value(0), target_group(SettingsGroup::SYSTEM) {}
min_value(0), max_value(0), step_value(0), list_index(0), target_group(SettingsGroup::SYSTEM) {}
// Constructor para opciones de tipo INT con valores mínimos, máximos e incremento
// Constructor para opciones de tipo INT
OptionEntry(std::string cap, SettingsGroup grp, OptionBehavior beh, void *var, ValueType t, int min, int max, int step)
: caption(cap), group(grp), behavior(beh), linked_variable(var), type(t),
min_value(min), max_value(max), step_value(step), target_group(SettingsGroup::SYSTEM) {}
min_value(min), max_value(max), step_value(step), list_index(0), target_group(SettingsGroup::SYSTEM) {}
// Constructor para opciones de tipo FOLDER que referencian otro grupo
// Constructor para opciones de tipo LIST
OptionEntry(std::string cap, SettingsGroup grp, OptionBehavior beh, void *var, std::vector<std::string> values)
: caption(cap), group(grp), behavior(beh), linked_variable(var), type(ValueType::LIST),
min_value(0), max_value(0), step_value(0), value_list(values), list_index(0), target_group(SettingsGroup::SYSTEM) {}
// Constructor para opciones de tipo FOLDER
OptionEntry(std::string cap, SettingsGroup grp, OptionBehavior beh, SettingsGroup tgtGrp)
: caption(cap), group(grp), behavior(beh), linked_variable(nullptr), type(ValueType::FOLDER),
min_value(0), max_value(0), step_value(0), target_group(tgtGrp) {}
min_value(0), max_value(0), step_value(0), list_index(0), target_group(tgtGrp) {}
// Método para modificar el valor de la opción
void adjustValue(bool adjust_up)
@@ -124,6 +133,25 @@ private:
bool &value = *(static_cast<bool *>(linked_variable));
value = !value;
}
else if (type == ValueType::LIST && !value_list.empty())
{
list_index = adjust_up ? (list_index + 1) % value_list.size()
: (list_index - 1 + value_list.size()) % value_list.size();
// Idioma
if (linked_variable == &options.pending_changes.new_language)
{
options.pending_changes.new_language = lang::getCodeFromName(value_list[list_index]);
options.pending_changes.has_pending_changes = true;
}
// Dificultad
if (linked_variable == &options.pending_changes.new_difficulty)
{
// options.pending_changes.new_difficulty =
options.pending_changes.has_pending_changes = true;
}
}
}
}
@@ -136,6 +164,8 @@ private:
return (*(static_cast<bool *>(linked_variable))) ? lang::getText("[SERVICE_MENU] ON") : lang::getText("[SERVICE_MENU] OFF");
case ValueType::INT:
return std::to_string(*(static_cast<int *>(linked_variable)));
case ValueType::LIST:
return value_list.empty() ? "" : value_list[list_index];
default:
return "";
}
@@ -143,18 +173,18 @@ private:
};
// --- Variables internas ---
bool enabled_ = false; // Indica si el menú de servicio está activo
SDL_FRect rect_; // Rectángulo que define el área del menú de servicio
std::shared_ptr<Text> element_text_; // Objeto para escribir el texto de los elementos
std::shared_ptr<Text> title_text_; // Objeto para escribir el texto del título
size_t selected_ = 0; // Índice del elemento del menú seleccionado
Uint32 counter_ = 0; // Contador interno
std::vector<OptionEntry> options_; // Listado con todas las opciones del menú de servicio
std::vector<OptionEntry> display_options_; // Opciones actualmente mostradas en pantalla
OptionPairs option_pairs_; // Opciones actuales del menú (filtradas por grupo)
SettingsGroup current_settings_group_; // Grupo de opciones actualmente activo
SettingsGroup previous_settings_group_; // Grupo de opciones anterior
Aspect aspect_ = Aspect::ASPECT1; // Estilo visual del menú
bool enabled_ = false; // Indica si el menú de servicio está activo
SDL_FRect rect_; // Rectángulo que define el área del menú de servicio
std::shared_ptr<Text> element_text_; // Objeto para escribir el texto de los elementos
std::shared_ptr<Text> title_text_; // Objeto para escribir el texto del título
size_t selected_ = 0; // Índice del elemento del menú seleccionado
Uint32 counter_ = 0; // Contador interno
std::vector<OptionEntry> options_; // Listado con todas las opciones del menú de servicio
std::vector<OptionEntry *> display_options_; // Opciones actualmente mostradas en pantalla (punteros)
OptionPairs option_pairs_; // Opciones actuales del menú (filtradas por grupo)
SettingsGroup current_settings_group_; // Grupo de opciones actualmente activo
SettingsGroup previous_settings_group_; // Grupo de opciones anterior
Aspect aspect_ = Aspect::ASPECT1; // Estilo visual del menú
// --- Variables de aspecto ---
Color bg_color_ = SERV_MENU_BG_COLOR; // Color de fondo
@@ -179,19 +209,21 @@ private:
void resize(); // Cambia el tamaño de la ventana de menu
// --- Métodos internos: Gestión de opciones ---
void initializeOptions(); // Crea todas las opciones del menú de servicio
OptionPairs getOptionPairs(SettingsGroup group) const; // Devuelve las opciones como pares de strings para un grupo
std::vector<OptionEntry> getOptionsByGroup(SettingsGroup group) const; // Devuelve las opciones de un grupo
void initializeOptions(); // Crea todas las opciones del menú de servicio
OptionPairs getOptionPairs(SettingsGroup group) const; // Devuelve las opciones como pares de strings para un grupo
std::vector<OptionEntry *> getOptionsByGroup(SettingsGroup group); // Devuelve punteros a las opciones de un grupo
// --- Métodos internos: Lógica de menú ---
void applySettings(SettingsGroup group); // Aplica la configuración de un grupo
void updateMenu(SettingsGroup group); // Actualiza las opciones mostradas según el grupo
void AdjustListValues(); // Ajusta los valores de las opciones tipo lista
// --- Métodos internos: Utilidades ---
void updateCounter(); // Actualiza el contador interno
int calculateMenuHeight() const; // Calcula la altura del menú
int findLargestGroupSize() const; // Devuelve el tamaño del grupo más grande
GroupAlignment getGroupAlignment(SettingsGroup group) const; // Devuelve la alineación del grupo
void updateCounter(); // Actualiza el contador interno
int calculateMenuHeight() const; // Calcula la altura del menú
int findLargestGroupSize() const; // Devuelve el tamaño del grupo más grande
GroupAlignment getGroupAlignment(SettingsGroup group) const; // Devuelve la alineación del grupo
OptionEntry *getOptionEntryByCaption(const std::string &caption); // Devuelve un puntero a OptionEntry a partir del caption
// --- Patrón Singleton ---
ServiceMenu(); // Constructor privado