//! Interactive events demo for zcatui. //! //! Demonstrates keyboard and mouse event handling. //! Press 'q' or ESC to quit. //! //! Run with: zig build run-events-demo const std = @import("std"); const zcatui = @import("zcatui"); const Terminal = zcatui.Terminal; const Buffer = zcatui.Buffer; const Rect = zcatui.Rect; const Style = zcatui.Style; const Color = zcatui.Color; const Event = zcatui.Event; const KeyCode = zcatui.KeyCode; const Block = zcatui.widgets.Block; const Borders = zcatui.widgets.Borders; const Layout = zcatui.Layout; const Constraint = zcatui.Constraint; /// Application state const AppState = struct { last_event: ?Event = null, key_count: u32 = 0, mouse_x: u16 = 0, mouse_y: u16 = 0, mouse_clicks: u32 = 0, running: bool = true, }; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); // Initialize terminal var term = try Terminal.init(allocator); defer term.deinit(); // Enable mouse capture try term.enableMouseCapture(); // Enable focus events try term.enableFocusChange(); var state = AppState{}; // Main loop while (state.running) { // Draw UI try term.drawWithContext(&state, render); // Poll for events (100ms timeout) if (try term.pollEvent(100)) |event| { handleEvent(&state, event); } } } fn handleEvent(state: *AppState, event: Event) void { state.last_event = event; switch (event) { .key => |key| { state.key_count += 1; // Quit on 'q' or ESC switch (key.code) { .esc => state.running = false, .char => |c| { if (c == 'q' or c == 'Q') { state.running = false; } }, else => {}, } }, .mouse => |mouse| { state.mouse_x = mouse.column; state.mouse_y = mouse.row; if (mouse.kind == .down) { state.mouse_clicks += 1; } }, .resize => |_| { // Terminal handles resize automatically }, else => {}, } } fn render(state: *AppState, area: Rect, buf: *Buffer) void { // Create layout: header, content, footer const chunks = Layout.vertical(&.{ Constraint.length(3), Constraint.min(0), Constraint.length(3), }).split(area); // Header const header = Block.init() .title(" zcatui Events Demo ") .setBorders(Borders.all) .style(Style.default.fg(Color.cyan)); header.render(chunks.get(0), buf); // Content - show event info renderContent(state, chunks.get(1), buf); // Footer const footer_text = "Press 'q' or ESC to quit | Mouse enabled"; const footer = Block.init() .setBorders(Borders.all) .style(Style.default.fg(Color.blue)); const footer_area = chunks.get(2); footer.render(footer_area, buf); // Render footer text manually const inner = footer.inner(footer_area); _ = buf.setString(inner.left(), inner.top(), footer_text, Style.default); } fn renderContent(state: *AppState, area: Rect, buf: *Buffer) void { const content = Block.init() .title(" Event Info ") .setBorders(Borders.all); content.render(area, buf); const inner = content.inner(area); var y = inner.top(); // Key count var key_buf: [64]u8 = undefined; const key_str = std.fmt.bufPrint(&key_buf, "Key presses: {d}", .{state.key_count}) catch "???"; _ = buf.setString(inner.left(), y, key_str, Style.default.fg(Color.green)); y += 1; // Mouse position var mouse_buf: [64]u8 = undefined; const mouse_str = std.fmt.bufPrint(&mouse_buf, "Mouse position: ({d}, {d})", .{ state.mouse_x, state.mouse_y }) catch "???"; _ = buf.setString(inner.left(), y, mouse_str, Style.default.fg(Color.yellow)); y += 1; // Mouse clicks var clicks_buf: [64]u8 = undefined; const clicks_str = std.fmt.bufPrint(&clicks_buf, "Mouse clicks: {d}", .{state.mouse_clicks}) catch "???"; _ = buf.setString(inner.left(), y, clicks_str, Style.default.fg(Color.magenta)); y += 2; // Last event _ = buf.setString(inner.left(), y, "Last event:", Style.default.bold()); y += 1; if (state.last_event) |event| { const event_str = formatEvent(event); _ = buf.setString(inner.left() + 2, y, event_str, Style.default.fg(Color.white)); } else { _ = buf.setString(inner.left() + 2, y, "(none)", Style.default); } } fn formatEvent(event: Event) []const u8 { return switch (event) { .key => |key| switch (key.code) { .char => "Key: char", .enter => "Key: Enter", .esc => "Key: Escape", .tab => "Key: Tab", .backspace => "Key: Backspace", .up => "Key: Up", .down => "Key: Down", .left => "Key: Left", .right => "Key: Right", .home => "Key: Home", .end => "Key: End", .page_up => "Key: PageUp", .page_down => "Key: PageDown", .delete => "Key: Delete", .insert => "Key: Insert", .f => "Key: F-key", else => "Key: other", }, .mouse => |mouse| switch (mouse.kind) { .down => "Mouse: click", .up => "Mouse: release", .drag => "Mouse: drag", .moved => "Mouse: move", .scroll_up => "Mouse: scroll up", .scroll_down => "Mouse: scroll down", else => "Mouse: other", }, .resize => "Resize", .focus_gained => "Focus gained", .focus_lost => "Focus lost", .paste => "Paste", }; }