窗口与 UI
std.graphics.ui 以组件树组织界面。Widget 保存通用状态,Panel、Label、Button、Slider 等组件继承它;布局、绘制和事件行为通过接口约定与方法覆写组合。
一个可检查的组件示例
这个仓库示例建立窗口、面板和自定义组件,检查布局、绘制、点击与移除组件后的状态清理。它是行为测试,不会显示原生窗口。
kelyra
import std.graphics.ui;
class CountingPainter: std.graphics.ui.Painter {
pub fills: i32;
pub init() { fills = 0; }
pub fn fill(bounds: *std.graphics.ui.Rect, color: *std.graphics.ui.Color) -> void {
fills = fills + 1;
}
pub fn text(bounds: *std.graphics.ui.Rect, content: *c.char,
color: *std.graphics.ui.Color) -> void {}
}
class Probe: std.graphics.ui.Widget {
pub clicks: i32;
pub paints: i32;
pub layouts: i32;
pub init(x: i32, y: i32, width: i32, height: i32) {
super(x, y, width, height);
clicks = 0;
paints = 0;
layouts = 0;
this.focusable = true;
}
@override pub fn arrange(area: *std.graphics.ui.Rect) -> void {
layouts = layouts + 1;
super.arrange(area);
}
@override pub fn paint(painter: *std.graphics.ui.Painter) -> void {
paints = paints + 1;
super.paint(painter);
}
@override pub fn on_event(event: *std.graphics.ui.Event) -> void {
if event.kind == std.graphics.ui.EventKind.Click { clicks = clicks + 1; }
super.on_event(event);
}
}
@main
pub fn main() -> i32 {
let window = std.graphics.ui.Window(200, 120);
let panel = std.graphics.ui.Panel(10, 10, 180, 100);
let probe = Probe(5, 5, 50, 30);
if !window.add(&panel) || !panel.add(&probe) { return 1; }
if probe.frame.x != 15 || probe.frame.y != 15 { return 2; }
let painter = CountingPainter();
window.paint(&painter);
if probe.paints != 1 || probe.layouts < 1 || painter.fills != 1 {
return 3;
}
window.pointer(std.graphics.ui.EventKind.PointerDown, 20, 20);
window.pointer(std.graphics.ui.EventKind.PointerUp, 20, 20);
if probe.clicks != 1 { return 4; }
let component: *std.graphics.ui.Component = &probe;
let event = std.graphics.ui.Event();
event.kind = std.graphics.ui.EventKind.Click;
component.on_event(&event);
if probe.clicks != 2 { return 5; }
window.pointer(std.graphics.ui.EventKind.PointerDown, 20, 20);
let probe_widget: *std.graphics.ui.Widget = &probe;
if window.capture as usize != probe_widget as usize { return 6; }
window.remove(&panel);
if window.capture as usize != 0 || window.focused as usize != 0 ||
panel.parent as usize != 0 { return 7; }
return 0;
}原生窗口
Windows 后端位于 std.graphics.ui.win。窗口消息先由 Win32 窗口过程收集,再由 poll() 送进组件树,包括创建和拉伸时同步到达的消息。Event 提供鼠标左、右、中、扩展键、滚轮、键盘虚拟键与扫描码、重复次数,以及 Unicode 文本输入。关闭事件可以通过 event.handled = true 取消。需要直接发送或检查 Win32 消息时,可以使用 std.win.message 和 std.win.input。
kstd/examples/ui_input_smoke_example.kly 展示这些事件的检验。
Windows 图形窗口示例目前使用 std.graphics.window 打开窗口并绘制三角形。它依赖编译好的 Kelyra Shader 与 DX12 环境。完整流程见Shader 与图形。
Linux 的 Vulkan 图形示例已有代码,但跨平台 UI 后端仍在设计与完善;不能把 std.graphics.ui 的行为测试等同于已完成的跨平台原生组件渲染。