167 lines
4.8 KiB
Zig
167 lines
4.8 KiB
Zig
// SPDX-License-Identifier: LCL-1.0
|
|
// Copyright (c) 2026 Markus Maiwald
|
|
// Stewardship: Self Sovereign Society Foundation
|
|
//
|
|
// This file is part of the Nexus Commonwealth.
|
|
// See legal/LICENSE_COMMONWEALTH.md for license terms.
|
|
|
|
//! Rumpk HAL: UI Layer (The Persona)
|
|
//!
|
|
//! Bridges microui (C) with the Zig HAL and Framebuffer.
|
|
//! Handles GUI rendering, layout management, and the boot animation loop.
|
|
//!
|
|
//! SAFETY: Integrates with a C-based GUI library via @cImport.
|
|
//! Global context is initialized by `init()` before use in the UI fiber.
|
|
|
|
const std = @import("std");
|
|
const fb = @import("framebuffer.zig");
|
|
|
|
// GPU Driver (extern)
|
|
extern fn virtio_gpu_flush() void;
|
|
pub const c = @cImport({
|
|
@cInclude("microui.h");
|
|
});
|
|
|
|
// --- STATIC MEMORY ---
|
|
// SAFETY(UI): Context is initialized by `c.mu_init(&ctx)` in `init()`.
|
|
var ctx: c.mu_Context = undefined;
|
|
|
|
// --- FONT (The "8-bit" classic) ---
|
|
// Minimal placeholder font (0-127 ascii) - 1KB
|
|
const font_bitmap: [128][8]u8 = [_][8]u8{[_]u8{0xFF} ** 8} ** 128; // Blocks for now
|
|
|
|
// --- CALL BACKS ---
|
|
fn text_width_cb(font: ?*anyopaque, str: [*c]const u8, len: c_int) callconv(.c) c_int {
|
|
_ = font;
|
|
// assuming 8x8 monospaced
|
|
|
|
// If len is -1, treat as null terminated
|
|
var l = len;
|
|
if (l == -1 and str != null) {
|
|
l = 0;
|
|
var s = str;
|
|
while (s[0] != 0) {
|
|
l += 1;
|
|
s += 1;
|
|
}
|
|
}
|
|
return l * 8;
|
|
}
|
|
|
|
fn text_height_cb(font: ?*anyopaque) callconv(.c) c_int {
|
|
_ = font;
|
|
return 8;
|
|
}
|
|
|
|
// --- THE RENDERER (The Paint Brush) ---
|
|
pub fn render() void {
|
|
var cmd: [*c]c.mu_Command = null;
|
|
|
|
// Iterate over microui command list
|
|
// Note: mu_next_command takes pointers
|
|
while (c.mu_next_command(&ctx, &cmd) != 0) {
|
|
switch (cmd.*.type) {
|
|
c.MU_COMMAND_TEXT => {
|
|
// draw_text(cmd.text.str, cmd.text.pos, cmd.text.color);
|
|
// For now, ignore text drawing to avoid font complexity in step 1
|
|
},
|
|
c.MU_COMMAND_RECT => {
|
|
draw_rect(cmd.*.rect.rect, cmd.*.rect.color);
|
|
},
|
|
c.MU_COMMAND_ICON => {
|
|
// TODO: Draw simple icons (close button X)
|
|
draw_rect(cmd.*.icon.rect, cmd.*.icon.color); // Placeholder
|
|
},
|
|
c.MU_COMMAND_CLIP => {
|
|
// fb.set_clip(cmd.clip.rect);
|
|
// Adaptation needed for C to Zig struct
|
|
fb.set_clip(.{
|
|
.x = cmd.*.clip.rect.x,
|
|
.y = cmd.*.clip.rect.y,
|
|
.w = cmd.*.clip.rect.w,
|
|
.h = cmd.*.clip.rect.h,
|
|
});
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
// PUSH TO HOST (The Retina)
|
|
virtio_gpu_flush();
|
|
}
|
|
|
|
// --- HELPER: Draw Rect ---
|
|
fn draw_rect(r: c.mu_Rect, color: c.mu_Color) void {
|
|
// Convert microui Color to ARGB
|
|
const argb = (@as(u32, 255) << 24) |
|
|
(@as(u32, color.r) << 16) |
|
|
(@as(u32, color.g) << 8) |
|
|
@as(u32, color.b);
|
|
|
|
// Plot to L0 Framebuffer
|
|
fb.fill_rect(r.x, r.y, r.w, r.h, argb);
|
|
}
|
|
|
|
// --- INITIALIZATION ---
|
|
pub fn init() void {
|
|
c.mu_init(&ctx);
|
|
// Hook up text width callback (Required by microui)
|
|
ctx.text_width = text_width_cb;
|
|
ctx.text_height = text_height_cb;
|
|
}
|
|
|
|
// --- KERNEL IMPORTS ---
|
|
extern fn fiber_yield() void;
|
|
|
|
extern fn fiber_sleep(ms: i32) void;
|
|
extern fn matrix_init() void;
|
|
extern fn matrix_update() bool;
|
|
|
|
// --- THE UI LOOP (Fiber Entry) ---
|
|
export fn ui_fiber_entry() void {
|
|
init();
|
|
matrix_init();
|
|
|
|
var matrix_alive: bool = true;
|
|
|
|
while (true) {
|
|
if (matrix_alive) {
|
|
// --- THE GREETING (High Compute) ---
|
|
matrix_alive = matrix_update();
|
|
|
|
// Push the Rain to the GPU
|
|
virtio_gpu_flush();
|
|
|
|
// 33ms Frame Time (~30 FPS)
|
|
fiber_sleep(33);
|
|
} else {
|
|
// --- THE HUD / VOID (Low Compute) ---
|
|
// 1. Begin Frame
|
|
c.mu_begin(&ctx);
|
|
|
|
// 2. Define Layout (The Logic)
|
|
if (c.mu_begin_window(&ctx, "Nexus HUD", c.mu_rect(10, 10, 300, 200)) != 0) {
|
|
c.mu_layout_row(&ctx, 1, &[_]i32{-1}, 0);
|
|
c.mu_label(&ctx, "System Status: ONLINE");
|
|
|
|
c.mu_layout_row(&ctx, 2, &[_]i32{ 80, -1 }, 0);
|
|
c.mu_label(&ctx, "CPU:");
|
|
c.mu_draw_rect(&ctx, c.mu_rect(100, 50, 150, 20), c.mu_color(0, 255, 0, 255)); // Mock bar
|
|
|
|
if (c.mu_button(&ctx, "REBOOT") != 0) {
|
|
// hal_reboot();
|
|
}
|
|
|
|
c.mu_end_window(&ctx);
|
|
}
|
|
|
|
// 3. End Frame & Paint
|
|
c.mu_end(&ctx);
|
|
render();
|
|
|
|
// 1s Sleep - No need to render UI every 30ms if static
|
|
fiber_sleep(1000);
|
|
}
|
|
}
|
|
}
|