New modules (13): - src/resize.zig: SIGWINCH terminal resize detection - src/drag.zig: Mouse drag state and Splitter panels - src/diagnostic.zig: Elm-style error messages with code snippets - src/debug.zig: Debug overlay (FPS, timing, widget count) - src/profile.zig: Performance profiling with scoped timers - src/sixel.zig: Sixel graphics encoding for terminal images - src/async_loop.zig: epoll-based async event loop with timers - src/compose.zig: Widget composition utilities - src/shortcuts.zig: Keyboard shortcut registry - src/widgets/logo.zig: ASCII art logo widget Enhanced modules: - src/layout.zig: Added Constraint.ratio(num, denom) - src/terminal.zig: Integrated resize handling - src/root.zig: Re-exports all new modules New examples (9): - resize_demo, splitter_demo, dirtree_demo - help_demo, markdown_demo, progress_demo - spinner_demo, syntax_demo, viewport_demo Package manager: - build.zig.zon: Zig package manager support Stats: 60+ source files, 186+ tests, 20 executables 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
151 lines
3.8 KiB
Zig
151 lines
3.8 KiB
Zig
//! 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)),
|
|
);
|
|
}
|