diff --git a/crates/tek_core/src/space.rs b/crates/tek_core/src/space.rs index 7bf26ce3..5427c160 100644 --- a/crates/tek_core/src/space.rs +++ b/crates/tek_core/src/space.rs @@ -9,6 +9,7 @@ pub trait Coordinate: Send + Sync + Copy + Ord + PartialEq + Eq + Debug + Display + Default + From + Into + + Into + Into { fn minus (self, other: Self) -> Self { @@ -29,6 +30,7 @@ impl Coordinate for T where + Ord + PartialEq + Eq + Debug + Display + Default + From + Into + + Into + Into {} @@ -87,12 +89,10 @@ pub trait Size { } } } - impl Size for (N, N) { fn x (&self) -> N { self.0 } fn y (&self) -> N { self.1 } } - impl Size for [N;2] { fn x (&self) -> N { self[0] } fn y (&self) -> N { self[1] } @@ -880,6 +880,31 @@ impl, B: Widget> Widget for Split(PhantomData, AtomicUsize, AtomicUsize); + +impl Measure { + pub fn w (&self) -> usize { self.1.load(Ordering::Relaxed) } + pub fn h (&self) -> usize { self.2.load(Ordering::Relaxed) } + pub fn wh (&self) -> [usize;2] { [self.w(), self.h()] } + pub fn set_w (&self, w: impl Into) { self.1.store(w.into(), Ordering::Relaxed) } + pub fn set_h (&self, h: impl Into) { self.2.store(h.into(), Ordering::Relaxed) } + pub fn set_wh (&self, w: impl Into, h: impl Into) { self.set_w(w); self.set_h(h); } + pub fn new () -> Self { Self(PhantomData::default(), 0.into(), 0.into()) } +} + +impl Widget for Measure { + type Engine = E; + fn layout (&self, _: E::Size) -> Perhaps { + Ok(Some([0u16.into(), 0u16.into()].into())) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + self.set_w(to.area().w()); + self.set_h(to.area().h()); + Ok(()) + } +} + /// A scrollable area. pub struct Scroll< E: Engine, diff --git a/crates/tek_sequencer/src/arranger.rs b/crates/tek_sequencer/src/arranger.rs index 268859e4..552dde42 100644 --- a/crates/tek_sequencer/src/arranger.rs +++ b/crates/tek_sequencer/src/arranger.rs @@ -66,10 +66,8 @@ pub struct Arrangement { pub focused: bool, /// Background color of arrangement pub color: Color, - /// Width of arrangement area at last render - pub width: AtomicUsize, - /// Height of arrangement area at last render - pub height: AtomicUsize, + /// Width and height of arrangement area at last render + pub size: Measure, } /// Represents a track in the arrangement pub struct ArrangementTrack { @@ -238,8 +236,7 @@ impl Arrangement { tracks: vec![], focused: false, color: Color::Rgb(28, 35, 25), - width: 0.into(), - height: 0.into(), + size: Measure::new(), } } pub fn activate (&mut self) { diff --git a/crates/tek_sequencer/src/arranger_tui.rs b/crates/tek_sequencer/src/arranger_tui.rs index 84801da8..dfd685a3 100644 --- a/crates/tek_sequencer/src/arranger_tui.rs +++ b/crates/tek_sequencer/src/arranger_tui.rs @@ -146,30 +146,21 @@ impl<'a> Content for VerticalArranger<'a, Tui> { let rows: &[(usize, usize)] = rows.as_ref(); let cols: &[(usize, usize)] = cols.as_ref(); let any_size = |_|Ok(Some([0,0])); - // store render area - add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{ - let [x, y, w, h] = to.area(); - self.0.width.store(w as usize, Ordering::Relaxed); - self.0.height.store(h as usize, Ordering::Relaxed); - Ok(()) - }))?; - + add(&self.0.size)?; // column separators add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{ let area = to.area(); let style = Some(Style::default().fg(COLOR_SEPARATOR)); - for x in cols.iter().map(|col|col.1) { + Ok(for x in cols.iter().map(|col|col.1) { let x = scene_title_w + area.x() + x as u16; for y in area.y()..area.y2() { to.blit(&"▎", x, y, style); } - } - Ok(()) + }) }))?; - // row separators add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{ let area = to.area(); - for y in rows.iter().map(|row|row.1) { + Ok(for y in rows.iter().map(|row|row.1) { let y = area.y() + (y / PPQ) as u16 + 1; if y >= to.buffer.area.height { break } for x in area.x()..area.x2().saturating_sub(2) { @@ -179,10 +170,8 @@ impl<'a> Content for VerticalArranger<'a, Tui> { cell.underline_color = COLOR_SEPARATOR; } } - } - Ok(()) + }) }))?; - // track titles let header = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0))=>{ let name = track.name.read().unwrap(); @@ -211,13 +200,11 @@ impl<'a> Content for VerticalArranger<'a, Tui> { .bg(track.color) .push_x(scene_title_w) }); - // scene titles let scene_name = |scene, playing: bool, height|row!( if playing { "▶ " } else { " " }, TuiStyle::bold((scene as &Scene).name.read().unwrap().as_str(), true), ).fixed_xy(scene_title_w, height); - // scene clips let scene_clip = |scene, track: usize, w: u16, h: u16|Layers::new(move |add|{ let mut color = clip_bg; @@ -233,27 +220,22 @@ impl<'a> Content for VerticalArranger<'a, Tui> { }; add(&Background(color)) }).fixed_xy(w, h); - - add(&col!( - header, - col!( - // scenes: - (scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => { - let height = 1.max((pulses / PPQ) as u16); - let playing = scene.is_playing(tracks); - Stack::right(move |add| { - // scene title: - add(&scene_name(scene, playing, height).bg(scene.color))?; - // clip per track: - for (track, w) in cols.iter().map(|col|col.0).enumerate() { - add(&scene_clip(scene, track, w as u16, height))?; - } - Ok(()) - }).fixed_y(height) - } - ), - ))?; - + // tracks and scenes + add(&col!(header, col!( + // scenes: + (scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => { + let height = 1.max((pulses / PPQ) as u16); + let playing = scene.is_playing(tracks); + Stack::right(move |add| { + // scene title: + add(&scene_name(scene, playing, height).bg(scene.color))?; + // clip per track: + Ok(for (track, w) in cols.iter().map(|col|col.0).enumerate() { + add(&scene_clip(scene, track, w as u16, height))?; + }) + }).fixed_y(height) + } + )))?; // cursor add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{ let area = to.area(); @@ -317,18 +299,14 @@ impl<'a> Content for VerticalArranger<'a, Tui> { } } Ok(()) - }))?; - - Ok(()) + })) }).bg(bg).grow_y(1).border(border); - let title_color = if self.0.focused { Color::Rgb(150, 160, 90) } else { Color::Rgb(120, 130, 100) }; - let w = self.0.width.load(Ordering::Relaxed); - let h = self.0.height.load(Ordering::Relaxed); + let [w, h] = self.0.size.wh(); let lower_right = TuiStyle::fg(format!("{w}x{h}"), title_color) .pull_x(1).align_se().fill_xy(); lay!(content, lower_right)