Add: Sistema de páginas para selección de temas + 5 nuevos temas

Implementación:
- 5 nuevos temas (2 estáticos: CRIMSON, EMERALD / 3 dinámicos: FIRE, AURORA, VOLCANIC)
- Sistema de páginas con Numpad Enter (Página 1 ↔ Página 2)
- Shift+B para ciclar temas hacia atrás
- Página 1: 9 temas estáticos + SUNRISE (Numpad 1-9, 0)
- Página 2: 5 temas dinámicos animados (Numpad 1-5)

Motivo:
- Shift+Numpad no funciona en Windows (limitación hardware/OS)
- Solución: Toggle de página con Numpad Enter

Archivos modificados:
- defines.h: Añadidos 5 nuevos ColorTheme enum values
- theme_manager.h: Añadido cyclePrevTheme() + actualizada doc 10→15 temas
- theme_manager.cpp: Implementados 5 nuevos temas + cyclePrevTheme()
- engine.h: Añadida variable theme_page_ (0 o 1)
- engine.cpp: Handlers Numpad Enter, KP_1-9,0 con sistema de páginas, SDLK_B con Shift detection
- CLAUDE.md: Documentación actualizada con tablas de 2 páginas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-09 18:04:13 +02:00
parent f1bafc8a4f
commit c50ecbc02a
6 changed files with 380 additions and 96 deletions

View File

