//! Spinner Demo - Shows all spinner styles //! //! Run with: zig build spinner-demo const std = @import("std"); const zcatui = @import("zcatui"); const Terminal = zcatui.Terminal; const Rect = zcatui.Rect; const Buffer = zcatui.Buffer; const Style = zcatui.Style; const Color = zcatui.Color; const Block = zcatui.widgets.Block; const Borders = zcatui.widgets.Borders; const Spinner = zcatui.widgets.Spinner; const SpinnerStyle = zcatui.widgets.SpinnerStyle; const styles = [_]SpinnerStyle{ .dots, .dots_braille, .line, .arrows, .box_corners, .circle, .blocks, }; const style_names = [_][]const u8{ "Dots", "Braille", "Line", "Arrows", "Box", "Circle", "Blocks", }; const messages = [_][]const u8{ "Loading...", "Processing...", "Compiling...", "Connecting...", "Syncing...", "Waiting...", "Downloading...", }; /// State for the demo const State = struct { frame: u64 = 0, selected_style: usize = 0, running: bool = true, }; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); var term = try Terminal.init(allocator); defer term.deinit(); var state = State{}; // Main loop while (state.running) { try term.drawWithContext(&state, render); // Poll events (non-blocking) if (try term.pollEvent(50)) |event| { switch (event) { .key => |key| { switch (key.code) { .char => |c| { if (c == 'q') state.running = false; // Number keys 1-7 to select style if (c >= '1' and c <= '7') { state.selected_style = c - '1'; } }, .up => { if (state.selected_style > 0) state.selected_style -= 1; }, .down => { if (state.selected_style < styles.len - 1) state.selected_style += 1; }, .esc => state.running = false, else => {}, } }, else => {}, } } state.frame +%= 1; } } fn render(state: *State, area: Rect, buf: *Buffer) void { // Draw border const block = Block.init() .title(" Spinner Styles ") .setBorders(Borders.all) .borderStyle((Style{}).fg(Color.cyan)); block.render(area, buf); const inner = Rect.init(2, 2, area.width -| 4, area.height -| 4); // Draw all spinners var y: u16 = 0; for (styles, 0..) |style, i| { if (y >= inner.height -| 2) break; const is_selected = i == state.selected_style; const row_style = if (is_selected) (Style{}).fg(Color.yellow).bold() else Style{}; // Style name var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "{s:<10}", .{style_names[i]}) catch "???"; _ = buf.setString(inner.x, inner.y + y, name, row_style); // Spinner var spinner = Spinner.init(style) .setLabel(messages[i]); // Tick based on frame var tick_count: u64 = 0; while (tick_count < state.frame) : (tick_count += 1) { spinner.tick(); } spinner.render( Rect.init(inner.x + 12, inner.y + y, inner.width -| 12, 1), buf, ); y += 2; } // Instructions at bottom const help_y = area.height -| 2; _ = buf.setString( 2, help_y, "Press 1-7 to select style, up/down to navigate, q to quit", (Style{}).fg(Color.rgb(100, 100, 100)), ); }