Immediate Mode GUI library for Zig with software rendering. Core features: - SDL2 backend for cross-platform window/events - Software rasterizer (works everywhere, including SSH) - Macro recording system (cornerstone feature, like Vim) - Command-list rendering (DrawRect, DrawText, etc.) - Layout system with constraints - Color/Style system with themes Project structure: - src/core/: context, command, input, layout, style - src/macro/: MacroRecorder, MacroPlayer, MacroStorage - src/render/: Framebuffer, SoftwareRenderer, Font - src/backend/: Backend interface, SDL2 implementation - examples/: hello.zig, macro_demo.zig - docs/: Architecture, research (Gio, immediate-mode libs, Simifactu) Build: zig build (requires SDL2-devel) Tests: 16 tests passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
159 lines
3.5 KiB
Zig
159 lines
3.5 KiB
Zig
//! DrawCommand - Rendering commands for the software rasterizer
|
|
//!
|
|
//! The immediate mode UI generates a list of DrawCommands each frame.
|
|
//! The software rasterizer then processes these commands to produce pixels.
|
|
//!
|
|
//! This is the "command list" approach (like microui), not vertex buffers.
|
|
|
|
const Style = @import("style.zig");
|
|
|
|
/// A single draw command
|
|
pub const DrawCommand = union(enum) {
|
|
/// Draw a filled rectangle
|
|
rect: RectCommand,
|
|
|
|
/// Draw text
|
|
text: TextCommand,
|
|
|
|
/// Draw a line
|
|
line: LineCommand,
|
|
|
|
/// Draw a rectangle outline (border)
|
|
rect_outline: RectOutlineCommand,
|
|
|
|
/// Begin clipping to a rectangle
|
|
clip: ClipCommand,
|
|
|
|
/// End clipping
|
|
clip_end,
|
|
|
|
/// No operation (placeholder)
|
|
nop,
|
|
};
|
|
|
|
/// Draw a filled rectangle
|
|
pub const RectCommand = struct {
|
|
x: i32,
|
|
y: i32,
|
|
w: u32,
|
|
h: u32,
|
|
color: Style.Color,
|
|
};
|
|
|
|
/// Draw text at a position
|
|
pub const TextCommand = struct {
|
|
x: i32,
|
|
y: i32,
|
|
text: []const u8,
|
|
color: Style.Color,
|
|
/// null means default font
|
|
font: ?*anyopaque = null,
|
|
};
|
|
|
|
/// Draw a line between two points
|
|
pub const LineCommand = struct {
|
|
x1: i32,
|
|
y1: i32,
|
|
x2: i32,
|
|
y2: i32,
|
|
color: Style.Color,
|
|
};
|
|
|
|
/// Draw a rectangle outline
|
|
pub const RectOutlineCommand = struct {
|
|
x: i32,
|
|
y: i32,
|
|
w: u32,
|
|
h: u32,
|
|
color: Style.Color,
|
|
thickness: u32 = 1,
|
|
};
|
|
|
|
/// Begin clipping to a rectangle
|
|
pub const ClipCommand = struct {
|
|
x: i32,
|
|
y: i32,
|
|
w: u32,
|
|
h: u32,
|
|
};
|
|
|
|
// =============================================================================
|
|
// Helper constructors
|
|
// =============================================================================
|
|
|
|
/// Create a rect command
|
|
pub fn rect(x: i32, y: i32, w: u32, h: u32, color: Style.Color) DrawCommand {
|
|
return .{ .rect = .{
|
|
.x = x,
|
|
.y = y,
|
|
.w = w,
|
|
.h = h,
|
|
.color = color,
|
|
} };
|
|
}
|
|
|
|
/// Create a text command
|
|
pub fn text(x: i32, y: i32, str: []const u8, color: Style.Color) DrawCommand {
|
|
return .{ .text = .{
|
|
.x = x,
|
|
.y = y,
|
|
.text = str,
|
|
.color = color,
|
|
} };
|
|
}
|
|
|
|
/// Create a line command
|
|
pub fn line(x1: i32, y1: i32, x2: i32, y2: i32, color: Style.Color) DrawCommand {
|
|
return .{ .line = .{
|
|
.x1 = x1,
|
|
.y1 = y1,
|
|
.x2 = x2,
|
|
.y2 = y2,
|
|
.color = color,
|
|
} };
|
|
}
|
|
|
|
/// Create a rect outline command
|
|
pub fn rectOutline(x: i32, y: i32, w: u32, h: u32, color: Style.Color) DrawCommand {
|
|
return .{ .rect_outline = .{
|
|
.x = x,
|
|
.y = y,
|
|
.w = w,
|
|
.h = h,
|
|
.color = color,
|
|
} };
|
|
}
|
|
|
|
/// Create a clip command
|
|
pub fn clip(x: i32, y: i32, w: u32, h: u32) DrawCommand {
|
|
return .{ .clip = .{
|
|
.x = x,
|
|
.y = y,
|
|
.w = w,
|
|
.h = h,
|
|
} };
|
|
}
|
|
|
|
/// Create a clip end command
|
|
pub fn clipEnd() DrawCommand {
|
|
return .clip_end;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Tests
|
|
// =============================================================================
|
|
|
|
const std = @import("std");
|
|
|
|
test "DrawCommand creation" {
|
|
const cmd = rect(10, 20, 100, 50, Style.Color.red);
|
|
switch (cmd) {
|
|
.rect => |r| {
|
|
try std.testing.expectEqual(@as(i32, 10), r.x);
|
|
try std.testing.expectEqual(@as(i32, 20), r.y);
|
|
try std.testing.expectEqual(@as(u32, 100), r.w);
|
|
try std.testing.expectEqual(@as(u32, 50), r.h);
|
|
},
|
|
else => unreachable,
|
|
}
|
|
}
|