@@ -9,10 +9,10 @@
void ThemeManager::initialize() {
themes_.clear();
themes_.reserve(10); // 7 estáticos + 3 dinámicos
themes_.reserve(15); // 9 estáticos + 6 dinámicos
// ========================================
// TEMAS ESTÁTICOS (índices 0-6)
// TEMAS ESTÁTICOS (índices 0-8)
// ========================================
// 0: SUNSET (Atardecer) - Naranjas, rojos, amarillos, rosas
@@ -128,11 +128,37 @@ void ThemeManager::initialize() {
}
));
// 7: CRIMSON (Carmesí) - Fondo negro-rojo oscuro, pelotas rojas uniformes
themes_.push_back(std::make_unique<StaticTheme>(
"CRIMSON",
"CARMESI",
255, 100, 100, // Color texto: rojo 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>{
{220, 20, 60}, {220, 20, 60}, {220, 20, 60}, {220, 20, 60},
{220, 20, 60}, {220, 20, 60}, {220, 20, 60}, {220, 20, 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
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>{
{50, 205, 50}, {50, 205, 50}, {50, 205, 50}, {50, 205, 50},
{50, 205, 50}, {50, 205, 50}, {50, 205, 50}, {50, 205, 50}
}
));
// ========================================
// TEMAS DINÁMICOS (índices 7-9)
// TEMAS DINÁMICOS (índices 9-14)
// ========================================
// 7: SUNRISE (Amanecer) - Noche → Alba → Día (loop)
// 9: SUNRISE (Amanecer) - Noche → Alba → Día (loop)
themes_.push_back(std::make_unique<DynamicTheme>(
"SUNRISE",
"AMANECER",
@@ -173,7 +199,7 @@ void ThemeManager::initialize() {
true // Loop = true
));
// 8: OCEAN WAVES (Olas Oceánicas) - Azul oscuro ↔ Turquesa (loop)
// 10: OCEAN WAVES (Olas Oceánicas) - Azul oscuro ↔ Turquesa (loop)
themes_.push_back(std::make_unique<DynamicTheme>(
"OCEAN WAVES",
"OLAS OCEANICAS",
@@ -204,7 +230,7 @@ void ThemeManager::initialize() {
true // Loop = true
));
// 9: NEON PULSE (Pulso Neón) - Negro → Neón brillante (rápido ping-pong)
// 11: NEON PULSE (Pulso Neón) - Negro → Neón brillante (rápido ping-pong)
themes_.push_back(std::make_unique<DynamicTheme>(
"NEON PULSE",
"PULSO NEON",
@@ -234,6 +260,159 @@ void ThemeManager::initialize() {
},
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)
{
60.0f / 255.0f, 20.0f / 255.0f, 10.0f / 255.0f, // Fondo superior: rojo muy oscuro
20.0f / 255.0f, 10.0f / 255.0f, 0.0f / 255.0f, // Fondo inferior: casi negro
std::vector<Color>{
{120, 40, 20}, {140, 35, 15}, {130, 38, 18}, {125, 42, 22},
{135, 37, 16}, {128, 40, 20}, {132, 39, 19}, {138, 36, 17}
},
0.0f // Estado inicial
},
// Keyframe 1: Llamas naranjas (transición)
{
180.0f / 255.0f, 80.0f / 255.0f, 20.0f / 255.0f, // Fondo superior: naranja fuerte
100.0f / 255.0f, 30.0f / 255.0f, 10.0f / 255.0f, // Fondo inferior: rojo oscuro
std::vector<Color>{
{255, 140, 0}, {255, 120, 10}, {255, 160, 20}, {255, 130, 5},
{255, 150, 15}, {255, 125, 8}, {255, 145, 12}, {255, 135, 18}
},
3.5f // 3.5 segundos para llegar
},
// Keyframe 2: Inferno brillante (clímax)
{
255.0f / 255.0f, 180.0f / 255.0f, 80.0f / 255.0f, // Fondo superior: amarillo-naranja brillante
220.0f / 255.0f, 100.0f / 255.0f, 30.0f / 255.0f, // Fondo inferior: naranja intenso
std::vector<Color>{
{255, 220, 100}, {255, 200, 80}, {255, 240, 120}, {255, 210, 90},
{255, 230, 110}, {255, 205, 85}, {255, 225, 105}, {255, 215, 95}
},
3.0f // 3 segundos para llegar
},
// Keyframe 3: Vuelta a llamas (antes de reiniciar loop)
{
180.0f / 255.0f, 80.0f / 255.0f, 20.0f / 255.0f, // Fondo superior: naranja fuerte
100.0f / 255.0f, 30.0f / 255.0f, 10.0f / 255.0f, // Fondo inferior: rojo oscuro
std::vector<Color>{
{255, 140, 0}, {255, 120, 10}, {255, 160, 20}, {255, 130, 5},
{255, 150, 15}, {255, 125, 8}, {255, 145, 12}, {255, 135, 18}
},
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)
{
30.0f / 255.0f, 80.0f / 255.0f, 60.0f / 255.0f, // Fondo superior: verde oscuro
10.0f / 255.0f, 20.0f / 255.0f, 30.0f / 255.0f, // Fondo inferior: azul muy oscuro
std::vector<Color>{
{100, 255, 180}, {80, 240, 160}, {120, 255, 200}, {90, 245, 170},
{110, 255, 190}, {85, 242, 165}, {105, 252, 185}, {95, 248, 175}
},
0.0f // Estado inicial
},
// Keyframe 1: Violeta aurora (transición)
{
120.0f / 255.0f, 60.0f / 255.0f, 180.0f / 255.0f, // Fondo superior: violeta
40.0f / 255.0f, 20.0f / 255.0f, 80.0f / 255.0f, // Fondo inferior: violeta oscuro
std::vector<Color>{
{200, 100, 255}, {180, 80, 240}, {220, 120, 255}, {190, 90, 245},
{210, 110, 255}, {185, 85, 242}, {205, 105, 252}, {195, 95, 248}
},
5.0f // 5 segundos para llegar (transición lenta)
},
// Keyframe 2: Cian aurora (clímax)
{
60.0f / 255.0f, 180.0f / 255.0f, 220.0f / 255.0f, // Fondo superior: cian brillante
20.0f / 255.0f, 80.0f / 255.0f, 120.0f / 255.0f, // Fondo inferior: azul oscuro
std::vector<Color>{
{100, 220, 255}, {80, 200, 240}, {120, 240, 255}, {90, 210, 245},
{110, 230, 255}, {85, 205, 242}, {105, 225, 252}, {95, 215, 248}
},
4.5f // 4.5 segundos para llegar
},
// Keyframe 3: Vuelta a violeta (antes de reiniciar)
{
120.0f / 255.0f, 60.0f / 255.0f, 180.0f / 255.0f, // Fondo superior: violeta
40.0f / 255.0f, 20.0f / 255.0f, 80.0f / 255.0f, // Fondo inferior: violeta oscuro
std::vector<Color>{
{200, 100, 255}, {180, 80, 240}, {220, 120, 255}, {190, 90, 245},
{210, 110, 255}, {185, 85, 242}, {205, 105, 252}, {195, 95, 248}
},
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",
"VOLCAN",
200, 120, 80, // Color texto: naranja apagado
std::vector<DynamicThemeKeyframe>{
// Keyframe 0: Ceniza oscura (pre-erupción)
{
40.0f / 255.0f, 40.0f / 255.0f, 45.0f / 255.0f, // Fondo superior: gris oscuro
20.0f / 255.0f, 15.0f / 255.0f, 15.0f / 255.0f, // Fondo inferior: casi negro
std::vector<Color>{
{80, 80, 90}, {75, 75, 85}, {85, 85, 95}, {78, 78, 88},
{82, 82, 92}, {76, 76, 86}, {84, 84, 94}, {79, 79, 89}
},
0.0f // Estado inicial
},
// Keyframe 1: Erupción naranja-roja (explosión)
{
180.0f / 255.0f, 60.0f / 255.0f, 30.0f / 255.0f, // Fondo superior: naranja-rojo
80.0f / 255.0f, 20.0f / 255.0f, 10.0f / 255.0f, // Fondo inferior: rojo oscuro
std::vector<Color>{
{255, 80, 40}, {255, 100, 50}, {255, 70, 35}, {255, 90, 45},
{255, 75, 38}, {255, 95, 48}, {255, 85, 42}, {255, 78, 40}
},
3.0f // 3 segundos para erupción (rápido)
},
// Keyframe 2: Lava brillante (clímax)
{
220.0f / 255.0f, 120.0f / 255.0f, 40.0f / 255.0f, // Fondo superior: naranja brillante
180.0f / 255.0f, 60.0f / 255.0f, 20.0f / 255.0f, // Fondo inferior: naranja-rojo
std::vector<Color>{
{255, 180, 80}, {255, 200, 100}, {255, 170, 70}, {255, 190, 90},
{255, 175, 75}, {255, 195, 95}, {255, 185, 85}, {255, 178, 78}
},
3.5f // 3.5 segundos para lava máxima
},
// Keyframe 3: Enfriamiento (vuelta a ceniza gradual)
{
100.0f / 255.0f, 80.0f / 255.0f, 70.0f / 255.0f, // Fondo superior: gris-naranja
50.0f / 255.0f, 40.0f / 255.0f, 35.0f / 255.0f, // Fondo inferior: gris oscuro
std::vector<Color>{
{150, 120, 100}, {140, 110, 90}, {160, 130, 110}, {145, 115, 95},
{155, 125, 105}, {142, 112, 92}, {158, 128, 108}, {148, 118, 98}
},
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...)
));
}
// ============================================================================
@@ -296,6 +475,17 @@ void ThemeManager::cycleTheme() {
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()) {