Text, many performance improvements
This commit is contained in:
187
lib/ui/src/tree.rs
Normal file
187
lib/ui/src/tree.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user