//! WASM Demo - zcatgui running in a web browser //! //! Build with: //! zig build wasm-demo //! //! Then serve the `web/` directory and open index.html const std = @import("std"); const zcatgui = @import("zcatgui"); // Use WASM allocator const allocator = std.heap.wasm_allocator; // Global state (since WASM is single-threaded) var ctx: ?*zcatgui.Context = null; var backend: ?*WasmBackend = null; var running: bool = true; // Demo state var counter: i32 = 0; var checkbox_checked: bool = false; var slider_value: f32 = 0.5; var text_buffer: [256]u8 = [_]u8{0} ** 256; var text_len: usize = 0; const WasmBackend = zcatgui.backend.wasm.WasmBackend; /// Called once at startup export fn wasm_main() void { init() catch |err| { zcatgui.backend.wasm.log("Init error: {}", .{err}); }; } /// Called every frame export fn wasm_frame() void { if (ctx) |c| { frame(c) catch |err| { zcatgui.backend.wasm.log("Frame error: {}", .{err}); }; } } fn init() !void { // Initialize backend const be = try allocator.create(WasmBackend); be.* = try WasmBackend.init(800, 600); backend = be; // Initialize context const c = try allocator.create(zcatgui.Context); c.* = try zcatgui.Context.init(allocator, 800, 600); ctx = c; zcatgui.backend.wasm.log("zcatgui WASM initialized!", .{}); } fn frame(c: *zcatgui.Context) !void { const be = backend.?; // Process events while (be.backend().pollEvent()) |event| { switch (event) { .quit => running = false, .key => |k| c.input.handleKeyEvent(k), .mouse => |m| { // Update mouse position c.input.setMousePos(m.x, m.y); // Update mouse buttons if (m.button) |btn| { c.input.setMouseButton(btn, m.pressed); } // Update scroll if (m.scroll_x != 0 or m.scroll_y != 0) { c.input.addScroll(m.scroll_x, m.scroll_y); } }, .resize => |r| { // Handle resize _ = r; }, .text_input => |t| { // Handle text input if (text_len < text_buffer.len - 1) { const slice = t.text[0..t.len]; for (slice) |char| { if (text_len < text_buffer.len - 1) { text_buffer[text_len] = char; text_len += 1; } } } }, } } // Begin frame c.beginFrame(); // Set theme const theme = zcatgui.Style.Theme.dark; // Title c.layout.row_height = 40; zcatgui.labelEx(c, "zcatgui WASM Demo", .{ .alignment = .center, .color = theme.primary, }); c.layout.row_height = 20; zcatgui.label(c, "Running in WebAssembly!"); // Spacing c.layout.row_height = 10; zcatgui.label(c, ""); // Counter section c.layout.row_height = 32; var buf: [64]u8 = undefined; const counter_text = std.fmt.bufPrint(&buf, "Counter: {d}", .{counter}) catch "Counter: ?"; zcatgui.label(c, counter_text); // Buttons if (zcatgui.button(c, "Increment")) { counter += 1; } if (zcatgui.button(c, "Decrement")) { counter -= 1; } if (zcatgui.button(c, "Reset")) { counter = 0; } // Checkbox c.layout.row_height = 10; zcatgui.label(c, ""); c.layout.row_height = 32; if (zcatgui.checkbox(c, &checkbox_checked, "Enable feature")) { // Checkbox changed } // Progress bar c.layout.row_height = 10; zcatgui.label(c, ""); c.layout.row_height = 32; var slider_buf: [32]u8 = undefined; const slider_label = std.fmt.bufPrint(&slider_buf, "Progress: {d:.0}%", .{slider_value * 100}) catch "Progress: ?"; zcatgui.label(c, slider_label); // Progress bar showing value _ = zcatgui.widgets.progress.bar(c, slider_value); // Info c.layout.row_height = 10; zcatgui.label(c, ""); c.layout.row_height = 24; zcatgui.labelEx(c, "Press keys to type, Tab to navigate", .{ .alignment = .center, .color = zcatgui.Color.rgb(128, 128, 128), }); // End frame c.endFrame(); // Render var fb = zcatgui.render.Framebuffer.init(allocator, 800, 600) catch return; defer fb.deinit(); // Clear with background color fb.clear(theme.background); // Execute draw commands var renderer = zcatgui.render.SoftwareRenderer.init(&fb); renderer.executeAll(c.commands.items); // Present to canvas be.backend().present(&fb); }