use crate::*; /// Entry point for main loop pub trait App { fn run (self, context: T) -> Usually; } /// Platform backend. pub trait Engine: Send + Sync + Sized { /// Input event type type Input: Input; /// Result of handling input type Handled; /// Render target type Output: Output; /// Unit of length type Unit: Coordinate; /// Rectangle without offset type Size: Size + From<[Self::Unit;2]> + Debug + Copy; /// Rectangle with offset type Area: Area + From<[Self::Unit;4]> + Debug + Copy; /// Prepare before run fn setup (&mut self) -> Usually<()> { Ok(()) } /// True if done fn exited (&self) -> bool; /// Clean up after run fn teardown (&mut self) -> Usually<()> { Ok(()) } } /// Current input state pub trait Input { /// Type of input event type Event; /// Currently handled event fn event (&self) -> &Self::Event; /// Whether component should exit fn is_done (&self) -> bool; /// Mark component as done fn done (&self); } /// Rendering target pub trait Output { /// Current output area fn area (&self) -> E::Area; /// Mutable pointer to area fn area_mut (&mut self) -> &mut E::Area; /// Render widget in area fn render_in (&mut self, area: E::Area, widget: &dyn Widget) -> Usually<()>; } /// Cast to dynamic pointer pub fn widget > (w: &T) -> &dyn Widget { w as &dyn Widget } /// A renderable component pub trait Widget: Send + Sync { /// Engine for which this component is implemented type Engine: Engine; /// Minimum size to use fn layout (&self, to: ::Size) -> Perhaps<::Size> { Ok(Some(to)) } /// Draw to output render target fn render (&self,to: &mut ::Output) -> Usually<()>; } impl Widget for &dyn Widget { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { (*self).layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { (*self).render(to) } } impl Widget for &mut dyn Widget { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { (**self).layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { (**self).render(to) } } impl<'a, E: Engine> Widget for Box + 'a> { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { (**self).layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { (**self).render(to) } } impl> Widget for Arc { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { self.as_ref().layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { self.as_ref().render(to) } } impl> Widget for Mutex { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { self.lock().unwrap().layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { self.lock().unwrap().render(to) } } impl> Widget for RwLock { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { self.read().unwrap().layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { self.read().unwrap().render(to) } } impl> Widget for Option { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten()) } fn render (&self, to: &mut E::Output) -> Usually<()> { self.as_ref().map(|widget|widget.render(to)).unwrap_or(Ok(())) } } /// A custom [Widget] defined by passing layout and render closures in place. pub struct CustomWidget< E: Engine, L: Send + Sync + Fn(E::Size)->Perhaps, R: Send + Sync + Fn(&mut E::Output)->Usually<()> >(L, R, PhantomData); impl< E: Engine, L: Send + Sync + Fn(E::Size)->Perhaps, R: Send + Sync + Fn(&mut E::Output)->Usually<()> > CustomWidget { pub fn new (layout: L, render: R) -> Self { Self(layout, render, Default::default()) } } impl< E: Engine, L: Send + Sync + Fn(E::Size)->Perhaps, R: Send + Sync + Fn(&mut E::Output)->Usually<()> > Widget for CustomWidget { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { self.0(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { self.1(to) } } /// A [Widget] that contains other [Widget]s pub trait Content: Send + Sync { type Engine: Engine; fn content (&self) -> impl Widget::Engine>; } /// Every struct that has [Content] is a renderable [Widget]. impl> Widget for W { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { self.content().layout(to) } fn render (&self, to: &mut E::Output) -> Usually<()> { match self.layout(to.area().wh().into())? { Some(wh) => to.render_in(to.area().clip(wh).into(), &self.content()), None => Ok(()) } } } /// Handle input pub trait Handle: Send + Sync { fn handle (&mut self, context: &E::Input) -> Perhaps; } impl> Handle for &mut H { fn handle (&mut self, context: &E::Input) -> Perhaps { (*self).handle(context) } } impl> Handle for Option { fn handle (&mut self, context: &E::Input) -> Perhaps { if let Some(ref mut handle) = self { handle.handle(context) } else { Ok(None) } } } impl Handle for Mutex where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.lock().unwrap().handle(context) } } impl Handle for Arc> where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.lock().unwrap().handle(context) } } impl Handle for RwLock where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.write().unwrap().handle(context) } } impl Handle for Arc> where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.write().unwrap().handle(context) } } /// A UI component that can render itself as a [Widget], and [Handle] input. pub trait Component: Widget + Handle {} /// Everything that implements [Widget] and [Handle] is a [Component]. impl + Handle> Component for C {} /// A UI component that has [Content] and can [Handle] input. pub trait ContentComponent: Widget + Handle {} /// Everything that implements [Content] and [Handle] is a [Component]. impl + Handle> ContentComponent for C {} /// A component that can exit. pub trait Exit: Send { fn exited (&self) -> bool; fn exit (&mut self); fn boxed (self) -> Box where Self: Sized + 'static { Box::new(self) } } /// Marker trait for [Component]s that can [Exit]. pub trait ExitableComponent: Exit + Component where E: Engine { /// Perform type erasure for collecting heterogeneous components. fn boxed (self) -> Box> where Self: Sized + 'static { Box::new(self) } } /// All [Components]s that implement [Exit] implement [ExitableComponent]. impl + Exit> ExitableComponent for C {}