Varios arreglos a tot lo de definir botons dins del service menu i lo de triar mando
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
"[DEFINE_BUTTONS] TITLE": "define buttons title",
|
||||
"[DEFINE_BUTTONS] FIRE_LEFT": "Disparar cap a l'esquerra",
|
||||
"[DEFINE_BUTTONS] FIRE_UP": "Disparar cap amunt amunt amunt amunt",
|
||||
"[DEFINE_BUTTONS] FIRE_UP": "Disparar cap amunt",
|
||||
"[DEFINE_BUTTONS] FIRE_RIGHT": "Disparar cap a la dreta",
|
||||
"[DEFINE_BUTTONS] START": "Start",
|
||||
"[DEFINE_BUTTONS] SERVICE_MENU": "Menu de servei",
|
||||
|
||||
@@ -24,7 +24,7 @@ DefineButtons::DefineButtons()
|
||||
|
||||
// Crear la ventana de mensaje
|
||||
WindowMessage::Config config;
|
||||
config.bg_color = Color{20, 30, 50, 224}; // Fondo azul oscuro semi-transparente
|
||||
config.bg_color = Color{20, 30, 50, 240}; // Fondo azul oscuro semi-transparente
|
||||
config.border_color = Color{100, 150, 200, 255}; // Borde azul claro
|
||||
config.title_color = Color{100, 150, 200, 255}; // Titulo azul claro
|
||||
config.text_color = Color{220, 220, 220, 255}; // Texto gris claro
|
||||
@@ -157,8 +157,8 @@ void DefineButtons::checkEnd() {
|
||||
if (window_message_) {
|
||||
window_message_->clearTexts();
|
||||
window_message_->addText(Lang::getText("[DEFINE_BUTTONS] CONFIGURATION_COMPLETE"));
|
||||
window_message_->autoSize();
|
||||
window_message_->centerOnScreen();
|
||||
//window_message_->autoSize();
|
||||
//window_message_->centerOnScreen();
|
||||
}
|
||||
|
||||
// Se deshabilitará desde el ServiceMenu después de un breve delay
|
||||
@@ -178,26 +178,9 @@ void DefineButtons::updateWindowMessage() {
|
||||
window_message_->clearTexts();
|
||||
|
||||
if (index_button_ < buttons_.size()) {
|
||||
// Mostrar progreso
|
||||
/*std::string progress = "(" + std::to_string(index_button_ + 1) + "/" +
|
||||
std::to_string(buttons_.size()) + ")";
|
||||
window_message_->addText(progress);
|
||||
window_message_->addText("");*/
|
||||
|
||||
// Instrucción actual
|
||||
std::string instruction = Lang::getText("[DEFINE_BUTTONS] PRESS_BUTTON_FOR") + ":";
|
||||
window_message_->addText(instruction);
|
||||
window_message_->addText(buttons_.at(index_button_).label);
|
||||
|
||||
// Botones ya configurados
|
||||
/*if (index_button_ > 0) {
|
||||
window_message_->addText("");
|
||||
window_message_->addText(Lang::getText("[DEFINE_BUTTONS] CONFIGURED") + ":");
|
||||
|
||||
for (size_t i = 0; i < index_button_; ++i) {
|
||||
std::string configured = "✓ " + buttons_[i].label;
|
||||
window_message_->addText(configured);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -30,16 +30,7 @@ void check(const SDL_Event &event) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ServiceMenu::get()->isEnabled()) {
|
||||
ServiceMenu::get()->handleEvent(event); // Método que vamos a crear
|
||||
|
||||
// Si DefineButtons está activo, no procesar más eventos
|
||||
if (ServiceMenu::get()->isDefiningButtons()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ServiceMenu::get()->handleEvent(event);
|
||||
Mouse::handleEvent(event);
|
||||
|
||||
static auto *input_ = Input::get();
|
||||
|
||||
@@ -183,95 +183,6 @@ auto checkServiceButton() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba las entradas del menú de servicio
|
||||
auto checkServiceInputs() -> bool {
|
||||
if (!ServiceMenu::get()->isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Teclado
|
||||
{
|
||||
// Arriba
|
||||
if (Input::get()->checkAction(Input::Action::UP, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
ServiceMenu::get()->setSelectorUp();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Abajo
|
||||
if (Input::get()->checkAction(Input::Action::DOWN, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
ServiceMenu::get()->setSelectorDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Derecha
|
||||
if (Input::get()->checkAction(Input::Action::RIGHT, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
ServiceMenu::get()->adjustOption(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Izquierda
|
||||
if (Input::get()->checkAction(Input::Action::LEFT, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
ServiceMenu::get()->adjustOption(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Aceptar
|
||||
if (Input::get()->checkAction(Input::Action::SM_SELECT, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
ServiceMenu::get()->selectOption();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Atras
|
||||
if (Input::get()->checkAction(Input::Action::SM_BACK, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
ServiceMenu::get()->moveBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Mandos
|
||||
{
|
||||
auto gamepads = Input::get()->getGamepads();
|
||||
for (auto gamepad : gamepads) {
|
||||
// Arriba
|
||||
if (Input::get()->checkAction(Input::Action::UP, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
ServiceMenu::get()->setSelectorUp();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Abajo
|
||||
if (Input::get()->checkAction(Input::Action::DOWN, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
ServiceMenu::get()->setSelectorDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Derecha
|
||||
if (Input::get()->checkAction(Input::Action::RIGHT, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
ServiceMenu::get()->adjustOption(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Izquierda
|
||||
if (Input::get()->checkAction(Input::Action::LEFT, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
ServiceMenu::get()->adjustOption(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Aceptar
|
||||
if (Input::get()->checkAction(Input::Action::SM_SELECT, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
ServiceMenu::get()->selectOption();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Atras
|
||||
if (Input::get()->checkAction(Input::Action::SM_BACK, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
ServiceMenu::get()->moveBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba las entradas fuera del menú de servicio
|
||||
auto checkInputs() -> bool {
|
||||
// Teclado
|
||||
@@ -370,7 +281,7 @@ auto check() -> bool {
|
||||
if (checkServiceButton()) {
|
||||
return true;
|
||||
}
|
||||
if (checkServiceInputs()) {
|
||||
if (ServiceMenu::get()->checkInput()) {
|
||||
return true;
|
||||
}
|
||||
if (checkInputs()) {
|
||||
|
||||
@@ -296,22 +296,28 @@ auto getGamepadInfo(Player::Id player_id) -> std::string {
|
||||
|
||||
// Asigna los mandos físicos basándose en la configuración actual.
|
||||
void GamepadManager::assignAndLinkGamepads() {
|
||||
// 1. Obtenemos todos los mandos físicos que están conectados ahora mismo.
|
||||
// 1. Obtenemos los mandos físicos conectados.
|
||||
auto physical_gamepads = Input::get()->getGamepads();
|
||||
|
||||
// 2. Reiniciamos las asignaciones actuales y guardamos los datos deseados de la config.
|
||||
// 2. Reiniciamos las asignaciones actuales.
|
||||
std::array<std::string, MAX_PLAYERS> desired_paths;
|
||||
for (size_t i = 0; i < MAX_PLAYERS; ++i) {
|
||||
desired_paths[i] = gamepads_[i].path;
|
||||
gamepads_[i].instance = nullptr;
|
||||
}
|
||||
|
||||
// 3. Vector para rastrear los mandos físicos que ya hemos asignado.
|
||||
// 3. Vector para rastrear los mandos ya asignados.
|
||||
std::vector<std::shared_ptr<Input::Gamepad>> assigned_instances;
|
||||
|
||||
// --- Ejecutamos las pasadas de asignación ---
|
||||
// --- Ejecutamos las pasadas de asignación y limpieza ---
|
||||
// Pasada 1: Intenta asignar por la ruta guardada.
|
||||
assignGamepadsByPath(desired_paths, physical_gamepads, assigned_instances);
|
||||
|
||||
// Pasada 2: Asigna los mandos restantes a los jugadores libres.
|
||||
assignRemainingGamepads(physical_gamepads, assigned_instances);
|
||||
|
||||
// Pasada 3: Limpia los datos de los slots que se quedaron sin mando.
|
||||
clearUnassignedGamepadSlots();
|
||||
}
|
||||
|
||||
// --- PRIMERA PASADA: Intenta asignar mandos basándose en la ruta guardada ---
|
||||
@@ -328,7 +334,12 @@ void GamepadManager::assignGamepadsByPath(
|
||||
// Buscamos un mando físico que coincida con la ruta y no esté ya asignado.
|
||||
for (const auto& physical_gamepad : physical_gamepads) {
|
||||
if (physical_gamepad->path == desired_path && !isGamepadAssigned(physical_gamepad, assigned_instances)) {
|
||||
|
||||
// Asignamos y actualizamos TODOS los datos.
|
||||
gamepads_[i].instance = physical_gamepad;
|
||||
gamepads_[i].name = physical_gamepad->name; // <--- LA LÍNEA QUE FALTABA
|
||||
// No es necesario actualizar la path aquí porque ya coincide.
|
||||
|
||||
assigned_instances.push_back(physical_gamepad);
|
||||
break; // Mando encontrado para este jugador, pasamos al siguiente.
|
||||
}
|
||||
@@ -361,6 +372,21 @@ void GamepadManager::assignRemainingGamepads(
|
||||
}
|
||||
}
|
||||
|
||||
// --- TERCERA PASADA: Limpia la información "fantasma" de los slots no asignados ---
|
||||
void GamepadManager::clearUnassignedGamepadSlots() {
|
||||
// Recorremos los slots de jugador una última vez.
|
||||
for (auto& gamepad_config : gamepads_) {
|
||||
// Si un slot no tiene una instancia física enlazada (instance == nullptr),
|
||||
// significa que no hay un mando para él.
|
||||
if (gamepad_config.instance == nullptr) {
|
||||
// Limpiamos sus datos de configuración para no mostrar información
|
||||
// de un mando que ya no está conectado.
|
||||
gamepad_config.name = "";
|
||||
gamepad_config.path = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Función auxiliar para comprobar si un mando físico ya está en la lista de asignados.
|
||||
// Devuelve 'true' si ya ha sido asignado, 'false' en caso contrario.
|
||||
auto GamepadManager::isGamepadAssigned(
|
||||
|
||||
@@ -238,6 +238,7 @@ class GamepadManager {
|
||||
void assignRemainingGamepads(
|
||||
const std::vector<std::shared_ptr<Input::Gamepad>>& physical_gamepads,
|
||||
std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances);
|
||||
void clearUnassignedGamepadSlots();
|
||||
[[nodiscard]] static auto isGamepadAssigned(
|
||||
const std::shared_ptr<Input::Gamepad>& physical_gamepad,
|
||||
const std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances) -> bool;
|
||||
|
||||
@@ -59,11 +59,6 @@ void MenuRenderer::render(const ServiceMenu *menu_state) {
|
||||
|
||||
std::string truncated_value = getTruncatedValue(option_pairs.at(i).second, available_width);
|
||||
|
||||
// Si la opción tiene Behavior::BOTH, añadir indicador visual
|
||||
if (i < display_options.size() && display_options[i]->getBehavior() == MenuOption::Behavior::BOTH) {
|
||||
truncated_value = "-" + truncated_value + "-";
|
||||
}
|
||||
|
||||
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_->length(truncated_value, -2);
|
||||
element_text_->writeColored(X, y, truncated_value, current_color, -2);
|
||||
@@ -72,11 +67,6 @@ void MenuRenderer::render(const ServiceMenu *menu_state) {
|
||||
const int available_width = rect_.w - (ServiceMenu::OPTIONS_HORIZONTAL_PADDING * 2);
|
||||
std::string truncated_caption = getTruncatedValue(option_pairs.at(i).first, available_width);
|
||||
|
||||
// Si la opción tiene Behavior::BOTH, añadir indicador visual
|
||||
if (i < display_options.size() && display_options[i]->getBehavior() == MenuOption::Behavior::BOTH) {
|
||||
truncated_caption = "-" + truncated_caption + "-";
|
||||
}
|
||||
|
||||
element_text_->writeDX(Text::CENTER | Text::COLOR, rect_.x + rect_.w / 2, y, truncated_caption, -2, current_color);
|
||||
}
|
||||
y += options_height_ + options_padding_;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <algorithm> // Para max
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "define_buttons.h" // Para DefineButtons
|
||||
#include "difficulty.h" // Para getCodeFromName, getNameFromCode
|
||||
#include "input.h" // Para Input
|
||||
#include "lang.h" // Para getText, getCodeFromName, getNameFromCode
|
||||
@@ -16,7 +17,6 @@
|
||||
#include "section.hpp" // Para Name, name, Options, options
|
||||
#include "ui/ui_message.h" // Para UIMessage
|
||||
#include "utils.h" // Para Zone
|
||||
#include "define_buttons.h" // Para DefineButtons
|
||||
|
||||
// Singleton
|
||||
ServiceMenu *ServiceMenu::instance = nullptr;
|
||||
@@ -39,6 +39,10 @@ ServiceMenu::ServiceMenu()
|
||||
}
|
||||
|
||||
void ServiceMenu::toggle() {
|
||||
if (define_buttons_ && define_buttons_->isEnabled()) {
|
||||
return; // No se puede mostrar u ocultar el menu de servicio si se estan definiendo los botones
|
||||
}
|
||||
|
||||
playBackSound();
|
||||
enabled_ = !enabled_;
|
||||
if (!enabled_) {
|
||||
@@ -85,9 +89,9 @@ void ServiceMenu::update() {
|
||||
// Si DefineButtons ha terminado, deshabilitarlo
|
||||
if (define_buttons_->isEnabled() && define_buttons_->isFinished()) {
|
||||
// Pequeño delay antes de cerrar
|
||||
static int finish_delay = 0;
|
||||
static size_t finish_delay = 0;
|
||||
finish_delay++;
|
||||
if (finish_delay > 60) { // 1 segundo a 60 FPS
|
||||
if (finish_delay > DEFINE_BUTTONS_FINISH_DELAY_FRAMES) {
|
||||
define_buttons_->disable();
|
||||
finish_delay = 0;
|
||||
}
|
||||
@@ -552,64 +556,93 @@ void ServiceMenu::handleEvent(const SDL_Event &event) {
|
||||
define_buttons_->checkEvents(event);
|
||||
return; // No procesar otros eventos mientras DefineButtons está activo
|
||||
}
|
||||
}
|
||||
|
||||
// Procesar eventos normales del ServiceMenu
|
||||
/*switch (event.type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
switch (event.key.key) {
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_BACKSPACE:
|
||||
moveBack();
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_KP_ENTER:
|
||||
selectOption();
|
||||
break;
|
||||
case SDLK_UP:
|
||||
bool ServiceMenu::checkInput() {
|
||||
if (!enabled_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (define_buttons_ && define_buttons_->isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto input = Input::get();
|
||||
// --- Teclado ---
|
||||
// Arriba
|
||||
if (input->checkAction(Input::Action::UP, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
setSelectorUp();
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
setSelectorDown();
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
adjustOption(false);
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
adjustOption(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
switch (event.gbutton.button) {
|
||||
case SDL_GAMEPAD_BUTTON_SOUTH:
|
||||
case SDL_GAMEPAD_BUTTON_BACK:
|
||||
moveBack();
|
||||
break;
|
||||
case SDL_GAMEPAD_BUTTON_EAST:
|
||||
case SDL_GAMEPAD_BUTTON_START:
|
||||
// Abajo
|
||||
if (input->checkAction(Input::Action::DOWN, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
setSelectorDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Derecha
|
||||
if (input->checkAction(Input::Action::RIGHT, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
adjustOption(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Izquierda
|
||||
if (input->checkAction(Input::Action::LEFT, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
adjustOption(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Aceptar
|
||||
if (input->checkAction(Input::Action::SM_SELECT, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
selectOption();
|
||||
break;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
||||
setSelectorUp();
|
||||
break;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
setSelectorDown();
|
||||
break;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
adjustOption(false);
|
||||
break;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
adjustOption(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}*/
|
||||
// Atras
|
||||
if (input->checkAction(Input::Action::SM_BACK, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||
moveBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Mandos ---
|
||||
auto gamepads = input->getGamepads();
|
||||
for (auto gamepad : gamepads) {
|
||||
// Arriba
|
||||
if (input->checkAction(Input::Action::UP, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
setSelectorUp();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Abajo
|
||||
if (input->checkAction(Input::Action::DOWN, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
setSelectorDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Derecha
|
||||
if (input->checkAction(Input::Action::RIGHT, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
adjustOption(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Izquierda
|
||||
if (input->checkAction(Input::Action::LEFT, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
adjustOption(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Aceptar
|
||||
if (input->checkAction(Input::Action::SM_SELECT, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
selectOption();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Atras
|
||||
if (input->checkAction(Input::Action::SM_BACK, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
moveBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -34,6 +34,7 @@ class ServiceMenu {
|
||||
static constexpr size_t MIN_WIDTH = 240;
|
||||
static constexpr size_t MIN_GAP_OPTION_VALUE = 30;
|
||||
static constexpr size_t SETTINGS_GROUP_SIZE = 6;
|
||||
static constexpr size_t DEFINE_BUTTONS_FINISH_DELAY_FRAMES = 60 * 3; // 3 segundo a 60 FPS
|
||||
|
||||
// --- Métodos de singleton ---
|
||||
static void init();
|
||||
@@ -56,8 +57,9 @@ class ServiceMenu {
|
||||
void moveBack();
|
||||
void checkEvents(const SDL_Event &event); // Nuevo método para eventos
|
||||
|
||||
// NUEVO: Método para manejar eventos (llamado desde GlobalEvents)
|
||||
// --- Método para manejar eventos (llamado desde GlobalEvents) ---
|
||||
void handleEvent(const SDL_Event &event);
|
||||
bool checkInput();
|
||||
|
||||
// NUEVO: Getter para saber si DefineButtons está activo
|
||||
[[nodiscard]] auto isDefiningButtons() const -> bool {
|
||||
|
||||
@@ -36,17 +36,20 @@ void WindowMessage::render() {
|
||||
SDL_RenderRect(renderer, &rect_);
|
||||
|
||||
float current_y = rect_.y + config_.padding;
|
||||
float available_width = getAvailableTextWidth();
|
||||
|
||||
// Dibujar título si existe
|
||||
if (!title_.empty()) {
|
||||
std::string visible_title = getTruncatedText(title_, available_width);
|
||||
text_renderer_->writeStyle(
|
||||
rect_.x + rect_.w / 2.0f,
|
||||
current_y,
|
||||
title_,
|
||||
visible_title,
|
||||
title_style_);
|
||||
current_y += text_renderer_->getCharacterSize() + config_.title_separator_spacing;
|
||||
|
||||
// Línea separadora debajo del título
|
||||
// Línea separadora debajo del título (solo si hay título visible)
|
||||
if (!visible_title.empty()) {
|
||||
SDL_SetRenderDrawColor(renderer, config_.border_color.r, config_.border_color.g,
|
||||
config_.border_color.b, config_.border_color.a);
|
||||
SDL_RenderLine(renderer,
|
||||
@@ -55,14 +58,18 @@ void WindowMessage::render() {
|
||||
rect_.x + rect_.w - config_.padding,
|
||||
current_y - config_.title_separator_spacing / 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Dibujar textos
|
||||
for (const auto& text : texts_) {
|
||||
std::string visible_text = getTruncatedText(text, available_width);
|
||||
if (!visible_text.empty()) {
|
||||
text_renderer_->writeStyle(
|
||||
rect_.x + rect_.w / 2.0f,
|
||||
current_y,
|
||||
text,
|
||||
visible_text,
|
||||
text_style_);
|
||||
}
|
||||
current_y += text_renderer_->getCharacterSize() + config_.line_spacing;
|
||||
}
|
||||
}
|
||||
@@ -285,3 +292,45 @@ auto WindowMessage::easeOut(float t) const -> float {
|
||||
// Función de suavizado ease-out cuadrática
|
||||
return 1.0f - (1.0f - t) * (1.0f - t);
|
||||
}
|
||||
|
||||
auto WindowMessage::getAvailableTextWidth() const -> float {
|
||||
// Ancho disponible = ancho total - padding en ambos lados
|
||||
return rect_.w - (config_.padding * 2.0f);
|
||||
}
|
||||
|
||||
auto WindowMessage::getTruncatedText(const std::string& text, float available_width) const -> std::string {
|
||||
if (text.empty()) {
|
||||
return text;
|
||||
}
|
||||
|
||||
// Si el texto completo cabe, devolverlo tal como está
|
||||
int text_width = text_renderer_->length(text, -2);
|
||||
if (text_width <= available_width) {
|
||||
return text;
|
||||
}
|
||||
|
||||
// Si no hay espacio suficiente, devolver string vacío
|
||||
if (available_width < 10.0f) { // Mínimo espacio para al menos un carácter
|
||||
return "";
|
||||
}
|
||||
|
||||
// Buscar cuántos caracteres caben usando búsqueda binaria
|
||||
int left = 0;
|
||||
int right = text.length();
|
||||
int best_length = 0;
|
||||
|
||||
while (left <= right) {
|
||||
int mid = (left + right) / 2;
|
||||
std::string partial = text.substr(0, mid);
|
||||
int partial_width = text_renderer_->length(partial, -2);
|
||||
|
||||
if (partial_width <= available_width) {
|
||||
best_length = mid;
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return text.substr(0, best_length);
|
||||
}
|
||||
@@ -169,6 +169,10 @@ class WindowMessage {
|
||||
// Función de suavizado (ease-out)
|
||||
[[nodiscard]] auto easeOut(float t) const -> float;
|
||||
|
||||
// Métodos para manejo de texto durante animación
|
||||
[[nodiscard]] auto getTruncatedText(const std::string& text, float available_width) const -> std::string;
|
||||
[[nodiscard]] auto getAvailableTextWidth() const -> float;
|
||||
|
||||
[[nodiscard]] auto calculateContentHeight() const -> float;
|
||||
[[nodiscard]] auto calculateContentWidth() const -> float;
|
||||
[[nodiscard]] auto getScreenWidth() const -> float;
|
||||
|
||||
Reference in New Issue
Block a user