feat(context): Add drawPanelFrame helper for DRY panel rendering

- Add PanelFrameConfig struct with has_focus, focus_bg, unfocus_bg, border_color options
- Add drawPanelFrame() method that encapsulates common panel rendering pattern:
  1. Update ColorTransition and request animation frame if needed
  2. Draw shadow when focused
  3. Draw beveled background
  4. Draw border outline
- Export ColorTransition from context module
- Reduces ~15 lines of repeated code per panel to single function call

🤖 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 20:33:28 +01:00
parent 49cd2e25b3
commit f71c9e6186

View file

@ -43,6 +43,8 @@ const Command = @import("command.zig");
const Input = @import("input.zig"); const Input = @import("input.zig");
const Layout = @import("layout.zig"); const Layout = @import("layout.zig");
const Style = @import("style.zig"); const Style = @import("style.zig");
const animation = @import("../render/animation.zig");
pub const ColorTransition = animation.ColorTransition;
const arena_mod = @import("../utils/arena.zig"); const arena_mod = @import("../utils/arena.zig");
const FrameArena = arena_mod.FrameArena; const FrameArena = arena_mod.FrameArena;
const focus_mod = @import("focus.zig"); const focus_mod = @import("focus.zig");
@ -558,6 +560,80 @@ pub const Context = struct {
} }); } });
} }
/// Draw a complete panel frame with focus-dependent styling.
/// Encapsulates the common pattern: transition -> shadow -> bevel -> border.
///
/// Usage:
/// ```zig
/// // In panel state:
/// bg_transition: zcatgui.Context.ColorTransition = .{},
///
/// // In draw:
/// ctx.drawPanelFrame(rect, &self.bg_transition, .{
/// .has_focus = panel_has_focus,
/// .focus_bg = colors.fondo_con_focus,
/// .unfocus_bg = colors.fondo_sin_focus,
/// .border_color = if (panel_has_focus) colors.borde_con_focus else colors.borde_sin_focus,
/// });
/// ```
pub const PanelFrameConfig = struct {
/// Whether the panel currently has focus
has_focus: bool = false,
/// Background color when focused
focus_bg: Style.Color = Style.Color.rgb(40, 40, 50),
/// Background color when not focused
unfocus_bg: Style.Color = Style.Color.rgb(30, 30, 40),
/// Border color (typically borde_con_focus or borde_sin_focus)
border_color: ?Style.Color = null,
/// Draw shadow when focused (default true)
draw_shadow: bool = true,
/// Draw bevel effect (default true)
draw_bevel: bool = true,
};
/// Draw a complete panel frame with focus transition and 3D effects.
/// Returns true if the transition is still animating (need more frames).
pub fn drawPanelFrame(
self: *Self,
rect: Layout.Rect,
transition: *ColorTransition,
config: PanelFrameConfig,
) bool {
// 1. Calculate target color and update transition
const target_bg = if (config.has_focus) config.focus_bg else config.unfocus_bg;
const animating = transition.update(target_bg, self.frame_delta_ms);
// Request animation frame if still transitioning
if (animating) {
self.requestAnimationFrame();
}
// 2. Draw shadow when focused
if (config.draw_shadow and config.has_focus) {
self.pushCommand(Command.shadowDrop(rect.x, rect.y, rect.w, rect.h, 0));
}
// 3. Draw background (beveled or flat)
if (config.draw_bevel) {
self.drawBeveledRect(rect.x, rect.y, rect.w, rect.h, transition.current);
} else {
self.pushCommand(.{ .rect = .{
.x = rect.x,
.y = rect.y,
.w = rect.w,
.h = rect.h,
.color = transition.current,
} });
}
// 4. Draw border if specified
if (config.border_color) |border| {
self.pushCommand(Command.rectOutline(rect.x, rect.y, rect.w, rect.h, border));
}
return animating;
}
/// Resize the context /// Resize the context
pub fn resize(self: *Self, width: u32, height: u32) void { pub fn resize(self: *Self, width: u32, height: u32) void {
self.width = width; self.width = width;