fix(buttons): Centrar texto V+H usando métricas del contexto

- button.zig: Usar ctx.measureText() y ctx.char_width para centrado
- label.zig: Mismo fix para centrado de labels
- animation.zig: Actualizar test ColorTransition para duration 500ms

Z-Design V2: El centrado ahora funciona correctamente con TTF fonts.
Antes usaba 8px hardcodeado, ahora usa métricas dinámicas del contexto.

🤖 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-30 19:58:45 +01:00
parent 9c29faaa81
commit 8f577e02b0
3 changed files with 25 additions and 15 deletions

View file

@ -765,13 +765,24 @@ test "ColorTransition basic" {
try std.testing.expect(trans.initialized); try std.testing.expect(trans.initialized);
try std.testing.expectEqual(@as(u8, 0), trans.current.r); try std.testing.expectEqual(@as(u8, 0), trans.current.r);
// Transition towards white over time // Transition towards white over time (250ms = 50% del delta, chase interpolation)
_ = trans.update(white, 100); // ~50% transition _ = trans.update(white, 250);
try std.testing.expect(trans.current.r > 0); try std.testing.expect(trans.current.r > 0);
try std.testing.expect(trans.current.r < 255); try std.testing.expect(trans.current.r < 255);
// Full duration reaches target // Chase interpolation: múltiples frames para converger
_ = trans.update(white, 200); // (cada frame mueve 50% del camino restante, necesita varios para llegar)
_ = trans.update(white, 250);
_ = trans.update(white, 250);
_ = trans.update(white, 250);
_ = trans.update(white, 250);
_ = trans.update(white, 250);
_ = trans.update(white, 250);
try std.testing.expect(trans.current.r >= 252); // Debe estar muy cerca de 255
// Delta >= duration snaps to target (t = 1.0)
trans.current = black;
_ = trans.update(white, 500);
try std.testing.expectEqual(@as(u8, 255), trans.current.r); try std.testing.expectEqual(@as(u8, 255), trans.current.r);
} }

View file

@ -123,9 +123,9 @@ pub fn buttonRect(ctx: *Context, bounds: Layout.Rect, text: []const u8, config:
} }
// Draw text centered (con offset +1px cuando está pulsado = "se hunde") // Draw text centered (con offset +1px cuando está pulsado = "se hunde")
const char_width: u32 = 8; // Z-Design V2: usar métricas del contexto para centrado correcto con TTF
const char_height: u32 = 8; const text_width = ctx.measureText(text);
const text_width = @as(u32, @intCast(text.len)) * char_width; const char_height = ctx.char_width; // Para fuentes cuadradas, height width
const press_offset: i32 = if (pressed) 1 else 0; const press_offset: i32 = if (pressed) 1 else 0;
const text_x = bounds.x + @as(i32, @intCast((bounds.w -| text_width) / 2)) + press_offset; 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;
@ -229,9 +229,9 @@ pub fn buttonStatefulRect(
} }
// Draw text centered (con offset +1px cuando está pulsado = "se hunde") // Draw text centered (con offset +1px cuando está pulsado = "se hunde")
const char_width: u32 = 8; // Z-Design V2: usar métricas del contexto para centrado correcto con TTF
const char_height: u32 = 8; const text_width = ctx.measureText(text);
const text_width = @as(u32, @intCast(text.len)) * char_width; const char_height = ctx.char_width; // Para fuentes cuadradas, height width
const press_offset: i32 = if (pressed) 1 else 0; const press_offset: i32 = if (pressed) 1 else 0;
const text_x = bounds.x + @as(i32, @intCast((bounds.w -| text_width) / 2)) + press_offset; 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;

View file

@ -42,9 +42,8 @@ pub fn labelRect(ctx: *Context, bounds: Layout.Rect, text: []const u8, config: L
if (inner.isEmpty()) return; if (inner.isEmpty()) return;
// Calculate text position based on alignment // Calculate text position based on alignment
// Assume 8 pixels per character (bitmap font) // Z-Design V2: usar métricas del contexto para centrado correcto con TTF
const char_width: u32 = 8; const text_width = ctx.measureText(text);
const text_width = @as(u32, @intCast(text.len)) * char_width;
const x: i32 = switch (config.alignment) { const x: i32 = switch (config.alignment) {
.left => inner.x, .left => inner.x,
@ -52,8 +51,8 @@ pub fn labelRect(ctx: *Context, bounds: Layout.Rect, text: []const u8, config: L
.right => inner.x + @as(i32, @intCast(inner.w -| text_width)), .right => inner.x + @as(i32, @intCast(inner.w -| text_width)),
}; };
// Center vertically (assume 8 pixel font height) // Center vertically usando métricas del contexto
const char_height: u32 = 8; const char_height = ctx.char_width; // Para fuentes cuadradas, height width
const y = inner.y + @as(i32, @intCast((inner.h -| char_height) / 2)); const y = inner.y + @as(i32, @intCast((inner.h -| char_height) / 2));
ctx.pushCommand(Command.text(x, y, text, config.color)); ctx.pushCommand(Command.text(x, y, text, config.color));