diff --git a/source/define_buttons.cpp b/source/define_buttons.cpp index 2a5971a..256f833 100644 --- a/source/define_buttons.cpp +++ b/source/define_buttons.cpp @@ -28,13 +28,14 @@ DefineButtons::DefineButtons() 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 - config.padding = 15.0f; - config.line_spacing = 5.0f; + config.padding = 15.0F; + config.line_spacing = 5.0F; config.title_separator_spacing = 15; - config.min_width = 250.0f; - config.text_safety_margin = 15.0f; + config.min_width = 250.0F; + config.text_safety_margin = 15.0F; config.min_width = 100; config.min_height = 32; + config.animation_duration = 0.5F; auto text_renderer = Resource::get()->getText("04b_25_flat"); window_message_ = std::make_unique( @@ -157,8 +158,6 @@ void DefineButtons::checkEnd() { if (window_message_) { window_message_->clearTexts(); window_message_->addText(Lang::getText("[DEFINE_BUTTONS] CONFIGURATION_COMPLETE")); - //window_message_->autoSize(); - //window_message_->centerOnScreen(); } // Se deshabilitará desde el ServiceMenu después de un breve delay diff --git a/source/ui/service_menu.h b/source/ui/service_menu.h index 1c1f8d9..1ec6857 100644 --- a/source/ui/service_menu.h +++ b/source/ui/service_menu.h @@ -55,7 +55,6 @@ class ServiceMenu { void adjustOption(bool adjust_up); void selectOption(); void moveBack(); - void checkEvents(const SDL_Event &event); // Nuevo método para eventos // --- Método para manejar eventos (llamado desde GlobalEvents) --- void handleEvent(const SDL_Event &event); diff --git a/source/ui/window_message.cpp b/source/ui/window_message.cpp index c26183f..8423dc7 100644 --- a/source/ui/window_message.cpp +++ b/source/ui/window_message.cpp @@ -35,48 +35,53 @@ void WindowMessage::render() { config_.border_color.b, config_.border_color.a); SDL_RenderRect(renderer, &rect_); - float current_y = rect_.y + config_.padding; - float available_width = getAvailableTextWidth(); + // Solo mostrar contenido si no estamos en animación de show/hide + if (shouldShowContent()) { + 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, - visible_title, - title_style_); - current_y += text_renderer_->getCharacterSize() + config_.title_separator_spacing; + // Dibujar título si existe + if (!title_.empty()) { + std::string visible_title = getTruncatedText(title_, available_width); + if (!visible_title.empty()) { + text_renderer_->writeStyle( + rect_.x + rect_.w / 2.0f, + current_y, + visible_title, + title_style_); + } + current_y += text_renderer_->getCharacterSize() + config_.title_separator_spacing; - // 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, - rect_.x + config_.padding, - current_y - config_.title_separator_spacing / 2.0f, - rect_.x + rect_.w - config_.padding, - current_y - config_.title_separator_spacing / 2.0f); + // 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, + rect_.x + config_.padding, + current_y - config_.title_separator_spacing / 2.0f, + 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, - visible_text, - text_style_); + // 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, + visible_text, + text_style_); + } + current_y += text_renderer_->getCharacterSize() + config_.line_spacing; } - current_y += text_renderer_->getCharacterSize() + config_.line_spacing; } } void WindowMessage::update() { - // Actualizar animación de redimensionado - if (resize_animation_.active) { + // Actualizar animaciones + if (show_hide_animation_.active || resize_animation_.active) { // Aquí necesitarías el delta_time del game loop // Por ahora usamos un valor fijo, pero idealmente se pasaría como parámetro float delta_time = 1.0f / 60.0f; // Asumiendo 60 FPS @@ -85,12 +90,37 @@ void WindowMessage::update() { } void WindowMessage::show() { - ensureTextFits(); + if (visible_) { + return; // Ya visible + } + visible_ = true; + ensureTextFits(); + + // Detener cualquier animación anterior + resize_animation_.stop(); + + // Iniciar animación de mostrar desde tamaño 0 + show_hide_animation_.startShow(rect_.w, rect_.h); + rect_.w = 0.0f; + rect_.h = 0.0f; + updatePosition(); // Reposicionar con tamaño 0 } void WindowMessage::hide() { - visible_ = false; + if (!visible_) { + return; // Ya oculto + } + + // Detener cualquier animación anterior + resize_animation_.stop(); + + // Guardar el tamaño actual para la animación + show_hide_animation_.target_width = rect_.w; + show_hide_animation_.target_height = rect_.h; + + // Iniciar animación de ocultar hacia tamaño 0 + show_hide_animation_.startHide(); } void WindowMessage::setTitle(const std::string& title) { @@ -137,6 +167,10 @@ void WindowMessage::centerOnScreen() { } void WindowMessage::autoSize() { + if (show_hide_animation_.active) { + return; // No redimensionar durante show/hide + } + if (resize_animation_.active) { resize_animation_.stop(); // Detener animación anterior } @@ -263,13 +297,63 @@ void WindowMessage::triggerAutoResize() { } void WindowMessage::updateAnimation(float delta_time) { + if (show_hide_animation_.active) { + updateShowHideAnimation(delta_time); + } + + if (resize_animation_.active) { + updateResizeAnimation(delta_time); + } +} + +void WindowMessage::updateShowHideAnimation(float delta_time) { + if (!show_hide_animation_.active) { + return; + } + + show_hide_animation_.elapsed += delta_time; + + if (show_hide_animation_.isFinished(config_.animation_duration)) { + // Animación terminada + if (show_hide_animation_.type == ShowHideAnimation::Type::SHOWING) { + // Mostrar completado + rect_.w = show_hide_animation_.target_width; + rect_.h = show_hide_animation_.target_height; + } else if (show_hide_animation_.type == ShowHideAnimation::Type::HIDING) { + // Ocultar completado + rect_.w = 0.0f; + rect_.h = 0.0f; + visible_ = false; + } + + show_hide_animation_.stop(); + updatePosition(); + } else { + // Interpolar el tamaño + float progress = easeOut(show_hide_animation_.getProgress(config_.animation_duration)); + + if (show_hide_animation_.type == ShowHideAnimation::Type::SHOWING) { + // Crecer desde 0 hasta el tamaño objetivo + rect_.w = show_hide_animation_.target_width * progress; + rect_.h = show_hide_animation_.target_height * progress; + } else if (show_hide_animation_.type == ShowHideAnimation::Type::HIDING) { + // Decrecer desde el tamaño actual hasta 0 + rect_.w = show_hide_animation_.target_width * (1.0f - progress); + rect_.h = show_hide_animation_.target_height * (1.0f - progress); + } + + updatePosition(); // Mantener la posición centrada durante la animación + } +} + +void WindowMessage::updateResizeAnimation(float delta_time) { if (!resize_animation_.active) { return; } resize_animation_.elapsed += delta_time; - if (resize_animation_.isFinished()) { + if (resize_animation_.isFinished(config_.animation_duration)) { // Animación terminada rect_.w = resize_animation_.target_width; rect_.h = resize_animation_.target_height; @@ -277,7 +361,7 @@ void WindowMessage::updateAnimation(float delta_time) { updatePosition(); } else { // Interpolar el tamaño - float progress = easeOut(resize_animation_.getProgress()); + float progress = easeOut(resize_animation_.getProgress(config_.animation_duration)); rect_.w = resize_animation_.start_width + (resize_animation_.target_width - resize_animation_.start_width) * progress; @@ -288,6 +372,11 @@ void WindowMessage::updateAnimation(float delta_time) { } } +auto WindowMessage::shouldShowContent() const -> bool { + // No mostrar contenido durante animaciones de show/hide + return !show_hide_animation_.active; +} + auto WindowMessage::easeOut(float t) const -> float { // Función de suavizado ease-out cuadrática return 1.0f - (1.0f - t) * (1.0f - t); diff --git a/source/ui/window_message.h b/source/ui/window_message.h index b89aef5..d67d7e7 100644 --- a/source/ui/window_message.h +++ b/source/ui/window_message.h @@ -37,6 +37,9 @@ class WindowMessage { // Margen de seguridad para texto float text_safety_margin; // Margen extra para evitar texto cortado + // Animaciones + float animation_duration; // Duración en segundos para todas las animaciones + // Constructor con valores por defecto Config() : bg_color{40, 40, 60, 220} @@ -51,6 +54,7 @@ class WindowMessage { , max_width_ratio{0.8f} , max_height_ratio{0.8f} , text_safety_margin{20.0f} + , animation_duration{0.3f} {} }; @@ -68,6 +72,8 @@ class WindowMessage { void show(); void hide(); [[nodiscard]] auto isVisible() const -> bool { return visible_; } + [[nodiscard]] auto isFullyVisible() const -> bool { return visible_ && !show_hide_animation_.active; } + [[nodiscard]] auto isAnimating() const -> bool { return resize_animation_.active || show_hide_animation_.active; } // Configuración de contenido void setTitle(const std::string& title); @@ -128,7 +134,6 @@ class WindowMessage { bool active = false; float start_width, start_height; float target_width, target_height; - float duration = 0.3f; // segundos float elapsed = 0.0f; void start(float from_w, float from_h, float to_w, float to_h) { @@ -145,15 +150,53 @@ class WindowMessage { elapsed = 0.0f; } - [[nodiscard]] auto isFinished() const -> bool { + [[nodiscard]] auto isFinished(float duration) const -> bool { return elapsed >= duration; } - [[nodiscard]] auto getProgress() const -> float { + [[nodiscard]] auto getProgress(float duration) const -> float { return std::min(elapsed / duration, 1.0f); } } resize_animation_; + // Animación de mostrar/ocultar + struct ShowHideAnimation { + enum class Type { NONE, SHOWING, HIDING }; + + Type type = Type::NONE; + bool active = false; + float target_width, target_height; // Tamaño final al mostrar + float elapsed = 0.0f; + + void startShow(float to_w, float to_h) { + type = Type::SHOWING; + target_width = to_w; + target_height = to_h; + elapsed = 0.0f; + active = true; + } + + void startHide() { + type = Type::HIDING; + elapsed = 0.0f; + active = true; + } + + void stop() { + type = Type::NONE; + active = false; + elapsed = 0.0f; + } + + [[nodiscard]] auto isFinished(float duration) const -> bool { + return elapsed >= duration; + } + + [[nodiscard]] auto getProgress(float duration) const -> float { + return std::min(elapsed / duration, 1.0f); + } + } show_hide_animation_; + // Estilos Text::Style title_style_; Text::Style text_style_; @@ -165,6 +208,8 @@ class WindowMessage { void ensureTextFits(); // Verifica y ajusta para que todo el texto sea visible void triggerAutoResize(); // Inicia redimensionado automático si está habilitado void updateAnimation(float delta_time); // Actualiza la animación de redimensionado + void updateShowHideAnimation(float delta_time); // Actualiza la animación de mostrar/ocultar + void updateResizeAnimation(float delta_time); // Actualiza la animación de redimensionado // Función de suavizado (ease-out) [[nodiscard]] auto easeOut(float t) const -> float; @@ -172,6 +217,7 @@ class WindowMessage { // 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 shouldShowContent() const -> bool; // Si mostrar el contenido (texto, líneas, etc.) [[nodiscard]] auto calculateContentHeight() const -> float; [[nodiscard]] auto calculateContentWidth() const -> float;