use std::{collections::HashMap, rc::Rc, sync::Arc};
use crate::{component::Component, state::Handler};
#[derive(Debug, Clone)]
pub struct Element {
pub element_type: ElementType,
pub props: HashMap<String, String>,
pub handlers: HashMap<String, Handler>,
pub children: Vec<Box<Element>>,
}
#[derive(Debug, Clone)]
pub enum ElementType {
Window,
Button,
Div,
Text(String),
Input,
Image,
Component(Rc<dyn Component>),
}
pub struct WindowSpec {
pub width: Option<f64>,
pub height: Option<f64>,
pub resizable: bool,
pub title: String,
}
pub fn window_spec(tree: &Element) -> WindowSpec {
let num = |key: &str| tree.props.get(key).and_then(|value| value.parse().ok());
WindowSpec {
width: num("width"),
height: num("height"),
title: tree.props.get("title").unwrap_or(&"".to_string()).clone(),
resizable: tree
.props
.get("resizable")
.map(|v| v != "false")
.unwrap_or(true),
}
}
#[macro_export]
macro_rules! ui {
(Window $($val:tt) *) => {
ui! { @element Window $($val)* }
};
(Div $($val:tt) *) => {
ui! { @element Div $($val)* }
};
(Button $($val:tt) *) => {
ui! { @element Button $($val)* }
};
(Input $($val:tt) *) => {
ui! { @element Input $($val)* }
};
(Image $($val:tt) *) => {
ui! { @element Image $($val)* }
};
(Text $contents:expr) => {
Box::new($crate::element::Element {
element_type: $crate::element::ElementType::Text($contents.into()),
props: HashMap::new(),
handlers: HashMap::new(),
children: vec![],
})
};
(CHILDREN $comp:ident) => {
$comp
};
($comp:ident $($val:tt) *) => {
{
let children = vec![];
$( children = vec!(ui! $val ); )*
Box::new($crate::element::Element {
element_type: $crate::element::ElementType::Component(std::rc::Rc::new($comp {})),
props: HashMap::new(),
handlers: HashMap::new(),
children,
})
}
};
(@element $el:ident $($prop:ident ($($val:tt)*))* { $($children:tt)* }) => {
{
use std::collections::HashMap;
let mut el = $crate::element::Element {
element_type: $crate::element::ElementType::$el,
props: HashMap::new(),
handlers: HashMap::new(),
children: vec![],
};
$( ui!(@prop el, $prop ($($val)*)); )*
ui!(@children el, $($children)*);
Box::new(el)
}
};
(@element $el:ident $($prop:ident ($($val:tt)*))*) => {
{
use std::collections::HashMap;
let mut el = $crate::element::Element {
element_type: $crate::element::ElementType::$el,
props: HashMap::new(),
handlers: HashMap::new(),
children: vec![],
};
$( ui!(@prop el, $prop ($($val)*)); )*
Box::new(el)
}
};
(@prop $el:ident, on_click($($val:tt)*)) => {
$el.handlers.insert("on_click".to_string(), $crate::state::Handler::Simple(($($val)*)));
};
(@prop $el:ident, on_resize($($val:tt)*)) => {
$el.handlers
.insert("on_resize".to_string(), $crate::state::Handler::Resize(std::rc::Rc::new(($($val)*))));
};
(@prop $el:ident, on_change($($val:tt)*)) => {
$el.handlers
.insert("on_change".to_string(), $crate::state::Handler::Change(std::rc::Rc::new(($($val)*))));
};
(@prop $el:ident, $prop:ident($($val:tt)*)) => {
$el.props
.insert(stringify!($prop).to_string(), format!("{}", ($($val)*)));
};
(@children $v:ident,) => {};
(@children $v:ident, Text $text:literal $($rest:tt)*) => {
$v.children.push(ui!(Text $text));
ui!(@children $v, $($rest)*);
};
(@children $v:ident, { $($inner:tt)* } $($rest:tt)*) => {
$v.children.push(ui! { $($inner)* });
ui!(@children $v, $($rest)*);
};
(@children $v:ident, CHILDREN $splice:ident $($rest:tt)*) => {
$v.children.push($splice);
ui!(@children $v, $($rest)*);
};
(@children $v:ident, $comp:ident { $($inner:tt)* } $($rest:tt)*) => {
$v.children.push(ui!($comp { $($inner)* }));
ui!(@children $v, $($rest)*);
};
}
#[derive(Clone)]
pub struct BlitFrame {
pub width: usize,
pub height: usize,
pub samples: u64,
pub pixels: Arc<Vec<u8>>,
pub version: u64,
}
impl BlitFrame {
pub fn empty() -> Self {
BlitFrame {
width: 0,
height: 0,
samples: 0,
pixels: Arc::new(Vec::new()),
version: 0,
}
}
}