generalize Fixed and bring back some more of the arranger

This commit is contained in:
🪞👃🪞 2024-09-17 00:38:22 +03:00
parent d577449b72
commit 2352b72377
4 changed files with 51 additions and 52 deletions

View file

@ -298,12 +298,32 @@ pub enum Fixed<U: Number, T> {
/// Enforce fixed width and height /// Enforce fixed width and height
XY(U, U, T), XY(U, U, T),
} }
impl<N: Number, T> Fixed<N, T> { impl<N: Number, T> Fixed<N, T> {
pub fn inner (&self) -> &T { pub fn inner (&self) -> &T {
match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, }
} }
} }
impl<E: Engine, T: Widget<Engine = E>> Widget for Fixed<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(match self {
Self::X(w, _) =>
if to.w() >= *w { Some([*w, to.h()].into()) } else { None },
Self::Y(h, _) =>
if to.h() >= *h { Some([to.w(), *h].into()) } else { None },
Self::XY(w, h, _)
=> if to.w() >= *w && to.h() >= *h { Some([*w, *h].into()) } else { None },
})
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
// 🡘 🡙 ←🡙→
if let Some(size) = self.layout(to.area().wh().into())? {
to.render_in(to.area().clip(size).into(), self.inner())
} else {
Ok(())
}
}
}
/// Enforce minimum size of drawing area /// Enforce minimum size of drawing area
pub enum Min<U: Number, T> { pub enum Min<U: Number, T> {

View file

@ -282,7 +282,7 @@ impl Widget for &str {
type Engine = Tui; type Engine = Tui;
fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> { fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
// TODO: line breaks // TODO: line breaks
Ok(Some([self.len() as u16, 1])) Ok(Some([self.chars().count() as u16, 1]))
} }
fn render (&self, to: &mut TuiOutput) -> Usually<()> { fn render (&self, to: &mut TuiOutput) -> Usually<()> {
let [x, y, ..] = to.area(); let [x, y, ..] = to.area();
@ -296,7 +296,7 @@ pub struct Styled<T: Widget<Engine = Tui>>(pub Option<Style>, pub T);
impl Widget for Styled<&str> { impl Widget for Styled<&str> {
type Engine = Tui; type Engine = Tui;
fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> { fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some([self.1.len() as u16, 1])) Ok(Some([self.1.chars().count() as u16, 1]))
} }
fn render (&self, to: &mut TuiOutput) -> Usually<()> { fn render (&self, to: &mut TuiOutput) -> Usually<()> {
// FIXME // FIXME
@ -318,25 +318,6 @@ impl Widget for Background {
} }
} }
impl<T: Widget<Engine = Tui>> Widget for Fixed<u16, T> {
type Engine = Tui;
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
Ok(match self {
Self::X(w, _) => (to.w() < *w).then(||[to.w() - *w, to.h()]),
Self::Y(h, _) => (to.h() < *h).then(||[to.w(), to.h() - *h]),
Self::XY(w, h, _) => (to.w() < *w && to.h() < *h).then(||[to.w() - *w, to.h() - *h])
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
}
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
// 🡘 🡙 ←🡙→
if let Some(size) = self.layout(to.area().wh())? {
to.render_in(to.area().clip(size), self.inner())
} else {
Ok(())
}
}
}
//impl<F> Widget for Layers<Tui, F> //impl<F> Widget for Layers<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

@ -359,12 +359,12 @@ impl<'a, 'b> Content for ArrangerViewVertical<'a, 'b, Tui> {
let Self(state, cols, rows) = self; let Self(state, cols, rows) = self;
let tracks = state.tracks.as_ref(); let tracks = state.tracks.as_ref();
let scenes = state.scenes.as_ref(); let scenes = state.scenes.as_ref();
let offset = 3 + scene_name_max_len(scenes) as u16; let offset = 4 + scene_name_max_len(scenes) as u16;
Layers::new(move |add|{ Layers::new(move |add|{
//.add_ref(&Background(Color::Rgb(30, 33, 36)))//COLOR_BG1))//bg_lo(state.focused, state.entered))) //.add_ref(&Background(Color::Rgb(30, 33, 36)))//COLOR_BG1))//bg_lo(state.focused, state.entered)))
add(&ColumnSeparators(offset, cols))?; add(&ColumnSeparators(offset, cols))?;
add(&RowSeparators(rows))?; add(&RowSeparators(rows))?;
add(&CursorFocus(state.selected, offset, cols, rows))?; add(&CursorFocus(state.focused, state.selected, offset, cols, rows))?;
add(&Split::down(|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))
@ -416,14 +416,14 @@ impl<'a> Widget for RowSeparators<'a> {
} }
struct CursorFocus<'a>( struct CursorFocus<'a>(
ArrangerFocus, u16, &'a [(usize, usize)], &'a [(usize, usize)] bool, ArrangerFocus, u16, &'a [(usize, usize)], &'a [(usize, usize)]
); );
impl<'a> Widget for CursorFocus<'a> { impl<'a> Widget for CursorFocus<'a> {
type Engine = Tui; type Engine = Tui;
fn render (&self, to: &mut TuiOutput) -> Usually<()> { fn render (&self, to: &mut TuiOutput) -> Usually<()> {
let area = to.area(); let area = to.area();
let Self(selected, offset, cols, rows) = *self; let Self(focused, selected, offset, cols, rows) = *self;
let get_track_area = |t: usize| [ let get_track_area = |t: usize| [
offset + area.x() + cols[t].1 as u16 - 1, offset + area.x() + cols[t].1 as u16 - 1,
area.y(), area.y(),
@ -447,7 +447,9 @@ impl<'a> Widget for CursorFocus<'a> {
let mut clip_area: Option<[u16;4]> = None; let mut clip_area: Option<[u16;4]> = None;
let area = match selected { let area = match selected {
ArrangerFocus::Mix => { ArrangerFocus::Mix => {
if focused {
to.fill_bg(area, COLOR_BG0); to.fill_bg(area, COLOR_BG0);
}
area area
}, },
ArrangerFocus::Track(t) => { ArrangerFocus::Track(t) => {
@ -473,6 +475,7 @@ impl<'a> Widget for CursorFocus<'a> {
to.fill_ul([area.x(), y - 1, area.w(), 1], COLOR_BG5); to.fill_ul([area.x(), y - 1, area.w(), 1], COLOR_BG5);
to.fill_ul([area.x(), y + height - 1, area.w(), 1], COLOR_BG5); to.fill_ul([area.x(), y + height - 1, area.w(), 1], COLOR_BG5);
} }
if focused {
if let Some(clip_area) = clip_area { if let Some(clip_area) = clip_area {
to.fill_bg(clip_area, COLOR_BG0); to.fill_bg(clip_area, COLOR_BG0);
} else if let Some(track_area) = track_area { } else if let Some(track_area) = track_area {
@ -480,6 +483,7 @@ impl<'a> Widget for CursorFocus<'a> {
} else if let Some(scene_area) = scene_area { } else if let Some(scene_area) = scene_area {
to.fill_bg(scene_area, COLOR_BG0); to.fill_bg(scene_area, COLOR_BG0);
} }
}
//Ok(Some(area)) //Ok(Some(area))
Ok(()) Ok(())
} }
@ -515,9 +519,7 @@ impl<'a> Content for SceneRows<'a> {
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(&Fixed::X(1.max((pulses / 96) as u16), SceneRow( add(&SceneRow(tracks, scene, columns, offset, 1.max((pulses / 96) as u16)))?;
tracks, scene, columns, offset
)))?;
} }
Ok(()) Ok(())
}) })
@ -525,28 +527,24 @@ impl<'a> Content for SceneRows<'a> {
} }
struct SceneRow<'a>( struct SceneRow<'a>(
&'a[Sequencer<Tui>], &'a Scene, &'a[(usize, usize)], u16 &'a[Sequencer<Tui>], &'a Scene, &'a[(usize, usize)], u16, u16
); );
impl<'a> Content for SceneRow<'a> { impl<'a> Content for SceneRow<'a> {
type Engine = Tui; type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {
let Self(tracks, scene, columns, _offset) = self; let Self(tracks, scene, columns, offset, height) = self;
let playing = scene.is_playing(tracks); let playing = scene.is_playing(tracks);
Split::right(move |add| { Fixed::Y(*height, Split::right(move |add| {
add(&Layers::new(|add|{ add(&Fixed::XY(offset.saturating_sub(1), *height, Split::right(|add|{
//add(&Split::right(|add|{ add(&if playing { "" } else { " " })?;
//add(&if playing { "▶" } else { " " })?; add(&scene.name.read().unwrap().as_str())
add(&scene.name.read().unwrap().as_str())?; })))?;
//}))?; for (track, (_w, _x)) in columns.iter().enumerate() {
//add(&Background(COLOR_BG1)) add(&SceneClip(tracks.get(track), scene.clips.get(track)))?;
}
Ok(()) Ok(())
}))?; }))
//for (track, (_w, _x)) in columns.iter().enumerate() {
//add(&SceneClip(tracks.get(track), scene.clips.get(track)))?;
//}
Ok(())
})
} }
} }

View file

@ -262,7 +262,7 @@ impl Content for TransportPlayPauseButton<Tui> {
type Engine = Tui; type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {
Layers::new(|add|{ Layers::new(|add|{
add(&Plus::X(1, Min::Y(2, Styled(match self.value { add(&Plus::X(1, Min::XY(11, 2, Styled(match self.value {
Some(TransportState::Stopped) => Some(GRAY_DIM.bold()), Some(TransportState::Stopped) => Some(GRAY_DIM.bold()),
Some(TransportState::Starting) => Some(GRAY_NOT_DIM_BOLD), Some(TransportState::Starting) => Some(GRAY_NOT_DIM_BOLD),
Some(TransportState::Rolling) => Some(WHITE_NOT_DIM_BOLD), Some(TransportState::Rolling) => Some(WHITE_NOT_DIM_BOLD),