use crate::*; /// Drawing target. /// /// ``` /// use crate::*; /// struct TestOut([u16;4]); /// impl Out for TestOut { /// type Unit = u16; /// type Size = [u16;2]; /// type Area = [u16;4]; /// fn area (&self) -> [u16;4] { /// self.0 /// } /// fn area_mut (&mut self) -> &mut [u16;4] { /// &mut self.0 /// } /// fn place_at + ?Sized> (&mut self, area: XYWH, _: &T) { /// println!("place_at: {area:?}"); /// () /// } /// } /// impl Draw for String { /// fn draw (&self, to: &mut TestOut) { /// to.area_mut().set_w(self.len() as u16); /// } /// } /// ``` pub trait Out: Send + Sync + Sized { /// Unit of length type Unit: Coord; /// Current output area fn area (&self) -> XYWH; /// Mutable pointer to area. fn area_mut (&mut self) -> &mut XYWH; /// Render drawable in area specified by `area` fn place_at <'t, T: Draw + ?Sized> (&mut self, area: XYWH, content: &'t T); /// Render drawable in area specified by `T::layout(self.area())` #[inline] fn place <'t, T: Content + ?Sized> (&mut self, content: &'t T) { self.place_at(content.layout(self.area()), content) } } /// A numeric type that can be used as coordinate. /// /// FIXME: Replace this ad-hoc trait with `num` crate. pub trait Coord: Send + Sync + Copy + Add + Sub + Mul + Div + Ord + PartialEq + Eq + Debug + Display + Default + From + Into + Into + Into { fn plus (self, other: Self) -> Self; fn minus (self, other: Self) -> Self { if self >= other { self - other } else { 0.into() } } fn atomic (self) -> AtomicUsize { AtomicUsize::new(self.into()) } fn zero () -> Self { 0.into() } } /// Drawable with dynamic dispatch. pub trait Draw { fn draw (&self, to: &mut O); } /// FIXME: This is a general implementation: should be called `Eval` and be part of [dizzle]. /// Matches [Language] expressions to renderings for a given [Output] target. pub trait View { fn view_expr <'a> (&'a self, _output: &mut O, expr: &'a impl Expression) -> Usually { Err(format!("View::view_expr: no exprs defined: {expr:?}").into()) } fn view_word <'a> (&'a self, _output: &mut O, word: &'a impl Symbol) -> Usually { Err(format!("View::view_word: no words defined: {word:?}").into()) } fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Language) -> Usually { let is_expr = dsl.expr(); let is_word = dsl.word(); match (dsl.expr(), dsl.word()) { (Ok(Some(e)), _ ) => self.view_expr(output, &e), (_, Ok(Some(w))) => self.view_word(output, &w), (Err(e), _ ) => Err(format!("invalid view expr:\n{dsl:?}\n{e}").into()), (_, Err(w) ) => Err(format!("invalid view word:\n{dsl:?}\n{w}").into()), (Ok(None), Ok(None) ) => Err(format!("empty view:\n{dsl:?}").into()), } } } /// Outputs combinator. pub trait Lay: Sized {} /// Drawable area of display. pub trait Layout { fn layout_x (&self, to: XYWH) -> O::Unit { to.x() } fn layout_y (&self, to: XYWH) -> O::Unit { to.y() } fn layout_w_min (&self, _t: XYWH) -> O::Unit { 0.into() } fn layout_w_max (&self, to: XYWH) -> O::Unit { to.w() } fn layout_w (&self, to: XYWH) -> O::Unit { to.w().max(self.layout_w_min(to)).min(self.layout_w_max(to)) } fn layout_h_min (&self, _t: XYWH) -> O::Unit { 0.into() } fn layout_h_max (&self, to: XYWH) -> O::Unit { to.h() } fn layout_h (&self, to: XYWH) -> O::Unit { to.h().max(self.layout_h_min(to)).min(self.layout_h_max(to)) } fn layout (&self, to: XYWH) -> XYWH { XYWH(self.layout_x(to), self.layout_y(to), self.layout_w(to), self.layout_h(to)) } } pub trait HasContent { fn content (&self) -> impl Content; } // TODO DOCUMENTME pub trait Content: Draw + Layout {} // Something that has an origin point (X, Y). pub trait HasXY { fn x (&self) -> N; fn y (&self) -> N; fn xy (&self) -> XY { XY(self.x(), self.y()) } } // Something that has a size (W, H). pub trait HasWH { fn w (&self) -> N; fn h (&self) -> N; fn wh (&self) -> WH { WH(self.w(), self.h()) } } // Something that has a 2D bounding box (X, Y, W, H). // // FIXME: The other way around? pub trait HasXYWH: HasXY + HasWH { fn x2 (&self) -> N { self.x().plus(self.w()) } fn y2 (&self) -> N { self.y().plus(self.h()) } fn xywh (&self) -> XYWH { XYWH(self.x(), self.y(), self.w(), self.h()) } fn expect_min (&self, w: N, h: N) -> Usually<&Self> { if self.w() < w || self.h() < h { Err(format!("min {w}x{h}").into()) } else { Ok(self) } } } // Something that has a [Measure] of its rendered size. pub trait Measured { fn measure (&self) -> &Measure; fn measure_width (&self) -> O::Unit { self.measure().w() } fn measure_height (&self) -> O::Unit { self.measure().h() } } pub trait HasPerf { fn perf (&self) -> &PerfModel; }