Early UI work.

This commit is contained in:
2026-03-20 16:46:18 -04:00
parent 9ab1167fef
commit 39ede248cf
15 changed files with 3560 additions and 1 deletions

210
lib/ui/src/scene.rs Normal file
View File

@@ -0,0 +1,210 @@
//! Renderer-oriented scene snapshot types.
use tracing::debug;
use crate::trace_targets;
pub type SceneVersion = u64;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Point {
pub x: f32,
pub y: f32,
}
impl Point {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct UiSize {
pub width: f32,
pub height: f32,
}
impl UiSize {
pub const fn new(width: f32, height: f32) -> Self {
Self { width, height }
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Rect {
pub origin: Point,
pub size: UiSize,
}
impl Rect {
pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
Self {
origin: Point::new(x, y),
size: UiSize::new(width, height),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self::rgba(r, g, b, 255)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Translation {
pub x: f32,
pub y: f32,
}
impl Translation {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Quad {
pub rect: Rect,
pub color: Color,
}
impl Quad {
pub const fn new(rect: Rect, color: Color) -> Self {
Self { rect, color }
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct GlyphInstance {
pub glyph: String,
pub position: Point,
pub advance: f32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreparedText {
pub text: String,
pub font_size: f32,
pub color: Color,
pub glyphs: Vec<GlyphInstance>,
}
impl PreparedText {
pub fn monospace(
text: impl Into<String>,
origin: Point,
font_size: f32,
advance: f32,
color: Color,
) -> Self {
let text = text.into();
let mut x = origin.x;
let mut glyphs = Vec::with_capacity(text.chars().count());
for ch in text.chars() {
glyphs.push(GlyphInstance {
glyph: ch.to_string(),
position: Point::new(x, origin.y),
advance,
});
x += advance;
}
Self {
text,
font_size,
color,
glyphs,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum DisplayItem {
Quad(Quad),
Text(PreparedText),
PushClip(Rect),
PopClip,
PushTransform(Translation),
PopTransform,
LayerBegin { opacity: f32 },
LayerEnd,
}
#[derive(Clone, Debug, PartialEq)]
pub struct SceneSnapshot {
pub version: SceneVersion,
pub logical_size: UiSize,
pub items: Vec<DisplayItem>,
}
impl SceneSnapshot {
pub fn new(version: SceneVersion, logical_size: UiSize) -> Self {
debug!(
target: trace_targets::SCENE,
event = "create_scene",
version,
width = logical_size.width,
height = logical_size.height,
"creating scene snapshot"
);
Self {
version,
logical_size,
items: Vec::new(),
}
}
pub fn item_count(&self) -> usize {
self.items.len()
}
pub fn push_item(&mut self, item: DisplayItem) -> &mut Self {
self.items.push(item);
self
}
pub fn push_quad(&mut self, rect: Rect, color: Color) -> &mut Self {
self.push_item(DisplayItem::Quad(Quad::new(rect, color)))
}
pub fn push_text(&mut self, text: PreparedText) -> &mut Self {
self.push_item(DisplayItem::Text(text))
}
pub fn push_clip(&mut self, rect: Rect) -> &mut Self {
self.push_item(DisplayItem::PushClip(rect))
}
pub fn pop_clip(&mut self) -> &mut Self {
self.push_item(DisplayItem::PopClip)
}
pub fn push_transform(&mut self, translation: Translation) -> &mut Self {
self.push_item(DisplayItem::PushTransform(translation))
}
pub fn pop_transform(&mut self) -> &mut Self {
self.push_item(DisplayItem::PopTransform)
}
pub fn begin_layer(&mut self, opacity: f32) -> &mut Self {
self.push_item(DisplayItem::LayerBegin { opacity })
}
pub fn end_layer(&mut self) -> &mut Self {
self.push_item(DisplayItem::LayerEnd)
}
}