implementing Fixed constraint

This commit is contained in:
🪞👃🪞 2024-09-12 20:19:07 +03:00
parent a57bb60ac9
commit 4b19abd98a
4 changed files with 66 additions and 10 deletions

View file

@ -385,6 +385,26 @@ impl<T> Align<T> {
} }
} }
/// Enforce fixed size of drawing area
pub enum Fixed<U: Number, T> {
/// Enforce fixed width
W(U, T),
/// Enforce fixed height
H(U, T),
/// Enforce fixed width and height
WH(U, U, T),
}
impl<N: Number, T> Fixed<N, T> {
pub fn inner (&self) -> &T {
match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}
}
}
/// Enforce minimum size of drawing area /// Enforce minimum size of drawing area
pub enum Min<U: Number, T> { pub enum Min<U: Number, T> {
/// Enforce minimum width /// Enforce minimum width

View file

@ -452,6 +452,31 @@ pub const NOT_DIM_BOLD: Style = Style {
sub_modifier: Modifier::DIM, sub_modifier: Modifier::DIM,
}; };
impl<T: Widget<Engine = Tui>> Widget for Fixed<u16, T> {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
Ok(match self {
Self::W(w, item) => if area.w() < *w { None } else {
item.layout(area)?.map(|[x, y, _, h]|[x, y, *w, h])
},
Self::H(h, item) => if area.w() < *h { None } else {
item.layout(area)?.map(|[x, y, w, _]|[x, y, w, *h])
},
Self::WH(w, h, item) => if area.w() < *w || area.h() < *h { None } else {
item.layout(area)?.map(|[x, y, _, _]|[x, y, *w, *h])
}
})
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
// 🡘 🡙 ←🡙→
if let Some(area) = self.layout(to.area())? {
to.render_in(area, self.inner())
} else {
Ok(None)
}
}
}
impl<F> Widget for Split<Tui, F> impl<F> Widget for Split<Tui, F>
where where
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = Tui>)->Usually<()>)->Usually<()> F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = Tui>)->Usually<()>)->Usually<()>

View file

@ -379,7 +379,7 @@ impl<'a, 'b> Content for ArrangerViewVertical<'a, 'b, Tui> {
add(&ColumnSeparators(offset, cols))?; add(&ColumnSeparators(offset, cols))?;
add(&RowSeparators(rows))?; add(&RowSeparators(rows))?;
add(&CursorFocus(state.selected, offset, cols, rows))?; add(&CursorFocus(state.selected, offset, cols, rows))?;
add(&Split::right(|add|{ add(&Split::down(|add|{
add(&TracksHeader(offset, cols, tracks))?; add(&TracksHeader(offset, cols, tracks))?;
add(&SceneRows(offset, cols, rows, tracks, scenes)) add(&SceneRows(offset, cols, rows, tracks, scenes))
})) }))
@ -496,7 +496,9 @@ impl<'a> Widget for CursorFocus<'a> {
} }
} }
struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer<Tui>]); struct TracksHeader<'a>(
u16, &'a[(usize, usize)], &'a [Sequencer<Tui>]
);
impl<'a> Content for TracksHeader<'a> { impl<'a> Content for TracksHeader<'a> {
type Engine = Tui; type Engine = Tui;
@ -514,22 +516,28 @@ impl<'a> Content for TracksHeader<'a> {
} }
} }
struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer<Tui>], &'a[Scene]); struct SceneRows<'a>(
u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer<Tui>], &'a[Scene]
);
impl<'a> Content for SceneRows<'a> { impl<'a> Content for SceneRows<'a> {
type Engine = Tui; type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {
let Self(offset, columns, rows, tracks, scenes) = *self; let Self(offset, columns, rows, tracks, scenes) = *self;
Split::down(move |add| { Split::down(move |add| {
for (scene, (_pulses, _)) in scenes.iter().zip(rows) { for (scene, (pulses, _)) in scenes.iter().zip(rows) {
add(&SceneRow(tracks, scene, columns, offset))?; add(&Fixed::H(1.max((pulses / 96) as u16), SceneRow(
tracks, scene, columns, offset
)))?;
} }
Ok(()) Ok(())
}) })
} }
} }
struct SceneRow<'a>(&'a[Sequencer<Tui>], &'a Scene, &'a[(usize, usize)], u16); struct SceneRow<'a>(
&'a[Sequencer<Tui>], &'a Scene, &'a[(usize, usize)], u16
);
impl<'a> Content for SceneRow<'a> { impl<'a> Content for SceneRow<'a> {
type Engine = Tui; type Engine = Tui;
@ -538,8 +546,10 @@ impl<'a> Content for SceneRow<'a> {
let playing = scene.is_playing(tracks); let playing = scene.is_playing(tracks);
Split::right(move |add| { Split::right(move |add| {
add(&Layers::new(|add|{ add(&Layers::new(|add|{
add(&if playing { "" } else { " " })?; add(&Split::right(|add|{
add(&scene.name.read().unwrap().as_str())?; add(&if playing { "" } else { " " })?;
add(&scene.name.read().unwrap().as_str())
}))?;
add(&FillBg(COLOR_BG1)) add(&FillBg(COLOR_BG1))
}))?; }))?;
for (track, (_w, _x)) in columns.iter().enumerate() { for (track, (_w, _x)) in columns.iter().enumerate() {

View file

@ -44,11 +44,12 @@ impl Content for Demo<Tui> {
add(&Align::Center("12345"))?; add(&Align::Center("12345"))?;
add(&Align::Center("FOO")) add(&Align::Center("FOO"))
}))?; }))?;
add(&Layers::new(|add|{ add(&Fixed::H(10, Layers::new(|add|{
add(&FillBg(Color::Rgb(0,0,128)))?; add(&FillBg(Color::Rgb(0,0,128)))?;
add(&Align::Center("1234567"))?; add(&Align::Center("1234567"))?;
add(&Align::Center("BAR")) add(&Align::Center("BAR"))
})) })))?;
Ok(())
})) }))
})) }))
} }