mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
cleanup Engine API and generalize Inset/Outset
This commit is contained in:
parent
4e0eb0c335
commit
0737769232
6 changed files with 118 additions and 91 deletions
|
|
@ -14,19 +14,22 @@ pub trait Engine: Send + Sync + Sized {
|
|||
/// Unit of distance.
|
||||
type Unit: Number;
|
||||
type Area: Area<Self::Unit> + From<[Self::Unit;4]> + Debug;
|
||||
type Size: Size<Self::Unit> + 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<Engine = Self>
|
||||
) -> Perhaps<Self::Area>;
|
||||
) -> Perhaps<Self::Area> {
|
||||
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<N: Number, T: Widget> Outset<N, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
match *self {
|
||||
Self::X(x, ref inner) => Shrink::X(x + x, inner as &dyn Widget<Engine = E>),
|
||||
Self::Y(y, ref inner) => Shrink::Y(y + y, inner as &dyn Widget<Engine = E>),
|
||||
Self::XY(x, y, ref inner) => Shrink::XY(x + x, y + y, inner as &dyn Widget<Engine = E>),
|
||||
}.layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
match *self {
|
||||
Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget<Engine = E>),
|
||||
Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget<Engine = E>),
|
||||
Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget<Engine = E>),
|
||||
}.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
match *self {
|
||||
Self::X(x, ref inner) => Grow::X(x + x, inner as &dyn Widget<Engine = E>),
|
||||
Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget<Engine = E>),
|
||||
Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget<Engine = E>),
|
||||
}.layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
match *self {
|
||||
Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget<Engine = E>),
|
||||
Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget<Engine = E>),
|
||||
Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget<Engine = E>),
|
||||
}.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
/// Move origin point of drawing area
|
||||
pub enum Plus<N: Number, T: Widget> {
|
||||
/// Move origin to the right
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait Point<N: Number> {
|
||||
pub trait Size<N: Number> {
|
||||
fn x (&self) -> N;
|
||||
fn y (&self) -> N;
|
||||
fn w (&self) -> N { self.x() }
|
||||
fn h (&self) -> N { self.y() }
|
||||
}
|
||||
|
||||
impl<N: Number> Point<N> for (N, N) {
|
||||
impl<N: Number> Size<N> for (N, N) {
|
||||
fn x (&self) -> N { self.0 }
|
||||
fn y (&self) -> N { self.1 }
|
||||
}
|
||||
|
||||
impl<N: Number> Point<N> for [N;2] {
|
||||
impl<N: Number> Size<N> for [N;2] {
|
||||
fn x (&self) -> N { self[0] }
|
||||
fn y (&self) -> N { self[1] }
|
||||
}
|
||||
|
|
@ -22,8 +22,11 @@ pub trait Area<N: Number>: 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<N: Number>: Copy {
|
|||
Ok(self)
|
||||
}
|
||||
}
|
||||
fn clip (&self, wh: impl Size<N>) -> [N;4] {
|
||||
[self.x(), self.y(), wh.w(), wh.h()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Number> Area<N> for (N, N, N, N) {
|
||||
|
|
|
|||
|
|
@ -1,32 +1,66 @@
|
|||
use crate::*;
|
||||
|
||||
struct TestEngine([u16;4], Vec<Vec<char>>);
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Engine = Self>
|
||||
) -> 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<T: Widget<Engine = Tui>> Content for Inset<u16, T> {
|
||||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
match self {
|
||||
Self::X(x, inner) => Plus::X(
|
||||
*x, Shrink::X(*x + *x, Align::X(inner as &dyn Widget<Engine = Tui>))
|
||||
),
|
||||
Self::Y(y, inner) => Plus::Y(
|
||||
*y, Shrink::X(*y + *y, Align::Y(inner as &dyn Widget<Engine = Tui>))
|
||||
),
|
||||
Self::XY(x, y, inner) => Plus::XY(
|
||||
*x, *y, Shrink::XY(*x, *y, Align::Center(inner as &dyn Widget<Engine = Tui>))
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Widget<Engine = Tui>> Widget for Outset<u16, T> {
|
||||
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<Engine = Tui>),
|
||||
Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget<Engine = Tui>),
|
||||
Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget<Engine = Tui>),
|
||||
}.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<Engine = Tui>),
|
||||
Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget<Engine = Tui>),
|
||||
Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget<Engine = Tui>),
|
||||
}.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Border<S: BorderStyle>(pub S);
|
||||
|
||||
impl<S: BorderStyle> Widget for Border<S> {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ impl Sequencer<Tui> {
|
|||
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()];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue