feat(bevel): API configurable de biseles 3D
Nueva API BevelStyle para control fino de efectos 3D: - effect: raised (elevado) o sunken (hundido) - inset: 0 (exterior) o 1 (interior) - light_top, light_left: intensidad de luz por borde - dark_bottom, dark_right: intensidad de sombra por borde - use_hsl: HSL (true) o RGB (false) Presets incluidos: - BevelStyle.raised_inset (default, botones) - BevelStyle.sunken_inset (botones presionados) - BevelStyle.raised_outer (estilo Windows 95) - BevelStyle.sunken_outer (estilo Windows 95) API: - ctx.drawBevel(x, y, w, h, color, style) - nueva función principal - ctx.drawBeveledRect() - wrapper compatibilidad (usa raised_inset) - ctx.drawBeveledRectPressed() - wrapper compatibilidad (usa sunken_inset) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
6732ac1fc5
commit
f17104c08b
1 changed files with 126 additions and 84 deletions
|
|
@ -495,17 +495,104 @@ pub const Context = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// High-level Drawing Helpers
|
// High-level Drawing Helpers - Bevel System
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
/// Draw a rectangle with 3D bevel effect
|
/// Configuración de estilo de bisel 3D
|
||||||
/// Creates illusion of depth with light from top-left
|
/// Permite control fino sobre el efecto visual
|
||||||
/// - Top/Left edges: lighter (raised)
|
pub const BevelStyle = struct {
|
||||||
/// - Bottom/Right edges: darker (shadow)
|
/// Tipo de efecto 3D
|
||||||
/// Note: Bevel is drawn INSIDE the rect (inset by 1px) to not overlap border
|
effect: Effect = .raised,
|
||||||
pub fn drawBeveledRect(self: *Self, x: i32, y: i32, w: u32, h: u32, base_color: Style.Color) void {
|
|
||||||
const light = base_color.lightenHsl(10);
|
/// Offset del bisel en pixels (0 = borde exterior, 1 = interior)
|
||||||
const dark = base_color.darkenHsl(15);
|
inset: u8 = 1,
|
||||||
|
|
||||||
|
/// Intensidad de la luz (0-100, típico 10-20)
|
||||||
|
light_top: u8 = 10,
|
||||||
|
light_left: u8 = 10,
|
||||||
|
|
||||||
|
/// Intensidad de la sombra (0-100, típico 10-20)
|
||||||
|
dark_bottom: u8 = 15,
|
||||||
|
dark_right: u8 = 15,
|
||||||
|
|
||||||
|
/// Usar HSL (true) o RGB (false) para calcular colores
|
||||||
|
use_hsl: bool = true,
|
||||||
|
|
||||||
|
pub const Effect = enum {
|
||||||
|
raised, // Elevado: luz arriba/izq, sombra abajo/der
|
||||||
|
sunken, // Hundido: sombra arriba/izq, luz abajo/der
|
||||||
|
};
|
||||||
|
|
||||||
|
// === PRESETS COMUNES ===
|
||||||
|
|
||||||
|
/// Bisel elevado interior (default, para botones)
|
||||||
|
pub const raised_inset = BevelStyle{};
|
||||||
|
|
||||||
|
/// Bisel hundido interior (para botones presionados)
|
||||||
|
pub const sunken_inset = BevelStyle{ .effect = .sunken };
|
||||||
|
|
||||||
|
/// Bisel elevado exterior (estilo Windows 95/StatusLine)
|
||||||
|
pub const raised_outer = BevelStyle{
|
||||||
|
.inset = 0,
|
||||||
|
.use_hsl = false,
|
||||||
|
.light_top = 15,
|
||||||
|
.light_left = 12,
|
||||||
|
.dark_bottom = 15,
|
||||||
|
.dark_right = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bisel hundido exterior (estilo Windows 95/StatusLine)
|
||||||
|
pub const sunken_outer = BevelStyle{
|
||||||
|
.effect = .sunken,
|
||||||
|
.inset = 0,
|
||||||
|
.use_hsl = false,
|
||||||
|
.light_top = 10,
|
||||||
|
.light_left = 8,
|
||||||
|
.dark_bottom = 20,
|
||||||
|
.dark_right = 15,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Dibuja un rectángulo con efecto bisel 3D configurable
|
||||||
|
///
|
||||||
|
/// Ejemplo de uso:
|
||||||
|
/// ```zig
|
||||||
|
/// // Bisel elevado (default)
|
||||||
|
/// ctx.drawBevel(x, y, w, h, color, .{});
|
||||||
|
///
|
||||||
|
/// // Bisel hundido exterior (estilo StatusLine)
|
||||||
|
/// ctx.drawBevel(x, y, w, h, color, BevelStyle.sunken_outer);
|
||||||
|
///
|
||||||
|
/// // Personalizado
|
||||||
|
/// ctx.drawBevel(x, y, w, h, color, .{ .effect = .raised, .inset = 0, .light_top = 20 });
|
||||||
|
/// ```
|
||||||
|
pub fn drawBevel(self: *Self, x: i32, y: i32, w: u32, h: u32, base_color: Style.Color, style: BevelStyle) void {
|
||||||
|
// Calcular colores de luz y sombra
|
||||||
|
const light_top = if (style.use_hsl)
|
||||||
|
base_color.lightenHsl(@floatFromInt(style.light_top))
|
||||||
|
else
|
||||||
|
base_color.lighten(style.light_top);
|
||||||
|
|
||||||
|
const light_left = if (style.use_hsl)
|
||||||
|
base_color.lightenHsl(@floatFromInt(style.light_left))
|
||||||
|
else
|
||||||
|
base_color.lighten(style.light_left);
|
||||||
|
|
||||||
|
const dark_bottom = if (style.use_hsl)
|
||||||
|
base_color.darkenHsl(@floatFromInt(style.dark_bottom))
|
||||||
|
else
|
||||||
|
base_color.darken(style.dark_bottom);
|
||||||
|
|
||||||
|
const dark_right = if (style.use_hsl)
|
||||||
|
base_color.darkenHsl(@floatFromInt(style.dark_right))
|
||||||
|
else
|
||||||
|
base_color.darken(style.dark_right);
|
||||||
|
|
||||||
|
// Determinar colores según efecto (raised vs sunken)
|
||||||
|
const top_color = if (style.effect == .raised) light_top else dark_bottom;
|
||||||
|
const left_color = if (style.effect == .raised) light_left else dark_right;
|
||||||
|
const bottom_color = if (style.effect == .raised) dark_bottom else light_top;
|
||||||
|
const right_color = if (style.effect == .raised) dark_right else light_left;
|
||||||
|
|
||||||
// Main fill
|
// Main fill
|
||||||
self.pushCommand(.{ .rect = .{
|
self.pushCommand(.{ .rect = .{
|
||||||
|
|
@ -516,102 +603,57 @@ pub const Context = struct {
|
||||||
.color = base_color,
|
.color = base_color,
|
||||||
} });
|
} });
|
||||||
|
|
||||||
// Bevel inset by 1px to stay inside border
|
// Calcular dimensiones según inset
|
||||||
const inner_w = if (w > 2) w - 2 else 1;
|
const offset: i32 = @intCast(style.inset);
|
||||||
const inner_h = if (h > 2) h - 2 else 1;
|
const size_reduction: u32 = @as(u32, style.inset) * 2;
|
||||||
|
const inner_w = if (w > size_reduction) w - size_reduction else 1;
|
||||||
|
const inner_h = if (h > size_reduction) h - size_reduction else 1;
|
||||||
|
|
||||||
// Top edge (light) - inset
|
// Top edge
|
||||||
self.pushCommand(.{ .rect = .{
|
self.pushCommand(.{ .rect = .{
|
||||||
.x = x + 1,
|
.x = x + offset,
|
||||||
.y = y + 1,
|
.y = y + offset,
|
||||||
.w = inner_w,
|
.w = inner_w,
|
||||||
.h = 1,
|
.h = 1,
|
||||||
.color = light,
|
.color = top_color,
|
||||||
} });
|
} });
|
||||||
|
|
||||||
// Left edge (light) - inset
|
// Left edge
|
||||||
self.pushCommand(.{ .rect = .{
|
self.pushCommand(.{ .rect = .{
|
||||||
.x = x + 1,
|
.x = x + offset,
|
||||||
.y = y + 1,
|
.y = y + offset + 1,
|
||||||
.w = 1,
|
.w = 1,
|
||||||
.h = inner_h,
|
.h = if (inner_h > 2) inner_h - 2 else 1,
|
||||||
.color = light,
|
.color = left_color,
|
||||||
} });
|
} });
|
||||||
|
|
||||||
// Bottom edge (dark) - inset
|
// Bottom edge
|
||||||
self.pushCommand(.{ .rect = .{
|
self.pushCommand(.{ .rect = .{
|
||||||
.x = x + 1,
|
.x = x + offset,
|
||||||
.y = y + @as(i32, @intCast(h)) - 2,
|
.y = y + @as(i32, @intCast(h)) - 1 - offset,
|
||||||
.w = inner_w,
|
.w = inner_w,
|
||||||
.h = 1,
|
.h = 1,
|
||||||
.color = dark,
|
.color = bottom_color,
|
||||||
} });
|
} });
|
||||||
|
|
||||||
// Right edge (dark) - inset
|
// Right edge
|
||||||
self.pushCommand(.{ .rect = .{
|
self.pushCommand(.{ .rect = .{
|
||||||
.x = x + @as(i32, @intCast(w)) - 2,
|
.x = x + @as(i32, @intCast(w)) - 1 - offset,
|
||||||
.y = y + 1,
|
.y = y + offset + 1,
|
||||||
.w = 1,
|
.w = 1,
|
||||||
.h = inner_h,
|
.h = if (inner_h > 2) inner_h - 2 else 1,
|
||||||
.color = dark,
|
.color = right_color,
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw a rectangle with inverted 3D bevel effect (pressed state)
|
/// Wrapper simple: bisel elevado interior (compatibilidad)
|
||||||
/// Dark edges on top/left, light on bottom/right
|
pub fn drawBeveledRect(self: *Self, x: i32, y: i32, w: u32, h: u32, base_color: Style.Color) void {
|
||||||
/// Note: Bevel is drawn INSIDE the rect (inset by 1px) to not overlap border
|
self.drawBevel(x, y, w, h, base_color, BevelStyle.raised_inset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper simple: bisel hundido interior (compatibilidad)
|
||||||
pub fn drawBeveledRectPressed(self: *Self, x: i32, y: i32, w: u32, h: u32, base_color: Style.Color) void {
|
pub fn drawBeveledRectPressed(self: *Self, x: i32, y: i32, w: u32, h: u32, base_color: Style.Color) void {
|
||||||
const light = base_color.lightenHsl(10);
|
self.drawBevel(x, y, w, h, base_color, BevelStyle.sunken_inset);
|
||||||
const dark = base_color.darkenHsl(15);
|
|
||||||
|
|
||||||
// Main fill
|
|
||||||
self.pushCommand(.{ .rect = .{
|
|
||||||
.x = x,
|
|
||||||
.y = y,
|
|
||||||
.w = w,
|
|
||||||
.h = h,
|
|
||||||
.color = base_color,
|
|
||||||
} });
|
|
||||||
|
|
||||||
// Bevel inset by 1px to stay inside border
|
|
||||||
const inner_w = if (w > 2) w - 2 else 1;
|
|
||||||
const inner_h = if (h > 2) h - 2 else 1;
|
|
||||||
|
|
||||||
// Top edge (dark - inverted) - inset
|
|
||||||
self.pushCommand(.{ .rect = .{
|
|
||||||
.x = x + 1,
|
|
||||||
.y = y + 1,
|
|
||||||
.w = inner_w,
|
|
||||||
.h = 1,
|
|
||||||
.color = dark,
|
|
||||||
} });
|
|
||||||
|
|
||||||
// Left edge (dark - inverted) - inset
|
|
||||||
self.pushCommand(.{ .rect = .{
|
|
||||||
.x = x + 1,
|
|
||||||
.y = y + 1,
|
|
||||||
.w = 1,
|
|
||||||
.h = inner_h,
|
|
||||||
.color = dark,
|
|
||||||
} });
|
|
||||||
|
|
||||||
// Bottom edge (light - inverted) - inset
|
|
||||||
self.pushCommand(.{ .rect = .{
|
|
||||||
.x = x + 1,
|
|
||||||
.y = y + @as(i32, @intCast(h)) - 2,
|
|
||||||
.w = inner_w,
|
|
||||||
.h = 1,
|
|
||||||
.color = light,
|
|
||||||
} });
|
|
||||||
|
|
||||||
// Right edge (light - inverted) - inset
|
|
||||||
self.pushCommand(.{ .rect = .{
|
|
||||||
.x = x + @as(i32, @intCast(w)) - 2,
|
|
||||||
.y = y + 1,
|
|
||||||
.w = 1,
|
|
||||||
.h = inner_h,
|
|
||||||
.color = light,
|
|
||||||
} });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw a complete panel frame with focus-dependent styling.
|
/// Draw a complete panel frame with focus-dependent styling.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue