REFERENCE.md - Comprehensive documentation for zcatgui library Contents: - Overview and design philosophy - Installation and build commands (all platforms) - Quick start guide with examples - Architecture diagram and file structure - Core modules documentation: - Context, Layout, Style, Input, Command - Clipboard, DragDrop, Shortcuts, Focus - Accessibility, Gesture recognition - All 37 widgets documented with categories: - Basic: Label, Button, TextInput, TextArea, Checkbox, Radio, Switch - Selection: Select, List, AutoComplete, Menu, Tabs - Data: Table, Tree, VirtualScroll - Input: Slider, NumberEntry, ColorPicker, DatePicker - Feedback: Progress, Tooltip, Toast, Badge, Loader - Layout: Split, Panel, Modal, ScrollArea, Surface, Grid, Resize, Divider - Navigation: AppBar, NavDrawer, Sheet, Breadcrumb, Discloser - Visual: Icon, IconButton, Image, RichText, Canvas, Chart - Interactive: Reorderable, Selectable - Rendering system: - Framebuffer, SoftwareRenderer - Bitmap and TTF fonts - Animation system (20+ easing functions, spring physics) - Effects (shadows, gradients, blur, AA) - Backend documentation: - SDL2 (desktop) - WASM (browser) with JS integration - Android (NDK) - iOS (UIKit bridge) - Macro system (record/playback) - Panel system (Lego architecture) - Performance utilities (arena, pools, benchmarks) - Theme system (5 built-in themes) - Accessibility system - Full API reference Stats: 35K LOC, 81 source files, 37 widgets, 4 backends 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1370 lines
33 KiB
Markdown
1370 lines
33 KiB
Markdown
# zcatgui Reference Manual
|
|
|
|
**Version**: 0.15.0
|
|
**Language**: Zig 0.15.2
|
|
**Paradigm**: Immediate Mode GUI
|
|
**Lines of Code**: ~35,000 across 81 source files
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Overview](#overview)
|
|
2. [Installation & Setup](#installation--setup)
|
|
3. [Quick Start](#quick-start)
|
|
4. [Architecture](#architecture)
|
|
5. [Core Modules](#core-modules)
|
|
6. [Widgets (37 total)](#widgets)
|
|
7. [Rendering System](#rendering-system)
|
|
8. [Animation & Effects](#animation--effects)
|
|
9. [Backend System](#backend-system)
|
|
10. [Macro System](#macro-system)
|
|
11. [Panel System](#panel-system)
|
|
12. [Performance Utilities](#performance-utilities)
|
|
13. [Theme System](#theme-system)
|
|
14. [Accessibility](#accessibility)
|
|
15. [Gesture Recognition](#gesture-recognition)
|
|
16. [API Reference](#api-reference)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
**zcatgui** is an immediate-mode GUI library for Zig featuring:
|
|
|
|
- **Software Rendering**: Works on any computer without GPU (SSH compatible)
|
|
- **Cross-Platform**: Linux, Windows, macOS, Web (WASM), Android, iOS
|
|
- **Macro System**: Record and replay user actions (cornerstone feature)
|
|
- **37 Widgets**: From basic labels to complex tables and charts
|
|
- **Zero External Dependencies**: Only SDL2 for desktop windowing
|
|
|
|
### Design Philosophy
|
|
|
|
```
|
|
"Maximum compatibility, minimum dependencies, total user control"
|
|
```
|
|
|
|
- Immediate mode = explicit state, no callbacks, no threading hell
|
|
- Software rendering first, GPU optional later
|
|
- Macro system integrated from the design phase
|
|
- Works on old laptops, new workstations, and via SSH
|
|
|
|
---
|
|
|
|
## Installation & Setup
|
|
|
|
### Requirements
|
|
|
|
- Zig 0.15.2
|
|
- SDL2 (for desktop builds only)
|
|
|
|
### Build Commands
|
|
|
|
```bash
|
|
# Build library and examples
|
|
zig build
|
|
|
|
# Run tests
|
|
zig build test
|
|
|
|
# Run examples
|
|
zig build hello # Hello world
|
|
zig build widgets-demo # Widget showcase
|
|
zig build table-demo # Table with split panels
|
|
zig build macro-demo # Macro recording demo
|
|
|
|
# Platform-specific builds
|
|
zig build wasm # Web (WASM) - outputs to web/
|
|
zig build android # Android ARM64
|
|
zig build android-x86 # Android x86_64 (emulator)
|
|
zig build ios # iOS ARM64 (device)
|
|
zig build ios-sim # iOS ARM64 (simulator)
|
|
```
|
|
|
|
### Project Integration
|
|
|
|
Add to your `build.zig.zon`:
|
|
```zig
|
|
.dependencies = .{
|
|
.zcatgui = .{
|
|
.path = "../path/to/zcatgui",
|
|
},
|
|
},
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
```zig
|
|
const zcatgui = @import("zcatgui");
|
|
const Context = zcatgui.Context;
|
|
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
const allocator = gpa.allocator();
|
|
|
|
// Initialize context
|
|
var ctx = try Context.init(allocator);
|
|
defer ctx.deinit();
|
|
|
|
// Main loop
|
|
while (ctx.running) {
|
|
ctx.beginFrame();
|
|
|
|
// Draw a button
|
|
if (zcatgui.button(&ctx, "Click me!")) {
|
|
// Handle click
|
|
}
|
|
|
|
// Draw a label
|
|
zcatgui.label(&ctx, "Hello, zcatgui!");
|
|
|
|
ctx.endFrame();
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Layer Diagram
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Layer 4: Widgets (37 widgets) │
|
|
│ Button, Table, Tree, Chart, Modal, etc. │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Layer 3: Macro System + Panels │
|
|
│ MacroRecorder, MacroPlayer, AutonomousPanel, Composites │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Layer 2: Core UI │
|
|
│ Context, Layout, Style, Input, Command, DragDrop, Gesture │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Layer 1: Rendering │
|
|
│ SoftwareRenderer, Framebuffer, Font, TTF, Animation │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Layer 0: Backends │
|
|
│ SDL2, WASM, Android, iOS │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### File Structure
|
|
|
|
```
|
|
zcatgui/
|
|
├── src/
|
|
│ ├── zcatgui.zig # Main entry point, re-exports
|
|
│ ├── core/ # Core modules
|
|
│ │ ├── context.zig # UI context, frame management
|
|
│ │ ├── layout.zig # Rect, Constraint, Layout
|
|
│ │ ├── style.zig # Color, Theme, ThemeManager
|
|
│ │ ├── input.zig # Key, Mouse, InputState
|
|
│ │ ├── command.zig # DrawCommand list
|
|
│ │ ├── clipboard.zig # Clipboard operations
|
|
│ │ ├── dragdrop.zig # Drag and drop system
|
|
│ │ ├── shortcuts.zig # Keyboard shortcuts
|
|
│ │ ├── focus_group.zig # Focus navigation
|
|
│ │ ├── accessibility.zig # A11y roles and states
|
|
│ │ └── gesture.zig # Touch gesture recognition
|
|
│ ├── widgets/ # 37 widgets
|
|
│ │ └── widgets.zig # Re-exports all widgets
|
|
│ ├── render/ # Rendering
|
|
│ │ ├── framebuffer.zig # Pixel buffer
|
|
│ │ ├── software.zig # Software rasterizer
|
|
│ │ ├── font.zig # Bitmap fonts
|
|
│ │ ├── ttf.zig # TrueType fonts
|
|
│ │ ├── animation.zig # Easing, Animation, Spring
|
|
│ │ ├── effects.zig # Shadow, Gradient, Blur
|
|
│ │ └── antialiasing.zig # AA drawing functions
|
|
│ ├── backend/ # Platform backends
|
|
│ │ ├── backend.zig # Abstract interface
|
|
│ │ ├── sdl2.zig # SDL2 (desktop)
|
|
│ │ ├── wasm.zig # WebAssembly
|
|
│ │ ├── android.zig # Android NDK
|
|
│ │ └── ios.zig # iOS UIKit
|
|
│ ├── macro/ # Macro system
|
|
│ │ └── macro.zig # Recorder, Player, Storage
|
|
│ ├── panels/ # Panel architecture
|
|
│ │ ├── panels.zig # Re-exports
|
|
│ │ ├── panel.zig # AutonomousPanel
|
|
│ │ ├── composite.zig # Composite patterns
|
|
│ │ └── data_manager.zig # Observer pattern
|
|
│ └── utils/ # Utilities
|
|
│ ├── utils.zig # Re-exports
|
|
│ ├── arena.zig # FrameArena, ScopedArena
|
|
│ ├── pool.zig # ObjectPool, CommandPool
|
|
│ ├── benchmark.zig # Timer, Benchmark
|
|
│ └── testing.zig # TestRunner, Assertions
|
|
├── examples/ # Example applications
|
|
├── web/ # WASM build output
|
|
├── ios/ # iOS bridge files
|
|
└── docs/ # Documentation
|
|
```
|
|
|
|
---
|
|
|
|
## Core Modules
|
|
|
|
### Context (`src/core/context.zig`)
|
|
|
|
The UI context manages frame lifecycle, command queue, and dirty regions.
|
|
|
|
```zig
|
|
const Context = zcatgui.Context;
|
|
|
|
// Create context
|
|
var ctx = try Context.init(allocator);
|
|
defer ctx.deinit();
|
|
|
|
// Frame lifecycle
|
|
ctx.beginFrame();
|
|
// ... draw widgets ...
|
|
ctx.endFrame();
|
|
|
|
// Access components
|
|
ctx.layout // LayoutState
|
|
ctx.input // InputState
|
|
ctx.commands // Command list
|
|
ctx.frame_arena // Per-frame allocator
|
|
|
|
// Dirty rectangle tracking
|
|
ctx.invalidateRect(rect);
|
|
ctx.needsRedraw();
|
|
ctx.getDirtyRects();
|
|
```
|
|
|
|
**Key Types:**
|
|
- `Context` - Main UI context
|
|
- `FrameStats` - Performance statistics
|
|
|
|
---
|
|
|
|
### Layout (`src/core/layout.zig`)
|
|
|
|
Rectangle and constraint-based layout system.
|
|
|
|
```zig
|
|
const Layout = zcatgui.Layout;
|
|
const Rect = zcatgui.Rect;
|
|
const Constraint = zcatgui.Constraint;
|
|
|
|
// Create rectangles
|
|
const rect = Rect.init(x, y, width, height);
|
|
|
|
// Rectangle operations
|
|
rect.contains(point_x, point_y)
|
|
rect.intersection(other_rect)
|
|
rect.union_rect(other_rect)
|
|
rect.isEmpty()
|
|
rect.left(), rect.right(), rect.top(), rect.bottom()
|
|
rect.center()
|
|
rect.inset(amount)
|
|
rect.expand(amount)
|
|
|
|
// Constraints
|
|
const constraint = Constraint{
|
|
.min_width = 100,
|
|
.max_width = 500,
|
|
.min_height = 50,
|
|
.max_height = 200,
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### Style (`src/core/style.zig`)
|
|
|
|
Colors and theming system.
|
|
|
|
```zig
|
|
const Style = zcatgui.Style;
|
|
const Color = zcatgui.Color;
|
|
const Theme = zcatgui.Theme;
|
|
|
|
// Color creation
|
|
const red = Color.rgb(255, 0, 0);
|
|
const semi_transparent = Color.rgba(255, 0, 0, 128);
|
|
|
|
// Predefined colors
|
|
Color.white, Color.black, Color.red, Color.green, Color.blue
|
|
Color.primary, Color.secondary, Color.success, Color.warning, Color.danger
|
|
|
|
// Color operations
|
|
color.toABGR() // For framebuffer
|
|
color.blend(background) // Alpha blending
|
|
color.withAlpha(128) // New alpha value
|
|
|
|
// Theme system
|
|
const theme = zcatgui.currentTheme();
|
|
theme.colors.primary
|
|
theme.colors.background
|
|
theme.colors.text
|
|
```
|
|
|
|
**Built-in Themes:** `dark`, `light`, `high_contrast`, `nord`, `dracula`
|
|
|
|
---
|
|
|
|
### Input (`src/core/input.zig`)
|
|
|
|
Keyboard and mouse input handling.
|
|
|
|
```zig
|
|
const Input = zcatgui.Input;
|
|
const InputState = Input.InputState;
|
|
|
|
// In your frame loop
|
|
const input = &ctx.input;
|
|
|
|
// Keyboard
|
|
input.keyPressed(.enter) // Just pressed this frame
|
|
input.keyReleased(.escape) // Just released
|
|
input.keyDown(.left_shift) // Currently held
|
|
input.getChar() // Text input character
|
|
|
|
// Mouse
|
|
input.mousePressed(.left)
|
|
input.mouseReleased(.right)
|
|
input.mouseDown(.middle)
|
|
const pos = input.mousePos(); // {x, y}
|
|
input.mouseDelta() // Movement since last frame
|
|
input.scrollDelta() // Scroll wheel
|
|
|
|
// Modifiers
|
|
input.keyDown(.left_ctrl) or input.keyDown(.right_ctrl)
|
|
input.keyDown(.left_shift) or input.keyDown(.right_shift)
|
|
input.keyDown(.left_alt) or input.keyDown(.right_alt)
|
|
```
|
|
|
|
**Key Enum:** 130+ keys including `.a`-`.z`, `.F1`-`.F12`, `.space`, `.enter`, `.tab`, `.escape`, arrow keys, numpad, etc.
|
|
|
|
---
|
|
|
|
### Command (`src/core/command.zig`)
|
|
|
|
Draw command system for batched rendering.
|
|
|
|
```zig
|
|
const Command = zcatgui.Command;
|
|
|
|
// Command types
|
|
Command.rect(x, y, w, h, color) // Filled rectangle
|
|
Command.rectOutline(x, y, w, h, color, thickness)
|
|
Command.text(x, y, text, color, font) // Text rendering
|
|
Command.line(x1, y1, x2, y2, color) // Line
|
|
Command.clip(x, y, w, h) // Push clip region
|
|
Command.clipEnd() // Pop clip region
|
|
Command.nop // No operation
|
|
```
|
|
|
|
---
|
|
|
|
## Widgets
|
|
|
|
### Basic Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Label** | `widgets/label.zig` | Static text display |
|
|
| **Button** | `widgets/button.zig` | Clickable button with importance levels |
|
|
| **TextInput** | `widgets/text_input.zig` | Single-line text entry |
|
|
| **TextArea** | `widgets/textarea.zig` | Multi-line text editor |
|
|
| **Checkbox** | `widgets/checkbox.zig` | Boolean toggle |
|
|
| **Radio** | `widgets/radio.zig` | Radio button groups |
|
|
| **Switch** | `widgets/switch.zig` | Toggle switch (iOS style) |
|
|
|
|
### Selection Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Select** | `widgets/select.zig` | Dropdown selection |
|
|
| **List** | `widgets/list.zig` | Scrollable list |
|
|
| **AutoComplete** | `widgets/autocomplete.zig` | ComboBox with filtering |
|
|
| **Menu** | `widgets/menu.zig` | Dropdown/context menus |
|
|
| **Tabs** | `widgets/tabs.zig` | Tab container |
|
|
|
|
### Data Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Table** | `widgets/table.zig` | Editable data table with sorting |
|
|
| **Tree** | `widgets/tree.zig` | Hierarchical tree view |
|
|
| **VirtualScroll** | `widgets/virtual_scroll.zig` | Virtualized list for large data |
|
|
|
|
### Input Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Slider** | `widgets/slider.zig` | Range selection |
|
|
| **NumberEntry** | `widgets/numberentry.zig` | Numeric input with validation |
|
|
| **ColorPicker** | `widgets/colorpicker.zig` | Color selection |
|
|
| **DatePicker** | `widgets/datepicker.zig` | Date selection calendar |
|
|
|
|
### Feedback Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Progress** | `widgets/progress.zig` | Bar, circle, and spinner |
|
|
| **Tooltip** | `widgets/tooltip.zig` | Hover tooltips |
|
|
| **Toast** | `widgets/toast.zig` | Non-blocking notifications |
|
|
| **Badge** | `widgets/badge.zig` | Status labels and tags |
|
|
| **Loader** | `widgets/loader.zig` | Loading indicators |
|
|
|
|
### Layout Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Split** | `widgets/split.zig` | HSplit/VSplit draggable panels |
|
|
| **Panel** | `widgets/panel.zig` | Container with title bar |
|
|
| **Modal** | `widgets/modal.zig` | Dialog windows |
|
|
| **ScrollArea** | `widgets/scroll.zig` | Scrollable content region |
|
|
| **Surface** | `widgets/surface.zig` | Elevated container (material) |
|
|
| **Grid** | `widgets/grid.zig` | Grid layout container |
|
|
| **Resize** | `widgets/resize.zig` | Resizable container |
|
|
| **Divider** | `widgets/divider.zig` | Visual separator |
|
|
|
|
### Navigation Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **AppBar** | `widgets/appbar.zig` | Top app bar |
|
|
| **NavDrawer** | `widgets/navdrawer.zig` | Side navigation |
|
|
| **Sheet** | `widgets/sheet.zig` | Bottom/side sheets |
|
|
| **Breadcrumb** | `widgets/breadcrumb.zig` | Navigation breadcrumbs |
|
|
| **Discloser** | `widgets/discloser.zig` | Expand/collapse sections |
|
|
|
|
### Visual Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Icon** | `widgets/icon.zig` | Icon display |
|
|
| **IconButton** | `widgets/iconbutton.zig` | Icon-only button |
|
|
| **Image** | `widgets/image.zig` | Image display with caching |
|
|
| **RichText** | `widgets/richtext.zig` | Styled text spans |
|
|
| **Canvas** | `widgets/canvas.zig` | Custom drawing area |
|
|
| **Chart** | `widgets/chart.zig` | Line, bar, pie charts |
|
|
|
|
### Interactive Widgets
|
|
|
|
| Widget | File | Description |
|
|
|--------|------|-------------|
|
|
| **Reorderable** | `widgets/reorderable.zig` | Drag-to-reorder list |
|
|
| **Selectable** | `widgets/selectable.zig` | Selection container |
|
|
|
|
---
|
|
|
|
### Widget Usage Examples
|
|
|
|
#### Button
|
|
|
|
```zig
|
|
// Simple button
|
|
if (zcatgui.button(&ctx, "Click me")) {
|
|
// Handle click
|
|
}
|
|
|
|
// Button with importance
|
|
if (zcatgui.buttonPrimary(&ctx, "Submit")) { ... }
|
|
if (zcatgui.buttonDanger(&ctx, "Delete")) { ... }
|
|
|
|
// Full configuration
|
|
const result = zcatgui.widgets.button.buttonEx(&ctx, "Save", .{
|
|
.importance = .primary,
|
|
.disabled = false,
|
|
.width = 120,
|
|
}, .{});
|
|
```
|
|
|
|
#### TextInput
|
|
|
|
```zig
|
|
var text_state = zcatgui.TextInputState{};
|
|
var buffer: [256]u8 = undefined;
|
|
|
|
const result = zcatgui.textInput(&ctx, &text_state, &buffer);
|
|
if (result.changed) {
|
|
// Text was modified
|
|
}
|
|
if (result.submitted) {
|
|
// Enter was pressed
|
|
}
|
|
```
|
|
|
|
#### Table
|
|
|
|
```zig
|
|
const columns = [_]zcatgui.widgets.Column{
|
|
.{ .name = "Name", .width = 150 },
|
|
.{ .name = "Age", .width = 80, .column_type = .number },
|
|
.{ .name = "Email", .width = 200 },
|
|
};
|
|
|
|
var table_state = zcatgui.widgets.TableState{};
|
|
|
|
const result = zcatgui.widgets.table.table(
|
|
&ctx,
|
|
&table_state,
|
|
&columns,
|
|
data,
|
|
row_count,
|
|
);
|
|
|
|
if (result.cell_edited) {
|
|
// Handle cell edit
|
|
}
|
|
if (result.row_added) {
|
|
// Add new row
|
|
}
|
|
```
|
|
|
|
#### Slider
|
|
|
|
```zig
|
|
var slider_state = zcatgui.widgets.SliderState{};
|
|
slider_state.setValue(50, 0, 100); // Initial value
|
|
|
|
const result = zcatgui.widgets.slider.slider(&ctx, &slider_state);
|
|
if (result.changed) {
|
|
const value = slider_state.getValueInt(0, 100);
|
|
}
|
|
```
|
|
|
|
#### Modal
|
|
|
|
```zig
|
|
var show_modal = false;
|
|
|
|
if (zcatgui.button(&ctx, "Open Modal")) {
|
|
show_modal = true;
|
|
}
|
|
|
|
if (show_modal) {
|
|
const result = zcatgui.widgets.modal.alert(
|
|
&ctx,
|
|
"Confirmation",
|
|
"Are you sure?",
|
|
);
|
|
if (result.confirmed or result.cancelled) {
|
|
show_modal = false;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Rendering System
|
|
|
|
### Framebuffer (`src/render/framebuffer.zig`)
|
|
|
|
Software pixel buffer.
|
|
|
|
```zig
|
|
const Framebuffer = zcatgui.render.Framebuffer;
|
|
|
|
var fb = try Framebuffer.init(allocator, 800, 600);
|
|
defer fb.deinit();
|
|
|
|
// Operations
|
|
fb.clear(Color.black);
|
|
fb.setPixel(x, y, color);
|
|
fb.getPixel(x, y);
|
|
fb.fillRect(x, y, w, h, color);
|
|
fb.drawRect(x, y, w, h, color); // Outline
|
|
fb.drawLine(x1, y1, x2, y2, color);
|
|
fb.drawHLine(x, y, w, color);
|
|
fb.drawVLine(x, y, h, color);
|
|
|
|
// For blitting to backend
|
|
fb.getData() // []const u32
|
|
fb.getPitch() // Bytes per row
|
|
```
|
|
|
|
### SoftwareRenderer (`src/render/software.zig`)
|
|
|
|
Executes draw commands on framebuffer.
|
|
|
|
```zig
|
|
const SoftwareRenderer = zcatgui.render.SoftwareRenderer;
|
|
|
|
var renderer = SoftwareRenderer.init(&framebuffer);
|
|
renderer.setDefaultFont(&font);
|
|
|
|
// Execute commands
|
|
renderer.execute(command);
|
|
renderer.executeAll(command_slice);
|
|
|
|
// Clipping
|
|
renderer.getClip(); // Current clip rect
|
|
```
|
|
|
|
### Font System
|
|
|
|
**Bitmap Fonts** (`src/render/font.zig`):
|
|
```zig
|
|
const Font = zcatgui.render.Font;
|
|
|
|
// Built-in 8x8 font
|
|
const font = zcatgui.render.default_font;
|
|
|
|
font.charWidth() // 8
|
|
font.charHeight() // 8
|
|
font.textWidth("Hello") // 40
|
|
|
|
font.drawChar(fb, x, y, 'A', color, clip);
|
|
font.drawText(fb, x, y, "Hello", color, clip);
|
|
```
|
|
|
|
**TrueType Fonts** (`src/render/ttf.zig`):
|
|
```zig
|
|
const TtfFont = zcatgui.render.TtfFont;
|
|
|
|
var ttf = try TtfFont.loadFromFile(allocator, "font.ttf");
|
|
defer ttf.deinit();
|
|
|
|
const metrics = ttf.getMetrics();
|
|
ttf.renderGlyph(codepoint, size);
|
|
```
|
|
|
|
---
|
|
|
|
## Animation & Effects
|
|
|
|
### Animation (`src/render/animation.zig`)
|
|
|
|
**Easing Functions:**
|
|
```zig
|
|
const Easing = zcatgui.Easing;
|
|
|
|
Easing.linear(t)
|
|
Easing.easeInQuad(t), Easing.easeOutQuad(t), Easing.easeInOutQuad(t)
|
|
Easing.easeInCubic(t), Easing.easeOutCubic(t), Easing.easeInOutCubic(t)
|
|
Easing.easeInSine(t), Easing.easeOutSine(t), Easing.easeInOutSine(t)
|
|
Easing.easeInExpo(t), Easing.easeOutExpo(t), Easing.easeInOutExpo(t)
|
|
Easing.easeInElastic(t), Easing.easeOutElastic(t)
|
|
Easing.easeInBounce(t), Easing.easeOutBounce(t), Easing.easeInOutBounce(t)
|
|
Easing.easeInBack(t), Easing.easeOutBack(t), Easing.easeInOutBack(t)
|
|
```
|
|
|
|
**Animation:**
|
|
```zig
|
|
const Animation = zcatgui.Animation;
|
|
|
|
var anim = Animation.create(0, 100, 1000, Easing.easeOutCubic);
|
|
anim.start(current_time_ms);
|
|
|
|
// In frame loop
|
|
const value = anim.getValue(current_time_ms);
|
|
if (anim.isComplete(current_time_ms)) {
|
|
// Animation done
|
|
}
|
|
```
|
|
|
|
**Spring Physics:**
|
|
```zig
|
|
const Spring = zcatgui.Spring;
|
|
const SpringConfig = zcatgui.SpringConfig;
|
|
|
|
var spring = Spring.create(0, 100, .{
|
|
.stiffness = 100,
|
|
.damping = 10,
|
|
.mass = 1,
|
|
});
|
|
|
|
// Each frame
|
|
spring.update(dt_seconds);
|
|
const value = spring.getValue();
|
|
if (spring.isSettled()) { ... }
|
|
```
|
|
|
|
**AnimationManager:**
|
|
```zig
|
|
const AnimationManager = zcatgui.AnimationManager;
|
|
|
|
var manager = AnimationManager.init();
|
|
manager.startAnimation(id, animation, time);
|
|
manager.getValue(id, time);
|
|
manager.stopAnimation(id);
|
|
manager.update(time);
|
|
```
|
|
|
|
### Effects (`src/render/effects.zig`)
|
|
|
|
**Shadows:**
|
|
```zig
|
|
const Shadow = zcatgui.Shadow;
|
|
|
|
const shadow = Shadow{
|
|
.offset_x = 4,
|
|
.offset_y = 4,
|
|
.blur_radius = 8,
|
|
.color = Color.rgba(0, 0, 0, 128),
|
|
};
|
|
|
|
// Presets
|
|
Shadow.soft() // Subtle shadow
|
|
Shadow.hard() // No blur
|
|
Shadow.drop(offset, blur)
|
|
|
|
zcatgui.applyShadow(framebuffer, rect, shadow);
|
|
```
|
|
|
|
**Gradients:**
|
|
```zig
|
|
const Gradient = zcatgui.Gradient;
|
|
|
|
// Types
|
|
Gradient.horizontal(start_color, end_color)
|
|
Gradient.vertical(start_color, end_color)
|
|
Gradient.diagonal(start_color, end_color)
|
|
|
|
const gradient = Gradient{
|
|
.start_color = Color.rgb(255, 0, 0),
|
|
.end_color = Color.rgb(0, 0, 255),
|
|
.direction = .radial,
|
|
};
|
|
|
|
zcatgui.applyGradient(framebuffer, rect, gradient);
|
|
```
|
|
|
|
**Color Operations:**
|
|
```zig
|
|
zcatgui.interpolateColor(color_a, color_b, t) // Blend
|
|
zcatgui.applyOpacity(color, 0.5) // Reduce alpha
|
|
zcatgui.highlight(color, 50) // Lighter
|
|
zcatgui.lowlight(color, 50) // Darker
|
|
zcatgui.applyBlur(framebuffer, rect, radius) // Box blur
|
|
```
|
|
|
|
### Anti-aliasing (`src/render/antialiasing.zig`)
|
|
|
|
```zig
|
|
const AA = zcatgui.render.antialiasing;
|
|
|
|
// Quality levels
|
|
AAQuality.none, AAQuality.low, AAQuality.medium, AAQuality.high
|
|
|
|
// AA drawing functions
|
|
zcatgui.drawLineAA(fb, x1, y1, x2, y2, color, quality)
|
|
zcatgui.drawCircleAA(fb, cx, cy, radius, color, quality)
|
|
zcatgui.drawRoundedRectAA(fb, rect, corner_radius, color, quality)
|
|
zcatgui.drawEllipseAA(fb, rect, color, quality)
|
|
zcatgui.drawPolygonAA(fb, points, color, quality)
|
|
```
|
|
|
|
---
|
|
|
|
## Backend System
|
|
|
|
### Abstract Interface (`src/backend/backend.zig`)
|
|
|
|
```zig
|
|
const Backend = zcatgui.backend.Backend;
|
|
|
|
// VTable interface
|
|
backend.pollEvent() // ?Event
|
|
backend.present(fb) // Display framebuffer
|
|
backend.getSize() // {width, height}
|
|
backend.deinit() // Cleanup
|
|
```
|
|
|
|
**Event Types:**
|
|
```zig
|
|
const Event = zcatgui.backend.Event;
|
|
|
|
event.key // KeyEvent
|
|
event.mouse // MouseEvent
|
|
event.resize // {width, height}
|
|
event.quit // Window close
|
|
event.text_input // Unicode text
|
|
```
|
|
|
|
### SDL2 Backend (`src/backend/sdl2.zig`)
|
|
|
|
Desktop platform (Linux, Windows, macOS).
|
|
|
|
```zig
|
|
const Sdl2Backend = zcatgui.backend.Sdl2Backend;
|
|
|
|
var backend = try Sdl2Backend.init(allocator, "My App", 800, 600);
|
|
defer backend.deinit();
|
|
|
|
while (backend.pollEvent()) |event| {
|
|
// Handle events
|
|
}
|
|
|
|
backend.present(&framebuffer);
|
|
```
|
|
|
|
### WASM Backend (`src/backend/wasm.zig`)
|
|
|
|
Browser via WebAssembly.
|
|
|
|
```zig
|
|
// Zig side - exports these functions
|
|
export fn wasm_main() void { ... }
|
|
export fn wasm_frame(time: f64) void { ... }
|
|
export fn wasm_resize(w: u32, h: u32) void { ... }
|
|
export fn wasm_mouse_move(x: i32, y: i32) void { ... }
|
|
export fn wasm_mouse_button(btn: u8, down: bool) void { ... }
|
|
export fn wasm_key_event(code: u16, down: bool) void { ... }
|
|
```
|
|
|
|
**JavaScript integration** (`web/zcatgui.js`):
|
|
```javascript
|
|
// Load and initialize
|
|
const app = await ZcatguiApp.create('canvas-id', 'zcatgui-demo.wasm');
|
|
app.start();
|
|
```
|
|
|
|
Build: `zig build wasm` outputs to `web/zcatgui-demo.wasm` (18KB)
|
|
|
|
### Android Backend (`src/backend/android.zig`)
|
|
|
|
Native Android via NDK.
|
|
|
|
```zig
|
|
// Exports for JNI
|
|
export fn ANativeActivity_onCreate(...) void { ... }
|
|
|
|
// Logging
|
|
zcatgui.backend.android.log("Message: {}", .{value});
|
|
```
|
|
|
|
Build: `zig build android` (ARM64), `zig build android-x86` (emulator)
|
|
|
|
### iOS Backend (`src/backend/ios.zig`)
|
|
|
|
iOS via UIKit bridge.
|
|
|
|
**Zig side:**
|
|
```zig
|
|
// Extern C functions called from Objective-C
|
|
extern fn ios_view_init(w: u32, h: u32) void;
|
|
extern fn ios_view_present(pixels: [*]const u32, w: u32, h: u32) void;
|
|
extern fn ios_poll_event(buffer: [*]u8) u32;
|
|
```
|
|
|
|
**Objective-C bridge** (`ios/ZcatguiBridge.m`):
|
|
- `ZcatguiView`: UIView subclass for framebuffer display
|
|
- `ZcatguiViewController`: View controller with CADisplayLink render loop
|
|
- Touch event handling with queue
|
|
|
|
Build: `zig build ios` (device), `zig build ios-sim` (simulator)
|
|
|
|
---
|
|
|
|
## Macro System
|
|
|
|
The macro system is a **cornerstone feature** of zcatgui, enabling recording and playback of user actions.
|
|
|
|
### Design Philosophy
|
|
|
|
**Raw keys, not semantic commands:**
|
|
- Simpler (less code = less bugs)
|
|
- Like Vim (proven to work)
|
|
- Minimal memory usage
|
|
|
|
### MacroRecorder (`src/macro/macro.zig`)
|
|
|
|
```zig
|
|
const MacroRecorder = zcatgui.MacroRecorder;
|
|
|
|
var recorder = MacroRecorder.init(allocator);
|
|
defer recorder.deinit();
|
|
|
|
// Record
|
|
recorder.start();
|
|
recorder.record(key_event); // Call for each key event
|
|
const events = recorder.stop();
|
|
|
|
// Save/Load
|
|
try recorder.save("macro.zcm");
|
|
try recorder.load("macro.zcm");
|
|
|
|
// Convert to named macro
|
|
const macro = try recorder.toMacro("my_macro");
|
|
```
|
|
|
|
### MacroPlayer
|
|
|
|
```zig
|
|
const MacroPlayer = zcatgui.MacroPlayer;
|
|
|
|
// Injection function
|
|
fn injectKey(event: KeyEvent) void {
|
|
// Add to input queue
|
|
}
|
|
|
|
// Playback
|
|
MacroPlayer.play(events, injectKey);
|
|
MacroPlayer.playWithDelay(events, injectKey, 50); // 50ms between keys
|
|
```
|
|
|
|
### MacroStorage
|
|
|
|
```zig
|
|
const MacroStorage = zcatgui.macro.MacroStorage;
|
|
|
|
var storage = MacroStorage.init(allocator);
|
|
defer storage.deinit();
|
|
|
|
try storage.store(macro);
|
|
const m = storage.get("macro_name");
|
|
storage.remove("macro_name");
|
|
const names = storage.list();
|
|
```
|
|
|
|
### File Format
|
|
|
|
```
|
|
ZCATGUI_MACRO_V1
|
|
<key_code>,<modifiers>,<char>,<pressed>
|
|
...
|
|
```
|
|
|
|
---
|
|
|
|
## Panel System
|
|
|
|
Lego-style composable panels based on Simifactu architecture.
|
|
|
|
### AutonomousPanel (`src/panels/panel.zig`)
|
|
|
|
Self-contained UI component with own state, UI, and logic.
|
|
|
|
```zig
|
|
const AutonomousPanel = zcatgui.panels.AutonomousPanel;
|
|
|
|
const panel = AutonomousPanel{
|
|
.id = "my_panel",
|
|
.panel_type = .content,
|
|
.state = .active,
|
|
.build_fn = myBuildFn,
|
|
.refresh_fn = myRefreshFn,
|
|
.data_change_fn = myDataChangeFn,
|
|
};
|
|
```
|
|
|
|
### Composite Patterns (`src/panels/composite.zig`)
|
|
|
|
```zig
|
|
const composite = zcatgui.panels.composite;
|
|
|
|
// Vertical stack
|
|
var vstack = composite.VerticalComposite.init();
|
|
vstack.add(panel1);
|
|
vstack.add(panel2);
|
|
|
|
// Horizontal stack
|
|
var hstack = composite.HorizontalComposite.init();
|
|
|
|
// Split with draggable divider
|
|
var split = composite.SplitComposite.init(.horizontal, 0.5);
|
|
|
|
// Tabs
|
|
var tabs = composite.TabComposite.init();
|
|
tabs.addTab("Tab 1", panel1);
|
|
tabs.addTab("Tab 2", panel2);
|
|
|
|
// Grid layout
|
|
var grid = composite.GridComposite.init(3, 2); // 3 columns, 2 rows
|
|
```
|
|
|
|
### DataManager (`src/panels/data_manager.zig`)
|
|
|
|
Observer pattern for panel communication.
|
|
|
|
```zig
|
|
const DataManager = zcatgui.panels.DataManager;
|
|
|
|
var manager = DataManager.init(allocator);
|
|
defer manager.deinit();
|
|
|
|
// Subscribe to changes
|
|
manager.subscribe("data_key", myCallback);
|
|
|
|
// Notify changes
|
|
manager.notify(.{
|
|
.key = "data_key",
|
|
.change_type = .modified,
|
|
.data = payload,
|
|
});
|
|
|
|
// Global access
|
|
zcatgui.panels.setDataManager(&manager);
|
|
const dm = zcatgui.panels.getDataManager();
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Utilities
|
|
|
|
### FrameArena (`src/utils/arena.zig`)
|
|
|
|
Per-frame allocator with O(1) reset.
|
|
|
|
```zig
|
|
const FrameArena = zcatgui.FrameArena;
|
|
|
|
var arena = try FrameArena.init(allocator, 1024 * 1024);
|
|
defer arena.deinit();
|
|
|
|
// Each frame
|
|
arena.reset();
|
|
const temp = arena.alloc(u8, 100);
|
|
// No need to free - reset clears everything
|
|
```
|
|
|
|
### ObjectPool (`src/utils/pool.zig`)
|
|
|
|
Generic object pool for frequently reused objects.
|
|
|
|
```zig
|
|
const ObjectPool = zcatgui.ObjectPool;
|
|
|
|
var pool = ObjectPool(MyType).init(allocator, 100);
|
|
defer pool.deinit();
|
|
|
|
const obj = pool.acquire();
|
|
// Use obj...
|
|
pool.release(obj);
|
|
```
|
|
|
|
### CommandPool
|
|
|
|
Specialized pool for draw commands.
|
|
|
|
```zig
|
|
const CommandPool = zcatgui.CommandPool;
|
|
|
|
var pool = CommandPool.init(allocator);
|
|
defer pool.deinit();
|
|
|
|
const cmd = pool.acquire();
|
|
pool.releaseAll();
|
|
```
|
|
|
|
### Benchmark (`src/utils/benchmark.zig`)
|
|
|
|
```zig
|
|
const Timer = zcatgui.Timer;
|
|
const Benchmark = zcatgui.Benchmark;
|
|
const FrameTimer = zcatgui.FrameTimer;
|
|
|
|
// Simple timing
|
|
var timer = Timer.start();
|
|
// ... work ...
|
|
const elapsed_ns = timer.elapsed();
|
|
|
|
// Statistics
|
|
var bench = Benchmark.init();
|
|
for (iterations) |_| {
|
|
timer = Timer.start();
|
|
// ... work ...
|
|
bench.addSample(timer.elapsed());
|
|
}
|
|
bench.average();
|
|
bench.min();
|
|
bench.max();
|
|
bench.stddev();
|
|
bench.median();
|
|
|
|
// Frame timing
|
|
var frame_timer = FrameTimer.init();
|
|
// Each frame
|
|
frame_timer.tick();
|
|
frame_timer.fps();
|
|
frame_timer.frameTimeMs();
|
|
```
|
|
|
|
### AllocationTracker
|
|
|
|
```zig
|
|
const AllocationTracker = zcatgui.AllocationTracker;
|
|
|
|
var tracker = AllocationTracker.init();
|
|
tracker.trackAlloc(size);
|
|
tracker.trackFree(size);
|
|
tracker.currentBytes();
|
|
tracker.peakBytes();
|
|
tracker.totalAllocations();
|
|
```
|
|
|
|
---
|
|
|
|
## Theme System
|
|
|
|
### Built-in Themes
|
|
|
|
```zig
|
|
const ThemeManager = zcatgui.ThemeManager;
|
|
|
|
// Get global manager
|
|
var manager = zcatgui.getThemeManager();
|
|
|
|
// Switch themes
|
|
manager.setTheme(.dark);
|
|
manager.setTheme(.light);
|
|
manager.setTheme(.high_contrast);
|
|
manager.setTheme(.nord);
|
|
manager.setTheme(.dracula);
|
|
|
|
// Get current theme
|
|
const theme = zcatgui.currentTheme();
|
|
theme.colors.primary
|
|
theme.colors.secondary
|
|
theme.colors.background
|
|
theme.colors.surface
|
|
theme.colors.text
|
|
theme.colors.text_secondary
|
|
theme.colors.border
|
|
theme.colors.success
|
|
theme.colors.warning
|
|
theme.colors.danger
|
|
```
|
|
|
|
### Custom Themes
|
|
|
|
```zig
|
|
const custom_theme = Theme{
|
|
.name = "custom",
|
|
.colors = .{
|
|
.primary = Color.rgb(100, 150, 200),
|
|
.background = Color.rgb(30, 30, 30),
|
|
// ... etc
|
|
},
|
|
};
|
|
|
|
manager.registerTheme("custom", custom_theme);
|
|
```
|
|
|
|
---
|
|
|
|
## Accessibility
|
|
|
|
### Roles (`src/core/accessibility.zig`)
|
|
|
|
```zig
|
|
const A11yRole = zcatgui.A11yRole;
|
|
|
|
A11yRole.button
|
|
A11yRole.checkbox
|
|
A11yRole.radio
|
|
A11yRole.textbox
|
|
A11yRole.slider
|
|
A11yRole.progressbar
|
|
A11yRole.listbox
|
|
A11yRole.tree
|
|
A11yRole.table
|
|
A11yRole.dialog
|
|
// ... and more
|
|
```
|
|
|
|
### States
|
|
|
|
```zig
|
|
const A11yState = zcatgui.A11yState;
|
|
|
|
const state = A11yState{
|
|
.disabled = false,
|
|
.focused = true,
|
|
.selected = false,
|
|
.checked = true,
|
|
.expanded = false,
|
|
};
|
|
```
|
|
|
|
### Info
|
|
|
|
```zig
|
|
const A11yInfo = zcatgui.A11yInfo;
|
|
|
|
// Create info for widgets
|
|
A11yInfo.button("Submit")
|
|
A11yInfo.checkbox("Accept terms", is_checked)
|
|
A11yInfo.slider("Volume", 0, 100, current_value)
|
|
A11yInfo.progressBar("Loading", progress)
|
|
A11yInfo.listItem("Item 1", position, total)
|
|
|
|
// Announce for screen readers
|
|
var buf: [256]u8 = undefined;
|
|
const announcement = info.announce(&buf);
|
|
```
|
|
|
|
### Manager
|
|
|
|
```zig
|
|
const A11yManager = zcatgui.A11yManager;
|
|
|
|
var manager = A11yManager.init(allocator);
|
|
defer manager.deinit();
|
|
|
|
manager.register(widget_id, a11y_info);
|
|
manager.setFocus(widget_id);
|
|
manager.queueAnnouncement("File saved", .polite);
|
|
```
|
|
|
|
---
|
|
|
|
## Gesture Recognition
|
|
|
|
### GestureRecognizer (`src/core/gesture.zig`)
|
|
|
|
```zig
|
|
const GestureRecognizer = zcatgui.GestureRecognizer;
|
|
const GestureType = zcatgui.GestureType;
|
|
|
|
var recognizer = GestureRecognizer.init(.{
|
|
.double_tap_time_ms = 300,
|
|
.long_press_time_ms = 500,
|
|
.swipe_min_distance = 50,
|
|
.swipe_min_velocity = 200,
|
|
});
|
|
|
|
// Each frame
|
|
const result = recognizer.update(&input_state, current_time_ms);
|
|
|
|
// Check gestures
|
|
if (recognizer.detected(.tap)) { ... }
|
|
if (recognizer.detected(.double_tap)) { ... }
|
|
if (recognizer.detected(.long_press)) { ... }
|
|
if (recognizer.detected(.swipe_left)) { ... }
|
|
if (recognizer.isDragging()) {
|
|
const delta = recognizer.dragDelta();
|
|
}
|
|
```
|
|
|
|
**Gesture Types:**
|
|
- `.tap` - Single tap
|
|
- `.double_tap` - Double tap
|
|
- `.long_press` - Press and hold
|
|
- `.drag` - Press and move
|
|
- `.swipe_left`, `.swipe_right`, `.swipe_up`, `.swipe_down`
|
|
- `.pinch`, `.rotate` (future touch support)
|
|
|
|
---
|
|
|
|
## API Reference
|
|
|
|
### Main Module Exports (`src/zcatgui.zig`)
|
|
|
|
```zig
|
|
// Core
|
|
pub const Context
|
|
pub const Layout
|
|
pub const Style
|
|
pub const Input
|
|
pub const Command
|
|
pub const clipboard
|
|
pub const dragdrop
|
|
pub const shortcuts
|
|
pub const focus_group
|
|
pub const accessibility
|
|
pub const gesture
|
|
|
|
// Rendering
|
|
pub const render.Framebuffer
|
|
pub const render.SoftwareRenderer
|
|
pub const render.Font
|
|
pub const render.TtfFont
|
|
pub const render.animation
|
|
pub const render.effects
|
|
pub const render.antialiasing
|
|
|
|
// Animation (re-exports)
|
|
pub const Animation
|
|
pub const AnimationManager
|
|
pub const Easing
|
|
pub const Spring
|
|
pub const SpringConfig
|
|
pub const lerp
|
|
pub const lerpInt
|
|
|
|
// Effects (re-exports)
|
|
pub const Shadow
|
|
pub const Gradient
|
|
pub const applyShadow
|
|
pub const applyGradient
|
|
pub const applyBlur
|
|
pub const interpolateColor
|
|
pub const highlight
|
|
pub const lowlight
|
|
|
|
// Backend
|
|
pub const backend.Backend
|
|
pub const backend.Sdl2Backend // Desktop only
|
|
pub const backend.wasm // WASM only
|
|
pub const backend.android // Android only
|
|
pub const backend.ios // iOS only
|
|
|
|
// Macro
|
|
pub const macro
|
|
pub const MacroRecorder
|
|
pub const MacroPlayer
|
|
pub const KeyEvent
|
|
|
|
// Widgets (37 total)
|
|
pub const widgets
|
|
|
|
// Widget shortcuts
|
|
pub const label, labelEx, labelColored, labelCentered
|
|
pub const button, buttonEx, buttonPrimary, buttonDanger
|
|
pub const textInput, textInputEx, TextInputState
|
|
pub const checkbox, checkboxEx
|
|
pub const select, selectEx, SelectState
|
|
pub const list, listEx, ListState
|
|
pub const FocusManager, FocusRing
|
|
|
|
// Panels
|
|
pub const panels
|
|
|
|
// Utils
|
|
pub const utils
|
|
pub const FrameArena
|
|
pub const ScopedArena
|
|
pub const ObjectPool
|
|
pub const CommandPool
|
|
pub const RingBuffer
|
|
pub const Benchmark
|
|
pub const Timer
|
|
pub const FrameTimer
|
|
pub const AllocationTracker
|
|
|
|
// Types
|
|
pub const Color
|
|
pub const Rect
|
|
pub const Constraint
|
|
pub const Theme
|
|
pub const ThemeManager
|
|
```
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 0.15.0 | 2025-12-09 | Mobile/Web backends (WASM, Android, iOS) |
|
|
| 0.14.1 | 2025-12-09 | Gio parity phase - 12 widgets + gesture system |
|
|
| 0.1.0 | 2025-12-09 | Initial release - core + macros + basic widgets |
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
MIT License
|
|
|
|
---
|
|
|
|
## Related Projects
|
|
|
|
- **zcatui**: TUI library for terminal interfaces (sibling project)
|
|
- **microui**: Inspiration for minimal architecture
|
|
- **DVUI**: Reference Zig immediate-mode implementation
|
|
- **Gio**: Go immediate-mode GUI (feature parity target)
|
|
|
|
---
|
|
|
|
*Generated: 2025-12-09*
|