Text, many performance improvements

This commit is contained in:
2026-03-20 19:23:55 -04:00
parent 39ede248cf
commit 00fe1daa0c
18 changed files with 3432 additions and 26 deletions

187
lib/ui/src/tree.rs Normal file
View File

@@ -0,0 +1,187 @@
use crate::scene::Color;
use crate::text::{TextStyle, TextWrap};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FlexDirection {
Row,
Column,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Edges {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}
impl Edges {
pub const ZERO: Self = Self {
top: 0.0,
right: 0.0,
bottom: 0.0,
left: 0.0,
};
pub const fn all(value: f32) -> Self {
Self {
top: value,
right: value,
bottom: value,
left: value,
}
}
pub const fn symmetric(horizontal: f32, vertical: f32) -> Self {
Self {
top: vertical,
right: horizontal,
bottom: vertical,
left: horizontal,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Style {
pub direction: FlexDirection,
pub width: Option<f32>,
pub height: Option<f32>,
pub flex_grow: f32,
pub gap: f32,
pub padding: Edges,
pub background: Option<Color>,
}
impl Default for Style {
fn default() -> Self {
Self {
direction: FlexDirection::Column,
width: None,
height: None,
flex_grow: 0.0,
gap: 0.0,
padding: Edges::ZERO,
background: None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
enum ElementContent {
Container,
Text(TextNode),
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct TextNode {
pub text: String,
pub style: TextStyle,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Element {
pub style: Style,
pub children: Vec<Element>,
content: ElementContent,
}
impl Element {
pub fn new() -> Self {
Self {
style: Style::default(),
children: Vec::new(),
content: ElementContent::Container,
}
}
pub fn text(text: impl Into<String>, style: TextStyle) -> Self {
Self {
style: Style::default(),
children: Vec::new(),
content: ElementContent::Text(TextNode {
text: text.into(),
style,
}),
}
}
pub fn paragraph(text: impl Into<String>, style: TextStyle) -> Self {
Self::text(text, style.with_wrap(TextWrap::Word))
}
pub fn row() -> Self {
Self::new().direction(FlexDirection::Row)
}
pub fn column() -> Self {
Self::new().direction(FlexDirection::Column)
}
pub fn direction(mut self, direction: FlexDirection) -> Self {
self.style.direction = direction;
self
}
pub fn width(mut self, width: f32) -> Self {
self.style.width = Some(width);
self
}
pub fn height(mut self, height: f32) -> Self {
self.style.height = Some(height);
self
}
pub fn flex(mut self, flex_grow: f32) -> Self {
self.style.flex_grow = flex_grow.max(0.0);
self
}
pub fn gap(mut self, gap: f32) -> Self {
self.style.gap = gap.max(0.0);
self
}
pub fn padding(mut self, padding: Edges) -> Self {
self.style.padding = padding;
self
}
pub fn background(mut self, color: Color) -> Self {
self.style.background = Some(color);
self
}
pub fn child(mut self, child: Element) -> Self {
self.assert_container();
self.children.push(child);
self
}
pub fn children(mut self, children: impl IntoIterator<Item = Element>) -> Self {
self.assert_container();
self.children.extend(children);
self
}
pub(crate) fn text_node(&self) -> Option<&TextNode> {
match &self.content {
ElementContent::Text(text) => Some(text),
ElementContent::Container => None,
}
}
fn assert_container(&self) {
assert!(
matches!(self.content, ElementContent::Container),
"text elements cannot contain children"
);
}
}
impl Default for Element {
fn default() -> Self {
Self::new()
}
}