From f71c9e6186c4e4039e9fd96529d1f7ac78047ba2 Mon Sep 17 00:00:00 2001 From: "R.Eugenio" Date: Tue, 30 Dec 2025 20:33:28 +0100 Subject: [PATCH] feat(context): Add drawPanelFrame helper for DRY panel rendering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/core/context.zig | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/core/context.zig b/src/core/context.zig index 1443cc7..0b764a1 100644 --- a/src/core/context.zig +++ b/src/core/context.zig @@ -43,6 +43,8 @@ const Command = @import("command.zig"); const Input = @import("input.zig"); const Layout = @import("layout.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 FrameArena = arena_mod.FrameArena; 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 pub fn resize(self: *Self, width: u32, height: u32) void { self.width = width;