use crate::*; // TODO: Convert to component // pub enum Align { Center, NW, N, NE, E, SE, S, SW, W, } pub fn center_box (area: Rect, w: u16, h: u16) -> Rect { let width = w.min(area.width * 3 / 5); let height = h.min(area.width * 3 / 5); let x = area.x + (area.width - width) / 2; let y = area.y + (area.height - height) / 2; Rect { x, y, width, height } } /// Trait for structs that compute drawing area before rendering pub trait Layout: Render { fn layout (&self, area: E::Area) -> Perhaps; } /// Enforce minimum size of drawing area pub enum Min { W(U, L), H(U, L), WH(U, U, L), } /// Enforce maximum size of drawing area pub enum Max { W(U, L), H(U, L), WH(U, U, L), } /// Expand drawing area pub enum Outset { W(U, L), H(U, L), WH(U, U, L), } /// Shrink drawing area pub enum Inset { W(U, L), H(U, L), WH(U, U, L), } /// Move origin point of drawing area pub enum Offset { X(U, L), Y(U, L), XY(U, U, L), } impl> Layout for Min { fn layout (&self, area: E::Area) -> Perhaps { match self { Self::W(w, item) => if area.w() < *w { Ok(None) } else { // TODO: axis clamp (subtract from x if width goes out of area item.layout([area.x(), area.y(), area.w().max(*w), area.h()].into()) }, Self::H(h, item) => if area.w() < *h { Ok(None) } else { // TODO: axis clamp (subtract from x if width goes out of area item.layout([area.x(), area.y(), area.w(), area.h().max(*h)].into()) }, Self::WH(w, h, item) => if area.w() < *w || area.h() < *h { Ok(None) } else { item.layout([area.x(), area.y(), area.w().max(*w), area.h().max(*h)].into()) } } } } impl> Layout for Max { fn layout (&self, area: E::Area) -> Perhaps { match self { Self::W(w, item) => { // TODO: axis clamp (subtract from x if width goes out of area item.layout([area.x(), area.y(), area.w().min(*w), area.h()].into()) }, Self::H(h, item) => { // TODO: axis clamp (subtract from x if width goes out of area item.layout([area.x(), area.y(), area.w(), area.h().min(*h)].into()) }, Self::WH(w, h, item) => { item.layout([area.x(), area.y(), area.w().min(*w), area.h().min(*h)].into()) } } } } impl> Layout for Outset { fn layout (&self, area: E::Area) -> Perhaps { match self { Self::W(w, item) => if area.x() < *w { Ok(None) } else { item.layout([area.x() - *w, area.y(), area.w() + *w, area.h()].into()) }, Self::H(h, item) => if area.y() < *h { Ok(None) } else { item.layout([area.x(), area.y() - *h, area.w(), area.h() + *h].into()) }, Self::WH(w, h, item) => if area.x() < *w || area.y() < *h { Ok(None) } else { item.layout([area.x()-*w, area.y() - *h, area.w() + *w, area.h() + *h].into()) } } } } impl> Layout for Inset { fn layout (&self, area: E::Area) -> Perhaps { match self { Self::W(w, item) => if area.w() < *w { Ok(None) } else { item.layout([area.x() + *w, area.y(), area.w() - *w, area.h()].into()) }, Self::H(h, item) => if area.h() < *h { Ok(None) } else { item.layout([area.x(), area.y() + *h, area.w(), area.h() - *h].into()) }, Self::WH(w, h, item) => if area.w() < *w || area.h() < *h { Ok(None) } else { item.layout([area.x() - *w, area.y() - *h, area.w() + *w, area.h() + *h].into()) } } } } impl> Layout for Offset { fn layout (&self, area: E::Area) -> Perhaps { match self { Self::X(x, item) => if area.w() < *x { Ok(None) } else { item.layout([area.x() + *x, area.y(), area.w() - *x, area.h()].into()) }, Self::Y(y, item) => if area.h() < *y { Ok(None) } else { item.layout([area.x(), area.y() + *y, area.w(), area.h() - *y].into()) }, Self::XY(x, y, item) => if area.w() < *x || area.h() < *y { Ok(None) } else { item.layout([area.x() + *x, area.y() + *y, area.w() - *x, area.h() - *y].into()) } } } } impl + Layout> Render for Min { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) .map(|to|match self { Self::W(_, inner) => inner, Self::H(_, inner) => inner, Self::WH(_, _, inner) => inner, }.render(to)) .transpose() .map(|x|x.flatten()) } } impl + Layout> Render for Max { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) .map(|to|match self { Self::W(_, inner) => inner, Self::H(_, inner) => inner, Self::WH(_, _, inner) => inner, }.render(to)) .transpose() .map(|x|x.flatten()) } } impl + Layout> Render for Inset { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) .map(|to|match self { Self::W(_, inner) => inner, Self::H(_, inner) => inner, Self::WH(_, _, inner) => inner, }.render(to)) .transpose() .map(|x|x.flatten()) } } impl + Layout> Render for Outset { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) .map(|to|match self { Self::W(_, inner) => inner, Self::H(_, inner) => inner, Self::WH(_, _, inner) => inner, }.render(to)) .transpose() .map(|x|x.flatten()) } } impl + Layout> Render for Offset { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) .map(|to|match self { Self::X(_, inner) => inner, Self::Y(_, inner) => inner, Self::XY(_, _, inner) => inner, }.render(to)) .transpose() .map(|x|x.flatten()) } }