diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index d3bdd65c..c668acfd 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -14,19 +14,22 @@ pub trait Engine: Send + Sync + Sized { /// Unit of distance. type Unit: Number; type Area: Area + From<[Self::Unit;4]> + Debug; + type Size: Size + From<[Self::Unit;2]> + Debug; type HandleInput; type Handled; - // FIXME - fn area (&self) -> Self::Area; - // FIXME - fn with_area (&mut self, x: Self::Unit, y: Self::Unit, w: Self::Unit, h: Self::Unit) - -> &mut Self; - // FIXME - fn render_in ( + #[inline] fn area (&self) -> Self::Area; + #[inline] fn area_mut (&mut self) -> &mut Self::Area; + #[inline] fn render_in ( &mut self, area: Self::Area, widget: &impl Widget - ) -> Perhaps; + ) -> Perhaps { + let last = self.area(); + *self.area_mut() = area; + let next = widget.render(self)?; + *self.area_mut() = last; + Ok(next) + } } pub trait Widget: Send + Sync { @@ -600,6 +603,42 @@ impl Outset { } } +impl> Widget for Inset { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + match *self { + Self::X(x, ref inner) => Shrink::X(x + x, inner as &dyn Widget), + Self::Y(y, ref inner) => Shrink::Y(y + y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Shrink::XY(x + x, y + y, inner as &dyn Widget), + }.layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + match *self { + Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), + Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), + }.render(to) + } +} + +impl> Widget for Outset { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + match *self { + Self::X(x, ref inner) => Grow::X(x + x, inner as &dyn Widget), + Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget), + }.layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + match *self { + Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), + Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), + }.render(to) + } +} + /// Move origin point of drawing area pub enum Plus { /// Move origin to the right diff --git a/crates/tek_core/src/space.rs b/crates/tek_core/src/space.rs index 706926d5..bb1b8dbc 100644 --- a/crates/tek_core/src/space.rs +++ b/crates/tek_core/src/space.rs @@ -1,18 +1,18 @@ use crate::*; -pub trait Point { +pub trait Size { fn x (&self) -> N; fn y (&self) -> N; fn w (&self) -> N { self.x() } fn h (&self) -> N { self.y() } } -impl Point for (N, N) { +impl Size for (N, N) { fn x (&self) -> N { self.0 } fn y (&self) -> N { self.1 } } -impl Point for [N;2] { +impl Size for [N;2] { fn x (&self) -> N { self[0] } fn y (&self) -> N { self[1] } } @@ -22,8 +22,11 @@ pub trait Area: Copy { fn y (&self) -> N; fn w (&self) -> N; fn h (&self) -> N; - fn x2 (&self) -> N { self.x() + self.w() - 1.into() } - fn y2 (&self) -> N { self.y() + self.h() - 1.into() } + fn x2 (&self) -> N { self.x() + self.w() } + fn y2 (&self) -> N { self.y() + self.h() } + fn wh (&self) -> [N;2] { + [self.w(), self.h()] + } fn xywh (&self) -> [N;4] { [self.x(), self.y(), self.w(), self.h()] } @@ -37,6 +40,9 @@ pub trait Area: Copy { Ok(self) } } + fn clip (&self, wh: impl Size) -> [N;4] { + [self.x(), self.y(), wh.w(), wh.h()] + } } impl Area for (N, N, N, N) { diff --git a/crates/tek_core/src/test.rs b/crates/tek_core/src/test.rs index 5c77f7d2..86f239d6 100644 --- a/crates/tek_core/src/test.rs +++ b/crates/tek_core/src/test.rs @@ -1,32 +1,66 @@ use crate::*; +struct TestEngine([u16;4], Vec>); + +impl Engine for TestEngine { + type Unit = u16; + type Size = [Self::Unit;2]; + type Area = [Self::Unit;4]; + type HandleInput = Self; + type Handled = bool; + fn exited (&self) -> bool { + true + } + fn area (&self) -> Self::Area { + self.0 + } + fn area_mut (&mut self) -> &mut Self::Area { + &mut self.0 + } +} + #[derive(Copy, Clone)] struct TestArea(u16, u16); impl Widget for TestArea { - type Engine = Tui; + type Engine = TestEngine; fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> { Ok(Some([to[0], to[1], self.0, self.1])) } - fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { - self.layout(to.area()) + fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> { + if let Some(layout) = self.layout(to.area())? { + for y in layout.y()..layout.y()+layout.h()-1 { + for x in layout.x()..layout.x()+layout.w()-1 { + to.1[y as usize][x as usize] = '*'; + } + } + Ok(Some(layout)) + } else { + Ok(None) + } } } #[test] -fn test_0 () -> Usually<()> { - let area: [u16;4] = [0, 0, 10, 10]; - let test = TestArea(4, 4); - assert_eq!(test.layout(area)?, - Some([0, 0, 4, 4])); - assert_eq!(Outset::X(1, test).layout(area)?, - Some([0, 0, 6, 4])); - assert_eq!(Align::X(test).layout(area)?, - Some([3, 0, 4, 4])); - assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, - Some([2, 0, 6, 4])); - assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, - Some([2, 0, 6, 4])); +fn test_plus_minus () -> Usually<()> { + let area = [0, 0, 10, 10]; + let engine = TestEngine(area, vec![vec![' ';10];10]); + let test = TestArea(4, 4); + assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); + assert_eq!(Plus::X(1, test).layout(area)?, Some([1, 0, 4, 4])); + Ok(()) +} + +#[test] +fn test_outset_align () -> Usually<()> { + let area = [0, 0, 10, 10]; + let engine = TestEngine(area, vec![vec![' ';10];10]); + let test = TestArea(4, 4); + assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); + assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4])); + assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4])); + assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4])); + assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4])); Ok(()) } diff --git a/crates/tek_core/src/tui.rs b/crates/tek_core/src/tui.rs index bb401a2e..d442c8e8 100644 --- a/crates/tek_core/src/tui.rs +++ b/crates/tek_core/src/tui.rs @@ -22,6 +22,7 @@ pub struct Tui { impl Engine for Tui { type Unit = u16; + type Size = [Self::Unit;2]; type Area = [Self::Unit;4]; type HandleInput = Self; type Handled = bool; @@ -45,24 +46,11 @@ impl Engine for Tui { self.backend.show_cursor()?; disable_raw_mode().map_err(Into::into) } - // FIXME - fn area (&self) -> Self::Area { + #[inline] fn area (&self) -> Self::Area { self.area } - #[inline] - fn with_area (&mut self, x: u16, y: u16, w: u16, h: u16) -> &mut Self { - self.with_rect([x, y, w, h]); - self - } - #[inline] - fn render_in ( - &mut self, area: [u16;4], widget: &impl Widget - ) -> Perhaps<[u16;4]> { - let last = self.area; - self.area = area; - let next = widget.render(self)?; - self.area = last; - Ok(next) + #[inline] fn area_mut (&mut self) -> &mut Self::Area { + &mut self.area } } impl Tui { @@ -183,13 +171,6 @@ impl Tui { Ok(Some([x, y, text.len() as u16, 1])) } #[inline] - pub fn alter_area ( - &mut self, alter: impl Fn([u16;4])->[u16;4] - ) -> &mut Self { - let [x, y, w, h] = alter(self.area.xywh()); - self.with_area(x, y, w, h) - } - #[inline] pub fn with_rect (&mut self, area: [u16;4]) -> &mut Self { self.area = area; self @@ -425,41 +406,6 @@ where } } -impl> Content for Inset { - type Engine = Tui; - fn content (&self) -> impl Widget { - match self { - Self::X(x, inner) => Plus::X( - *x, Shrink::X(*x + *x, Align::X(inner as &dyn Widget)) - ), - Self::Y(y, inner) => Plus::Y( - *y, Shrink::X(*y + *y, Align::Y(inner as &dyn Widget)) - ), - Self::XY(x, y, inner) => Plus::XY( - *x, *y, Shrink::XY(*x, *y, Align::Center(inner as &dyn Widget)) - ), - } - } -} - -impl> Widget for Outset { - type Engine = Tui; - fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> { - match *self { - Self::X(x, ref inner) => Grow::X(x + x, inner as &dyn Widget), - Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget), - Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget), - }.layout(to) - } - fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { - match *self { - Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), - Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), - Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), - }.render(to) - } -} - pub struct Border(pub S); impl Widget for Border { diff --git a/crates/tek_sequencer/src/arranger.rs b/crates/tek_sequencer/src/arranger.rs index aa449d18..a934ffa7 100644 --- a/crates/tek_sequencer/src/arranger.rs +++ b/crates/tek_sequencer/src/arranger.rs @@ -407,9 +407,11 @@ impl<'a> Widget for RowSeparators<'a> { break } for x in area.x()..area.x2().saturating_sub(2) { - let cell = to.buffer().get_mut(x, y); - cell.modifier = Modifier::UNDERLINED; - cell.underline_color = Nord::SEPARATOR; + if x < to.buffer().area.x && y < to.buffer().area.y { + let cell = to.buffer().get_mut(x, y); + cell.modifier = Modifier::UNDERLINED; + cell.underline_color = Nord::SEPARATOR; + } } } Ok(Some(area)) diff --git a/crates/tek_sequencer/src/sequencer.rs b/crates/tek_sequencer/src/sequencer.rs index 8fde92c4..3966cf91 100644 --- a/crates/tek_sequencer/src/sequencer.rs +++ b/crates/tek_sequencer/src/sequencer.rs @@ -412,7 +412,7 @@ impl Sequencer { add(&SequenceLoopRange)?; add(&SequenceNoteRange)?; Ok(()) - }).render(to.with_area(area.x(), area.y(), 10, area.h()))?; + }).render(to.with_rect([area.x(), area.y(), 10, area.h()]))?; let area = [area.x() + 10, area.y(), area.w().saturating_sub(10), area.h().min(66)]; Lozenge(Style::default().fg(Nord::BG2)).draw(to.with_rect(area))?; let area = [area.x() + 1, area.y(), area.w().saturating_sub(1), area.h()];