Add: Sistema de notificaciones con colores de fondo temáticos
CARACTERÍSTICAS:
- Notificaciones con fondo personalizado por tema (15 temas)
- Soporte completo para temas estáticos y dinámicos
- Interpolación LERP de colores durante transiciones
- Actualización por frame durante animaciones de temas
IMPLEMENTACIÓN:
Theme System:
- Añadido getNotificationBackgroundColor() a interfaz Theme
- StaticTheme: Color fijo por tema
- DynamicTheme: Interpolación entre keyframes
- ThemeManager: LERP durante transiciones (PHASE 3)
- ThemeSnapshot: Captura color para transiciones suaves
Colores por Tema:
Estáticos (9):
- SUNSET: Púrpura oscuro (120, 40, 80)
- OCEAN: Azul marino (20, 50, 90)
- NEON: Púrpura oscuro (60, 0, 80)
- FOREST: Marrón tierra (70, 50, 30)
- RGB: Gris claro (220, 220, 220)
- MONOCHROME: Gris oscuro (50, 50, 50)
- LAVENDER: Violeta oscuro (80, 50, 100)
- CRIMSON: Rojo oscuro (80, 10, 10)
- EMERALD: Verde oscuro (10, 80, 10)
Dinámicos (6, 20 keyframes totales):
- SUNRISE: 3 keyframes (noche→alba→día)
- OCEAN_WAVES: 2 keyframes (profundo→claro)
- NEON_PULSE: 2 keyframes (apagado→encendido)
- FIRE: 4 keyframes (brasas→llamas→inferno→llamas)
- AURORA: 4 keyframes (verde→violeta→cian→violeta)
- VOLCANIC: 4 keyframes (ceniza→erupción→lava→enfriamiento)
Notifier:
- Añadido SDL_Color bg_color a estructura Notification
- Método show() acepta parámetro bg_color
- renderBackground() usa color dinámico (no negro fijo)
- Soporte para cambios de color cada frame
Engine:
- Obtiene color de fondo desde ThemeManager
- Pasa bg_color al notifier en cada notificación
- Sincronizado con tema activo y transiciones
FIXES:
- TEXT_ABSOLUTE_SIZE cambiado de 16px a 12px (múltiplo nativo)
- Centrado de notificaciones corregido en F3 fullscreen
- updatePhysicalWindowSize() usa SDL_GetCurrentDisplayMode en F3
- Notificaciones centradas correctamente en ventana/F3/F4
🎨 Generated with Claude Code
This commit is contained in:
@@ -96,6 +96,8 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
|
||||
// SDL ya inicializado arriba para validación
|
||||
{
|
||||
// Crear ventana principal (fullscreen si se especifica)
|
||||
// NOTA: SDL_WINDOW_HIGH_PIXEL_DENSITY removido por incompatibilidad con STRETCH mode (F4)
|
||||
// El DPI se detectará manualmente con SDL_GetWindowSizeInPixels()
|
||||
Uint32 window_flags = SDL_WINDOW_OPENGL;
|
||||
if (fullscreen) {
|
||||
window_flags |= SDL_WINDOW_FULLSCREEN;
|
||||
@@ -285,11 +287,14 @@ void Engine::update() {
|
||||
updateShape();
|
||||
}
|
||||
|
||||
// Actualizar texto (sin cambios en la lógica)
|
||||
// Actualizar texto (OBSOLETO: sistema antiguo, se mantiene por compatibilidad temporal)
|
||||
if (show_text_) {
|
||||
show_text_ = !(SDL_GetTicks() - text_init_time_ > TEXT_DURATION);
|
||||
}
|
||||
|
||||
// Actualizar sistema de notificaciones
|
||||
notifier_.update(current_time);
|
||||
|
||||
// Actualizar Modo DEMO (auto-play)
|
||||
updateDemoMode();
|
||||
|
||||
@@ -874,6 +879,10 @@ void Engine::render() {
|
||||
float text_scale_x = static_cast<float>(physical_window_width_) / static_cast<float>(current_screen_width_);
|
||||
float text_scale_y = static_cast<float>(physical_window_height_) / static_cast<float>(current_screen_height_);
|
||||
|
||||
// SISTEMA DE TEXTO ANTIGUO DESHABILITADO
|
||||
// Reemplazado completamente por el sistema de notificaciones (Notifier)
|
||||
// El doble renderizado causaba que aparecieran textos duplicados detrás de las notificaciones
|
||||
/*
|
||||
if (show_text_) {
|
||||
// Obtener datos del tema actual (delegado a ThemeManager)
|
||||
int text_color_r, text_color_g, text_color_b;
|
||||
@@ -898,6 +907,7 @@ void Engine::render() {
|
||||
text_renderer_.printPhysical(theme_x, theme_y, theme_name_es, text_color_r, text_color_g, text_color_b, text_scale_x, text_scale_y);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Debug display (solo si está activado con tecla H)
|
||||
if (show_debug_) {
|
||||
@@ -992,6 +1002,9 @@ void Engine::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// Renderizar notificaciones (siempre al final, sobre todo lo demás)
|
||||
notifier_.render();
|
||||
|
||||
SDL_RenderPresent(renderer_);
|
||||
}
|
||||
|
||||
@@ -1033,13 +1046,47 @@ void Engine::setText() {
|
||||
// Suprimir textos durante modos demo
|
||||
if (current_app_mode_ != AppMode::MANUAL) return;
|
||||
|
||||
// Generar texto de número de pelotas
|
||||
int num_balls = BALL_COUNT_SCENARIOS[scenario_];
|
||||
std::string notification_text;
|
||||
if (num_balls == 1) {
|
||||
text_ = "1 pelota";
|
||||
notification_text = "1 Pelota";
|
||||
} else if (num_balls < 1000) {
|
||||
notification_text = std::to_string(num_balls) + " Pelotas";
|
||||
} else {
|
||||
text_ = std::to_string(num_balls) + " pelotas";
|
||||
// Formato con separador de miles para números grandes
|
||||
notification_text = std::to_string(num_balls / 1000) + "," +
|
||||
(num_balls % 1000 < 100 ? "0" : "") +
|
||||
(num_balls % 1000 < 10 ? "0" : "") +
|
||||
std::to_string(num_balls % 1000) + " Pelotas";
|
||||
}
|
||||
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2; // Centrar texto
|
||||
|
||||
// Obtener color del tema actual para la notificación
|
||||
int text_r, text_g, text_b;
|
||||
theme_manager_->getCurrentThemeTextColor(text_r, text_g, text_b);
|
||||
SDL_Color notification_color = {
|
||||
static_cast<Uint8>(text_r),
|
||||
static_cast<Uint8>(text_g),
|
||||
static_cast<Uint8>(text_b),
|
||||
255
|
||||
};
|
||||
|
||||
// Obtener color de fondo de la notificación desde el tema
|
||||
int bg_r, bg_g, bg_b;
|
||||
theme_manager_->getCurrentNotificationBackgroundColor(bg_r, bg_g, bg_b);
|
||||
SDL_Color notification_bg_color = {
|
||||
static_cast<Uint8>(bg_r),
|
||||
static_cast<Uint8>(bg_g),
|
||||
static_cast<Uint8>(bg_b),
|
||||
255
|
||||
};
|
||||
|
||||
// Mostrar notificación
|
||||
notifier_.show(notification_text, NOTIFICATION_DURATION, notification_color, notification_bg_color);
|
||||
|
||||
// Sistema antiguo (mantener temporalmente para compatibilidad)
|
||||
text_ = notification_text;
|
||||
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
|
||||
show_text_ = true;
|
||||
text_init_time_ = SDL_GetTicks();
|
||||
}
|
||||
@@ -1136,6 +1183,9 @@ void Engine::toggleFullscreen() {
|
||||
|
||||
fullscreen_enabled_ = !fullscreen_enabled_;
|
||||
SDL_SetWindowFullscreen(window_, fullscreen_enabled_);
|
||||
|
||||
// Actualizar dimensiones físicas después del cambio
|
||||
updatePhysicalWindowSize();
|
||||
}
|
||||
|
||||
void Engine::toggleRealFullscreen() {
|
||||
@@ -1388,13 +1438,27 @@ void Engine::zoomOut() {
|
||||
|
||||
void Engine::updatePhysicalWindowSize() {
|
||||
if (real_fullscreen_enabled_) {
|
||||
// En fullscreen real, usar resolución del display
|
||||
// En fullscreen real (F4), usar resolución del display
|
||||
physical_window_width_ = current_screen_width_;
|
||||
physical_window_height_ = current_screen_height_;
|
||||
} else if (fullscreen_enabled_) {
|
||||
// En fullscreen F3, obtener tamaño REAL del display (no del framebuffer lógico)
|
||||
// SDL_GetRenderOutputSize() falla en F3 (devuelve tamaño lógico 960x720)
|
||||
// Necesitamos el tamaño FÍSICO real de la pantalla
|
||||
int num_displays = 0;
|
||||
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
||||
if (displays != nullptr && num_displays > 0) {
|
||||
const auto* dm = SDL_GetCurrentDisplayMode(displays[0]);
|
||||
if (dm != nullptr) {
|
||||
physical_window_width_ = dm->w;
|
||||
physical_window_height_ = dm->h;
|
||||
}
|
||||
SDL_free(displays);
|
||||
}
|
||||
} else {
|
||||
// En modo ventana, obtener tamaño real de la ventana (lógica * zoom)
|
||||
// En modo ventana, obtener tamaño FÍSICO real del framebuffer
|
||||
int window_w = 0, window_h = 0;
|
||||
SDL_GetWindowSize(window_, &window_w, &window_h);
|
||||
SDL_GetWindowSizeInPixels(window_, &window_w, &window_h);
|
||||
physical_window_width_ = window_w;
|
||||
physical_window_height_ = window_h;
|
||||
}
|
||||
@@ -1407,8 +1471,35 @@ void Engine::updatePhysicalWindowSize() {
|
||||
// Reinicializar TextRenderers con nuevo tamaño de fuente
|
||||
text_renderer_.cleanup();
|
||||
text_renderer_debug_.cleanup();
|
||||
text_renderer_notifier_.cleanup();
|
||||
|
||||
text_renderer_.init(renderer_, TEXT_FONT_PATH, font_size, TEXT_ANTIALIASING);
|
||||
text_renderer_debug_.init(renderer_, TEXT_FONT_PATH, font_size, TEXT_ANTIALIASING);
|
||||
|
||||
// TextRenderer para notificaciones: Detectar DPI y ajustar tamaño
|
||||
// En pantallas Retina/HiDPI, el texto necesita ser más grande para ser legible
|
||||
int logical_w = 0, logical_h = 0;
|
||||
SDL_GetWindowSize(window_, &logical_w, &logical_h);
|
||||
|
||||
// Usar physical_window_width_ que ya contiene el tamaño real del framebuffer
|
||||
// (calculado arriba con SDL_GetRenderOutputSize o current_screen_width_)
|
||||
int pixels_w = physical_window_width_;
|
||||
|
||||
// Calcular escala DPI (1.0 normal, 2.0 Retina, 3.0 en algunos displays)
|
||||
float dpi_scale = (logical_w > 0) ? static_cast<float>(pixels_w) / static_cast<float>(logical_w) : 1.0f;
|
||||
|
||||
// Ajustar tamaño de fuente base (16px) por escala DPI
|
||||
// Retina macOS: 16px * 2.0 = 32px (legible)
|
||||
// Normal: 16px * 1.0 = 16px
|
||||
int notification_font_size = static_cast<int>(TEXT_ABSOLUTE_SIZE * dpi_scale);
|
||||
if (notification_font_size < 12) notification_font_size = 12; // Mínimo legible
|
||||
|
||||
text_renderer_notifier_.init(renderer_, TEXT_FONT_PATH, notification_font_size, TEXT_ANTIALIASING);
|
||||
|
||||
// Inicializar/actualizar Notifier con nuevas dimensiones
|
||||
// NOTA: init() es seguro de llamar múltiples veces, solo actualiza punteros y dimensiones
|
||||
// Esto asegura que el notifier tenga las referencias correctas tras resize/fullscreen
|
||||
notifier_.init(renderer_, &text_renderer_notifier_, physical_window_width_, physical_window_height_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user