use std::fmt::Debug;
use crate::{Axis, Color, Painter, PerAxis, Rect, Stroke, TSTransform, TextStyle, Vec2, Margin};
use super::{Id, Layout, Size};
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum UIRef {
Null,
Some(usize)
}
impl Debug for UIRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Null => write!(f, "null"),
Self::Some(idx) => f.debug_tuple("some").field(idx).finish(),
}
}
}
impl UIRef {
pub fn is_some(&self) -> bool {
matches!(self, Self::Some(_))
}
pub fn as_option(&self) -> Option<Self> {
match self {
UIRef::Null => None,
UIRef::Some(_) => Some(*self),
}
}
}
pub struct UINodeParams {
pub(crate) size: PerAxis<Size>,
pub(crate) layout: Layout,
pub(crate) margin: Margin,
pub(crate) interaction_margin: Margin,
pub(crate) transform: TSTransform,
pub(crate) fill: Color,
pub(crate) rounding: f32,
pub(crate) stroke: Stroke,
pub(crate) clip: bool,
pub(crate) text: Option<String>,
pub(crate) text_style: TextStyle,
pub(crate) id_source: Option<u64>,
pub(crate) mouse: bool,
pub(crate) scroll: bool,
pub(crate) has_interaction_priority: bool,
pub(crate) on_paint: Option<Box<dyn FnOnce(&mut Painter, Rect)>>
}
impl UINodeParams {
pub fn new(w: Size, h: Size) -> Self {
Self {
size: PerAxis::new(w, h),
layout: Layout::new(Axis::Y),
margin: Margin::ZERO,
interaction_margin: Margin::ZERO,
transform: TSTransform::IDENTITY,
fill: Color::TRANSPARENT,
rounding: 0.0,
stroke: Stroke::NONE,
clip: true,
text: None,
text_style: TextStyle::default(),
id_source: None,
mouse: false,
scroll: false,
has_interaction_priority: false,
on_paint: None
}
}
pub fn new_per_axis(size: PerAxis<Size>) -> Self {
Self::new(size.x, size.y)
}
pub fn with_size(mut self, w: Size, h: Size) -> Self {
self.size.x = w;
self.size.y = h;
self
}
pub fn with_layout(mut self, layout: Layout) -> Self {
self.layout = layout;
self
}
pub fn with_margin(mut self, margin: Margin) -> Self {
self.margin = margin;
self
}
pub fn with_interaction_margin(mut self, margin: Margin) -> Self {
self.interaction_margin = margin;
self
}
pub fn with_transform(mut self, transform: TSTransform) -> Self {
self.transform = transform;
self
}
pub fn with_fill(mut self, color: Color) -> Self {
self.fill = color;
self
}
pub fn with_rounding(mut self, rounding: f32) -> Self {
self.rounding = rounding;
self
}
pub fn with_stroke(mut self, stroke: Stroke) -> Self {
self.stroke = stroke;
self
}
pub fn with_clip(mut self, clip: bool) -> Self {
self.clip = clip;
self
}
pub fn no_clip(self) -> Self {
self.with_clip(false)
}
pub fn with_text<S: Into<String>>(mut self, text: S) -> Self {
self.text = Some(text.into());
self
}
pub fn with_text_style(mut self, style: TextStyle) -> Self {
self.text_style = style;
self
}
pub fn sense_mouse(mut self) -> Self {
self.mouse = true;
self
}
pub fn sense_scroll(mut self) -> Self {
self.scroll = true;
self
}
pub fn with_interaction_priority(mut self) -> Self {
self.has_interaction_priority = true;
self
}
pub fn on_paint<F: FnOnce(&mut Painter, Rect) + 'static>(mut self, on_paint: F) -> Self {
self.on_paint = Some(Box::new(on_paint));
self
}
}
pub(crate) struct UINode {
pub(crate) id: Id,
pub(crate) next: UIRef,
pub(crate) prev: UIRef,
pub(crate) first_child: UIRef,
pub(crate) last_child: UIRef,
pub(crate) n_children: u64,
pub(crate) parent: UIRef,
pub(crate) params: UINodeParams,
pub(crate) rect: Rect,
pub(crate) transform: TSTransform,
pub(crate) basis_size: Vec2,
pub(crate) frac_units: Vec2
}
impl UINode {
pub(crate) fn new(parent_id: Id, sibling_idx: u64, params: UINodeParams) -> Self {
Self {
id: Id(ahash::RandomState::with_seeds(1, 9, 8, 4).hash_one((parent_id, params.id_source.unwrap_or(sibling_idx)))),
next: UIRef::Null,
prev: UIRef::Null,
first_child: UIRef::Null,
last_child: UIRef::Null,
n_children: 0,
parent: UIRef::Null,
params,
rect: Rect::ZERO,
transform: TSTransform::IDENTITY,
basis_size: Vec2::ZERO,
frac_units: Vec2::ONE
}
}
}
pub(crate) struct UITree {
pub(crate) nodes: Vec<UINode>,
pub(crate) layers: Vec<UIRef>
}
impl UITree {
pub(crate) fn new() -> Self {
Self {
nodes: Vec::new(),
layers: Vec::new()
}
}
pub(crate) fn get(&self, node: UIRef) -> &UINode {
match node {
UIRef::Null => panic!("cannot get null node ref."),
UIRef::Some(idx) => &self.nodes[idx],
}
}
pub(crate) fn get_mut(&mut self, node: UIRef) -> &mut UINode {
match node {
UIRef::Null => panic!("cannot get null node ref."),
UIRef::Some(idx) => &mut self.nodes[idx],
}
}
pub(crate) fn add_node(&mut self, node: UINode) -> UIRef {
self.nodes.push(node);
UIRef::Some(self.nodes.len() - 1)
}
pub(crate) fn add_layer(&mut self, size: Vec2) -> UIRef {
let layer = self.add_node(UINode::new(
Id(0),
self.layers.len() as u64,
UINodeParams::new(Size::px(size.x), Size::px(size.y))
));
self.layers.push(layer);
layer
}
}