use crate::*; use std::ops::Deref; /// Render target. pub trait Output: Send + Sync + Sized { /// Unit of length type Unit: Coordinate; /// Rectangle without offset type Size: Size; /// Rectangle with offset type Area: Area; /// Current output area fn area (&self) -> Self::Area; /// Mutable pointer to area fn area_mut (&mut self) -> &mut Self::Area; /// Render widget in area fn place (&mut self, area: Self::Area, content: &impl Render); #[inline] fn x (&self) -> Self::Unit { self.area().x() } #[inline] fn y (&self) -> Self::Unit { self.area().y() } #[inline] fn w (&self) -> Self::Unit { self.area().w() } #[inline] fn h (&self) -> Self::Unit { self.area().h() } #[inline] fn wh (&self) -> Self::Size { self.area().wh().into() } } /// Renderable with dynamic dispatch. pub trait Render { /// Compute layout. fn layout (&self, area: E::Area) -> E::Area; /// Write data to display. fn render (&self, output: &mut E); /// Perform type erasure, turning `self` into an opaque [RenderBox]. fn boxed <'a> (self) -> RenderBox<'a, E> where Self: Send + Sync + Sized + 'a { Box::new(self) as RenderBox<'a, E> } } /// Most importantly, every [Content] is also a [Render]. /// /// However, the converse does not hold true. /// Instead, the [Content::content] method returns an /// opaque [Render] pointer. impl> Render for C { fn layout (&self, area: E::Area) -> E::Area { Content::layout(self, area) } fn render (&self, output: &mut E) { Content::render(self, output) } } /// Opaque pointer to a renderable living on the heap. /// /// Return this from [Content::content] to use dynamic dispatch. pub type RenderBox<'a, E> = Box>; /// You can render from a box. impl<'a, E: Output> Content for RenderBox<'a, E> { fn content (&self) -> impl Render { self.deref() } //fn boxed <'b> (self) -> RenderBox<'b, E> where Self: Sized + 'b { self } } /// Opaque pointer to a renderable. pub type RenderDyn<'a, E> = dyn Render + Send + Sync + 'a; /// You can render from an opaque pointer. impl<'a, E: Output> Content for &RenderDyn<'a, E> where Self: Sized { fn content (&self) -> impl Render { #[allow(suspicious_double_ref_op)] self.deref() } fn layout (&self, area: E::Area) -> E::Area { #[allow(suspicious_double_ref_op)] Render::layout(self.deref(), area) } fn render (&self, output: &mut E) { #[allow(suspicious_double_ref_op)] Render::render(self.deref(), output) } } /// Composable renderable with static dispatch. pub trait Content { /// Return a [Render]able of a specific type. fn content (&self) -> impl Render { () } /// Perform layout. By default, delegates to [Self::content]. fn layout (&self, area: E::Area) -> E::Area { self.content().layout(area) } /// Draw to output. By default, delegates to [Self::content]. fn render (&self, output: &mut E) { self.content().render(output) } } /// Every pointer to [Content] is a [Content]. impl> Content for &C { fn content (&self) -> impl Render { (*self).content() } fn layout (&self, area: E::Area) -> E::Area { (*self).layout(area) } fn render (&self, output: &mut E) { (*self).render(output) } } /// The platonic ideal unit of [Content]: total emptiness at dead center (e=1vg^sqrt(-1)) impl Content for () { fn layout (&self, area: E::Area) -> E::Area { area.center().to_area_pos().into() } fn render (&self, _: &mut E) {} } impl> Content for Option { fn content (&self) -> impl Render { self.as_ref() } fn layout (&self, area: E::Area) -> E::Area { self.as_ref() .map(|content|content.layout(area)) .unwrap_or([0.into(), 0.into(), 0.into(), 0.into(),].into()) } fn render (&self, output: &mut E) { self.as_ref() .map(|content|content.render(output)); } } /// Implement [Content] with composable content for a struct. #[macro_export] macro_rules! content { // Implement for all [Output]s. (|$self:ident:$Struct:ty| $content:expr) => { impl Content for $Struct { fn content (&$self) -> impl Render { Some($content) } } }; // Implement for specific [Output]. ($Output:ty:| $self:ident: $Struct:ident$(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)? |$content:expr) => { impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output> for $Struct $(<$($($L)? $($T)?),+>)? { fn content (&$self) -> impl Render<$Output> { $content } } }; } /// Implement [Content] with custom rendering for a struct. #[macro_export] macro_rules! render { (|$self:ident:$Struct:ident $(< $($L:lifetime),* $($T:ident $(:$Trait:path)?),* >)?, $to:ident | $render:expr) => { impl <$($($L),*)? E: Output, $($T$(:$Trait)?),*> Content for $Struct $(<$($L),* $($T),*>>)? { fn render (&$self, $to: &mut E) { $render } } }; ($Output:ty:| $self:ident: $Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?, $to:ident |$render:expr) => { impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output> for $Struct $(<$($($L)? $($T)?),+>)? { fn render (&$self, $to: &mut $Output) { $render } } }; }