From bc370c3b7d7a77586ca56a384ceb766b5ab742c1 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Tue, 5 Aug 2025 14:05:21 +0200 Subject: [PATCH] Afegides traduccions per a elements nous de service menu --- data/lang/ba_BA.json | 9 ++++ data/lang/en_UK.json | 10 ++++ data/lang/es_ES.json | 9 ++++ source/ui/menu_renderer.cpp | 100 ++++++++++++++++++++++++++++++++---- source/ui/menu_renderer.h | 9 +++- source/ui/service_menu.cpp | 16 +++--- 6 files changed, 134 insertions(+), 19 deletions(-) diff --git a/data/lang/ba_BA.json b/data/lang/ba_BA.json index cbce31e..1a69ad6 100644 --- a/data/lang/ba_BA.json +++ b/data/lang/ba_BA.json @@ -92,6 +92,15 @@ "[SERVICE_MENU] HARD": "Dificil", "[SERVICE_MENU] NEED_RESTART_MESSAGE": "Reiniciar per aplicar canvis", "[SERVICE_MENU] ENABLE_SHUTDOWN": "Permetre apagar el sistema", + "[SERVICE_MENU] CONTROLS": "Controls", + "[SERVICE_MENU] KEYBOARD": "Teclat", + "[SERVICE_MENU] PLAYER1": "Jugador 1", + "[SERVICE_MENU] PLAYER2": "Jugador 2", + "[SERVICE_MENU] CONTROLLER1": "Mando 1", + "[SERVICE_MENU] CONTROLLER2": "Mando 2", + "[SERVICE_MENU] CONFIGURE1": "Configurar Mando 1", + "[SERVICE_MENU] CONFIGURE2": "Configurar Mando 2", + "[SERVICE_MENU] NO_CONTROLLER": "Cap", "[SCOREBOARD] 1": "Jugador 1", "[SCOREBOARD] 2": "Jugador 2", diff --git a/data/lang/en_UK.json b/data/lang/en_UK.json index e5d6d88..42dd9e0 100644 --- a/data/lang/en_UK.json +++ b/data/lang/en_UK.json @@ -92,6 +92,16 @@ "[SERVICE_MENU] HARD": "Hard", "[SERVICE_MENU] NEED_RESTART_MESSAGE": "Restart to apply changes", "[SERVICE_MENU] ENABLE_SHUTDOWN": "Enable shutdown", + "[SERVICE_MENU] CONTROLS": "Controls", + "[SERVICE_MENU] KEYBOARD": "Keyboard", + "[SERVICE_MENU] PLAYER1": "Player 1", + "[SERVICE_MENU] PLAYER2": "Player 2", + "[SERVICE_MENU] CONTROLLER1": "Controller 1", + "[SERVICE_MENU] CONTROLLER2": "Controller 2", + "[SERVICE_MENU] CONFIGURE1": "Configure Controller 1", + "[SERVICE_MENU] CONFIGURE2": "Configure Controller 2", + "[SERVICE_MENU] NO_CONTROLLER": "None", + "[SCOREBOARD] 1": "Player 1", "[SCOREBOARD] 2": "Player 2", diff --git a/data/lang/es_ES.json b/data/lang/es_ES.json index 432fe6f..8dc479e 100644 --- a/data/lang/es_ES.json +++ b/data/lang/es_ES.json @@ -92,6 +92,15 @@ "[SERVICE_MENU] HARD": "Dificil", "[SERVICE_MENU] NEED_RESTART_MESSAGE": "Reiniciar para aplicar cambios", "[SERVICE_MENU] ENABLE_SHUTDOWN": "Permitir apagar el sistema", + "[SERVICE_MENU] CONTROLS": "Controles", + "[SERVICE_MENU] KEYBOARD": "Teclado", + "[SERVICE_MENU] PLAYER1": "Jugador 1", + "[SERVICE_MENU] PLAYER2": "Jugador 2", + "[SERVICE_MENU] CONTROLLER1": "Mando 1", + "[SERVICE_MENU] CONTROLLER2": "Mando 2", + "[SERVICE_MENU] CONFIGURE1": "Configurar Mando 1", + "[SERVICE_MENU] CONFIGURE2": "Configurar Mando 2", + "[SERVICE_MENU] NO_CONTROLLER": "Ninguno", "[SCOREBOARD] 1": "Jugador 1", "[SCOREBOARD] 2": "Jugador 2", diff --git a/source/ui/menu_renderer.cpp b/source/ui/menu_renderer.cpp index 72c5e9b..2da1da9 100644 --- a/source/ui/menu_renderer.cpp +++ b/source/ui/menu_renderer.cpp @@ -1,6 +1,6 @@ #include "menu_renderer.h" -#include // Para max +#include // Para max, min #include // Para pair, move #include "color.h" // Para Color, generateMirroredCycle, ColorCycleStyle @@ -8,10 +8,12 @@ #include "param.h" // Para Param, param, ParamServiceMenu, ParamGame #include "screen.h" // Para Screen #include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR -#include "utils.h" // Para Zone +#include "utils.h" // Para Zone, truncateWithEllipsis MenuRenderer::MenuRenderer(const ServiceMenu *menu_state, std::shared_ptr element_text, std::shared_ptr title_text) - : element_text_(std::move(element_text)), title_text_(std::move(title_text)) {} + : element_text_(std::move(element_text)), title_text_(std::move(title_text)) { + initializeMaxSizes(); +} void MenuRenderer::render(const ServiceMenu *menu_state) { // Dibuja la sombra @@ -48,11 +50,22 @@ void MenuRenderer::render(const ServiceMenu *menu_state) { const Color ¤t_color = IS_SELECTED ? param.service_menu.selected_color : param.service_menu.text_color; if (menu_state->getCurrentGroupAlignment() == ServiceMenu::GroupAlignment::LEFT) { + // Para opciones alineadas a la izquierda, truncamos el valor si es necesario + const int available_width = rect_.w - (ServiceMenu::OPTIONS_HORIZONTAL_PADDING * 2) - + element_text_->lenght(option_pairs.at(i).first, -2) - + ServiceMenu::MIN_GAP_OPTION_VALUE; + + const std::string truncated_value = getTruncatedValue(option_pairs.at(i).second, available_width); + element_text_->writeColored(rect_.x + ServiceMenu::OPTIONS_HORIZONTAL_PADDING, y, option_pairs.at(i).first, current_color, -2); - const int X = rect_.x + rect_.w - ServiceMenu::OPTIONS_HORIZONTAL_PADDING - element_text_->lenght(option_pairs.at(i).second, -2); - element_text_->writeColored(X, y, option_pairs.at(i).second, current_color, -2); + const int X = rect_.x + rect_.w - ServiceMenu::OPTIONS_HORIZONTAL_PADDING - element_text_->lenght(truncated_value, -2); + element_text_->writeColored(X, y, truncated_value, current_color, -2); } else { - element_text_->writeDX(TEXT_CENTER | TEXT_COLOR, rect_.x + rect_.w / 2, y, option_pairs.at(i).first, -2, current_color); + // Para opciones centradas, también truncamos si es necesario + const int available_width = rect_.w - (ServiceMenu::OPTIONS_HORIZONTAL_PADDING * 2); + const std::string truncated_caption = getTruncatedValue(option_pairs.at(i).first, available_width); + + element_text_->writeDX(TEXT_CENTER | TEXT_COLOR, rect_.x + rect_.w / 2, y, truncated_caption, -2, current_color); } y += options_height_ + options_padding_; } @@ -80,6 +93,13 @@ void MenuRenderer::setLayout(const ServiceMenu *menu_state) { setSize(menu_state); } +void MenuRenderer::initializeMaxSizes() { + // Establecemos los límites máximos basados en el tamaño de la pantalla + // Dejamos un margen del 10% en cada lado para que el menú no ocupe toda la pantalla + max_menu_width_ = static_cast(param.game.game_area.rect.w * 0.9f); + max_menu_height_ = static_cast(param.game.game_area.rect.h * 0.9f); +} + void MenuRenderer::setAnchors(const ServiceMenu *menu_state) { size_t max_entries = 0; for (int i = 0; i < 5; ++i) { @@ -102,10 +122,11 @@ void MenuRenderer::setAnchors(const ServiceMenu *menu_state) { } auto MenuRenderer::calculateNewRect(const ServiceMenu *menu_state) -> SDL_FRect { - width_ = getMenuWidthForGroup(menu_state->getCurrentGroup()); + width_ = std::min(static_cast(getMenuWidthForGroup(menu_state->getCurrentGroup())), max_menu_width_); + const auto &display_options = menu_state->getDisplayOptions(); lower_height_ = ((!display_options.empty() ? display_options.size() - 1 : 0) * (options_height_ + options_padding_)) + options_height_ + (lower_padding_ * 2); - height_ = upper_height_ + lower_height_; + height_ = std::min(upper_height_ + lower_height_, max_menu_height_); return {(param.game.width - width_) / 2.0F, (param.game.height - height_) / 2.0F, (float)width_, (float)height_}; } @@ -165,14 +186,21 @@ void MenuRenderer::precalculateMenuWidths(const std::vectorlenght(option->getCaption(), -2)); if (menu_state->getCurrentGroupAlignment() == ServiceMenu::GroupAlignment::LEFT) { - max_value_width = std::max(max_value_width, option->getMaxValueWidth(element_text_.get())); + // Para calcular el ancho máximo, necesitamos considerar la truncación + int max_available_value_width = static_cast(max_menu_width_) - max_option_width - + (ServiceMenu::OPTIONS_HORIZONTAL_PADDING * 2) - + ServiceMenu::MIN_GAP_OPTION_VALUE; + + int actual_value_width = getTruncatedValueWidth(option->getValueAsString(), max_available_value_width); + max_value_width = std::max(max_value_width, actual_value_width); } } size_t total_width = max_option_width + (ServiceMenu::OPTIONS_HORIZONTAL_PADDING * 2); if (menu_state->getCurrentGroupAlignment() == ServiceMenu::GroupAlignment::LEFT) { total_width += ServiceMenu::MIN_GAP_OPTION_VALUE + max_value_width; } - group_menu_widths_[group] = std::max((int)ServiceMenu::MIN_WIDTH, (int)total_width); + group_menu_widths_[group] = std::min(std::max((int)ServiceMenu::MIN_WIDTH, (int)total_width), + static_cast(max_menu_width_)); } } @@ -197,4 +225,56 @@ auto MenuRenderer::getAnimatedSelectedColor() const -> Color { auto MenuRenderer::setRect(SDL_FRect rect) -> SDL_FRect { border_rect_ = {rect.x - 1, rect.y + 1, rect.w + 2, rect.h - 2}; return rect; +} + +auto MenuRenderer::getTruncatedValueWidth(const std::string &value, int available_width) const -> int { + int value_width = element_text_->lenght(value, -2); + if (value_width <= available_width) { + return value_width; + } + + // Calculamos cuántos caracteres podemos mostrar más los puntos suspensivos + // Estimamos el ancho de los puntos suspensivos como 3 caracteres promedio + int ellipsis_width = element_text_->lenght("...", -2); + int available_for_text = available_width - ellipsis_width; + + if (available_for_text <= 0) { + return ellipsis_width; // Solo mostramos los puntos suspensivos + } + + // Calculamos aproximadamente cuántos caracteres caben + float char_width = static_cast(value_width) / value.length(); + size_t max_chars = static_cast(available_for_text / char_width); + + // Verificamos el ancho real del texto truncado + std::string truncated = truncateWithEllipsis(value, max_chars); + return element_text_->lenght(truncated, -2); +} + +auto MenuRenderer::getTruncatedValue(const std::string &value, int available_width) const -> std::string { + int value_width = element_text_->lenght(value, -2); + if (value_width <= available_width) { + return value; + } + + // Calculamos cuántos caracteres podemos mostrar + int ellipsis_width = element_text_->lenght("...", -2); + int available_for_text = available_width - ellipsis_width; + + if (available_for_text <= 0) { + return "..."; // Solo mostramos los puntos suspensivos + } + + // Calculamos aproximadamente cuántos caracteres caben + float char_width = static_cast(value_width) / value.length(); + size_t max_chars = static_cast(available_for_text / char_width); + + // Ajustamos iterativamente hasta que el texto quepa + std::string truncated = truncateWithEllipsis(value, max_chars); + while (element_text_->lenght(truncated, -2) > available_width && max_chars > 1) { + max_chars--; + truncated = truncateWithEllipsis(value, max_chars); + } + + return truncated; } \ No newline at end of file diff --git a/source/ui/menu_renderer.h b/source/ui/menu_renderer.h index f9ed3e3..7f51520 100644 --- a/source/ui/menu_renderer.h +++ b/source/ui/menu_renderer.h @@ -49,6 +49,10 @@ class MenuRenderer { size_t lower_padding_ = 0; Uint32 color_counter_ = 0; + // --- Límites de tamaño máximo --- + size_t max_menu_width_ = 0; + size_t max_menu_height_ = 0; + // --- Variables para animación de resize --- SDL_FRect rect_anim_from_{}; SDL_FRect rect_anim_to_{}; @@ -60,6 +64,7 @@ class MenuRenderer { std::array group_menu_widths_ = {}; // --- Métodos privados de la vista --- + void initializeMaxSizes(); void setAnchors(const ServiceMenu *menu_state); auto calculateNewRect(const ServiceMenu *menu_state) -> SDL_FRect; void resize(const ServiceMenu *menu_state); @@ -70,4 +75,6 @@ class MenuRenderer { [[nodiscard]] auto getAnimatedSelectedColor() const -> Color; void updateColorCounter(); auto setRect(SDL_FRect rect) -> SDL_FRect; -}; + [[nodiscard]] auto getTruncatedValueWidth(const std::string &value, int available_width) const -> int; + [[nodiscard]] auto getTruncatedValue(const std::string &value, int available_width) const -> std::string; +}; \ No newline at end of file diff --git a/source/ui/service_menu.cpp b/source/ui/service_menu.cpp index 5c38e06..e17c6d6 100644 --- a/source/ui/service_menu.cpp +++ b/source/ui/service_menu.cpp @@ -247,7 +247,7 @@ void ServiceMenu::initializeOptions() { // CONTROLS options_.push_back(std::make_unique( - "Mando Jugador 1", + Lang::getText("[SERVICE_MENU] CONTROLLER1"), SettingsGroup::CONTROLS, Input::get()->getControllerNames(), []() { @@ -258,7 +258,7 @@ void ServiceMenu::initializeOptions() { })); options_.push_back(std::make_unique( - "Mando Jugador 2", + Lang::getText("[SERVICE_MENU] CONTROLLER2"), SettingsGroup::CONTROLS, Input::get()->getControllerNames(), []() { @@ -269,11 +269,11 @@ void ServiceMenu::initializeOptions() { })); options_.push_back(std::make_unique( - "Teclat", + Lang::getText("[SERVICE_MENU] KEYBOARD"), SettingsGroup::CONTROLS, std::vector{ - "Jugador 1", - "Jugador 2"}, + Lang::getText("[SERVICE_MENU] PLAYER1"), + Lang::getText("[SERVICE_MENU] PLAYER2")}, []() { return Lang::getNameFromCode(Options::pending_changes.new_language); }, @@ -410,7 +410,7 @@ void ServiceMenu::initializeOptions() { // MAIN MENU options_.push_back(std::make_unique( - "Controls", + Lang::getText("[SERVICE_MENU] CONTROLS"), SettingsGroup::MAIN, SettingsGroup::CONTROLS)); @@ -459,9 +459,9 @@ auto ServiceMenu::settingsGroupToString(SettingsGroup group) -> std::string { case SettingsGroup::MAIN: return Lang::getText("[SERVICE_MENU] TITLE"); case SettingsGroup::CONTROLS: - return Lang::getText("[SERVICE_MENU] TITLE"); + return Lang::getText("[SERVICE_MENU] CONTROLS"); case SettingsGroup::VIDEO: - return "Controls"; + return Lang::getText("[SERVICE_MENU] VIDEO"); case SettingsGroup::AUDIO: return Lang::getText("[SERVICE_MENU] AUDIO"); case SettingsGroup::SETTINGS: