Server: ThemeConfig entity + CRUD (GET/PUT /theme), SQLite persistence, ThemeUpdate broadcast to ESP32 on save and initial connect. Client: render engine uses theme colors, full-screen redraw on theme change. SPA: theme page with color pickers + presets, layout preview with TS port of layout engine, justify/align controls on containers. DisplayHint refactored to struct (kind + h_align + v_align).
84 lines
2.3 KiB
Rust
84 lines
2.3 KiB
Rust
use client_domain::{
|
|
BoundingBox, Color, DrawCommand, FontMetrics, FontSize, HAlign, RenderEngine, ThemeConfig,
|
|
VAlign,
|
|
};
|
|
|
|
fn metrics() -> FontMetrics {
|
|
FontMetrics {
|
|
small: (6, 10),
|
|
large: (10, 20),
|
|
}
|
|
}
|
|
|
|
fn theme() -> ThemeConfig {
|
|
ThemeConfig::default()
|
|
}
|
|
|
|
fn bounds(w: u16, h: u16) -> BoundingBox {
|
|
BoundingBox::new(0, 0, w, h)
|
|
}
|
|
|
|
#[test]
|
|
fn textblock_renders_plain_text() {
|
|
let engine = RenderEngine::new(metrics(), theme());
|
|
let cmds = engine.render_text("hello", bounds(100, 40), HAlign::Left, VAlign::Top);
|
|
|
|
assert_eq!(cmds.len(), 1);
|
|
assert_eq!(cmds[0].text, "hello");
|
|
assert_eq!(cmds[0].x, 0);
|
|
assert_eq!(cmds[0].y, 0);
|
|
assert_eq!(cmds[0].color, theme().text);
|
|
assert_eq!(cmds[0].font, FontSize::Small);
|
|
}
|
|
|
|
#[test]
|
|
fn text_centered_horizontally() {
|
|
let engine = RenderEngine::new(metrics(), theme());
|
|
// "hi" = 12px, bounds = 100px → offset = 44
|
|
let cmds = engine.render_text("hi", bounds(100, 40), HAlign::Center, VAlign::Top);
|
|
|
|
assert_eq!(cmds[0].x, 44);
|
|
}
|
|
|
|
#[test]
|
|
fn text_centered_vertically() {
|
|
let engine = RenderEngine::new(metrics(), theme());
|
|
// 1 line = 10px height, bounds = 40px → offset = 15
|
|
let cmds = engine.render_text("hi", bounds(100, 40), HAlign::Left, VAlign::Middle);
|
|
|
|
assert_eq!(cmds[0].y, 15);
|
|
}
|
|
|
|
#[test]
|
|
fn text_wraps_and_stacks_lines() {
|
|
let engine = RenderEngine::new(metrics(), theme());
|
|
// "hello world" at 40px wide → "hello" + "world", each at 6x10
|
|
let cmds = engine.render_text("hello world", bounds(40, 100), HAlign::Left, VAlign::Top);
|
|
|
|
assert_eq!(cmds.len(), 2);
|
|
assert_eq!(cmds[0].text, "hello");
|
|
assert_eq!(cmds[0].y, 0);
|
|
assert_eq!(cmds[1].text, "world");
|
|
assert_eq!(cmds[1].y, 10);
|
|
}
|
|
|
|
#[test]
|
|
fn colored_markup_produces_colored_spans() {
|
|
let engine = RenderEngine::new(metrics(), theme());
|
|
let cmds = engine.render_text("{accent}hi{/}", bounds(100, 40), HAlign::Left, VAlign::Top);
|
|
|
|
assert_eq!(cmds.len(), 1);
|
|
assert_eq!(cmds[0].text, "hi");
|
|
assert_eq!(cmds[0].color, theme().accent);
|
|
}
|
|
|
|
#[test]
|
|
fn bounds_offset_applied() {
|
|
let engine = RenderEngine::new(metrics(), theme());
|
|
let b = BoundingBox::new(10, 20, 100, 40);
|
|
let cmds = engine.render_text("hi", b, HAlign::Left, VAlign::Top);
|
|
|
|
assert_eq!(cmds[0].x, 10);
|
|
assert_eq!(cmds[0].y, 20);
|
|
}
|