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;