fix(panels): Semáforo reubicado - texto + cuadrado a la derecha

- Título: x+28 para dejar espacio al semáforo (antes x+10)
- Semáforo: "Viendo ■" alineado a la derecha (antes ■ izquierda, texto derecha)
- Botones: visual_adjust +2px para compensar baseline TTF
- contrastTextColor como fallback para títulos sin base_color

Layout final: "[N] Título                    Estado ■"

🤖 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 13:17:37 +01:00
parent d657a25ba7
commit 0f16a77ae4
3 changed files with 32 additions and 22 deletions

View file

@ -665,14 +665,18 @@ pub const Context = struct {
break :blk config.border_color;
};
// Título adaptativo: siempre alta legibilidad (blanco teñido sobre fondo oscuro)
// Título adaptativo: siempre alta legibilidad
// - Si hay title_color explícito: usarlo
// - Si hay base_color: derivar con tinte sutil
// - Si no hay ninguno: contrastTextColor sobre focus_bg (blanco/negro según fondo)
const title_color: ?Style.Color = blk: {
if (config.title_color) |tc| break :blk tc;
if (config.base_color) |base| {
const derived = Style.derivePanelFrameColors(base);
break :blk derived.title_color; // Siempre legible, focus o no
}
break :blk border_color;
// FIX: usar contraste sobre fondo, NO border_color (que es oscuro)
break :blk Style.contrastTextColor(focus_bg);
};
// 1. Calculate target color and update transition
@ -707,11 +711,12 @@ pub const Context = struct {
self.pushCommand(Command.rectOutline(rect.x, rect.y, rect.w, rect.h, border));
}
// 5. Draw title if specified (margen 10,5 para aire visual)
// 5. Draw title if specified (margen 28,5 para dejar espacio al semáforo de estado)
// El semáforo de DetailPanelBase se dibuja en (x+8, y+4) con 12x12px
if (config.title) |title| {
if (title_color) |tc| {
self.pushCommand(.{ .text = .{
.x = rect.x + 10,
.x = rect.x + 28,
.y = rect.y + 5,
.text = title,
.color = tc,

View file

@ -225,32 +225,37 @@ pub const DetailPanelBase = struct {
// Dibujo: Semaforo
// =========================================================================
/// Dibuja el semaforo de estado en la esquina superior izquierda del rect.
/// Dibuja el semaforo de estado en la esquina superior derecha del rect.
///
/// Muestra:
/// - Cuadrado de color (12x12) indicando el estado
/// - Texto del estado en la esquina superior derecha
/// Layout: "[N] Título Viendo ■"
/// - Texto del estado primero (ej: "Viendo", "Editando", "Guardando...")
/// - Cuadrado de color (12x12) como remate visual al final
pub fn drawSemaphore(self: *Self, ctx: *Context, rect: Rect) void {
const state_color = self.state.getColor();
const state_text = self.state.getText();
// Cuadrado de color (indicador visual)
ctx.pushCommand(.{ .rect = .{
.x = rect.x + 8,
.y = rect.y + 4,
.w = 12,
.h = 12,
.color = state_color,
} });
// Posiciones: texto + cuadrado alineados a la derecha
// Cuadrado: 12x12 con 8px de margen del borde derecho
const square_x = rect.x + @as(i32, @intCast(rect.w)) - 20;
// Texto: antes del cuadrado, con 8px de separación
const text_x = rect.x + @as(i32, @intCast(rect.w)) - 100;
// Texto del estado (esquina derecha)
const text_x = rect.x + @as(i32, @intCast(rect.w)) - 80;
// 1. Texto del estado
ctx.pushCommand(.{ .text = .{
.x = text_x,
.y = rect.y + 4,
.text = state_text,
.color = state_color,
} });
// 2. Cuadrado de color (indicador visual al final)
ctx.pushCommand(.{ .rect = .{
.x = square_x,
.y = rect.y + 4,
.w = 12,
.h = 12,
.color = state_color,
} });
}
// =========================================================================

View file

@ -132,11 +132,11 @@ 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 V5: usar char_height real + offset -1 para compensar efecto 3D
// Z-Design V5: usar char_height real + offset +2 para compensar baseline TTF
const text_width = ctx.measureText(text);
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 visual_adjust: i32 = 2; // Compensa baseline de fuente TTF (DroidSans 14pt)
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 + visual_adjust;
@ -248,11 +248,11 @@ pub fn buttonStatefulRect(
}
// Draw text centered (con offset +1px cuando está pulsado = "se hunde")
// Z-Design V5: usar char_height real + offset -1 para compensar efecto 3D
// Z-Design V5: usar char_height real + offset +2 para compensar baseline TTF
const text_width = ctx.measureText(text);
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 visual_adjust: i32 = 2; // Compensa baseline de fuente TTF (DroidSans 14pt)
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 + visual_adjust;