use crate::*; pub enum Full<'a, S: Screen, I: Draw> { __(PhantomData<&'a S>), W(I), H(I), WH(I), } pub enum Exact<'a, S: Screen, I: Draw, X: Into>> { __(PhantomData<&'a S>), W(I, X), H(I, X), WH(I, X, X), } pub enum Push<'a, S: Screen, I: Draw, X: Into>> { __(PhantomData<&'a S>), X(I, X), Y(I, X), XY(I, X, X), } pub enum Pull<'a, S: Screen, I: Draw, X: Into>> { __(PhantomData<&'a S>), X(I, X), Y(I, X), XY(I, X, X), } pub enum Min<'a, S: Screen, I: Draw, X: Into>> { __(PhantomData<&'a S>), W(I, X), H(I, X), WH(I, X, X), } pub enum Max<'a, S: Screen, I: Draw, X: Into>> { __(PhantomData<&'a S>), W(I, X), H(I, X), WH(I, X, X), } pub enum Pad<'a, S: Screen, I: Draw, X: Into>> { __(PhantomData<&'a S>), X(I, X), Y(I, X), XY(I, X, X), } /// ``` /// # use ::tengri::*; fn test_layout_full () -> Usually<()> { /// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1))); /// assert_eq!(check_layout("1".full_w())?, Some(XYWH(1u16, 1, 80, 1))); /// assert_eq!(check_layout("1".full_h())?, Some(XYWH(1u16, 1, 1, 25))); /// assert_eq!(check_layout("1".full_wh())?, Some(XYWH(1u16, 1, 80, 25))); /// # Ok(()) } /// ``` pub trait LayoutFull<'a, S: Screen>: Draw + Sized { fn full_w (self) -> Full<'a, S, Self> { Full::W(self) } fn full_h (self) -> Full<'a, S, Self> { Full::H(self) } fn full_wh (self) -> Full<'a, S, Self> { Full::WH(self) } } /// ``` /// # use ::tengri::*; fn test_layout_exact () -> Usually<()> { /// assert_eq!(check_layout("FOOBAR\nKILROY")?, Some(XYWH(1, 1, 6, 2))); /// assert_eq!(check_layout("FOOBAR\nKILROY".exact_w(3))?, Some(XYWH(1, 1, 3, 2))); /// assert_eq!(check_layout("FOOBAR\nKILROY".exact_h(1))?, Some(XYWH(1, 1, 6, 1))); /// assert_eq!(check_layout("FOOBAR\nKILROY".exact_wh(2, 1))?, Some(XYWH(1, 1, 2, 1))); /// # Ok(()) } /// ``` pub trait LayoutExact<'a, S: Screen>: Draw + Sized { fn exact_w > + Copy> (self, w: X) -> Exact<'a, S, Self, X> { Exact::W(self, w) } fn exact_h > + Copy> (self, h: X) -> Exact<'a, S, Self, X> { Exact::H(self, h) } fn exact_wh > + Copy> (self, w: X, h: X) -> Exact<'a, S, Self, X> { Exact::WH(self, w, h) } } /// ``` /// # use ::tengri::*; fn test_layout_min () -> Usually<()> { /// assert_eq!(check_layout("1".min_w(5))?, Some(XYWH(1u16, 1, 5, 1))); /// assert_eq!(check_layout("1".min_h(5))?, Some(XYWH(1u16, 1, 1, 5))); /// assert_eq!(check_layout("1".min_wh(5, 5))?, Some(XYWH(1u16, 1, 5, 5))); /// assert_eq!(check_layout("123456".min_w(5))?, Some(XYWH(1u16, 1, 6, 1))); /// # Ok(()) } /// ``` pub trait LayoutMin<'a, S: Screen>: Draw + Sized { fn min_w > + Copy> (self, w: X) -> Min<'a, S, Self, X> { Min::W(self, w) } fn min_h > + Copy> (self, h: X) -> Min<'a, S, Self, X> { Min::H(self, h) } fn min_wh > + Copy> (self, w: X, h: X) -> Min<'a, S, Self, X> { Min::WH(self, w, h) } } pub trait LayoutMax<'a, S: Screen>: Draw + Sized { fn max_w > + Copy> (self, w: X) -> Max<'a, S, Self, X> { Max::W(self, w) } fn max_h > + Copy> (self, h: X) -> Max<'a, S, Self, X> { Max::H(self, h) } fn max_wh > + Copy> (self, w: X, h: X) -> Max<'a, S, Self, X> { Max::WH(self, w, h) } } pub trait LayoutPad<'a, S: Screen>: Draw + Sized { fn pad_w > + Copy> (self, w: X) -> Pad<'a, S, Self, X> { Pad::X(self, w) } fn pad_h > + Copy> (self, h: X) -> Pad<'a, S, Self, X> { Pad::Y(self, h) } fn pad_wh > + Copy> (self, w: X, h: X) -> Pad<'a, S, Self, X> { Pad::XY(self, w, h) } } /// ``` /// # use ::tengri::*; fn test_layout_pull () -> Usually<()> { /// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1))); /// assert_eq!(check_layout("1".push_x(1))?, Some(XYWH(2u16, 1, 1, 1))); /// assert_eq!(check_layout("1".push_y(1))?, Some(XYWH(1u16, 2, 1, 1))); /// assert_eq!(check_layout("1".push_xy(1, 1))?, Some(XYWH(2u16, 2, 1, 1))); /// # Ok(()) } /// ``` pub trait LayoutPush<'a, S: Screen>: Draw + Sized { fn push_x > + Copy> (self, w: X) -> Push<'a, S, Self, X> { Push::X(self, w) } fn push_y > + Copy> (self, h: X) -> Push<'a, S, Self, X> { Push::Y(self, h) } fn push_xy > + Copy> (self, w: X, h: X) -> Push<'a, S, Self, X> { Push::XY(self, w, h) } } /// ``` /// # use ::tengri::*; fn test_layout_push () -> Usually<()> { /// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1))); /// assert_eq!(check_layout("1".pull_x(1))?, Some(XYWH(0u16, 1, 1, 1))); /// assert_eq!(check_layout("1".pull_y(1))?, Some(XYWH(1u16, 0, 1, 1))); /// assert_eq!(check_layout("1".pull_xy(1, 1))?, Some(XYWH(0u16, 0, 1, 1))); /// # Ok(()) } /// ``` pub trait LayoutPull<'a, S: Screen>: Draw + Sized { fn pull_x > + Copy> (self, w: X) -> Pull<'a, S, Self, X> { Pull::X(self, w) } fn pull_y > + Copy> (self, h: X) -> Pull<'a, S, Self, X> { Pull::Y(self, h) } fn pull_xy > + Copy> (self, w: X, h: X) -> Pull<'a, S, Self, X> { Pull::XY(self, w, h) } } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_full (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.nth(1)?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("full/x") | Some("full/w") => Full::W(thunk).draw(to)?, Some("full/y") | Some("full/h") => Full::H(thunk).draw(to)?, Some("full/xy") | Some("full/wh") => Full::WH(thunk).draw(to)?, frag => return Err(format!("full: invalid variant: {frag:?}").into()) }) } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_exact (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("exact/w") => thunk.exact_w( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("exact/h") => thunk.exact_h( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("exact/wh") => thunk.exact_wh( state.namespace(&expr.nth(1)?)?, state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("exact: invalid variant: {:?}", expr.head()?).into()) }) } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_min (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("min/w") => thunk.min_w( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("min/h") => thunk.min_h( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("min/wh") => thunk.min_wh( state.namespace(&expr.nth(1)?)?, state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("min: invalid variant: {:?}", expr.head()?).into()) }) } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_max (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("max/w") => thunk.max_w( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("max/h") => thunk.max_h( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("max/wh") => thunk.max_wh( state.namespace(&expr.nth(1)?)?, state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("max: invalid variant: {:?}", expr.head()?).into()) }) } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_push (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("push/w") => thunk.push_x(state.namespace(&expr.nth(1)?)?).draw(to)?, Some("push/h") => thunk.push_y(state.namespace(&expr.nth(1)?)?).draw(to)?, Some("push/wh") => thunk.push_xy( state.namespace(&expr.nth(1)?)?, state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("push: invalid variant: {:?}", expr.head()?).into()) }) } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_pull (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("pull/w") => thunk.pull_x(state.namespace(&expr.nth(1)?)?).draw(to)?, Some("pull/h") => thunk.pull_y(state.namespace(&expr.nth(1)?)?).draw(to)?, Some("pull/wh") => thunk.pull_xy( state.namespace(&expr.nth(1)?)?, state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("pull: invalid variant: {:?}", expr.head()?).into()) }) } #[cfg(all(feature = "draw", feature = "eval"))] pub fn kw_pad (state: &S, to: &mut O, expr: &str) -> Perhaps> where O: Screen, S: Interpret>> + Namespace + Namespace + Namespace> { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x|state.interpret(screen, x)))); Ok(match expr.head()? { Some("pad/w") => thunk.pad_w( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("pad/h") => thunk.pad_h( state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("pad/wh") => thunk.pad_wh( state.namespace(&expr.nth(1)?)?, state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("pad: invalid variant: {:?}", expr.head()?).into()) }) } impl <'a, S: Screen, I: Draw> Draw for Full<'a, S, I> { fn draw (&self, to: &mut S) -> Drawn { let XYWH(x0, y0, w0, h0) = to.area(); let item = match self { Self::W(i) => i, Self::H(i) => i, Self::WH(i) => i, _ => unreachable!() }; let (x1, y1, w1, h1) = match self { Self::W(..) => (Some(x0), None, Some(w0), None), Self::H(..) => (None, Some(y0), None, Some(h0)), Self::WH(..) => (Some(x0), Some(y0), Some(w0), Some(h0)), _ => unreachable!() }; Ok(to.draw(to.area(), item)?.map(|XYWH(x2, y2, w2, h2)|XYWH( x1.unwrap_or(x2), y1.unwrap_or(y2), w1.unwrap_or(w2), h1.unwrap_or(h2), ))) } } impl <'a, S: Screen, I: Draw, X: Into> + Copy> Draw for Exact<'a, S, I, X> { fn draw (&self, to: &mut S) -> Drawn { let XYWH(x0, y0, w0, h0) = to.area(); let (item, w1, h1) = match self { Self::W(item, w1) => (item, (*w1).into(), None), Self::H(item, h1) => (item, None, (*h1).into()), Self::WH(item, w1, h1) => (item, (*w1).into(), (*h1).into()), _ => unreachable!() }; let w1 = w1.unwrap_or(w0); let h1 = h1.unwrap_or(h0); let area = XYWH(x0, y0, w1, h1); let area = to.draw(area, item)?; Ok(area.map(|XYWH(x2, y2, w2, h2)|match self { Self::W(..) => XYWH(x0, y2, w1, h2), Self::H(..) => XYWH(x2, y0, w2, h1), Self::WH(..) => XYWH(x0, y0, w1, h1), _ => unreachable!() })) } } impl <'a, S: Screen, I: Draw, X: Into> + Copy> Draw for Min<'a, S, I, X> { fn draw (&self, to: &mut S) -> Drawn { let XYWH(x0, y0, w0, h0) = to.area(); let (item, w1, h1) = match self { Self::W(item, w1) => (item, (*w1).into(), None), Self::H(item, h1) => (item, None, (*h1).into()), Self::WH(item, w1, h1) => (item, (*w1).into(), (*h1).into()), _ => return Ok(None) }; Ok(to.draw(XYWH( x0, y0, w1.map(|w1|w1.max(w0)).unwrap_or(w0), h1.map(|h1|h1.max(h0)).unwrap_or(h0) ), item)?.map(|XYWH(x2, y2, w2, h2)|XYWH( x2, y2, w1.map(|w1|w1.max(w2)).unwrap_or(w2), h1.map(|h1|h1.max(h2)).unwrap_or(h2) ))) } } impl <'a, S: Screen, I: Draw, X: Into> + Copy> Draw for Max<'a, S, I, X> { fn draw (&self, to: &mut S) -> Drawn { let XYWH(x, y, w0, h0) = to.area(); let (item, w, h) = match self { Self::W(item, w) => (item, (*w).into().unwrap_or(w0), h0), Self::H(item, h) => (item, w0, (*h).into().unwrap_or(h0)), Self::WH(item, w, h) => (item, (*w).into().unwrap_or(h0), (*h).into().unwrap_or(h0)), _ => return Ok(None) }; to.draw(XYWH(x, y, if w0 > w { w } else { w0 }, if h0 > h { h } else { h0 }), item) } } impl <'a, S: Screen, I: Draw, X: Into> + Copy> Draw for Push<'a, S, I, X> { fn draw (&self, to: &mut S) -> Drawn { match self { Self::__(_) => unreachable!(), Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => { to.draw(XYWH(x + (*x1).into().unwrap_or_default(), y, w, h), item) }, Self::Y(item, y1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => { to.draw(XYWH(x, y + (*y1).into().unwrap_or_default(), w, h), item) }, Self::XY(item, x1, y1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => { to.draw(XYWH(x + (*x1).into().unwrap_or_default(), y + (*y1).into().unwrap_or_default(), w, h), item) }, _ => Ok(None) } } } impl <'a, S: Screen, I: Draw, X: Into> + Copy> Draw for Pull<'a, S, I, X> { fn draw (&self, to: &mut S) -> Drawn { match self { Self::__(_) => unreachable!(), Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => { to.draw(XYWH(x.minus((*x1).into().unwrap_or_default()), y, w, h), item) }, Self::Y(item, y1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => { to.draw(XYWH(x, y.minus((*y1).into().unwrap_or_default()), w, h), item) }, Self::XY(item, x1, y1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => { to.draw(XYWH(x.minus((*x1).into().unwrap_or_default()), y.minus((*y1).into().unwrap_or_default()), w, h), item) }, _ => Ok(None) } } } impl <'a, S: Screen, I: Draw, X: Into> + Copy> Draw for Pad<'a, S, I, X> { fn draw (&self, to: &mut S) -> Drawn { let XYWH(x, y, w0, h0) = to.area(); let (item, w, h) = match self { Self::X(item, w) => (item, (*w).into().unwrap_or_default(), Default::default()), Self::Y(item, h) => (item, Default::default(), (*h).into().unwrap_or_default()), Self::XY(item, w, h) => (item, (*w).into().unwrap_or_default(), (*h).into().unwrap_or_default()), _ => return Ok(None) }; to.draw(XYWH( x.plus(w), y.plus(h), w0.minus(w).minus(w), h0.minus(h).minus(h), ), item) } } impl<'a, S: Screen, T: Draw> LayoutFull<'a, S> for T {} impl<'a, S: Screen, T: Draw> LayoutExact<'a, S> for T {} impl<'a, S: Screen, T: Draw> LayoutMin<'a, S> for T {} impl<'a, S: Screen, T: Draw> LayoutMax<'a, S> for T {} impl<'a, S: Screen, T: Draw> LayoutPush<'a, S> for T {} impl<'a, S: Screen, T: Draw> LayoutPull<'a, S> for T {} impl<'a, S: Screen, T: Draw> LayoutPad<'a, S> for T {} pub fn check_layout <'a> (t: impl Draw) -> Drawn { Tui::Layout(XYWH(1u16, 1, 80, 25)).size(None, t) }