fix(visual): Títulos legibles + botones centrados

Fix legibilidad títulos:
- title_color: 85% soft_white + 15% tinte del base_color
- Antes: base.lightenHsl(90) → azul claro sobre azul oscuro (ilegible)
- Ahora: blanco con tinte sutil → máximo contraste + identidad visual

Fix centrado vertical botones:
- Añadido char_height al Context (default 14px para TTF)
- button.zig: usa char_height en vez de char_width
- Offset visual -1px para compensar efecto 3D del bisel

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
R.Eugenio 2025-12-31 12:15:13 +01:00
parent f7e1e346be
commit d657a25ba7
3 changed files with 21 additions and 10 deletions

View file

@ -115,6 +115,9 @@ pub const Context = struct {
/// Default character width for fallback measurement (bitmap fonts)
char_width: u32 = 8,
/// Default character height for vertical centering (TTF fonts typically 1.2-1.5x width)
char_height: u32 = 14,
/// Idle timeout for cursor blinking (ms). After this time without input,
/// cursor becomes solid and no animation frames are needed.
pub const CURSOR_IDLE_TIMEOUT_MS: u64 = 20000;
@ -341,6 +344,11 @@ pub const Context = struct {
self.char_width = width;
}
/// Set character height for vertical centering (TTF fonts)
pub fn setCharHeight(self: *Self, height: u32) void {
self.char_height = height;
}
/// Get current time in milliseconds
pub fn getTime(self: Self) u64 {
return self.current_time_ms;

View file

@ -1382,13 +1382,14 @@ pub fn derivePanelFrameColors(base: Color) DerivedPanelColors {
// Blend fijo: 20% color con focus, 12% sin focus
const focus_bg = base.blendTowards(black, 80); // 20% color
// Título adaptativo: contraste máximo según luminosidad del fondo
// Fondos oscuros (L < 0.5) blanco teñido, claros negro teñido
// Título: BLANCO con tinte sutil del color base para identidad
// El contraste viene del blanco, el tinte da coherencia visual
// Fondos oscuros blanco teñido, claros negro teñido
const bg_luminance = focus_bg.perceptualLuminance();
const title_color = if (bg_luminance < 0.5)
base.lightenHsl(90) // Blanco teñido (mantiene tono del panel)
Color.soft_white.blendTowards(base, 15) // 85% blanco + 15% tinte del panel
else
base.darkenHsl(90); // Negro teñido
Color.soft_black.blendTowards(base, 15); // 85% negro + 15% tinte
return .{
.focus_bg = focus_bg,

View file

@ -132,12 +132,13 @@ pub fn buttonRect(ctx: *Context, bounds: Layout.Rect, text: []const u8, config:
}
// Draw text centered (con offset +1px cuando está pulsado = "se hunde")
// Z-Design V2: usar métricas del contexto para centrado correcto con TTF
// Z-Design V5: usar char_height real + offset -1 para compensar efecto 3D
const text_width = ctx.measureText(text);
const char_height = ctx.char_width; // Para fuentes cuadradas, height width
const char_height = ctx.char_height;
const press_offset: i32 = if (pressed) 1 else 0;
const visual_adjust: i32 = -1; // Compensa efecto 3D del bisel que "hunde" visualmente
const text_x = bounds.x + @as(i32, @intCast((bounds.w -| text_width) / 2)) + press_offset;
const text_y = bounds.y + @as(i32, @intCast((bounds.h -| char_height) / 2)) + press_offset;
const text_y = bounds.y + @as(i32, @intCast((bounds.h -| char_height) / 2)) + press_offset + visual_adjust;
ctx.pushCommand(Command.text(text_x, text_y, text, fg_color));
@ -247,12 +248,13 @@ pub fn buttonStatefulRect(
}
// Draw text centered (con offset +1px cuando está pulsado = "se hunde")
// Z-Design V2: usar métricas del contexto para centrado correcto con TTF
// Z-Design V5: usar char_height real + offset -1 para compensar efecto 3D
const text_width = ctx.measureText(text);
const char_height = ctx.char_width; // Para fuentes cuadradas, height width
const char_height = ctx.char_height;
const press_offset: i32 = if (pressed) 1 else 0;
const visual_adjust: i32 = -1; // Compensa efecto 3D del bisel que "hunde" visualmente
const text_x = bounds.x + @as(i32, @intCast((bounds.w -| text_width) / 2)) + press_offset;
const text_y = bounds.y + @as(i32, @intCast((bounds.h -| char_height) / 2)) + press_offset;
const text_y = bounds.y + @as(i32, @intCast((bounds.h -| char_height) / 2)) + press_offset + visual_adjust;
ctx.pushCommand(Command.text(text_x, text_y, text, fg_color));