use fui_macros::ui; use std::cell::RefCell; use std::rc::Rc; use typed_builder::TypedBuilder; use typemap::{Key, TypeMap}; /// Children collection of a control. /// /// The simplified version to handle only static children /// for the test purposes. pub enum Children { /// The collection has no items. None, /// The collection has a single child. SingleStatic(Rc>), /// The collection is a list of controls. MultipleStatic(Vec>>), } impl Children { /// Creates an empty children collection. pub fn empty() -> Self { Children::None } /// Constructs Children collection from /// vector of Children collections. pub fn from(children_vec: Vec) -> Self { let mut static_children: Vec>> = Vec::new(); for next in children_vec { match next { Children::None => (), Children::SingleStatic(item) => { static_children.push(item); } Children::MultipleStatic(mut items) => { static_children.append(&mut items); } } } if static_children.len() == 1 { Children::SingleStatic(static_children.into_iter().next().unwrap()) } else if static_children.len() > 1 { Children::MultipleStatic(static_children) } else { Children::None } } /// Returns number of controls in the children collection. pub fn len(&self) -> usize { match self { Children::None => 0, Children::SingleStatic(_) => 1, Children::MultipleStatic(x) => x.len(), } } /// Tries to get Rc reference to the control at the `index` position. pub fn get(&self, index: usize) -> Option>> { match self { Children::None => None, Children::SingleStatic(x) => { if index == 0 { Some(x.clone()) } else { None } } Children::MultipleStatic(x) => x.get(index).map(|el| el.clone()), } } } /// Converts a single control to Children collection. impl From>> for Children { fn from(item: Rc>) -> Children { Children::SingleStatic(item) } } /// Converts a single control to ChildEntry. impl From>> for Children { fn from(item: Rc>) -> Children { Children::SingleStatic(item) } } pub struct ChildrenIterator<'a> { source: &'a Children, pos: usize, len: usize, } impl<'a> Iterator for ChildrenIterator<'a> { type Item = Rc>; fn next(&mut self) -> Option>> { if self.pos < self.len { self.pos += 1; self.source.get(self.pos - 1) } else { None } } } impl<'a> DoubleEndedIterator for ChildrenIterator<'a> { fn next_back(&mut self) -> Option>> { if self.len > self.pos { self.len -= 1; self.source.get(self.len) } else { None } } } impl<'a> IntoIterator for &'a Children { type Item = Rc>; type IntoIter = ChildrenIterator<'a>; fn into_iter(self) -> ChildrenIterator<'a> { ChildrenIterator { source: self, pos: 0, len: self.len(), } } } // attached value Row of type i32 struct Row; impl Key for Row { type Value = i32; } pub trait ControlObject { fn draw(&mut self) -> String; } pub struct ViewContext { attached_values: TypeMap, children: Children, } pub trait Style { fn draw(&self, data: &mut D) -> String; } pub struct StyledControl { pub data: D, pub style: Box>, pub attached_values: TypeMap, pub children: Children, } impl StyledControl { pub fn new( data: D, style: Box>, attached_values: TypeMap, children: Children, ) -> Rc> { Rc::new(RefCell::new(StyledControl { data: data, attached_values: attached_values, style, children: children, })) } } impl ControlObject for StyledControl { fn draw(&mut self) -> String { let name = self.style.draw(&mut self.data); let mut attached_values = "".to_string(); if let Some(row_attached_value) = self.attached_values.get::() { attached_values += &format!(".Row({})", row_attached_value); } let children = { let vec: Vec = (&self.children) .into_iter() .map(|c| c.borrow_mut().draw()) .collect(); vec.join(",") }; name + &attached_values + "{" + &children + "}" } } #[derive(Debug, TypedBuilder)] pub struct Horizontal { #[builder(default = 0)] pub spacing: i32, } impl Horizontal { pub fn to_view( self, style: Option>>, context: ViewContext, ) -> Rc>> { StyledControl::new( self, style.unwrap_or_else(|| { Box::new(DefaultHorizontalStyle::new( DefaultHorizontalStyleParams::builder().build(), )) }), context.attached_values, context.children, ) } } #[derive(TypedBuilder)] pub struct DefaultHorizontalStyleParams {} pub struct DefaultHorizontalStyle {} impl DefaultHorizontalStyle { pub fn new(_params: DefaultHorizontalStyleParams) -> Self { DefaultHorizontalStyle {} } } impl Style for DefaultHorizontalStyle { fn draw(&self, data: &mut Horizontal) -> String { format!("Horizontal({})", data.spacing) } } #[derive(Debug, TypedBuilder)] pub struct Button {} impl Button { pub fn to_view( self, style: Option>>, context: ViewContext, ) -> Rc>> { StyledControl::new( self, style.unwrap_or_else(|| { Box::new(DefaultButtonStyle::new( DefaultButtonStyleParams::builder().build(), )) }), context.attached_values, context.children, ) } } #[derive(TypedBuilder)] pub struct DefaultButtonStyleParams {} pub struct DefaultButtonStyle {} impl DefaultButtonStyle { pub fn new(_params: DefaultButtonStyleParams) -> Self { DefaultButtonStyle {} } } impl Style