//! Android Demo - zcatgui running on Android //! //! Build with: //! zig build android-demo -Dtarget=aarch64-linux-android //! //! This creates a native Android activity that runs the zcatgui demo. const std = @import("std"); const zcatgui = @import("zcatgui"); const AndroidBackend = zcatgui.backend.android.AndroidBackend; const log = zcatgui.backend.android.log; // Global state (Android native activities are single-instance) var ctx: ?*zcatgui.Context = null; var allocator: std.mem.Allocator = undefined; // Demo state var counter: i32 = 0; var checkbox_checked: bool = false; var slider_value: f32 = 0.5; /// Main loop - called from a separate thread fn mainLoop() void { allocator = std.heap.page_allocator; // Wait for window to be ready while (!zcatgui.backend.android.isRunning()) { std.Thread.sleep(10 * std.time.ns_per_ms); } const size = zcatgui.backend.android.getWindowSize(); if (size.width == 0 or size.height == 0) { log("Invalid window size", .{}); return; } // Initialize context const c = allocator.create(zcatgui.Context) catch { log("Failed to allocate context", .{}); return; }; c.* = zcatgui.Context.init(allocator, size.width, size.height) catch { log("Failed to init context", .{}); allocator.destroy(c); return; }; ctx = c; log("zcatgui Android initialized: {}x{}", .{ size.width, size.height }); // Main loop while (zcatgui.backend.android.isRunning()) { frame() catch |err| { log("Frame error: {}", .{err}); break; }; // ~60 FPS std.Thread.sleep(16 * std.time.ns_per_ms); } // Cleanup if (ctx) |context| { context.deinit(); allocator.destroy(context); ctx = null; } log("zcatgui Android shutdown", .{}); } fn frame() !void { const c = ctx orelse return; const be = zcatgui.backend.android.getBackend() orelse return; // Get current size (may have changed due to rotation) const size = zcatgui.backend.android.getWindowSize(); if (size.width == 0 or size.height == 0) return; // Process events while (be.backend().pollEvent()) |event| { switch (event) { .quit => { be.running = false; return; }, .key => |k| c.input.handleKeyEvent(k), .mouse => |m| { c.input.setMousePos(m.x, m.y); if (m.button) |btn| { c.input.setMouseButton(btn, m.pressed); } if (m.scroll_x != 0 or m.scroll_y != 0) { c.input.addScroll(m.scroll_x, m.scroll_y); } }, .resize => |r| { // Handle resize (screen rotation) _ = r; }, .text_input => {}, } } // Begin frame c.beginFrame(); // Set theme (use high contrast for mobile) const theme = zcatgui.Style.Theme.dark; // Large touch-friendly UI c.layout.row_height = 60; // Title zcatgui.labelEx(c, "zcatgui Android Demo", .{ .alignment = .center, .color = theme.primary, }); c.layout.row_height = 40; zcatgui.label(c, "Touch to interact!"); // Spacing c.layout.row_height = 20; zcatgui.label(c, ""); // Counter section c.layout.row_height = 50; var buf: [64]u8 = undefined; const counter_text = std.fmt.bufPrint(&buf, "Counter: {d}", .{counter}) catch "Counter: ?"; zcatgui.label(c, counter_text); // Large buttons for touch c.layout.row_height = 80; if (zcatgui.button(c, "+")) { counter += 1; } if (zcatgui.button(c, "-")) { counter -= 1; } if (zcatgui.button(c, "Reset")) { counter = 0; } // Checkbox c.layout.row_height = 20; zcatgui.label(c, ""); c.layout.row_height = 60; if (zcatgui.checkbox(c, &checkbox_checked, "Enable feature")) { // Checkbox changed } // Progress bar c.layout.row_height = 20; zcatgui.label(c, ""); c.layout.row_height = 40; 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); c.layout.row_height = 30; _ = zcatgui.widgets.progress.bar(c, slider_value); // End frame c.endFrame(); // Render var fb = try zcatgui.render.Framebuffer.init(allocator, size.width, size.height); defer fb.deinit(); fb.clear(theme.background); var renderer = zcatgui.render.SoftwareRenderer.init(&fb); renderer.executeAll(c.commands.items); // Present to screen be.backend().present(&fb); } // Thread entry point - Android's main thread handles UI, we run zcatgui in background export fn android_main() void { mainLoop(); } // Alternative: Use native activity thread directly (for simpler apps) comptime { // Ensure ANativeActivity_onCreate is exported from android.zig _ = zcatgui.backend.android; }