zcatgui/examples/widgets_demo.zig
reugenio 6ac3856ae2 feat: zcatgui v0.5.0 - Complete widget library + research docs
Widgets implemented (13 total):
- Label: Static text with alignment
- Button: With importance levels (primary/normal/danger)
- TextInput: Single-line text entry with cursor
- Checkbox: Boolean toggle
- Select: Dropdown selection
- List: Scrollable selectable list
- Focus: Focus manager with tab navigation
- Table: Editable table with dirty tracking, keyboard nav
- Split: HSplit/VSplit draggable panels
- Panel: Container with title bar, collapsible
- Modal: Dialogs (alert, confirm, inputDialog)
- AutoComplete: ComboBox with prefix/contains/fuzzy matching

Core improvements:
- InputState now tracks keyboard state (keys_down, key_events)
- Full keyboard navigation for Table widget

Research documentation:
- WIDGET_COMPARISON.md: zcatgui vs DVUI vs Gio vs zcatui
- SIMIFACTU_ADVANCEDTABLE.md: Analysis of 10K LOC table component
- LEGO_PANELS_SYSTEM.md: Modular panel composition architecture

Examples:
- widgets_demo.zig: All basic widgets showcase
- table_demo.zig: Table, Split, Panel demonstration

All tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 11:00:49 +01:00

177 lines
5.1 KiB
Zig

//! Widget Demo - Showcase all zcatgui widgets
//!
//! This example demonstrates all available widgets:
//! - Label (static text)
//! - Button (clickable)
//! - TextInput (editable text)
//! - Checkbox (boolean toggle)
//! - Select (dropdown)
//! - List (scrollable selection)
//!
//! Run with: zig build widgets-demo
const std = @import("std");
const zcatgui = @import("zcatgui");
const Context = zcatgui.Context;
const Color = zcatgui.Color;
const Layout = zcatgui.Layout;
const Command = zcatgui.Command;
const print = std.debug.print;
pub fn main() !void {
print("=== zcatgui Widget Demo ===\n\n", .{});
print("This demo shows all available widgets.\n", .{});
print("In a real application, this would open a window.\n\n", .{});
// Create context
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var ctx = Context.init(allocator, 800, 600);
defer ctx.deinit();
// Widget state
var name_buf: [64]u8 = undefined;
var name_input = zcatgui.TextInputState.init(&name_buf);
name_input.setText("Hello World");
var email_buf: [128]u8 = undefined;
var email_input = zcatgui.TextInputState.init(&email_buf);
var remember_me = true;
var newsletter = false;
var country_select = zcatgui.SelectState{};
const countries = [_][]const u8{ "Spain", "France", "Germany", "Italy", "Portugal" };
var file_list = zcatgui.ListState{};
const files = [_][]const u8{
"document.pdf",
"image.png",
"video.mp4",
"music.mp3",
"archive.zip",
"notes.txt",
"config.json",
"data.csv",
};
var click_count: u32 = 0;
// Simulate a few frames
print("Simulating 3 frames of UI rendering...\n\n", .{});
for (0..3) |frame| {
ctx.beginFrame();
// Set up layout
ctx.layout.row_height = 24;
print("--- Frame {} ---\n", .{frame + 1});
// Title
zcatgui.labelEx(&ctx, "Widget Demo", .{
.color = Color.primary,
.alignment = .center,
});
// Spacing
ctx.layout.row_height = 8;
_ = ctx.layout.nextRect(); // Empty row for spacing
ctx.layout.row_height = 24;
// Name input
zcatgui.label(&ctx, "Name:");
_ = zcatgui.textInput(&ctx, &name_input);
// Email input
zcatgui.label(&ctx, "Email:");
_ = zcatgui.textInputEx(&ctx, &email_input, .{
.placeholder = "user@example.com",
});
// Checkboxes
ctx.layout.row_height = 20;
_ = zcatgui.checkbox(&ctx, &remember_me, "Remember me");
_ = zcatgui.checkbox(&ctx, &newsletter, "Subscribe to newsletter");
// Country select
ctx.layout.row_height = 30;
zcatgui.label(&ctx, "Country:");
_ = zcatgui.select(&ctx, &country_select, &countries);
// Buttons
ctx.layout.row_height = 32;
// Simulate click on frame 2
if (frame == 1) {
ctx.input.setMousePos(100, 250);
ctx.input.setMouseButton(.left, true);
} else if (frame == 2) {
ctx.input.setMouseButton(.left, false);
}
if (zcatgui.buttonPrimary(&ctx, "Submit")) {
click_count += 1;
print(" -> Button clicked! Count: {}\n", .{click_count});
}
if (zcatgui.buttonDanger(&ctx, "Cancel")) {
print(" -> Cancel clicked!\n", .{});
}
// File list
ctx.layout.row_height = 150;
zcatgui.label(&ctx, "Files:");
_ = zcatgui.list(&ctx, &file_list, &files);
// Status
ctx.layout.row_height = 20;
var status_buf: [128]u8 = undefined;
const status = std.fmt.bufPrint(&status_buf, "Commands: {} | Clicks: {}", .{
ctx.commands.items.len,
click_count,
}) catch "Error";
zcatgui.labelColored(&ctx, status, Color.secondary);
ctx.endFrame();
print(" Generated {} draw commands\n", .{ctx.commands.items.len});
// Print some command details
var rect_count: usize = 0;
var text_count: usize = 0;
var line_count: usize = 0;
for (ctx.commands.items) |cmd| {
switch (cmd) {
.rect => rect_count += 1,
.text => text_count += 1,
.line => line_count += 1,
else => {},
}
}
print(" Rects: {}, Text: {}, Lines: {}\n", .{ rect_count, text_count, line_count });
}
print("\n", .{});
print("Widget state after 3 frames:\n", .{});
print(" Name: \"{s}\"\n", .{name_input.text()});
print(" Email: \"{s}\"\n", .{email_input.text()});
print(" Remember me: {}\n", .{remember_me});
print(" Newsletter: {}\n", .{newsletter});
print(" Country: {s}\n", .{
if (zcatgui.widgets.select.getSelectedText(country_select, &countries)) |c| c else "(none)",
});
print(" Selected file: {s}\n", .{
if (zcatgui.widgets.list.getSelectedText(file_list, &files)) |f| f else "(none)",
});
print(" Click count: {}\n", .{click_count});
print("\n=== Demo Complete ===\n", .{});
}