diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index 354f19cf..c7fae556 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -15,7 +15,7 @@ pub trait Engine: Sized { /// Unit of distance. type Unit: Number; - type Area: Rectangle; + type Area: Area + From<[Self::Unit;4]>; type HandleInput; type Handled; diff --git a/crates/tek_core/src/engine/collect.rs b/crates/tek_core/src/engine/collect.rs index 048999a6..5ef3a398 100644 --- a/crates/tek_core/src/engine/collect.rs +++ b/crates/tek_core/src/engine/collect.rs @@ -1,15 +1,24 @@ use crate::*; pub enum Collected<'a, E: Engine> { - Box(Box + 'a>), - Ref(&'a (dyn Render + 'a)), + Box(Box + 'a>), + Ref(&'a (dyn Layout + 'a)), } impl<'a, E: Engine> Render for Collected<'a, E> { fn render (&self, to: &mut E) -> Perhaps { match self { - Self::Box(item) => (*item).render(to), - Self::Ref(item) => (*item).render(to), + Self::Box(inner) => (*inner).render(to), + Self::Ref(inner) => (*inner).render(to), + } + } +} + +impl<'a, E: Engine> Layout for &Collected<'a, E> { + fn layout (&self, area: E::Area) -> Perhaps { + match *self { + Collected::Box(inner) => (*inner).layout(area), + Collected::Ref(inner) => (*inner).layout(area), } } } @@ -25,9 +34,9 @@ impl<'a, E: Engine> Collection<'a, E> { } pub trait Collect<'a, E: Engine> { - fn add_box (self, item: Box + 'a>) -> Self; - fn add_ref (self, item: &'a dyn Render) -> Self; - fn add + Sized + 'a> (self, item: R) -> Self + fn add_box (self, item: Box + 'a>) -> Self; + fn add_ref (self, item: &'a dyn Layout) -> Self; + fn add + Sized + 'a> (self, item: R) -> Self where Self: Sized { self.add_box(Box::new(item)) @@ -35,11 +44,11 @@ pub trait Collect<'a, E: Engine> { } impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> { - fn add_box (mut self, item: Box + 'a>) -> Self { + fn add_box (mut self, item: Box + 'a>) -> Self { self.0.push(Collected::Box(item)); self } - fn add_ref (mut self, item: &'a dyn Render) -> Self { + fn add_ref (mut self, item: &'a dyn Layout) -> Self { self.0.push(Collected::Ref(item)); self } @@ -54,11 +63,11 @@ impl<'a, E: Engine> Layered<'a, E> { } impl<'a, E: Engine> Collect<'a, E> for Layered<'a, E> { - fn add_box (mut self, item: Box + 'a>) -> Self { + fn add_box (mut self, item: Box + 'a>) -> Self { self.0 = self.0.add_box(item); self } - fn add_ref (mut self, item: &'a dyn Render) -> Self { + fn add_ref (mut self, item: &'a dyn Layout) -> Self { self.0 = self.0.add_ref(item); self } @@ -103,11 +112,11 @@ impl<'a, E: Engine> Split<'a, E> { } impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> { - fn add_box (mut self, item: Box + 'a>) -> Self { + fn add_box (mut self, item: Box + 'a>) -> Self { self.items = self.items.add_box(item); self } - fn add_ref (mut self, item: &'a dyn Render) -> Self { + fn add_ref (mut self, item: &'a dyn Layout) -> Self { self.items = self.items.add_ref(item); self } diff --git a/crates/tek_core/src/engine/layout.rs b/crates/tek_core/src/engine/layout.rs index 5a71693f..a6c8b85e 100644 --- a/crates/tek_core/src/engine/layout.rs +++ b/crates/tek_core/src/engine/layout.rs @@ -2,7 +2,7 @@ use crate::*; /// Trait for structs that compute drawing area before rendering pub trait Layout: Render { - fn layout (&self, area: impl Rectangle) -> Perhaps>; + 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), } @@ -16,84 +16,84 @@ pub enum Inset { W(U, L), H(U, L), WH(U, U, L), } pub enum Offset { X(U, L), Y(U, L), XY(U, U, L), } impl> Layout for Min { - fn layout (&self, area: impl Rectangle) -> Perhaps> { + 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()]) + 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)]) + 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)]) + item.layout([area.x(), area.y(), area.w().max(*w), area.h().max(*h)].into()) } } } } impl> Layout for Max { - fn layout (&self, area: impl Rectangle) -> Perhaps> { + 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()]) + 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)]) + 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)]) + item.layout([area.x(), area.y(), area.w().min(*w), area.h().min(*h)].into()) } } } } impl> Layout for Outset { - fn layout (&self, area: impl Rectangle) -> Perhaps> { + 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()]) + 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]) + 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]) + item.layout([area.x()-*w, area.y() - *h, area.w() + *w, area.h() + *h].into()) } } } } impl> Layout for Inset { - fn layout (&self, area: impl Rectangle) -> Perhaps> { + 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()]) + 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]) + 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]) + item.layout([area.x() - *w, area.y() - *h, area.w() + *w, area.h() + *h].into()) } } } } impl> Layout for Offset { - fn layout (&self, area: impl Rectangle) -> Perhaps> { + 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()]) + 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]) + 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]) + item.layout([area.x() + *x, area.y() + *y, area.w() - *x, area.h() - *y].into()) } } } diff --git a/crates/tek_core/src/space.rs b/crates/tek_core/src/space.rs index de2c78eb..3cb29743 100644 --- a/crates/tek_core/src/space.rs +++ b/crates/tek_core/src/space.rs @@ -29,7 +29,7 @@ impl Point for [N;2] { } } -pub trait Rectangle { +pub trait Area { fn x (&self) -> N; fn y (&self) -> N; fn w (&self) -> N; @@ -42,7 +42,7 @@ pub trait Rectangle { } } -impl Rectangle for (N, N, N, N) { +impl Area for (N, N, N, N) { fn x (&self) -> N { self.0 } @@ -57,7 +57,7 @@ impl Rectangle for (N, N, N, N) { } } -impl Rectangle for [N;4] { +impl Area for [N;4] { fn x (&self) -> N { self[0] } diff --git a/crates/tek_core/src/tui.rs b/crates/tek_core/src/tui.rs index b587f028..dde008e7 100644 --- a/crates/tek_core/src/tui.rs +++ b/crates/tek_core/src/tui.rs @@ -224,7 +224,7 @@ pub fn half_block (lower: bool, upper: bool) -> Option { } } -impl Rectangle for Rect { +impl Area for Rect { fn x (&self) -> u16 { self.x } fn y (&self) -> u16 { self.y } fn w (&self) -> u16 { self.width } diff --git a/crates/tek_core/src/tui/tui_layout.rs b/crates/tek_core/src/tui/tui_layout.rs index f82ce793..f09a9485 100644 --- a/crates/tek_core/src/tui/tui_layout.rs +++ b/crates/tek_core/src/tui/tui_layout.rs @@ -16,91 +16,43 @@ impl<'a> Render for Split<'a, Tui> { } } +// TODO impl<'a> Split<'a, Tui> { - pub fn render_areas (&self, to: &mut Tui) -> Usually<(Rect, Vec)> { - // FIXME very shitty code - let Rect { mut x, mut y, mut width, mut height } = to.area(); + pub fn render_areas (&self, to: &mut Tui) -> Usually<(Rect, Vec>)> { + let area = to.area(); + let mut w = 0u16; + let mut h = 0u16; let mut areas = vec![]; - match self.direction { - Direction::Down => { width = 0 }, - Direction::Right => { height = 0 }, - _ => unimplemented!() - } - for (index, item) in self.items.0.iter().enumerate() { - match self.direction { - Direction::Down => { if height == 0 { break } }, - Direction::Right => { if width == 0 { break } }, - _ => unimplemented!() - } - let result = item.render(to.with_area(x, y, width, height))?.unwrap_or(Rect::default()); - let Rect { width: w, height: h, .. } = result; - match self.direction { - Direction::Down => { - y += h; - height = height.saturating_sub(h); - width = width.max(w); - }, - Direction::Right => { - x += w; - width = width.saturating_sub(w); - height = height.max(h); - }, - _ => unimplemented!() - }; - areas.push(result); - if self.focus == Some(index) { - Corners(Style::default().green().not_dim()).draw(to.with_rect(result))?; - } - } - let area = match self.direction { - Direction::Down => Rect { x: to.area.x, y: to.area.y, width, height: y }, - Direction::Right => Rect { x: to.area.x, y: to.area.y, width: x, height }, - _ => unimplemented!() - }; - //panic!("{:?}", Rect { x: to.area.x, y: to.area.y, width: x, height }); - Ok((Rect { x, y, width, height }, areas)) + Ok((match self.direction { + Direction::Down => { + for component in self.items.0.iter() { + if h >= area.h() { + break + } + let result = Offset::Y(h, component).render(to)?; + areas.push(result); + if let Some(Rect { width, height, .. }) = result { + h += height; + w = w.max(width) + } + } + Rect { x: area.x(), y: area.y(), width: w, height: h } + }, + Direction::Right => { + for component in self.items.0.iter() { + if w >= area.x() { + break + } + let result = Offset::X(w, component).render(to)?; + areas.push(result); + if let Some(Rect { width, height, .. }) = result { + w += width; + h = h.max(height) + } + } + Rect { x: area.x(), y: area.y(), width: w, height: h } + }, + _ => todo!() + }, areas)) } } - -// TODO -//impl<'a> Split<'a, Tui> { - //pub fn render_areas (&self, to: &mut Tui) - //-> Usually<(Rectangle, Vec>>)> - //{ - //let area = to.area(); - //let mut w = 0u16; - //let mut h = 0u16; - //let mut areas = vec![]; - //Ok((match self.direction { - //Direction::Down => { - //for component in self.items.0.iter() { - //if h >= area.h() { - //break - //} - //let result = Offset::Y(h, component).render(to)?; - //areas.push(result); - //if let Some(Rect { width, height, .. }) = result { - //h += height; - //w = w.max(width) - //} - //} - //(area.x(), area.y(), w, h) - //}, - //Direction::Right => { - //for component in self.items.0.iter() { - //if w >= area.x() { - //break - //} - //let result = Offset::X(w, component).render(to)?; - //areas.push(result); - //if let Some(Rect { width, height, .. }) = result { - //w += width; - //h = h.max(height) - //} - //} - //(area.x(), area.y(), w, h) - //}, - //_ => todo!() - //}, areas)) - //} -//}