use crate::*; impl Coord for u16 { fn plus (self, other: Self) -> Self { self.saturating_add(other) } } impl HasXY for XY { fn x (&self) -> N { self.0 } fn y (&self) -> N { self.1 } } impl HasWH for WH { fn w (&self) -> N { self.0 } fn h (&self) -> N { self.1 } } impl WH { fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] } fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] } fn to_area_pos (&self) -> [N;4] { let [x, y] = self.wh(); [x, y, 0.into(), 0.into()] } fn to_area_size (&self) -> [N;4] { let [w, h] = self.wh(); [0.into(), 0.into(), w, h] } fn expect_min (&self, w: N, h: N) -> Usually<&Self> { if self.w() < w || self.h() < h { return Err(format!("min {w}x{h}").into()) } Ok(self) } } impl XYWH { fn from_position (pos: impl Size) -> Self { let [x, y] = pos.wh(); [x, y, 0.into(), 0.into()] } fn from_size (size: impl Size) -> Self { let [w, h] = size.wh(); [0.into(), 0.into(), w, h] } fn lrtb (&self) -> [N;4] { [self.x(), self.x2(), self.y(), self.y2()] } fn center (&self) -> XY { [self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())] } fn centered (&self) -> XY { [self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())] } fn centered_x (&self, n: N) -> XYWH { let [x, y, w, h] = self.xywh(); [(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 [x, y, w, h] = self.xywh(); [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 [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] } fn iter_x (&self) -> impl Iterator where N: std::iter::Step { self.x()..(self.x()+self.w()) } fn iter_y (&self) -> impl Iterator where N: std::iter::Step { self.y()..(self.y()+self.h()) } fn clipped (&self, wh: impl Size) -> XYWH { [self.x(), self.y(), wh.w(), wh.h()] } fn clipped_h (&self, h: N) -> XYWH { [self.x(), self.y(), self.w(), self.h().min(h)] } fn clipped_w (&self, w: N) -> XYWH { [self.x(), self.y(), self.w().min(w), self.h()] } fn with_w (&self, w: N) -> XYWH { [self.x(), self.y(), w, self.h()] } fn with_h (&self, h: N) -> XYWH { [self.x(), self.y(), self.w(), h] } } impl HasXY for XYWH { fn x (&self) -> N { self.0 } fn y (&self) -> N { self.1 } } impl HasWH for XYWH { fn w (&self) -> N { self.2 } fn h (&self) -> N { self.3 } } impl super::ng::HasXY for O { // X coordinate of output area #[inline] fn x (&self) -> O::Unit { self.area().x() } // Y coordinate of output area #[inline] fn y (&self) -> O::Unit { self.area().y() } } impl super::ng::HasWH for O { // Width of output area #[inline] fn w (&self) -> O::Unit { self.area().w() } // Height of output area #[inline] fn h (&self) -> O::Unit { self.area().h() } } impl + Layout> Content for T {} impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a { fn as_ref (&self) -> &(dyn Draw + 'a) { self } } impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a { fn as_ref (&self) -> &(dyn Layout + 'a) { self } } pub trait HasContent { fn content (&self) -> impl Content; } impl Draw for () { fn draw (&self, _: &mut O) {} } impl Draw for fn(&mut O) { fn draw (&self, to: &mut O) { (*self)(to) } } impl Draw for Box> { fn draw (&self, to: &mut O) { (**self).draw(to) } } impl> Draw for &D { fn draw (&self, to: &mut O) { (*self).draw(to) } } impl> Draw for &mut D { fn draw (&self, to: &mut O) { (**self).draw(to) } } impl> Draw for Arc { fn draw (&self, to: &mut O) { (**self).draw(to) } } impl> Draw for RwLock { fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) } } impl> Draw for Option { fn draw (&self, to: &mut O) { if let Some(draw) = self { draw.draw(to) } } } //impl> Draw for T { //fn draw (&self, to: &mut O) { //let area = to.area(); //*to.area_mut() = self.0; //self.content().draw(to); //*to.area_mut() = area; //} //} impl, F: Fn()->T> Lazy { pub const fn new (thunk: F) -> Self { Self(thunk, PhantomData) } } impl Thunk { pub const fn new (draw: F) -> Self { Self(PhantomData, draw) } } impl Layout for Thunk {} impl Draw for Thunk { fn draw (&self, to: &mut O) { (self.1)(to) } } impl Memo { pub fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } } pub fn update (&mut self, newval: T, draw: impl Fn(&mut U, &T, &T)->R) -> Option { if newval != self.value { let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value); self.value = newval; return Some(result); } None } } impl Direction { pub fn split_fixed (self, area: impl Area, a: N) -> ([N;4],[N;4]) { let [x, y, w, h] = area.xywh(); match self { 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 Size for (N, N) { fn x (&self) -> N { self.0 } fn y (&self) -> N { self.1 } } impl Size for [N;2] { fn x (&self) -> N { self[0] } fn y (&self) -> N { self[1] } } impl>> HasSize for T { fn size (&self) -> &Measure { self.get() } } impl Clone for Measure { fn clone (&self) -> Self { Self { __: Default::default(), x: self.x.clone(), y: self.y.clone(), } } } impl Layout for Measure {} impl PartialEq for Measure { fn eq (&self, other: &Self) -> bool { self.x.load(Relaxed) == other.x.load(Relaxed) && self.y.load(Relaxed) == other.y.load(Relaxed) } } // TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small impl Draw for Measure { fn draw (&self, to: &mut O) { self.x.store(to.area().w().into(), Relaxed); self.y.store(to.area().h().into(), Relaxed); } } impl Debug for Measure { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("Measure").field("width", &self.x).field("height", &self.y).finish() } } impl Measure { pub fn set_w (&self, w: impl Into) -> &Self { self.x.store(w.into(), Relaxed); self } pub fn set_h (&self, h: impl Into) -> &Self { self.y.store(h.into(), Relaxed); self } pub fn set_wh (&self, w: impl Into, h: impl Into) -> &Self { self.set_w(w); self.set_h(h); self } 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.into()), y: Arc::new(y.into()), } } } impl From<[O::Unit; 2]> for Measure { fn from ([x, y]: [O::Unit; 2]) -> Self { Self::new(x, y) } } impl Layout for () { 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 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 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 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 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 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 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 { fn content (&self) -> impl Content { &self.1 } } impl> Draw for Bounded { fn draw (&self, to: &mut O) { let area = to.area(); *to.area_mut() = self.0; self.1.draw(to); *to.area_mut() = area; } } impl> When { /// Create a binary condition. pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) } } impl> Layout for When { fn layout (&self, to: O::Area) -> O::Area { let Self(cond, item, ..) = self; if *cond { item.layout(to) } else { O::Area::zero().into() } } } impl> Draw for When { fn draw (&self, to: &mut O) { let Self(cond, item, ..) = self; if *cond { Bounded(self.layout(to.area()), item).draw(to) } } } impl, B: Content> Either { /// Create a ternary view condition. pub const fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b, PhantomData) } } impl, B: Layout> Layout for Either { fn layout (&self, to: E::Area) -> E::Area { let Self(cond, a, b, ..) = self; if *cond { a.layout(to) } else { b.layout(to) } } } impl, B: Content> Draw for Either { fn draw (&self, to: &mut E) { let Self(cond, a, b, ..) = self; let area = self.layout(to.area()); if *cond { Bounded(area, a).draw(to) } else { Bounded(area, b).draw(to) } } } push_pull!(Push: plus); push_pull!(Pull: minus); 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(_)) } } 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)) } } 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: 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 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()) } } // 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() } } impl Align { #[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) } #[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) } #[inline] pub const fn y (a: T) -> Self { Self(Alignment::Y, a) } #[inline] pub const fn n (a: T) -> Self { Self(Alignment::N, a) } #[inline] pub const fn s (a: T) -> Self { Self(Alignment::S, a) } #[inline] pub const fn e (a: T) -> Self { Self(Alignment::E, a) } #[inline] pub const fn w (a: T) -> Self { Self(Alignment::W, a) } #[inline] pub const fn nw (a: T) -> Self { Self(Alignment::NW, a) } #[inline] pub const fn sw (a: T) -> Self { Self(Alignment::SW, a) } #[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) } #[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) } } impl> Draw for Align { fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), &self.1).draw(to) } } impl> Layout for Align { 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.w(to) / 2.into()), NE | E | SE => to.x().plus(to.w()).minus(self.1.w(to)), _ => todo!(), } } 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.h(to) / 2.into()), SW | S | SE => to.y().plus(to.h()).minus(self.1.h(to)), _ => todo!(), } } } impl Pad { #[inline] pub const fn inner (&self) -> &A { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } } } impl Pad { #[inline] pub fn dx (&self) -> U { match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } } #[inline] pub fn dy (&self) -> U { 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 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) } #[inline] pub const fn e (a: Head, b: Tail) -> Self { Self(East, a, b) } #[inline] pub const fn w (a: Head, b: Tail) -> Self { Self(West, a, b) } #[inline] pub const fn a (a: Head, b: Tail) -> Self { Self(Above, a, b) } #[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) } } impl, Tail: Content> Draw for Bsp { fn draw (&self, to: &mut O) { match self.0 { South => { //panic!("{}", self.1.h(to.area())); let area_1 = self.1.layout(to.area()); 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); }, _ => todo!("{:?}", self.0) } //let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2); //panic!("{a:?} {b:?}"); //if self.0 == Below { //to.place_at(a, &self.1); //to.place_at(b, &self.2); //} else { //to.place_at(b, &self.2); //to.place_at(a, &self.1); //} } } impl, Tail: Layout> Layout for Bsp { 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 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 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 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 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 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: O::Area) -> O::Area { bsp_areas(area, self.0, &self.1, &self.2)[2] } } 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 [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 [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 [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 [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 [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()] }, } } impl<'a, O, A, B, I, F, G> Map where I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, { pub const fn new (get_iter: F, get_item: G) -> Self { Self { __: PhantomData, get_iter, get_item } } } impl_map_direction!(east, X, w); impl_map_direction!(south, Y, n); impl_map_direction!(west, X, e); impl_map_direction!(north, Y, s); impl<'a, O, A, B, I, F, G> Layout for Map where O: Out, B: Layout, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync { fn layout (&self, area: O::Area) -> O::Area { let Self { get_iter, get_item, .. } = self; let mut index = 0; let [mut min_x, mut min_y] = area.center(); let [mut max_x, mut max_y] = area.center(); for item in get_iter() { 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); max_y = max_y.max(y + h); index += 1; } let w = max_x - min_x; let h = max_y - min_y; //[min_x.into(), min_y.into(), w.into(), h.into()].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, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync { fn draw (&self, to: &mut O) { let Self { get_iter, get_item, .. } = self; let mut index = 0; let area = self.layout(to.area()); for item in get_iter() { let item = get_item(item, index); //to.place_at(area.into(), &item); to.place_at(item.layout(area), &item); index += 1; } } } #[inline] pub fn map_south( item_offset: O::Unit, item_height: O::Unit, item: impl Content ) -> impl Content { Push::Y(item_offset, Fixed::Y(item_height, Fill::X(item))) } #[inline] pub fn map_south_west( item_offset: O::Unit, item_height: O::Unit, item: impl Content ) -> impl Content { Push::Y(item_offset, Align::nw(Fixed::Y(item_height, Fill::X(item)))) } #[inline] pub fn map_east( item_offset: O::Unit, item_width: O::Unit, item: impl Content ) -> impl Content { Push::X(item_offset, Align::w(Fixed::X(item_width, Fill::Y(item)))) } impl Tryptich<(), (), ()> { pub fn center (h: u16) -> Self { Self { h, top: false, left: (0, ()), middle: (0, ()), right: (0, ()) } } pub fn top (h: u16) -> Self { Self { h, top: true, left: (0, ()), middle: (0, ()), right: (0, ()) } } } impl Tryptich { pub fn left (self, w: u16, content: D) -> Tryptich { Tryptich { left: (w, content), ..self } } pub fn middle (self, w: u16, content: D) -> Tryptich { Tryptich { middle: (w, content), ..self } } pub fn right (self, w: u16, content: D) -> Tryptich { Tryptich { right: (w, content), ..self } } } impl> Layout for Foreground { fn layout (&self, to: O::Area) -> O::Area { self.1.layout(to) } } impl> Layout for Background { fn layout (&self, to: O::Area) -> O::Area { self.1.layout(to) } } impl, V: Content> HasContent for FieldH { fn content (&self) -> impl Content { Bsp::e(&self.1, &self.2) } } impl, V: Content> Layout for FieldH { fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) } } impl, V: Content> Draw for FieldH { fn draw (&self, to: &mut O) { self.content().draw(to) } } impl, V: Content> HasContent for FieldV { fn content (&self) -> impl Content { Bsp::s(&self.1, &self.2) } } impl, V: Content> Layout for FieldV { 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: O::Area) -> O::Area { self.1.layout(area) } } impl Field { pub fn new (direction: Direction) -> Field { Field:: { direction, label: None, label_fg: None, label_bg: None, label_align: None, value: None, value_fg: None, value_bg: None, value_align: None, } } pub fn label ( self, label: Option, align: Option, fg: Option, bg: Option ) -> Field { Field:: { label, label_fg: fg, label_bg: bg, label_align: align, ..self } } pub fn value ( self, value: Option, align: Option, fg: Option, bg: Option ) -> Field { Field:: { value, value_fg: fg, value_bg: bg, value_align: align, ..self } } }