diff --git a/output/src/lib.rs b/output/src/lib.rs index 40d31f0..65c7580 100644 --- a/output/src/lib.rs +++ b/output/src/lib.rs @@ -16,7 +16,7 @@ pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::Relaxed} pub(crate) use std::marker::PhantomData; pub(crate) use dizzle::*; -// Define macros first, so that private macros are available in private modules: +// Define macros first, so that private macros are available in private modules. /// Clear a pre-allocated buffer, then write into it. #[macro_export] macro_rules! rewrite { @@ -117,8 +117,8 @@ macro_rules! layout_op_xy ( macro_rules! push_pull(($T:ident: $method: ident)=>{ layout_op_xy!(1: $T); impl> Layout for $T { - fn layout_x (&self, area: XYWH) -> O::Unit { area.x().$method(self.dx()) } - fn layout_y (&self, area: XYWH) -> O::Unit { area.y().$method(self.dy()) } + fn x (&self, area: O::Area) -> O::Unit { area.x().$method(self.dx()) } + fn y (&self, area: O::Area) -> O::Unit { area.y().$method(self.dy()) } } }); diff --git a/output/src/out_impls.rs b/output/src/out_impls.rs index 787d752..99dfdc6 100644 --- a/output/src/out_impls.rs +++ b/output/src/out_impls.rs @@ -49,62 +49,37 @@ impl WH { } } impl XYWH { - fn zero () -> Self { - Self(0.into(), 0.into(), 0.into(), 0.into()) - } - fn x2 (&self) -> N { - self.x().plus(self.w()) - } - fn y2 (&self) -> N { - self.y().plus(self.h()) - } - fn with_w (&self, w: N) -> XYWH { - Self(self.x(), self.y(), w, self.h()) - } - fn with_h (&self, h: N) -> XYWH { - Self(self.x(), self.y(), self.w(), h) - } - fn lrtb (&self) -> XYWH { - Self(self.x(), self.x2(), self.y(), self.y2()) - } - fn clipped_w (&self, w: N) -> XYWH { - Self(self.x(), self.y(), self.w().min(w), self.h()) - } - fn clipped_h (&self, h: N) -> XYWH { - Self(self.x(), self.y(), self.w(), self.h().min(h)) - } - fn clipped (&self, wh: WH) -> XYWH { - Self(self.x(), self.y(), wh.w(), wh.h()) - } + fn with_w (&self, w: N) -> XYWH { Self(self.x(), self.y(), w, self.h()) } + fn with_h (&self, h: N) -> XYWH { Self(self.x(), self.y(), self.w(), h) } + fn lrtb (&self) -> XYWH { Self(self.x(), self.x2(), self.y(), self.y2()) } + fn clipped_w (&self, w: N) -> XYWH { Self(self.x(), self.y(), self.w().min(w), self.h()) } + fn clipped_h (&self, h: N) -> XYWH { Self(self.x(), self.y(), self.w(), self.h().min(h)) } + fn clipped (&self, wh: impl HasWH) -> XYWH { Self(self.x(), self.y(), wh.w(), wh.h()) } /// Iterate over every covered X coordinate. fn iter_x (&self) -> impl Iterator where N: std::iter::Step { - let Self(x, _, w, _) = *self; - x..(x+w) + self.x()..(self.x()+self.w()) } /// Iterate over every covered Y coordinate. fn iter_y (&self) -> impl Iterator where N: std::iter::Step { - let Self(_, y, _, h) = *self; - y..(y+h) + self.y()..(self.y()+self.h()) } fn center (&self) -> XY { - let Self(x, y, w, h) = self; XY(self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())) } fn centered (&self) -> XY { - let Self(x, y, w, h) = *self; - XY(x.minus(w/2.into()), y.minus(h/2.into())) + XY(self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())) } fn centered_x (&self, n: N) -> XYWH { - let Self(x, y, w, h) = *self; - XYWH((x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()) + let [x, y, w, h] = self.xywh(); + Self((x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()) } fn centered_y (&self, n: N) -> XYWH { - let Self(x, y, w, h) = *self; - XYWH(x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n) + let [x, y, w, h] = self.xywh(); + Self(x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n) } fn centered_xy (&self, [n, m]: [N;2]) -> XYWH { - let Self(x, y, w, h) = *self; - XYWH((x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m) + let [x, y, w, h] = self.xywh(); + Self((x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m) } } @@ -192,20 +167,20 @@ impl Memo { } impl Direction { - pub fn split_fixed (self, area: XYWH, a: N) -> (XYWH, XYWH) { - let XYWH(x, y, w, h) = area; + pub fn split_fixed (self, area: impl HasXYWH, a: N) -> ([N;4],[N;4]) { + let XYWH(x, y, w, h) = area.xywh(); match self { - North => (XYWH(x, y.plus(h).minus(a), w, a), XYWH(x, y, w, h.minus(a))), - South => (XYWH(x, y, w, a), XYWH(x, y.plus(a), w, h.minus(a))), - East => (XYWH(x, y, a, h), XYWH(x.plus(a), y, w.minus(a), h)), - West => (XYWH(x.plus(w).minus(a), y, a, h), XYWH(x, y, w.minus(a), h)), - Above | Below => (area, area) + North => ([x, y.plus(h).minus(a), w, a], [x, y, w, h.minus(a)]), + South => ([x, y, w, a], [x, y.plus(a), w, h.minus(a)]), + East => ([x, y, a, h], [x.plus(a), y, w.minus(a), h]), + West => ([x.plus(w).minus(a), y, a, h], [x, y, w.minus(a), h]), + Above | Below => (area.xywh(), area.xywh()) } } } -impl>> Measured for T { - fn measure (&self) -> &Measure { +impl>> HasSize for T { + fn size (&self) -> &Measure { self.get() } } @@ -246,104 +221,97 @@ impl Measure { pub fn format (&self) -> Arc { format!("{}x{}", self.w(), self.h()).into() } pub fn of > (&self, item: T) -> Bsp, T> { Bsp::b(Fill::XY(self), item) } pub fn new (x: O::Unit, y: O::Unit) -> Self { - Self { __: PhantomData::default(), x: Arc::new(x.atomic()), y: Arc::new(y.atomic()), } + Self { __: PhantomData::default(), x: Arc::new(x.into()), y: Arc::new(y.into()), } } } -/// FIXME don't convert to u16 specifically -impl HasWH for Measure { - fn w (&self) -> O::Unit { (self.x.load(Relaxed) as u16).into() } - fn h (&self) -> O::Unit { (self.y.load(Relaxed) as u16).into() } -} -impl From> for Measure { - fn from (WH(x, y): WH) -> Self { Self::new(x, y) } +impl From<[O::Unit; 2]> for Measure { + fn from ([x, y]: [O::Unit; 2]) -> Self { Self::new(x, y) } } impl Layout for () { - fn layout_x (&self, a: XYWH) -> O::Unit { a.x() } - fn layout_y (&self, a: XYWH) -> O::Unit { a.y() } - fn layout_w (&self, _: XYWH) -> O::Unit { 0.into() } - fn layout_w_min (&self, _: XYWH) -> O::Unit { 0.into() } - fn layout_w_max (&self, _: XYWH) -> O::Unit { 0.into() } - fn layout_h (&self, _: XYWH) -> O::Unit { 0.into() } - fn layout_h_min (&self, _: XYWH) -> O::Unit { 0.into() } - fn layout_h_max (&self, _: XYWH) -> O::Unit { 0.into() } - fn layout (&self, a: XYWH) -> XYWH { XYWH(a.x(), a.y(), 0.into(), 0.into()) } + fn x (&self, a: O::Area) -> O::Unit { a.x() } + fn y (&self, a: O::Area) -> O::Unit { a.y() } + fn w (&self, _: O::Area) -> O::Unit { 0.into() } + fn w_min (&self, _: O::Area) -> O::Unit { 0.into() } + fn w_max (&self, _: O::Area) -> O::Unit { 0.into() } + fn h (&self, _: O::Area) -> O::Unit { 0.into() } + fn h_min (&self, _: O::Area) -> O::Unit { 0.into() } + fn h_max (&self, _: O::Area) -> O::Unit { 0.into() } + fn layout (&self, a: O::Area) -> O::Area { [a.x(), a.y(), 0.into(), 0.into()].into() } } impl> Layout for &L { - fn layout_x (&self, a: XYWH) -> O::Unit { (*self).layout_x(a) } - fn layout_y (&self, a: XYWH) -> O::Unit { (*self).layout_y(a) } - fn layout_w (&self, a: XYWH) -> O::Unit { (*self).layout_w(a) } - fn layout_w_min (&self, a: XYWH) -> O::Unit { (*self).layout_w_min(a) } - fn layout_w_max (&self, a: XYWH) -> O::Unit { (*self).layout_w_max(a) } - fn layout_h (&self, a: XYWH) -> O::Unit { (*self).layout_h(a) } - fn layout_h_min (&self, a: XYWH) -> O::Unit { (*self).layout_h_min(a) } - fn layout_h_max (&self, a: XYWH) -> O::Unit { (*self).layout_h_max(a) } - fn layout (&self, a: XYWH) -> XYWH { (*self).layout(a) } + fn x (&self, a: O::Area) -> O::Unit { (*self).x(a) } + fn y (&self, a: O::Area) -> O::Unit { (*self).y(a) } + fn w (&self, a: O::Area) -> O::Unit { (*self).w(a) } + fn w_min (&self, a: O::Area) -> O::Unit { (*self).w_min(a) } + fn w_max (&self, a: O::Area) -> O::Unit { (*self).w_max(a) } + fn h (&self, a: O::Area) -> O::Unit { (*self).h(a) } + fn h_min (&self, a: O::Area) -> O::Unit { (*self).h_min(a) } + fn h_max (&self, a: O::Area) -> O::Unit { (*self).h_max(a) } + fn layout (&self, a: O::Area) -> O::Area { (*self).layout(a) } } impl> Layout for &mut L { - fn layout_x (&self, a: XYWH) -> O::Unit { (**self).layout_x(a) } - fn layout_y (&self, a: XYWH) -> O::Unit { (**self).layout_y(a) } - fn layout_w (&self, a: XYWH) -> O::Unit { (**self).layout_w(a) } - fn layout_w_min (&self, a: XYWH) -> O::Unit { (**self).layout_w_min(a) } - fn layout_w_max (&self, a: XYWH) -> O::Unit { (**self).layout_w_max(a) } - fn layout_h (&self, a: XYWH) -> O::Unit { (**self).layout_h(a) } - fn layout_h_min (&self, a: XYWH) -> O::Unit { (**self).layout_h_min(a) } - fn layout_h_max (&self, a: XYWH) -> O::Unit { (**self).layout_h_max(a) } - fn layout (&self, a: XYWH) -> XYWH { (**self).layout(a) } + fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) } + fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) } + fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) } + fn w_min (&self, a: O::Area) -> O::Unit { (**self).w_min(a) } + fn w_max (&self, a: O::Area) -> O::Unit { (**self).w_max(a) } + fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) } + fn h_min (&self, a: O::Area) -> O::Unit { (**self).h_min(a) } + fn h_max (&self, a: O::Area) -> O::Unit { (**self).h_max(a) } + fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) } } impl> Layout for Arc { - fn layout_x (&self, a: XYWH) -> O::Unit { (**self).layout_x(a) } - fn layout_y (&self, a: XYWH) -> O::Unit { (**self).layout_y(a) } - fn layout_w (&self, a: XYWH) -> O::Unit { (**self).layout_w(a) } - fn layout_w_min (&self, a: XYWH) -> O::Unit { (**self).layout_w_min(a) } - fn layout_w_max (&self, a: XYWH) -> O::Unit { (**self).layout_w_max(a) } - fn layout_h (&self, a: XYWH) -> O::Unit { (**self).layout_h(a) } - fn layout_h_min (&self, a: XYWH) -> O::Unit { (**self).layout_h_min(a) } - fn layout_h_max (&self, a: XYWH) -> O::Unit { (**self).layout_h_max(a) } - fn layout (&self, a: XYWH) -> XYWH { (**self).layout(a) } + fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) } + fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) } + fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) } + fn w_min (&self, a: O::Area) -> O::Unit { (**self).w_min(a) } + fn w_max (&self, a: O::Area) -> O::Unit { (**self).w_max(a) } + fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) } + fn h_min (&self, a: O::Area) -> O::Unit { (**self).h_min(a) } + fn h_max (&self, a: O::Area) -> O::Unit { (**self).h_max(a) } + fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) } } impl Layout for Box> { - fn layout_x (&self, a: XYWH) -> O::Unit { (**self).layout_x(a) } - fn layout_y (&self, a: XYWH) -> O::Unit { (**self).layout_y(a) } - fn layout_w (&self, a: XYWH) -> O::Unit { (**self).layout_w(a) } - fn layout_w_min (&self, a: XYWH) -> O::Unit { (**self).layout_w_min(a) } - fn layout_w_max (&self, a: XYWH) -> O::Unit { (**self).layout_w_max(a) } - fn layout_h (&self, a: XYWH) -> O::Unit { (**self).layout_h(a) } - fn layout_h_min (&self, a: XYWH) -> O::Unit { (**self).layout_h_min(a) } - fn layout_h_max (&self, a: XYWH) -> O::Unit { (**self).layout_h_max(a) } - fn layout (&self, a: XYWH) -> XYWH { (**self).layout(a) } + fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) } + fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) } + fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) } + fn w_min (&self, a: O::Area) -> O::Unit { (**self).w_min(a) } + fn w_max (&self, a: O::Area) -> O::Unit { (**self).w_max(a) } + fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) } + fn h_min (&self, a: O::Area) -> O::Unit { (**self).h_min(a) } + fn h_max (&self, a: O::Area) -> O::Unit { (**self).h_max(a) } + fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) } } impl> Layout for RwLock { - fn layout_x (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_x(a) } - fn layout_y (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_y(a) } - fn layout_w (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_w(a) } - fn layout_w_min (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_w_min(a) } - fn layout_w_max (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_w_max(a) } - fn layout_h (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_h(a) } - fn layout_h_min (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_h_min(a) } - fn layout_h_max (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_h_max(a) } - fn layout (&self, a: XYWH) -> XYWH { self.read().unwrap().layout(a) } + fn x (&self, a: O::Area) -> O::Unit { self.read().unwrap().x(a) } + fn y (&self, a: O::Area) -> O::Unit { self.read().unwrap().y(a) } + fn w (&self, a: O::Area) -> O::Unit { self.read().unwrap().w(a) } + fn w_min (&self, a: O::Area) -> O::Unit { self.read().unwrap().w_min(a) } + fn w_max (&self, a: O::Area) -> O::Unit { self.read().unwrap().w_max(a) } + fn h (&self, a: O::Area) -> O::Unit { self.read().unwrap().h(a) } + fn h_min (&self, a: O::Area) -> O::Unit { self.read().unwrap().h_min(a) } + fn h_max (&self, a: O::Area) -> O::Unit { self.read().unwrap().h_max(a) } + fn layout (&self, a: O::Area) -> O::Area { self.read().unwrap().layout(a) } } impl> Layout for Option { - fn layout_x (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_x(to)).unwrap_or(to.x()) } - fn layout_y (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_y(to)).unwrap_or(to.y()) } - fn layout_w_min (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_w_min(to)).unwrap_or(0.into()) } - fn layout_w_max (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_w_max(to)).unwrap_or(0.into()) } - fn layout_w (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_w(to)).unwrap_or(0.into()) } - fn layout_h_min (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_h_min(to)).unwrap_or(0.into()) } - fn layout_h_max (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_h_max(to)).unwrap_or(0.into()) } - fn layout_h (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_h(to)).unwrap_or(0.into()) } - fn layout (&self, to: XYWH) -> XYWH { - let xywh = XYWH(self.layout_x(to), self.layout_y(to), self.layout_w(to), self.layout_h(to)); - self.as_ref().map(|c|c.layout(xywh)).unwrap_or(XYWH(to.x(), to.y(), 0.into(), 0.into())) - } + fn x (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.x(to)).unwrap_or(to.x()) } + fn y (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.y(to)).unwrap_or(to.y()) } + fn w_min (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.w_min(to)).unwrap_or(0.into()) } + fn w_max (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.w_max(to)).unwrap_or(0.into()) } + fn w (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.w(to)).unwrap_or(0.into()) } + fn h_min (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.h_min(to)).unwrap_or(0.into()) } + fn h_max (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.h_max(to)).unwrap_or(0.into()) } + fn h (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.h(to)).unwrap_or(0.into()) } + fn layout (&self, to: O::Area) -> O::Area { self.as_ref().map(|c|c.layout([self.x(to), self.y(to), self.w(to), self.h(to)].into())) + .unwrap_or([to.x(), to.y(), 0.into(), 0.into()].into()) } } impl> HasContent for Bounded { @@ -367,9 +335,9 @@ impl> When { } impl> Layout for When { - fn layout (&self, to: XYWH) -> XYWH { + fn layout (&self, to: O::Area) -> O::Area { let Self(cond, item, ..) = self; - if *cond { item.layout(to) } else { XYWH::::zero().into() } + if *cond { item.layout(to) } else { O::Area::zero().into() } } } @@ -388,7 +356,7 @@ impl, B: Content> Either { } impl, B: Layout> Layout for Either { - fn layout (&self, to: XYWH) -> XYWH { + fn layout (&self, to: E::Area) -> E::Area { let Self(cond, a, b, ..) = self; if *cond { a.layout(to) } else { b.layout(to) } } @@ -402,88 +370,77 @@ impl, B: Content> Draw for Either { } } -push_pull!(Push: plus); + push_pull!(Push: plus); -push_pull!(Pull: minus); + push_pull!(Pull: minus); -layout_op_xy!(0: Fill); + layout_op_xy!(0: Fill); + impl> Layout for Fill { + fn x (&self, area: O::Area) -> O::Unit { if self.dx() { area.x() } else { self.inner().x(area) } } + fn y (&self, area: O::Area) -> O::Unit { if self.dy() { area.y() } else { self.inner().y(area) } } + fn w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w(area) } } + fn w_min (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w_min(area) } } + fn w_max (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w_max(area) } } + fn h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h(area) } } + fn h_min (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h_min(area) } } + fn h_max (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h_max(area) } } + } + impl Fill { + #[inline] pub const fn dx (&self) -> bool { matches!(self, Self::X(_) | Self::XY(_)) } + #[inline] pub const fn dy (&self) -> bool { matches!(self, Self::Y(_) | Self::XY(_)) } + } -impl> Layout for Fill { - fn layout_x (&self, area: XYWH) -> O::Unit { if self.dx() { area.x() } else { self.inner().layout_x(area) } } - fn layout_y (&self, area: XYWH) -> O::Unit { if self.dy() { area.y() } else { self.inner().layout_y(area) } } - fn layout_w (&self, area: XYWH) -> O::Unit { if self.dx() { area.w() } else { self.inner().layout_w(area) } } - fn layout_w_min (&self, area: XYWH) -> O::Unit { if self.dx() { area.w() } else { self.inner().layout_w_min(area) } } - fn layout_w_max (&self, area: XYWH) -> O::Unit { if self.dx() { area.w() } else { self.inner().layout_w_max(area) } } - fn layout_h (&self, area: XYWH) -> O::Unit { if self.dy() { area.h() } else { self.inner().layout_h(area) } } - fn layout_h_min (&self, area: XYWH) -> O::Unit { if self.dy() { area.h() } else { self.inner().layout_h_min(area) } } - fn layout_h_max (&self, area: XYWH) -> O::Unit { if self.dy() { area.h() } else { self.inner().layout_h_max(area) } } -} + layout_op_xy!(1 opt: Fixed); + impl> Layout for Fixed { + fn w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w(area)) } + fn w_min (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w_min(area)) } + fn w_max (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w_max(area)) } + fn h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h(area)) } + fn h_min (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h_min(area)) } + fn h_max (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h_max(area)) } + } -impl Fill { - #[inline] pub const fn dx (&self) -> bool { matches!(self, Self::X(_) | Self::XY(_)) } - #[inline] pub const fn dy (&self) -> bool { matches!(self, Self::Y(_) | Self::XY(_)) } -} - -layout_op_xy!(1 opt: Fixed); - -impl> Layout for Fixed { - fn layout_w (&self, area: XYWH) -> O::Unit { self.dx().unwrap_or(self.inner().layout_w(area)) } - fn layout_w_min (&self, area: XYWH) -> O::Unit { self.dx().unwrap_or(self.inner().layout_w_min(area)) } - fn layout_w_max (&self, area: XYWH) -> O::Unit { self.dx().unwrap_or(self.inner().layout_w_max(area)) } - fn layout_h (&self, area: XYWH) -> O::Unit { self.dy().unwrap_or(self.inner().layout_h(area)) } - fn layout_h_min (&self, area: XYWH) -> O::Unit { self.dy().unwrap_or(self.inner().layout_h_min(area)) } - fn layout_h_max (&self, area: XYWH) -> O::Unit { self.dy().unwrap_or(self.inner().layout_h_max(area)) } -} - -layout_op_xy!(1 opt: Max); - -impl> Layout for Max { - fn layout (&self, area: XYWH) -> XYWH { - let XYWH(x, y, w, h) = self.inner().layout(area); - match self { - Self::X(mw, _) => XYWH(x, y, w.min(*mw), h ), - Self::Y(mh, _) => XYWH(x, y, w, h.min(*mh)), - Self::XY(mw, mh, _) => XYWH(x, y, w.min(*mw), h.min(*mh)), + layout_op_xy!(1 opt: Max); + impl> Layout for Max { + fn layout (&self, area: E::Area) -> E::Area { + let [x, y, w, h] = self.inner().layout(area).xywh(); + match self { + Self::X(mw, _) => [x, y, w.min(*mw), h ], + Self::Y(mh, _) => [x, y, w, h.min(*mh)], + Self::XY(mw, mh, _) => [x, y, w.min(*mw), h.min(*mh)], + }.into() } } -} -layout_op_xy!(1 opt: Min); - -impl> Layout for Min { - fn layout (&self, area: XYWH) -> XYWH { - let XYWH(x, y, w, h) = self.inner().layout(area); - match self { - Self::X(mw, _) => XYWH(x, y, w.max(*mw), h), - Self::Y(mh, _) => XYWH(x, y, w, h.max(*mh)), - Self::XY(mw, mh, _) => XYWH(x, y, w.max(*mw), h.max(*mh)), + layout_op_xy!(1 opt: Min); + impl> Layout for Min { + fn layout (&self, area: E::Area) -> E::Area { + let [x, y, w, h] = self.inner().layout(area).xywh(); + match self { + Self::X(mw, _) => [x, y, w.max(*mw), h], + Self::Y(mh, _) => [x, y, w, h.max(*mh)], + Self::XY(mw, mh, _) => [x, y, w.max(*mw), h.max(*mh)], + }.into() } } -} -layout_op_xy!(1 opt: Expand); - -impl> Layout for Expand { - fn layout_w (&self, to: XYWH) -> O::Unit { - self.inner().layout_w(to).plus(self.dx().unwrap_or_default()) + layout_op_xy!(1 opt: Expand); + impl> Layout for Expand { + fn w (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dx().unwrap_or_default()) } + fn h (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dy().unwrap_or_default()) } } - fn layout_h (&self, to: XYWH) -> O::Unit { - self.inner().layout_w(to).plus(self.dy().unwrap_or_default()) + + // FIXME: why they differ? + + layout_op_xy!(1 opt: Shrink); + impl> Layout for Shrink { + fn layout (&self, to: E::Area) -> E::Area { + let area = self.inner().layout(to); + let dx = self.dx().unwrap_or_default(); + let dy = self.dy().unwrap_or_default(); + [area.x(), area.y(), area.w().minus(dx), area.h().minus(dy)].into() + } } -} - -// FIXME: why they differ? - -layout_op_xy!(1 opt: Shrink); - -impl> Layout for Shrink { - fn layout (&self, to: XYWH) -> XYWH { - let area = self.inner().layout(to); - let dx = self.dx().unwrap_or_default(); - let dy = self.dy().unwrap_or_default(); - XYWH(area.x(), area.y(), area.w().minus(dx), area.h().minus(dy)) - } -} impl Align { #[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) } @@ -504,19 +461,19 @@ impl> Draw for Align { } impl> Layout for Align { - fn layout_x (&self, to: XYWH) -> O::Unit { + fn x (&self, to: O::Area) -> O::Unit { match self.0 { NW | W | SW => to.x(), - N | Center | S => to.x().plus(to.w() / 2.into()).minus(self.1.layout_w(to) / 2.into()), - NE | E | SE => to.x().plus(to.w()).minus(self.1.layout_w(to)), + N | Center | S => to.x().plus(to.w() / 2.into()).minus(self.1.w(to) / 2.into()), + NE | E | SE => to.x().plus(to.w()).minus(self.1.w(to)), _ => todo!(), } } - fn layout_y (&self, to: XYWH) -> O::Unit { + fn y (&self, to: O::Area) -> O::Unit { match self.0 { NW | N | NE => to.y(), - W | Center | E => to.y().plus(to.h() / 2.into()).minus(self.1.layout_h(to) / 2.into()), - SW | S | SE => to.y().plus(to.h()).minus(self.1.layout_h(to)), + W | Center | E => to.y().plus(to.h() / 2.into()).minus(self.1.h(to) / 2.into()), + SW | S | SE => to.y().plus(to.h()).minus(self.1.h(to)), _ => todo!(), } } @@ -528,7 +485,6 @@ impl Pad { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } } } - impl Pad { #[inline] pub fn dx (&self) -> U { use Pad::*; @@ -539,18 +495,15 @@ impl Pad { match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } } } - impl> Draw for Pad { fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } } - impl> Layout for Pad { - fn layout_x (&self, area: XYWH) -> O::Unit { area.x().plus(self.dx()) } - fn layout_y (&self, area: XYWH) -> O::Unit { area.x().plus(self.dx()) } - fn layout_w (&self, area: XYWH) -> O::Unit { area.w().minus(self.dx() * 2.into()) } - fn layout_h (&self, area: XYWH) -> O::Unit { area.h().minus(self.dy() * 2.into()) } + fn x (&self, area: O::Area) -> O::Unit { area.x().plus(self.dx()) } + fn y (&self, area: O::Area) -> O::Unit { area.x().plus(self.dx()) } + fn w (&self, area: O::Area) -> O::Unit { area.w().minus(self.dx() * 2.into()) } + fn h (&self, area: O::Area) -> O::Unit { area.h().minus(self.dy() * 2.into()) } } - impl Bsp { #[inline] pub const fn n (a: Head, b: Tail) -> Self { Self(North, a, b) } #[inline] pub const fn s (a: Head, b: Tail) -> Self { Self(South, a, b) } @@ -566,10 +519,12 @@ impl, Tail: Content> Draw for Bsp { South => { //panic!("{}", self.1.h(to.area())); let area_1 = self.1.layout(to.area()); - let area_2 = self.2.layout(XYWH( - to.area().x(), to.area().y().plus(area_1.h()), - to.area().w(), to.area().h().minus(area_1.h()) - )); + let area_2 = self.2.layout([ + to.area().x(), + to.area().y().plus(area_1.h()), + to.area().w(), + to.area().h().minus(area_1.h()) + ].into()); //panic!("{area_1:?} {area_2:?}"); to.place_at(area_1, &self.1); to.place_at(area_2, &self.2); @@ -587,95 +542,70 @@ impl, Tail: Content> Draw for Bsp { //} } } - impl, Tail: Layout> Layout for Bsp { - fn layout_w (&self, area: XYWH) -> O::Unit { - match self.0 { - Above | Below | North | South => self.1.layout_w(area).max(self.2.layout_w(area)), - East | West => self.1.layout_w_min(area).plus(self.2.layout_w(area)), - } + fn w (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.w(area).max(self.2.w(area)), East | West => self.1.w_min(area).plus(self.2.w(area)), } } - fn layout_w_min (&self, area: XYWH) -> O::Unit { - match self.0 { - Above | Below | North | South => self.1.layout_w_min(area).max(self.2.layout_w_min(area)), - East | West => self.1.layout_w_min(area).plus(self.2.layout_w_min(area)), - } + fn w_min (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.w_min(area).max(self.2.w_min(area)), East | West => self.1.w_min(area).plus(self.2.w_min(area)), } } - fn layout_w_max (&self, area: XYWH) -> O::Unit { - match self.0 { - Above | Below | North | South => self.1.layout_w_max(area).max(self.2.layout_w_max(area)), - East | West => self.1.layout_w_max(area).plus(self.2.layout_w_max(area)), - } + fn w_max (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.w_max(area).max(self.2.w_max(area)), East | West => self.1.w_max(area).plus(self.2.w_max(area)), } } - fn layout_h (&self, area: XYWH) -> O::Unit { - match self.0 { - Above | Below | East | West => self.1.layout_h(area).max(self.2.layout_h(area)), - North | South => self.1.layout_h(area).plus(self.2.layout_h(area)), - } + fn h (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | East | West => self.1.h(area).max(self.2.h(area)), North | South => self.1.h(area).plus(self.2.h(area)), } } - fn layout_h_min (&self, area: XYWH) -> O::Unit { - match self.0 { - Above | Below | East | West => self.1.layout_h_min(area).max(self.2.layout_h_min(area)), - North | South => self.1.layout_h_min(area).plus(self.2.layout_h_min(area)), - } + fn h_min (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | East | West => self.1.h_min(area).max(self.2.h_min(area)), North | South => self.1.h_min(area).plus(self.2.h_min(area)), } } - fn layout_h_max (&self, area: XYWH) -> O::Unit { - match self.0 { - Above | Below | North | South => self.1.layout_h_max(area).max(self.2.layout_h_max(area)), - East | West => self.1.layout_h_max(area).plus(self.2.layout_h_max(area)), - } + fn h_max (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.h_max(area).max(self.2.h_max(area)), East | West => self.1.h_max(area).plus(self.2.h_max(area)), } } - fn layout (&self, area: XYWH) -> XYWH { + fn layout (&self, area: O::Area) -> O::Area { bsp_areas(area, self.0, &self.1, &self.2)[2] } } -fn bsp_areas , B: Layout> ( - area: XYWH, - direction: Direction, - a: &A, - b: &B, -) -> [XYWH;3] { - let XYWH(x, y, w, h) = area; - let WH(aw, ah) = a.layout(area).wh(); - let WH(bw, bh) = b.layout(match direction { - South => XYWH(x, y + ah, w, h.minus(ah)), - North => XYWH(x, y, w, h.minus(ah)), - East => XYWH(x + aw, y, w.minus(aw), h), - West => XYWH(x, y, w.minus(aw), h), - Above => area, - Below => area, +fn bsp_areas , B: Layout> (area: O::Area, direction: Direction, a: &A, b: &B,) -> [O::Area;3] { + let [x, y, w, h] = area.xywh(); + let [aw, ah] = a.layout(area).wh(); + let [bw, bh] = b.layout(match direction { + Above | Below => area, + South => [x, y + ah, w, h.minus(ah)].into(), + North => [x, y, w, h.minus(ah)].into(), + East => [x + aw, y, w.minus(aw), h].into(), + West => [x, y, w.minus(aw), h].into(), }).wh(); match direction { Above | Below => { - let XYWH(x, y, w, h) = area.centered_xy([aw.max(bw), ah.max(bh)]); - let a = XYWH((x + w/2.into()).minus(aw/2.into()), (y + h/2.into()).minus(ah/2.into()), aw, ah); - let b = XYWH((x + w/2.into()).minus(bw/2.into()), (y + h/2.into()).minus(bh/2.into()), bw, bh); - [a.into(), b.into(), XYWH(x, y, w, h)] + let [x, y, w, h] = area.center_xy([aw.max(bw), ah.max(bh)]); + let a = [(x + w/2.into()).minus(aw/2.into()), (y + h/2.into()).minus(ah/2.into()), aw, ah]; + let b = [(x + w/2.into()).minus(bw/2.into()), (y + h/2.into()).minus(bh/2.into()), bw, bh]; + [a.into(), b.into(), [x, y, w, h].into()] }, South => { - let XYWH(x, y, w, h) = area.centered_xy([aw.max(bw), ah + bh]); - let a = XYWH((x + w/2.into()).minus(aw/2.into()), y, aw, ah); - let b = XYWH((x + w/2.into()).minus(bw/2.into()), y + ah, bw, bh); - [a.into(), b.into(), XYWH(x, y, w, h)] + let [x, y, w, h] = area.center_xy([aw.max(bw), ah + bh]); + let a = [(x + w/2.into()).minus(aw/2.into()), y, aw, ah]; + let b = [(x + w/2.into()).minus(bw/2.into()), y + ah, bw, bh]; + [a.into(), b.into(), [x, y, w, h].into()] }, North => { - let XYWH(x, y, w, h) = area.centered_xy([aw.max(bw), ah + bh]); - let a = XYWH((x + (w/2.into())).minus(aw/2.into()), y + bh, aw, ah); - let b = XYWH((x + (w/2.into())).minus(bw/2.into()), y, bw, bh); - [a.into(), b.into(), XYWH(x, y, w, h)] + let [x, y, w, h] = area.center_xy([aw.max(bw), ah + bh]); + let a = [(x + (w/2.into())).minus(aw/2.into()), y + bh, aw, ah]; + let b = [(x + (w/2.into())).minus(bw/2.into()), y, bw, bh]; + [a.into(), b.into(), [x, y, w, h].into()] }, East => { - let XYWH(x, y, w, h) = area.centered_xy([aw + bw, ah.max(bh)]); - let a = XYWH(x, (y + h/2.into()).minus(ah/2.into()), aw, ah); - let b = XYWH(x + aw, (y + h/2.into()).minus(bh/2.into()), bw, bh); - [a.into(), b.into(), XYWH(x, y, w, h)] + let [x, y, w, h] = area.center_xy([aw + bw, ah.max(bh)]); + let a = [x, (y + h/2.into()).minus(ah/2.into()), aw, ah]; + let b = [x + aw, (y + h/2.into()).minus(bh/2.into()), bw, bh]; + [a.into(), b.into(), [x, y, w, h].into()] }, West => { - let XYWH(x, y, w, h) = area.centered_xy([aw + bw, ah.max(bh)]); - let a = XYWH(x + bw, (y + h/2.into()).minus(ah/2.into()), aw, ah); - let b = XYWH(x, (y + h/2.into()).minus(bh/2.into()), bw, bh); - [a.into(), b.into(), XYWH(x, y, w, h)] + let [x, y, w, h] = area.center_xy([aw + bw, ah.max(bh)]); + let a = [x + bw, (y + h/2.into()).minus(ah/2.into()), aw, ah]; + let b = [x, (y + h/2.into()).minus(bh/2.into()), bw, bh]; + [a.into(), b.into(), [x, y, w, h].into()] }, } } @@ -705,13 +635,13 @@ impl<'a, O, A, B, I, F, G> Layout for Map where F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync { - fn layout (&self, area: XYWH) -> XYWH { + fn layout (&self, area: O::Area) -> O::Area { let Self { get_iter, get_item, .. } = self; let mut index = 0; - let XY(mut min_x, mut min_y) = area.centered(); - let XY(mut max_x, mut max_y) = area.center(); + let [mut min_x, mut min_y] = area.center(); + let [mut max_x, mut max_y] = area.center(); for item in get_iter() { - let XYWH(x, y, w, h) = get_item(item, index).layout(area); + let [x,y,w,h] = get_item(item, index).layout(area).xywh(); min_x = min_x.min(x); min_y = min_y.min(y); max_x = max_x.max(x + w); @@ -721,10 +651,9 @@ impl<'a, O, A, B, I, F, G> Layout for Map where let w = max_x - min_x; let h = max_y - min_y; //[min_x.into(), min_y.into(), w.into(), h.into()].into() - area.centered_xy([w.into(), h.into()]) + area.center_xy([w.into(), h.into()]).into() } } - impl<'a, O, A, B, I, F, G> Draw for Map where O: Out, B: Content, @@ -791,11 +720,15 @@ impl Tryptich { } impl> Layout for Foreground { - fn layout (&self, to: XYWH) -> XYWH { self.1.layout(to) } + fn layout (&self, to: O::Area) -> O::Area { + self.1.layout(to) + } } impl> Layout for Background { - fn layout (&self, to: XYWH) -> XYWH { self.1.layout(to) } + fn layout (&self, to: O::Area) -> O::Area { + self.1.layout(to) + } } impl, V: Content> HasContent for FieldH { @@ -803,7 +736,7 @@ impl, V: Content> HasContent for FieldH } impl, V: Content> Layout for FieldH { - fn layout (&self, to: XYWH) -> XYWH { self.content().layout(to) } + fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) } } impl, V: Content> Draw for FieldH { @@ -815,19 +748,17 @@ impl, V: Content> HasContent for FieldV } impl, V: Content> Layout for FieldV { - fn layout (&self, to: XYWH) -> XYWH { self.content().layout(to) } + fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) } } impl, V: Content> Draw for FieldV { fn draw (&self, to: &mut O) { self.content().draw(to) } } - impl> Layout for Border { - fn layout (&self, area: XYWH) -> XYWH { + fn layout (&self, area: O::Area) -> O::Area { self.1.layout(area) } } - impl Field { pub fn new (direction: Direction) -> Field { Field:: { diff --git a/output/src/out_structs.rs b/output/src/out_structs.rs index c267a29..22b6465 100644 --- a/output/src/out_structs.rs +++ b/output/src/out_structs.rs @@ -5,16 +5,14 @@ use crate::*; /// ``` /// let xy: XY = XY(0, 0); /// ``` -#[cfg_attr(test, derive(Arbitrary))] -#[derive(Copy, Clone, Default)] pub struct XY(pub C, pub C); +pub struct XY(pub C, pub C); /// A size (Width, Height). /// /// ``` /// let wh: WH = WH(0, 0); /// ``` -#[cfg_attr(test, derive(Arbitrary))] -#[derive(Copy, Clone, Default)] pub struct WH(pub C, pub C); +pub struct WH(pub C, pub C); /// Point with size. /// @@ -24,16 +22,15 @@ use crate::*; /// /// * [ ] TODO: anchor field (determines at which corner/side is X0 Y0) /// -#[cfg_attr(test, derive(Arbitrary))] -#[derive(Copy, Clone, Default)] pub struct XYWH(pub C, pub C, pub C, pub C); +pub struct XYWH(pub C, pub C, pub C, pub C); /// A cardinal direction. /// /// ``` /// let direction = Direction::Above; /// ``` -#[cfg_attr(test, derive(Arbitrary))] -#[derive(Copy, Clone, PartialEq, Debug)] pub enum Direction { +#[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(test, derive(Arbitrary))] +pub enum Direction { North, South, East, West, Above, Below } @@ -42,8 +39,8 @@ use crate::*; /// ``` /// let alignment = Align::Center; /// ``` -#[cfg_attr(test, derive(Arbitrary))] -#[derive(Debug, Copy, Clone, Default)] pub enum Alignment { +#[derive(Debug, Copy, Clone, Default)] +pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } @@ -53,7 +50,7 @@ use crate::*; /// let measure = Measure::default(); /// ``` #[derive(Default)] pub struct Measure { - pub __: PhantomData, + __: PhantomData, pub x: Arc, pub y: Arc, } @@ -133,8 +130,8 @@ pub enum Expand { X(U, A), Y(U, A), XY(U, U, A), } /// /// ``` /// use ::tengri::{output::*, tui::*}; -/// let area = XYWH(10u16, 10, 20, 20); -/// fn test (area: XYWH<16>, item: &impl Draw, expected: [u16;4]) { +/// let area: [u16;4] = [10, 10, 20, 20]; +/// fn test (area: [u16;4], item: &impl Draw, expected: [u16;4]) { /// assert_eq!(Content::layout(item, area), expected); /// assert_eq!(Draw::layout(item, area), expected); /// }; @@ -169,7 +166,7 @@ pub enum Pad { X(U, A), Y(U, A), XY(U, U, A), } /// ``` /// let bounded = Bounded(XYWH(0, 0, 0, 0), ""); /// ``` -pub struct Bounded(pub XYWH, pub D); +pub struct Bounded(pub O::Area, pub D); /// Draws items from an iterator. /// diff --git a/output/src/out_traits.rs b/output/src/out_traits.rs index 127d1ae..10196cb 100644 --- a/output/src/out_traits.rs +++ b/output/src/out_traits.rs @@ -15,7 +15,7 @@ use crate::*; /// fn area_mut (&mut self) -> &mut [u16;4] { /// &mut self.0 /// } -/// fn place_at + ?Sized> (&mut self, area: XYWH, _: &T) { +/// fn place_at + ?Sized> (&mut self, area: [u16;4], _: &T) { /// println!("place_at: {area:?}"); /// () /// } @@ -29,44 +29,24 @@ use crate::*; pub trait Out: Send + Sync + Sized { /// Unit of length type Unit: Coord; + /// Rectangle without offset + type Size: HasWH; + /// Rectangle with offset + type Area: HasXYWH; /// Current output area - fn area (&self) -> XYWH; + fn area (&self) -> Self::Area; /// Mutable pointer to area. - fn area_mut (&mut self) -> &mut XYWH; + fn area_mut (&mut self) -> &mut Self::Area; /// Render drawable in area specified by `area` - fn place_at <'t, T: Draw + ?Sized> (&mut self, area: XYWH, content: &'t T); + fn place_at <'t, T: Draw + ?Sized> (&mut self, area: Self::Area, 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) { + #[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); @@ -99,17 +79,15 @@ 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)) - } + fn x (&self, to: O::Area) -> O::Unit { to.x() } + fn y (&self, to: O::Area) -> O::Unit { to.y() } + fn w_min (&self, _t: O::Area) -> O::Unit { 0.into() } + fn w_max (&self, to: O::Area) -> O::Unit { to.w() } + fn w (&self, to: O::Area) -> O::Unit { to.w().max(self.w_min(to)).min(self.w_max(to)) } + fn h_min (&self, _t: O::Area) -> O::Unit { 0.into() } + fn h_max (&self, to: O::Area) -> O::Unit { to.h() } + fn h (&self, to: O::Area) -> O::Unit { to.h().max(self.h_min(to)).min(self.h_max(to)) } + fn layout (&self, to: O::Area) -> O::Area { [self.x(to), self.y(to), self.w(to), self.h(to)].into() } } pub trait HasContent { @@ -119,6 +97,25 @@ pub trait HasContent { // TODO DOCUMENTME pub trait Content: Draw + Layout {} +/// 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 zero () -> Self { 0.into() } + fn plus (self, other: Self) -> Self; + fn minus (self, other: Self) -> Self { if self >= other { self - other } else { 0.into() } } +} + // Something that has an origin point (X, Y). pub trait HasXY { fn x (&self) -> N; @@ -134,8 +131,6 @@ pub trait HasWH { } // 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()) } @@ -149,9 +144,9 @@ pub trait HasXYWH: HasXY + HasWH { } } -// 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() } +// TODO DOCUMENTME +pub trait HasSize { + fn size (&self) -> &Measure; + fn width (&self) -> O::Unit { self.size().w() } + fn height (&self) -> O::Unit { self.size().h() } } diff --git a/tui/src/lib.rs b/tui/src/lib.rs index 976d230..d9e16c6 100644 --- a/tui/src/lib.rs +++ b/tui/src/lib.rs @@ -1,9 +1,4 @@ #![feature(type_changing_struct_update, trait_alias)] - -use std::{time::Duration, thread::{spawn, JoinHandle}}; - -use unicode_width::*; - pub use ::{ dizzle, tengri_input, @@ -13,7 +8,6 @@ pub use ::{ palette, better_panic, }; - pub(crate) use ::{ dizzle::*, tengri_input::*, @@ -32,10 +26,11 @@ pub(crate) use ::{ crossterm::{ ExecutableCommand, terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode}, - event::{poll, read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}, + event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}, } }; - +mod tui_engine; pub use self::tui_engine::*; +mod tui_content; pub use self::tui_content::*; #[macro_export] macro_rules! tui_main { ($expr:expr) => { fn main () -> Usually<()> { @@ -46,256 +41,6 @@ pub(crate) use ::{ }; } -#[macro_export] macro_rules! has_color { - (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { - impl $(<$($L),*$($T $(: $U)?),*>)? HasColor for $Struct $(<$($L),*$($T),*>)? { - fn color (&$self) -> ItemColor { $cb } - } - } -} - -macro_rules! border { - ($($T:ident { - $nw:literal $n:literal $ne:literal $w:literal $e:literal $sw:literal $s:literal $se:literal - $($x:tt)* - }),+) => {$( - impl BorderStyle for $T { - const NW: &'static str = $nw; - const N: &'static str = $n; - const NE: &'static str = $ne; - const W: &'static str = $w; - const E: &'static str = $e; - const SW: &'static str = $sw; - const S: &'static str = $s; - const SE: &'static str = $se; - $($x)* - fn enabled (&self) -> bool { self.0 } - } - #[derive(Copy, Clone)] pub struct $T(pub bool, pub Style); - impl Layout for $T {} - impl Draw for $T { - fn draw (&self, to: &mut TuiOut) { - if self.enabled() { let _ = BorderStyle::draw(self, to); } - } - } - )+} -} - -mod tui_structs; pub use self::tui_structs::*; -mod tui_traits; pub use self::tui_traits::*; -mod tui_impls; pub use self::tui_impls::*; - -#[cfg(feature = "dsl")] -pub fn evaluate_output_expression_tui <'a, S> ( - state: &S, output: &mut TuiOut, expr: impl Expression + 'a -) -> Usually where - S: View - + for<'b>Namespace<'b, bool> - + for<'b>Namespace<'b, u16> - + for<'b>Namespace<'b, Color> -{ - // See `tengri_output::evaluate_output_expression` - let head = expr.head()?; - let mut frags = head.src()?.unwrap_or_default().split("/"); - let args = expr.tail(); - let arg0 = args.head(); - let tail0 = args.tail(); - let arg1 = tail0.head(); - let tail1 = tail0.tail(); - let _arg2 = tail1.head(); - match frags.next() { - - Some("text") => if let Some(src) = args?.src()? { output.place(&src) }, - - Some("fg") => { - let arg0 = arg0?.expect("fg: expected arg 0 (color)"); - output.place(&Tui::fg( - Namespace::::resolve(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color")), - Thunk::new(move|output: &mut TuiOut|state.view(output, &arg1).unwrap()), - )) - }, - - Some("bg") => { - let arg0 = arg0?.expect("bg: expected arg 0 (color)"); - output.place(&Tui::bg( - Namespace::::resolve(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color")), - Thunk::new(move|output: &mut TuiOut|state.view(output, &arg1).unwrap()), - )) - }, - - _ => return Ok(false) - - }; - Ok(true) -} - -pub fn named_key (token: &str) -> Option { - use KeyCode::*; - Some(match token { - "up" => Up, - "down" => Down, - "left" => Left, - "right" => Right, - "esc" | "escape" => Esc, - "enter" | "return" => Enter, - "delete" | "del" => Delete, - "backspace" => Backspace, - "tab" => Tab, - "space" => Char(' '), - "comma" => Char(','), - "period" => Char('.'), - "plus" => Char('+'), - "minus" | "dash" => Char('-'), - "equal" | "equals" => Char('='), - "underscore" => Char('_'), - "backtick" => Char('`'), - "lt" => Char('<'), - "gt" => Char('>'), - "cbopen" | "openbrace" => Char('{'), - "cbclose" | "closebrace" => Char('}'), - "bropen" | "openbracket" => Char('['), - "brclose" | "closebracket" => Char(']'), - "pgup" | "pageup" => PageUp, - "pgdn" | "pagedown" => PageDown, - "f1" => F(1), - "f2" => F(2), - "f3" => F(3), - "f4" => F(4), - "f5" => F(5), - "f6" => F(6), - "f7" => F(7), - "f8" => F(8), - "f9" => F(9), - "f10" => F(10), - "f11" => F(11), - "f12" => F(12), - _ => return None, - }) -} - -pub fn button_2 <'a> (key: impl Content, label: impl Content, editing: bool) -> impl Content { - Tui::bold(true, Bsp::e( - Tui::fg_bg(Tui::orange(), Tui::g(0), Bsp::e(Tui::fg(Tui::g(0), &"▐"), Bsp::e(key, Tui::fg(Tui::g(96), &"▐")))), - When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label)))) -} - -pub fn button_3 <'a> ( - key: impl Content, label: impl Content, value: impl Content, editing: bool, -) -> impl Content { - Tui::bold(true, Bsp::e( - Tui::fg_bg(Tui::orange(), Tui::g(0), - Bsp::e(Tui::fg(Tui::g(0), &"▐"), Bsp::e(key, Tui::fg(if editing { Tui::g(128) } else { Tui::g(96) }, "▐")))), - Bsp::e( - When::new(!editing, Bsp::e(Tui::fg_bg(Tui::g(255), Tui::g(96), label), Tui::fg_bg(Tui::g(128), Tui::g(96), &"▐"),)), - Bsp::e(Tui::fg_bg(Tui::g(224), Tui::g(128), value), Tui::fg_bg(Tui::g(128), Reset, &"▌"), )))) -} - -border! { - Square { - "┌" "─" "┐" - "│" "│" - "└" "─" "┘" fn style (&self) -> Option