diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index e28c75a7..db088707 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -385,6 +385,26 @@ impl Align { } } +/// Enforce fixed size of drawing area +pub enum Fixed { + /// Enforce fixed width + W(U, T), + /// Enforce fixed height + H(U, T), + /// Enforce fixed width and height + WH(U, U, T), +} + +impl Fixed { + 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 pub enum Min { /// Enforce minimum width diff --git a/crates/tek_core/src/tui.rs b/crates/tek_core/src/tui.rs index bb3c3d95..ba2db171 100644 --- a/crates/tek_core/src/tui.rs +++ b/crates/tek_core/src/tui.rs @@ -452,6 +452,31 @@ pub const NOT_DIM_BOLD: Style = Style { sub_modifier: Modifier::DIM, }; +impl> Widget for Fixed { + 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 Widget for Split where F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> diff --git a/crates/tek_sequencer/src/arranger.rs b/crates/tek_sequencer/src/arranger.rs index 9498b83d..92dd746b 100644 --- a/crates/tek_sequencer/src/arranger.rs +++ b/crates/tek_sequencer/src/arranger.rs @@ -379,7 +379,7 @@ impl<'a, 'b> Content for ArrangerViewVertical<'a, 'b, Tui> { add(&ColumnSeparators(offset, cols))?; add(&RowSeparators(rows))?; add(&CursorFocus(state.selected, offset, cols, rows))?; - add(&Split::right(|add|{ + add(&Split::down(|add|{ add(&TracksHeader(offset, cols, tracks))?; 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]); +struct TracksHeader<'a>( + u16, &'a[(usize, usize)], &'a [Sequencer] +); impl<'a> Content for TracksHeader<'a> { 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], &'a[Scene]); +struct SceneRows<'a>( + u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer], &'a[Scene] +); impl<'a> Content for SceneRows<'a> { type Engine = Tui; fn content (&self) -> impl Widget { let Self(offset, columns, rows, tracks, scenes) = *self; Split::down(move |add| { - for (scene, (_pulses, _)) in scenes.iter().zip(rows) { - add(&SceneRow(tracks, scene, columns, offset))?; + for (scene, (pulses, _)) in scenes.iter().zip(rows) { + add(&Fixed::H(1.max((pulses / 96) as u16), SceneRow( + tracks, scene, columns, offset + )))?; } Ok(()) }) } } -struct SceneRow<'a>(&'a[Sequencer], &'a Scene, &'a[(usize, usize)], u16); +struct SceneRow<'a>( + &'a[Sequencer], &'a Scene, &'a[(usize, usize)], u16 +); impl<'a> Content for SceneRow<'a> { type Engine = Tui; @@ -538,8 +546,10 @@ impl<'a> Content for SceneRow<'a> { let playing = scene.is_playing(tracks); Split::right(move |add| { add(&Layers::new(|add|{ - add(&if playing { "▶" } else { " " })?; - add(&scene.name.read().unwrap().as_str())?; + add(&Split::right(|add|{ + add(&if playing { "▶" } else { " " })?; + add(&scene.name.read().unwrap().as_str()) + }))?; add(&FillBg(COLOR_BG1)) }))?; for (track, (_w, _x)) in columns.iter().enumerate() { diff --git a/crates/tek_test/src/main.rs b/crates/tek_test/src/main.rs index a4005463..bdf71666 100644 --- a/crates/tek_test/src/main.rs +++ b/crates/tek_test/src/main.rs @@ -44,11 +44,12 @@ impl Content for Demo { add(&Align::Center("12345"))?; add(&Align::Center("FOO")) }))?; - add(&Layers::new(|add|{ + add(&Fixed::H(10, Layers::new(|add|{ add(&FillBg(Color::Rgb(0,0,128)))?; add(&Align::Center("1234567"))?; add(&Align::Center("BAR")) - })) + })))?; + Ok(()) })) })) }