Corregidos ~2570 issues automáticamente con clang-tidy --fix-errors más ajustes manuales posteriores: - modernize: designated-initializers, trailing-return-type, use-auto, avoid-c-arrays (→ std::array<>), use-ranges, use-emplace, deprecated-headers, use-equals-default, pass-by-value, return-braced-init-list, use-default-member-init - readability: math-missing-parentheses, implicit-bool-conversion, braces-around-statements, isolate-declaration, use-std-min-max, identifier-naming, else-after-return, redundant-casting, convert-member-functions-to-static, make-member-function-const, static-accessed-through-instance - performance: avoid-endl, unnecessary-value-param, type-promotion, inefficient-vector-operation - dead code: XOR_KEY (orphan tras eliminar encryptData/decryptData), dead stores en engine.cpp y png_shape.cpp - NOLINT justificado en 10 funciones con alta complejidad cognitiva (initialize, render, main, processEvents, update×3, performDemoAction, randomizeOnDemoStart, renderDebugHUD, AppLogo::update) Compilación: gcc -Wall sin warnings. clang-tidy: 0 issues. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
882 lines
40 KiB
C++
882 lines
40 KiB
C++
#include "theme_manager.hpp"
|
|
|
|
#include "themes/dynamic_theme.hpp"
|
|
#include "themes/static_theme.hpp"
|
|
|
|
// ============================================================================
|
|
// INICIALIZACIÓN
|
|
// ============================================================================
|
|
|
|
void ThemeManager::initialize() {
|
|
themes_.clear();
|
|
themes_.reserve(15); // 9 estáticos + 6 dinámicos
|
|
|
|
// ========================================
|
|
// TEMAS ESTÁTICOS (índices 0-8)
|
|
// ========================================
|
|
|
|
// 0: SUNSET (Atardecer) - Naranjas, rojos, amarillos, rosas
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Sunset",
|
|
"Atardecer",
|
|
255,
|
|
140,
|
|
60, // Color texto: naranja cálido
|
|
120,
|
|
40,
|
|
80, // Color fondo notificación: púrpura oscuro (contrasta con naranja)
|
|
180.0f / 255.0f,
|
|
140.0f / 255.0f,
|
|
100.0f / 255.0f, // Fondo superior: naranja suave
|
|
40.0f / 255.0f,
|
|
20.0f / 255.0f,
|
|
60.0f / 255.0f, // Fondo inferior: púrpura oscuro
|
|
std::vector<Color>{
|
|
{.r = 255, .g = 140, .b = 0},
|
|
{.r = 255, .g = 69, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 20, .b = 147},
|
|
{.r = 255, .g = 99, .b = 71},
|
|
{.r = 255, .g = 165, .b = 0},
|
|
{.r = 255, .g = 192, .b = 203},
|
|
{.r = 220, .g = 20, .b = 60}}));
|
|
|
|
// 1: OCEAN (Océano) - Azules, turquesas, blancos
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Ocean",
|
|
"Océano",
|
|
80,
|
|
200,
|
|
255, // Color texto: azul océano
|
|
20,
|
|
50,
|
|
90, // Color fondo notificación: azul marino oscuro (contrasta con cian)
|
|
100.0f / 255.0f,
|
|
150.0f / 255.0f,
|
|
200.0f / 255.0f, // Fondo superior: azul cielo
|
|
20.0f / 255.0f,
|
|
40.0f / 255.0f,
|
|
80.0f / 255.0f, // Fondo inferior: azul marino
|
|
std::vector<Color>{
|
|
{.r = 0, .g = 191, .b = 255},
|
|
{.r = 0, .g = 255, .b = 255},
|
|
{.r = 32, .g = 178, .b = 170},
|
|
{.r = 176, .g = 224, .b = 230},
|
|
{.r = 70, .g = 130, .b = 180},
|
|
{.r = 0, .g = 206, .b = 209},
|
|
{.r = 240, .g = 248, .b = 255},
|
|
{.r = 64, .g = 224, .b = 208}}));
|
|
|
|
// 2: NEON - Cian, magenta, verde lima, amarillo vibrante
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Neon",
|
|
"Neón",
|
|
255,
|
|
60,
|
|
255, // Color texto: magenta brillante
|
|
60,
|
|
0,
|
|
80, // Color fondo notificación: púrpura muy oscuro (contrasta con neón)
|
|
20.0f / 255.0f,
|
|
20.0f / 255.0f,
|
|
40.0f / 255.0f, // Fondo superior: negro azulado
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f, // Fondo inferior: negro
|
|
std::vector<Color>{
|
|
{.r = 0, .g = 255, .b = 255},
|
|
{.r = 255, .g = 0, .b = 255},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 255, .g = 255, .b = 0},
|
|
{.r = 255, .g = 20, .b = 147},
|
|
{.r = 0, .g = 255, .b = 127},
|
|
{.r = 138, .g = 43, .b = 226},
|
|
{.r = 255, .g = 69, .b = 0}}));
|
|
|
|
// 3: FOREST (Bosque) - Verdes, marrones, amarillos otoño
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Forest",
|
|
"Bosque",
|
|
100,
|
|
255,
|
|
100, // Color texto: verde natural
|
|
70,
|
|
50,
|
|
30, // Color fondo notificación: marrón oscuro tierra (contrasta con verde)
|
|
144.0f / 255.0f,
|
|
238.0f / 255.0f,
|
|
144.0f / 255.0f, // Fondo superior: verde claro
|
|
101.0f / 255.0f,
|
|
67.0f / 255.0f,
|
|
33.0f / 255.0f, // Fondo inferior: marrón tierra
|
|
std::vector<Color>{
|
|
{.r = 34, .g = 139, .b = 34},
|
|
{.r = 107, .g = 142, .b = 35},
|
|
{.r = 154, .g = 205, .b = 50},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 210, .g = 180, .b = 140},
|
|
{.r = 160, .g = 82, .b = 45},
|
|
{.r = 218, .g = 165, .b = 32},
|
|
{.r = 50, .g = 205, .b = 50}}));
|
|
|
|
// 4: RGB - Círculo cromático con 24 puntos (cada 15°)
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"RGB",
|
|
"RGB",
|
|
100,
|
|
100,
|
|
100, // Color texto: gris oscuro
|
|
220,
|
|
220,
|
|
220, // Color fondo notificación: gris muy claro (contrasta sobre blanco)
|
|
1.0f,
|
|
1.0f,
|
|
1.0f, // Fondo superior: blanco puro
|
|
1.0f,
|
|
1.0f,
|
|
1.0f, // Fondo inferior: blanco puro (sin degradado)
|
|
std::vector<Color>{
|
|
{.r = 255, .g = 0, .b = 0}, // 0° - Rojo puro
|
|
{.r = 255, .g = 64, .b = 0}, // 15° - Rojo-Naranja
|
|
{.r = 255, .g = 128, .b = 0}, // 30° - Naranja
|
|
{.r = 255, .g = 191, .b = 0}, // 45° - Naranja-Amarillo
|
|
{.r = 255, .g = 255, .b = 0}, // 60° - Amarillo puro
|
|
{.r = 191, .g = 255, .b = 0}, // 75° - Amarillo-Verde claro
|
|
{.r = 128, .g = 255, .b = 0}, // 90° - Verde-Amarillo
|
|
{.r = 64, .g = 255, .b = 0}, // 105° - Verde claro-Amarillo
|
|
{.r = 0, .g = 255, .b = 0}, // 120° - Verde puro
|
|
{.r = 0, .g = 255, .b = 64}, // 135° - Verde-Cian claro
|
|
{.r = 0, .g = 255, .b = 128}, // 150° - Verde-Cian
|
|
{.r = 0, .g = 255, .b = 191}, // 165° - Verde claro-Cian
|
|
{.r = 0, .g = 255, .b = 255}, // 180° - Cian puro
|
|
{.r = 0, .g = 191, .b = 255}, // 195° - Cian-Azul claro
|
|
{.r = 0, .g = 128, .b = 255}, // 210° - Azul-Cian
|
|
{.r = 0, .g = 64, .b = 255}, // 225° - Azul claro-Cian
|
|
{.r = 0, .g = 0, .b = 255}, // 240° - Azul puro
|
|
{.r = 64, .g = 0, .b = 255}, // 255° - Azul-Magenta claro
|
|
{.r = 128, .g = 0, .b = 255}, // 270° - Azul-Magenta
|
|
{.r = 191, .g = 0, .b = 255}, // 285° - Azul claro-Magenta
|
|
{.r = 255, .g = 0, .b = 255}, // 300° - Magenta puro
|
|
{.r = 255, .g = 0, .b = 191}, // 315° - Magenta-Rojo claro
|
|
{.r = 255, .g = 0, .b = 128}, // 330° - Magenta-Rojo
|
|
{.r = 255, .g = 0, .b = 64} // 345° - Magenta claro-Rojo
|
|
}));
|
|
|
|
// 5: MONOCHROME (Monocromo) - Fondo negro degradado, sprites blancos
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Monochrome",
|
|
"Monocromo",
|
|
200,
|
|
200,
|
|
200, // Color texto: gris claro
|
|
50,
|
|
50,
|
|
50, // Color fondo notificación: gris medio oscuro (contrasta con texto claro)
|
|
20.0f / 255.0f,
|
|
20.0f / 255.0f,
|
|
20.0f / 255.0f, // Fondo superior: gris muy oscuro
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f, // Fondo inferior: negro
|
|
std::vector<Color>{
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255},
|
|
{.r = 255, .g = 255, .b = 255}}));
|
|
|
|
// 6: LAVENDER (Lavanda) - Degradado violeta oscuro → azul medianoche, pelotas amarillo dorado
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Lavender",
|
|
"Lavanda",
|
|
255,
|
|
200,
|
|
100, // Color texto: amarillo cálido
|
|
80,
|
|
50,
|
|
100, // Color fondo notificación: violeta muy oscuro (contrasta con amarillo)
|
|
120.0f / 255.0f,
|
|
80.0f / 255.0f,
|
|
140.0f / 255.0f, // Fondo superior: violeta oscuro
|
|
25.0f / 255.0f,
|
|
30.0f / 255.0f,
|
|
60.0f / 255.0f, // Fondo inferior: azul medianoche
|
|
std::vector<Color>{
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0},
|
|
{.r = 255, .g = 215, .b = 0}}));
|
|
|
|
// 7: CRIMSON (Carmesí) - Fondo negro-rojo oscuro, pelotas rojas uniformes
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Crimson",
|
|
"Carmesí",
|
|
255,
|
|
100,
|
|
100, // Color texto: rojo claro
|
|
80,
|
|
10,
|
|
10, // Color fondo notificación: rojo muy oscuro (contrasta con texto claro)
|
|
40.0f / 255.0f,
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f, // Fondo superior: rojo muy oscuro
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f, // Fondo inferior: negro puro
|
|
std::vector<Color>{
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60},
|
|
{.r = 220, .g = 20, .b = 60}}));
|
|
|
|
// 8: EMERALD (Esmeralda) - Fondo negro-verde oscuro, pelotas verdes uniformes
|
|
themes_.push_back(std::make_unique<StaticTheme>(
|
|
"Emerald",
|
|
"Esmeralda",
|
|
100,
|
|
255,
|
|
100, // Color texto: verde claro
|
|
10,
|
|
80,
|
|
10, // Color fondo notificación: verde muy oscuro (contrasta con texto claro)
|
|
0.0f / 255.0f,
|
|
40.0f / 255.0f,
|
|
0.0f / 255.0f, // Fondo superior: verde muy oscuro
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f,
|
|
0.0f / 255.0f, // Fondo inferior: negro puro
|
|
std::vector<Color>{
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50},
|
|
{.r = 50, .g = 205, .b = 50}}));
|
|
|
|
// ========================================
|
|
// TEMAS DINÁMICOS (índices 9-14)
|
|
// ========================================
|
|
|
|
// 9: SUNRISE (Amanecer) - Noche → Alba → Día (loop)
|
|
themes_.push_back(std::make_unique<DynamicTheme>(
|
|
"Sunrise",
|
|
"Amanecer",
|
|
255,
|
|
200,
|
|
100, // Color texto: amarillo cálido
|
|
std::vector<DynamicThemeKeyframe>{
|
|
// Keyframe 0: Noche oscura (estado inicial)
|
|
{
|
|
.bg_top_r = 20.0f / 255.0f,
|
|
.bg_top_g = 25.0f / 255.0f,
|
|
.bg_top_b = 60.0f / 255.0f, // Fondo superior: azul medianoche
|
|
.bg_bottom_r = 10.0f / 255.0f,
|
|
.bg_bottom_g = 10.0f / 255.0f,
|
|
.bg_bottom_b = 30.0f / 255.0f, // Fondo inferior: azul muy oscuro
|
|
.notif_bg_r = 20,
|
|
.notif_bg_g = 30,
|
|
.notif_bg_b = 80, // Color fondo notificación: azul oscuro (noche)
|
|
.ball_colors = std::vector<Color>{
|
|
{.r = 100, .g = 100, .b = 150},
|
|
{.r = 120, .g = 120, .b = 170},
|
|
{.r = 90, .g = 90, .b = 140},
|
|
{.r = 110, .g = 110, .b = 160},
|
|
{.r = 95, .g = 95, .b = 145},
|
|
{.r = 105, .g = 105, .b = 155},
|
|
{.r = 100, .g = 100, .b = 150},
|
|
{.r = 115, .g = 115, .b = 165}},
|
|
.duration = 0.0f // Sin transición (estado inicial)
|
|
},
|
|
// Keyframe 1: Alba naranja-rosa
|
|
{
|
|
.bg_top_r = 180.0f / 255.0f,
|
|
.bg_top_g = 100.0f / 255.0f,
|
|
.bg_top_b = 120.0f / 255.0f, // Fondo superior: naranja-rosa
|
|
.bg_bottom_r = 255.0f / 255.0f,
|
|
.bg_bottom_g = 140.0f / 255.0f,
|
|
.bg_bottom_b = 100.0f / 255.0f, // Fondo inferior: naranja cálido
|
|
.notif_bg_r = 140,
|
|
.notif_bg_g = 60,
|
|
.notif_bg_b = 80, // Color fondo notificación: naranja-rojo oscuro (alba)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 180, .b = 100}, {.r = 255, .g = 160, .b = 80}, {.r = 255, .g = 200, .b = 120}, {.r = 255, .g = 150, .b = 90}, {.r = 255, .g = 190, .b = 110}, {.r = 255, .g = 170, .b = 95}, {.r = 255, .g = 185, .b = 105}, {.r = 255, .g = 165, .b = 88}},
|
|
.duration = 4.0f // 4 segundos para llegar aquí
|
|
},
|
|
// Keyframe 2: Día brillante amarillo
|
|
{
|
|
.bg_top_r = 255.0f / 255.0f,
|
|
.bg_top_g = 240.0f / 255.0f,
|
|
.bg_top_b = 180.0f / 255.0f, // Fondo superior: amarillo claro
|
|
.bg_bottom_r = 255.0f / 255.0f,
|
|
.bg_bottom_g = 255.0f / 255.0f,
|
|
.bg_bottom_b = 220.0f / 255.0f, // Fondo inferior: amarillo muy claro
|
|
.notif_bg_r = 200,
|
|
.notif_bg_g = 180,
|
|
.notif_bg_b = 140, // Color fondo notificación: amarillo oscuro (día)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 255, .b = 200}, {.r = 255, .g = 255, .b = 180}, {.r = 255, .g = 255, .b = 220}, {.r = 255, .g = 255, .b = 190}, {.r = 255, .g = 255, .b = 210}, {.r = 255, .g = 255, .b = 185}, {.r = 255, .g = 255, .b = 205}, {.r = 255, .g = 255, .b = 195}},
|
|
.duration = 3.0f // 3 segundos para llegar aquí
|
|
} // NOTA: Keyframe 3 (vuelta a noche) eliminado - loop=true lo maneja automáticamente
|
|
},
|
|
true // Loop = true
|
|
));
|
|
|
|
// 10: OCEAN WAVES (Olas Oceánicas) - Azul oscuro ↔ Turquesa (loop)
|
|
themes_.push_back(std::make_unique<DynamicTheme>(
|
|
"Ocean Waves",
|
|
"Olas Oceánicas",
|
|
100,
|
|
220,
|
|
255, // Color texto: cian claro
|
|
std::vector<DynamicThemeKeyframe>{
|
|
// Keyframe 0: Profundidad oceánica (azul oscuro)
|
|
{
|
|
.bg_top_r = 20.0f / 255.0f,
|
|
.bg_top_g = 50.0f / 255.0f,
|
|
.bg_top_b = 100.0f / 255.0f, // Fondo superior: azul marino
|
|
.bg_bottom_r = 10.0f / 255.0f,
|
|
.bg_bottom_g = 30.0f / 255.0f,
|
|
.bg_bottom_b = 60.0f / 255.0f, // Fondo inferior: azul muy oscuro
|
|
.notif_bg_r = 10,
|
|
.notif_bg_g = 30,
|
|
.notif_bg_b = 70, // Color fondo notificación: azul muy oscuro (profundidad)
|
|
.ball_colors = std::vector<Color>{
|
|
{.r = 60, .g = 100, .b = 180},
|
|
{.r = 50, .g = 90, .b = 170},
|
|
{.r = 70, .g = 110, .b = 190},
|
|
{.r = 55, .g = 95, .b = 175},
|
|
{.r = 65, .g = 105, .b = 185},
|
|
{.r = 58, .g = 98, .b = 172},
|
|
{.r = 62, .g = 102, .b = 182},
|
|
{.r = 52, .g = 92, .b = 168}},
|
|
.duration = 0.0f // Estado inicial
|
|
},
|
|
// Keyframe 1: Aguas poco profundas (turquesa brillante)
|
|
{
|
|
.bg_top_r = 100.0f / 255.0f,
|
|
.bg_top_g = 200.0f / 255.0f,
|
|
.bg_top_b = 230.0f / 255.0f, // Fondo superior: turquesa claro
|
|
.bg_bottom_r = 50.0f / 255.0f,
|
|
.bg_bottom_g = 150.0f / 255.0f,
|
|
.bg_bottom_b = 200.0f / 255.0f, // Fondo inferior: turquesa medio
|
|
.notif_bg_r = 30,
|
|
.notif_bg_g = 100,
|
|
.notif_bg_b = 140, // Color fondo notificación: turquesa oscuro (aguas poco profundas)
|
|
.ball_colors = std::vector<Color>{{.r = 100, .g = 220, .b = 255}, {.r = 90, .g = 210, .b = 245}, {.r = 110, .g = 230, .b = 255}, {.r = 95, .g = 215, .b = 250}, {.r = 105, .g = 225, .b = 255}, {.r = 98, .g = 218, .b = 248}, {.r = 102, .g = 222, .b = 252}, {.r = 92, .g = 212, .b = 242}},
|
|
.duration = 4.0f // 4 segundos para llegar
|
|
} // NOTA: Keyframe 2 (vuelta a profundidad) eliminado - loop=true lo maneja automáticamente
|
|
},
|
|
true // Loop = true
|
|
));
|
|
|
|
// 11: NEON PULSE (Pulso Neón) - Negro → Neón brillante (rápido ping-pong)
|
|
themes_.push_back(std::make_unique<DynamicTheme>(
|
|
"Neon Pulse",
|
|
"Pulso Neón",
|
|
255,
|
|
60,
|
|
255, // Color texto: magenta brillante
|
|
std::vector<DynamicThemeKeyframe>{
|
|
// Keyframe 0: Apagado (negro)
|
|
{
|
|
.bg_top_r = 0.0f / 255.0f,
|
|
.bg_top_g = 0.0f / 255.0f,
|
|
.bg_top_b = 0.0f / 255.0f, // Fondo superior: negro
|
|
.bg_bottom_r = 0.0f / 255.0f,
|
|
.bg_bottom_g = 0.0f / 255.0f,
|
|
.bg_bottom_b = 0.0f / 255.0f, // Fondo inferior: negro
|
|
.notif_bg_r = 30,
|
|
.notif_bg_g = 30,
|
|
.notif_bg_b = 30, // Color fondo notificación: gris muy oscuro (apagado)
|
|
.ball_colors = std::vector<Color>{
|
|
{.r = 40, .g = 40, .b = 40},
|
|
{.r = 50, .g = 50, .b = 50},
|
|
{.r = 45, .g = 45, .b = 45},
|
|
{.r = 48, .g = 48, .b = 48},
|
|
{.r = 42, .g = 42, .b = 42},
|
|
{.r = 47, .g = 47, .b = 47},
|
|
{.r = 44, .g = 44, .b = 44},
|
|
{.r = 46, .g = 46, .b = 46}},
|
|
.duration = 0.0f // Estado inicial
|
|
},
|
|
// Keyframe 1: Encendido (neón cian-magenta)
|
|
{
|
|
.bg_top_r = 20.0f / 255.0f,
|
|
.bg_top_g = 20.0f / 255.0f,
|
|
.bg_top_b = 40.0f / 255.0f, // Fondo superior: azul oscuro
|
|
.bg_bottom_r = 0.0f / 255.0f,
|
|
.bg_bottom_g = 0.0f / 255.0f,
|
|
.bg_bottom_b = 0.0f / 255.0f, // Fondo inferior: negro
|
|
.notif_bg_r = 60,
|
|
.notif_bg_g = 0,
|
|
.notif_bg_b = 80, // Color fondo notificación: púrpura oscuro (neón encendido)
|
|
.ball_colors = std::vector<Color>{{.r = 0, .g = 255, .b = 255}, {.r = 255, .g = 0, .b = 255}, {.r = 0, .g = 255, .b = 200}, {.r = 255, .g = 50, .b = 255}, {.r = 50, .g = 255, .b = 255}, {.r = 255, .g = 0, .b = 200}, {.r = 0, .g = 255, .b = 230}, {.r = 255, .g = 80, .b = 255}},
|
|
.duration = 1.5f // 1.5 segundos para encender (rápido)
|
|
} // NOTA: Keyframe 2 (vuelta a apagado) eliminado - loop=true crea ping-pong automáticamente
|
|
},
|
|
true // Loop = true
|
|
));
|
|
|
|
// 12: FIRE (Fuego Vivo) - Brasas → Llamas → Inferno (loop)
|
|
themes_.push_back(std::make_unique<DynamicTheme>(
|
|
"Fire",
|
|
"Fuego",
|
|
255,
|
|
150,
|
|
80, // Color texto: naranja cálido
|
|
std::vector<DynamicThemeKeyframe>{
|
|
// Keyframe 0: Brasas oscuras (estado inicial)
|
|
{
|
|
.bg_top_r = 60.0f / 255.0f,
|
|
.bg_top_g = 20.0f / 255.0f,
|
|
.bg_top_b = 10.0f / 255.0f, // Fondo superior: rojo muy oscuro
|
|
.bg_bottom_r = 20.0f / 255.0f,
|
|
.bg_bottom_g = 10.0f / 255.0f,
|
|
.bg_bottom_b = 0.0f / 255.0f, // Fondo inferior: casi negro
|
|
.notif_bg_r = 70,
|
|
.notif_bg_g = 20,
|
|
.notif_bg_b = 10, // Color fondo notificación: rojo muy oscuro (brasas)
|
|
.ball_colors = std::vector<Color>{
|
|
{.r = 120, .g = 40, .b = 20},
|
|
{.r = 140, .g = 35, .b = 15},
|
|
{.r = 130, .g = 38, .b = 18},
|
|
{.r = 125, .g = 42, .b = 22},
|
|
{.r = 135, .g = 37, .b = 16},
|
|
{.r = 128, .g = 40, .b = 20},
|
|
{.r = 132, .g = 39, .b = 19},
|
|
{.r = 138, .g = 36, .b = 17}},
|
|
.duration = 0.0f // Estado inicial
|
|
},
|
|
// Keyframe 1: Llamas naranjas (transición)
|
|
{
|
|
.bg_top_r = 180.0f / 255.0f,
|
|
.bg_top_g = 80.0f / 255.0f,
|
|
.bg_top_b = 20.0f / 255.0f, // Fondo superior: naranja fuerte
|
|
.bg_bottom_r = 100.0f / 255.0f,
|
|
.bg_bottom_g = 30.0f / 255.0f,
|
|
.bg_bottom_b = 10.0f / 255.0f, // Fondo inferior: rojo oscuro
|
|
.notif_bg_r = 110,
|
|
.notif_bg_g = 40,
|
|
.notif_bg_b = 10, // Color fondo notificación: naranja-rojo oscuro (llamas)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 140, .b = 0}, {.r = 255, .g = 120, .b = 10}, {.r = 255, .g = 160, .b = 20}, {.r = 255, .g = 130, .b = 5}, {.r = 255, .g = 150, .b = 15}, {.r = 255, .g = 125, .b = 8}, {.r = 255, .g = 145, .b = 12}, {.r = 255, .g = 135, .b = 18}},
|
|
.duration = 3.5f // 3.5 segundos para llegar
|
|
},
|
|
// Keyframe 2: Inferno brillante (clímax)
|
|
{
|
|
.bg_top_r = 255.0f / 255.0f,
|
|
.bg_top_g = 180.0f / 255.0f,
|
|
.bg_top_b = 80.0f / 255.0f, // Fondo superior: amarillo-naranja brillante
|
|
.bg_bottom_r = 220.0f / 255.0f,
|
|
.bg_bottom_g = 100.0f / 255.0f,
|
|
.bg_bottom_b = 30.0f / 255.0f, // Fondo inferior: naranja intenso
|
|
.notif_bg_r = 160,
|
|
.notif_bg_g = 80,
|
|
.notif_bg_b = 30, // Color fondo notificación: naranja oscuro (inferno)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 220, .b = 100}, {.r = 255, .g = 200, .b = 80}, {.r = 255, .g = 240, .b = 120}, {.r = 255, .g = 210, .b = 90}, {.r = 255, .g = 230, .b = 110}, {.r = 255, .g = 205, .b = 85}, {.r = 255, .g = 225, .b = 105}, {.r = 255, .g = 215, .b = 95}},
|
|
.duration = 3.0f // 3 segundos para llegar
|
|
},
|
|
// Keyframe 3: Vuelta a llamas (antes de reiniciar loop)
|
|
{
|
|
.bg_top_r = 180.0f / 255.0f,
|
|
.bg_top_g = 80.0f / 255.0f,
|
|
.bg_top_b = 20.0f / 255.0f, // Fondo superior: naranja fuerte
|
|
.bg_bottom_r = 100.0f / 255.0f,
|
|
.bg_bottom_g = 30.0f / 255.0f,
|
|
.bg_bottom_b = 10.0f / 255.0f, // Fondo inferior: rojo oscuro
|
|
.notif_bg_r = 110,
|
|
.notif_bg_g = 40,
|
|
.notif_bg_b = 10, // Color fondo notificación: naranja-rojo oscuro (llamas)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 140, .b = 0}, {.r = 255, .g = 120, .b = 10}, {.r = 255, .g = 160, .b = 20}, {.r = 255, .g = 130, .b = 5}, {.r = 255, .g = 150, .b = 15}, {.r = 255, .g = 125, .b = 8}, {.r = 255, .g = 145, .b = 12}, {.r = 255, .g = 135, .b = 18}},
|
|
.duration = 3.5f // 3.5 segundos para volver
|
|
} // Loop = true hará transición automática de keyframe 3 → keyframe 0
|
|
},
|
|
true // Loop = true (ciclo completo: brasas→llamas→inferno→llamas→brasas...)
|
|
));
|
|
|
|
// 13: AURORA (Aurora Boreal) - Verde → Violeta → Cian (loop)
|
|
themes_.push_back(std::make_unique<DynamicTheme>(
|
|
"Aurora",
|
|
"Aurora",
|
|
150,
|
|
255,
|
|
200, // Color texto: verde claro
|
|
std::vector<DynamicThemeKeyframe>{
|
|
// Keyframe 0: Verde aurora (estado inicial)
|
|
{
|
|
.bg_top_r = 30.0f / 255.0f,
|
|
.bg_top_g = 80.0f / 255.0f,
|
|
.bg_top_b = 60.0f / 255.0f, // Fondo superior: verde oscuro
|
|
.bg_bottom_r = 10.0f / 255.0f,
|
|
.bg_bottom_g = 20.0f / 255.0f,
|
|
.bg_bottom_b = 30.0f / 255.0f, // Fondo inferior: azul muy oscuro
|
|
.notif_bg_r = 15,
|
|
.notif_bg_g = 50,
|
|
.notif_bg_b = 40, // Color fondo notificación: verde muy oscuro (aurora verde)
|
|
.ball_colors = std::vector<Color>{
|
|
{.r = 100, .g = 255, .b = 180},
|
|
{.r = 80, .g = 240, .b = 160},
|
|
{.r = 120, .g = 255, .b = 200},
|
|
{.r = 90, .g = 245, .b = 170},
|
|
{.r = 110, .g = 255, .b = 190},
|
|
{.r = 85, .g = 242, .b = 165},
|
|
{.r = 105, .g = 252, .b = 185},
|
|
{.r = 95, .g = 248, .b = 175}},
|
|
.duration = 0.0f // Estado inicial
|
|
},
|
|
// Keyframe 1: Violeta aurora (transición)
|
|
{
|
|
.bg_top_r = 120.0f / 255.0f,
|
|
.bg_top_g = 60.0f / 255.0f,
|
|
.bg_top_b = 180.0f / 255.0f, // Fondo superior: violeta
|
|
.bg_bottom_r = 40.0f / 255.0f,
|
|
.bg_bottom_g = 20.0f / 255.0f,
|
|
.bg_bottom_b = 80.0f / 255.0f, // Fondo inferior: violeta oscuro
|
|
.notif_bg_r = 70,
|
|
.notif_bg_g = 30,
|
|
.notif_bg_b = 100, // Color fondo notificación: violeta oscuro (aurora violeta)
|
|
.ball_colors = std::vector<Color>{{.r = 200, .g = 100, .b = 255}, {.r = 180, .g = 80, .b = 240}, {.r = 220, .g = 120, .b = 255}, {.r = 190, .g = 90, .b = 245}, {.r = 210, .g = 110, .b = 255}, {.r = 185, .g = 85, .b = 242}, {.r = 205, .g = 105, .b = 252}, {.r = 195, .g = 95, .b = 248}},
|
|
.duration = 5.0f // 5 segundos para llegar (transición lenta)
|
|
},
|
|
// Keyframe 2: Cian aurora (clímax)
|
|
{
|
|
.bg_top_r = 60.0f / 255.0f,
|
|
.bg_top_g = 180.0f / 255.0f,
|
|
.bg_top_b = 220.0f / 255.0f, // Fondo superior: cian brillante
|
|
.bg_bottom_r = 20.0f / 255.0f,
|
|
.bg_bottom_g = 80.0f / 255.0f,
|
|
.bg_bottom_b = 120.0f / 255.0f, // Fondo inferior: azul oscuro
|
|
.notif_bg_r = 20,
|
|
.notif_bg_g = 90,
|
|
.notif_bg_b = 120, // Color fondo notificación: cian oscuro (aurora cian)
|
|
.ball_colors = std::vector<Color>{{.r = 100, .g = 220, .b = 255}, {.r = 80, .g = 200, .b = 240}, {.r = 120, .g = 240, .b = 255}, {.r = 90, .g = 210, .b = 245}, {.r = 110, .g = 230, .b = 255}, {.r = 85, .g = 205, .b = 242}, {.r = 105, .g = 225, .b = 252}, {.r = 95, .g = 215, .b = 248}},
|
|
.duration = 4.5f // 4.5 segundos para llegar
|
|
},
|
|
// Keyframe 3: Vuelta a violeta (antes de reiniciar)
|
|
{
|
|
.bg_top_r = 120.0f / 255.0f,
|
|
.bg_top_g = 60.0f / 255.0f,
|
|
.bg_top_b = 180.0f / 255.0f, // Fondo superior: violeta
|
|
.bg_bottom_r = 40.0f / 255.0f,
|
|
.bg_bottom_g = 20.0f / 255.0f,
|
|
.bg_bottom_b = 80.0f / 255.0f, // Fondo inferior: violeta oscuro
|
|
.notif_bg_r = 70,
|
|
.notif_bg_g = 30,
|
|
.notif_bg_b = 100, // Color fondo notificación: violeta oscuro (aurora violeta)
|
|
.ball_colors = std::vector<Color>{{.r = 200, .g = 100, .b = 255}, {.r = 180, .g = 80, .b = 240}, {.r = 220, .g = 120, .b = 255}, {.r = 190, .g = 90, .b = 245}, {.r = 210, .g = 110, .b = 255}, {.r = 185, .g = 85, .b = 242}, {.r = 205, .g = 105, .b = 252}, {.r = 195, .g = 95, .b = 248}},
|
|
.duration = 4.5f // 4.5 segundos para volver
|
|
} // Loop = true hará transición automática de keyframe 3 → keyframe 0
|
|
},
|
|
true // Loop = true (ciclo: verde→violeta→cian→violeta→verde...)
|
|
));
|
|
|
|
// 14: VOLCANIC (Erupción Volcánica) - Ceniza → Erupción → Lava (loop)
|
|
themes_.push_back(std::make_unique<DynamicTheme>(
|
|
"Volcanic",
|
|
"Volcán",
|
|
200,
|
|
120,
|
|
80, // Color texto: naranja apagado
|
|
std::vector<DynamicThemeKeyframe>{
|
|
// Keyframe 0: Ceniza oscura (pre-erupción)
|
|
{
|
|
.bg_top_r = 40.0f / 255.0f,
|
|
.bg_top_g = 40.0f / 255.0f,
|
|
.bg_top_b = 45.0f / 255.0f, // Fondo superior: gris oscuro
|
|
.bg_bottom_r = 20.0f / 255.0f,
|
|
.bg_bottom_g = 15.0f / 255.0f,
|
|
.bg_bottom_b = 15.0f / 255.0f, // Fondo inferior: casi negro
|
|
.notif_bg_r = 50,
|
|
.notif_bg_g = 50,
|
|
.notif_bg_b = 55, // Color fondo notificación: gris oscuro (ceniza)
|
|
.ball_colors = std::vector<Color>{
|
|
{.r = 80, .g = 80, .b = 90},
|
|
{.r = 75, .g = 75, .b = 85},
|
|
{.r = 85, .g = 85, .b = 95},
|
|
{.r = 78, .g = 78, .b = 88},
|
|
{.r = 82, .g = 82, .b = 92},
|
|
{.r = 76, .g = 76, .b = 86},
|
|
{.r = 84, .g = 84, .b = 94},
|
|
{.r = 79, .g = 79, .b = 89}},
|
|
.duration = 0.0f // Estado inicial
|
|
},
|
|
// Keyframe 1: Erupción naranja-roja (explosión)
|
|
{
|
|
.bg_top_r = 180.0f / 255.0f,
|
|
.bg_top_g = 60.0f / 255.0f,
|
|
.bg_top_b = 30.0f / 255.0f, // Fondo superior: naranja-rojo
|
|
.bg_bottom_r = 80.0f / 255.0f,
|
|
.bg_bottom_g = 20.0f / 255.0f,
|
|
.bg_bottom_b = 10.0f / 255.0f, // Fondo inferior: rojo oscuro
|
|
.notif_bg_r = 120,
|
|
.notif_bg_g = 30,
|
|
.notif_bg_b = 15, // Color fondo notificación: naranja-rojo oscuro (erupción)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 80, .b = 40}, {.r = 255, .g = 100, .b = 50}, {.r = 255, .g = 70, .b = 35}, {.r = 255, .g = 90, .b = 45}, {.r = 255, .g = 75, .b = 38}, {.r = 255, .g = 95, .b = 48}, {.r = 255, .g = 85, .b = 42}, {.r = 255, .g = 78, .b = 40}},
|
|
.duration = 3.0f // 3 segundos para erupción (rápido)
|
|
},
|
|
// Keyframe 2: Lava brillante (clímax)
|
|
{
|
|
.bg_top_r = 220.0f / 255.0f,
|
|
.bg_top_g = 120.0f / 255.0f,
|
|
.bg_top_b = 40.0f / 255.0f, // Fondo superior: naranja brillante
|
|
.bg_bottom_r = 180.0f / 255.0f,
|
|
.bg_bottom_g = 60.0f / 255.0f,
|
|
.bg_bottom_b = 20.0f / 255.0f, // Fondo inferior: naranja-rojo
|
|
.notif_bg_r = 150,
|
|
.notif_bg_g = 70,
|
|
.notif_bg_b = 25, // Color fondo notificación: naranja oscuro (lava)
|
|
.ball_colors = std::vector<Color>{{.r = 255, .g = 180, .b = 80}, {.r = 255, .g = 200, .b = 100}, {.r = 255, .g = 170, .b = 70}, {.r = 255, .g = 190, .b = 90}, {.r = 255, .g = 175, .b = 75}, {.r = 255, .g = 195, .b = 95}, {.r = 255, .g = 185, .b = 85}, {.r = 255, .g = 178, .b = 78}},
|
|
.duration = 3.5f // 3.5 segundos para lava máxima
|
|
},
|
|
// Keyframe 3: Enfriamiento (vuelta a ceniza gradual)
|
|
{
|
|
.bg_top_r = 100.0f / 255.0f,
|
|
.bg_top_g = 80.0f / 255.0f,
|
|
.bg_top_b = 70.0f / 255.0f, // Fondo superior: gris-naranja
|
|
.bg_bottom_r = 50.0f / 255.0f,
|
|
.bg_bottom_g = 40.0f / 255.0f,
|
|
.bg_bottom_b = 35.0f / 255.0f, // Fondo inferior: gris oscuro
|
|
.notif_bg_r = 80,
|
|
.notif_bg_g = 60,
|
|
.notif_bg_b = 50, // Color fondo notificación: gris-naranja oscuro (enfriamiento)
|
|
.ball_colors = std::vector<Color>{{.r = 150, .g = 120, .b = 100}, {.r = 140, .g = 110, .b = 90}, {.r = 160, .g = 130, .b = 110}, {.r = 145, .g = 115, .b = 95}, {.r = 155, .g = 125, .b = 105}, {.r = 142, .g = 112, .b = 92}, {.r = 158, .g = 128, .b = 108}, {.r = 148, .g = 118, .b = 98}},
|
|
.duration = 5.5f // 5.5 segundos para enfriamiento (lento)
|
|
} // Loop = true hará transición automática de keyframe 3 → keyframe 0
|
|
},
|
|
true // Loop = true (ciclo: ceniza→erupción→lava→enfriamiento→ceniza...)
|
|
));
|
|
}
|
|
|
|
// ============================================================================
|
|
// INTERFAZ UNIFICADA (PHASE 2)
|
|
// ============================================================================
|
|
|
|
void ThemeManager::switchToTheme(int theme_index) {
|
|
// Validar índice
|
|
if (theme_index < 0 || theme_index >= static_cast<int>(themes_.size())) {
|
|
return; // Índice inválido, no hacer nada
|
|
}
|
|
|
|
// Si ya estamos en ese tema, no hacer nada
|
|
if (theme_index == current_theme_index_ && !transitioning_) {
|
|
return;
|
|
}
|
|
|
|
// PHASE 3: Capturar snapshot del tema actual antes de cambiar
|
|
source_snapshot_ = captureCurrentSnapshot();
|
|
|
|
// Configurar transición LERP
|
|
source_theme_index_ = current_theme_index_;
|
|
target_theme_index_ = theme_index;
|
|
transitioning_ = true;
|
|
transition_progress_ = 0.0f;
|
|
|
|
// Cambiar tema activo (pero aún no visible por progress = 0.0)
|
|
current_theme_index_ = theme_index;
|
|
|
|
// Si es tema dinámico, reiniciar progreso
|
|
if (themes_[current_theme_index_]->needsUpdate()) {
|
|
themes_[current_theme_index_]->resetProgress();
|
|
}
|
|
}
|
|
|
|
void ThemeManager::update(float delta_time) {
|
|
// PHASE 3: Actualizar transición LERP si está activa
|
|
if (transitioning_) {
|
|
transition_progress_ += delta_time / transition_duration_;
|
|
|
|
if (transition_progress_ >= 1.0f) {
|
|
// Transición completada
|
|
transition_progress_ = 1.0f;
|
|
transitioning_ = false;
|
|
source_snapshot_.reset(); // Liberar snapshot (ya no se necesita)
|
|
}
|
|
}
|
|
|
|
// Actualizar animación del tema activo si es dinámico
|
|
if (themes_[current_theme_index_]->needsUpdate()) {
|
|
themes_[current_theme_index_]->update(delta_time);
|
|
}
|
|
}
|
|
|
|
void ThemeManager::cycleTheme() {
|
|
// Calcular siguiente tema con wraparound
|
|
int next_theme_index = (current_theme_index_ + 1) % static_cast<int>(themes_.size());
|
|
|
|
// Usar switchToTheme() para obtener transición LERP automáticamente
|
|
switchToTheme(next_theme_index);
|
|
}
|
|
|
|
void ThemeManager::cyclePrevTheme() {
|
|
// Calcular tema anterior con wraparound (14→13→...→1→0→14)
|
|
int prev_theme_index = (current_theme_index_ - 1);
|
|
if (prev_theme_index < 0) {
|
|
prev_theme_index = static_cast<int>(themes_.size()) - 1; // Wrap to último tema
|
|
}
|
|
|
|
// Usar switchToTheme() para obtener transición LERP automáticamente
|
|
switchToTheme(prev_theme_index);
|
|
}
|
|
|
|
void ThemeManager::pauseDynamic() {
|
|
// Solo funciona si el tema actual es dinámico
|
|
if (themes_[current_theme_index_]->needsUpdate()) {
|
|
themes_[current_theme_index_]->togglePause();
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// QUERIES DE COLORES
|
|
// ============================================================================
|
|
|
|
auto ThemeManager::getInterpolatedColor(size_t ball_index) const -> Color {
|
|
if (!transitioning_ || !source_snapshot_) {
|
|
// Sin transición: color directo del tema activo
|
|
return themes_[current_theme_index_]->getBallColor(ball_index, 0.0f);
|
|
}
|
|
|
|
// PHASE 3: Con transición: LERP entre snapshot origen y tema destino
|
|
Color source_color = source_snapshot_->ball_colors[ball_index % source_snapshot_->ball_colors.size()];
|
|
Color target_color = themes_[current_theme_index_]->getBallColor(ball_index, 0.0f);
|
|
|
|
return {
|
|
.r = static_cast<int>(lerp(static_cast<float>(source_color.r), static_cast<float>(target_color.r), transition_progress_)),
|
|
.g = static_cast<int>(lerp(static_cast<float>(source_color.g), static_cast<float>(target_color.g), transition_progress_)),
|
|
.b = static_cast<int>(lerp(static_cast<float>(source_color.b), static_cast<float>(target_color.b), transition_progress_))};
|
|
}
|
|
|
|
void ThemeManager::getBackgroundColors(float& top_r, float& top_g, float& top_b, float& bottom_r, float& bottom_g, float& bottom_b) const {
|
|
if (!transitioning_ || !source_snapshot_) {
|
|
// Sin transición: colores directos del tema activo
|
|
themes_[current_theme_index_]->getBackgroundColors(0.0f, top_r, top_g, top_b, bottom_r, bottom_g, bottom_b);
|
|
return;
|
|
}
|
|
|
|
// PHASE 3: Con transición: LERP entre snapshot origen y tema destino
|
|
float target_tr;
|
|
float target_tg;
|
|
float target_tb;
|
|
float target_br;
|
|
float target_bg;
|
|
float target_bb;
|
|
themes_[current_theme_index_]->getBackgroundColors(0.0f, target_tr, target_tg, target_tb, target_br, target_bg, target_bb);
|
|
|
|
top_r = lerp(source_snapshot_->bg_top_r, target_tr, transition_progress_);
|
|
top_g = lerp(source_snapshot_->bg_top_g, target_tg, transition_progress_);
|
|
top_b = lerp(source_snapshot_->bg_top_b, target_tb, transition_progress_);
|
|
|
|
bottom_r = lerp(source_snapshot_->bg_bottom_r, target_br, transition_progress_);
|
|
bottom_g = lerp(source_snapshot_->bg_bottom_g, target_bg, transition_progress_);
|
|
bottom_b = lerp(source_snapshot_->bg_bottom_b, target_bb, transition_progress_);
|
|
}
|
|
|
|
// ============================================================================
|
|
// QUERIES DE ESTADO
|
|
// ============================================================================
|
|
|
|
auto ThemeManager::isCurrentThemeDynamic() const -> bool {
|
|
return themes_[current_theme_index_]->needsUpdate();
|
|
}
|
|
|
|
auto ThemeManager::getCurrentThemeNameEN() const -> const char* {
|
|
return themes_[current_theme_index_]->getNameEN();
|
|
}
|
|
|
|
auto ThemeManager::getCurrentThemeNameES() const -> const char* {
|
|
return themes_[current_theme_index_]->getNameES();
|
|
}
|
|
|
|
void ThemeManager::getCurrentThemeTextColor(int& r, int& g, int& b) const {
|
|
if (!transitioning_ || !source_snapshot_) {
|
|
// Sin transición: color directo del tema activo
|
|
themes_[current_theme_index_]->getTextColor(r, g, b);
|
|
return;
|
|
}
|
|
|
|
// PHASE 3: Con transición: LERP entre snapshot origen y tema destino
|
|
int target_r;
|
|
int target_g;
|
|
int target_b;
|
|
themes_[current_theme_index_]->getTextColor(target_r, target_g, target_b);
|
|
|
|
r = static_cast<int>(lerp(static_cast<float>(source_snapshot_->text_color_r), static_cast<float>(target_r), transition_progress_));
|
|
g = static_cast<int>(lerp(static_cast<float>(source_snapshot_->text_color_g), static_cast<float>(target_g), transition_progress_));
|
|
b = static_cast<int>(lerp(static_cast<float>(source_snapshot_->text_color_b), static_cast<float>(target_b), transition_progress_));
|
|
}
|
|
|
|
void ThemeManager::getCurrentNotificationBackgroundColor(int& r, int& g, int& b) const {
|
|
if (!transitioning_ || !source_snapshot_) {
|
|
// Sin transición: color directo del tema activo
|
|
themes_[current_theme_index_]->getNotificationBackgroundColor(r, g, b);
|
|
return;
|
|
}
|
|
|
|
// PHASE 3: Con transición: LERP entre snapshot origen y tema destino
|
|
int target_r;
|
|
int target_g;
|
|
int target_b;
|
|
themes_[current_theme_index_]->getNotificationBackgroundColor(target_r, target_g, target_b);
|
|
|
|
r = static_cast<int>(lerp(static_cast<float>(source_snapshot_->notif_bg_r), static_cast<float>(target_r), transition_progress_));
|
|
g = static_cast<int>(lerp(static_cast<float>(source_snapshot_->notif_bg_g), static_cast<float>(target_g), transition_progress_));
|
|
b = static_cast<int>(lerp(static_cast<float>(source_snapshot_->notif_bg_b), static_cast<float>(target_b), transition_progress_));
|
|
}
|
|
|
|
auto ThemeManager::getInitialBallColor(int random_index) const -> Color {
|
|
// Obtener color inicial del tema activo (progress = 0.0f)
|
|
return themes_[current_theme_index_]->getBallColor(random_index, 0.0f);
|
|
}
|
|
|
|
// ============================================================================
|
|
// SISTEMA DE TRANSICIÓN LERP (PHASE 3)
|
|
// ============================================================================
|
|
|
|
auto ThemeManager::captureCurrentSnapshot() const -> std::unique_ptr<ThemeSnapshot> {
|
|
auto snapshot = std::make_unique<ThemeSnapshot>();
|
|
|
|
// Capturar colores de fondo
|
|
themes_[current_theme_index_]->getBackgroundColors(0.0f,
|
|
snapshot->bg_top_r,
|
|
snapshot->bg_top_g,
|
|
snapshot->bg_top_b,
|
|
snapshot->bg_bottom_r,
|
|
snapshot->bg_bottom_g,
|
|
snapshot->bg_bottom_b);
|
|
|
|
// Capturar color de texto
|
|
themes_[current_theme_index_]->getTextColor(
|
|
snapshot->text_color_r,
|
|
snapshot->text_color_g,
|
|
snapshot->text_color_b);
|
|
|
|
// Capturar color de fondo de notificaciones
|
|
themes_[current_theme_index_]->getNotificationBackgroundColor(
|
|
snapshot->notif_bg_r,
|
|
snapshot->notif_bg_g,
|
|
snapshot->notif_bg_b);
|
|
|
|
// Capturar nombres
|
|
snapshot->name_en = themes_[current_theme_index_]->getNameEN();
|
|
snapshot->name_es = themes_[current_theme_index_]->getNameES();
|
|
|
|
// Capturar colores de pelotas para el máximo real de esta sesión
|
|
// (SCENE_BALLS_8 o más si hay escenario custom)
|
|
snapshot->ball_colors.reserve(max_ball_count_);
|
|
for (int i = 0; i < max_ball_count_; i++) {
|
|
snapshot->ball_colors.push_back(
|
|
themes_[current_theme_index_]->getBallColor(i, 0.0f));
|
|
}
|
|
|
|
return snapshot;
|
|
}
|