diff --git a/crates/tek_sequencer/src/transport.rs b/crates/tek_sequencer/src/transport.rs index 3883503b..15c8d2a4 100644 --- a/crates/tek_sequencer/src/transport.rs +++ b/crates/tek_sequencer/src/transport.rs @@ -1,5 +1,7 @@ use crate::*; +const CORNERS: Corners = Corners(NOT_DIM_GREEN); + /// Stores and displays time-related state. pub struct TransportToolbar { /// Enable metronome? @@ -187,6 +189,36 @@ impl Audio for TransportToolbar { Control::Continue } } +impl Handle for TransportToolbar { + fn handle (&mut self, from: &Tui) -> Perhaps { + match from.event() { + key!(KeyCode::Left) => { + self.focus_prev(); + Ok(Some(true)) + }, + key!(KeyCode::Right) => { + self.focus_next(); + Ok(Some(true)) + }, + _ => self.focused_mut().handle(from) + } + } +} +impl Content for TransportToolbar { + type Engine = Tui; + fn content (&self) -> impl Widget { + Split::right(|add|{ + add(&self.playing)?; + add(&self.bpm)?; + add(&self.quant)?; + add(&self.sync)?; + add(&self.clock)?; + Ok(()) + }) + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// pub struct TransportPlayPauseButton { pub _engine: PhantomData, @@ -202,6 +234,8 @@ impl Focusable for TransportPlayPauseButton { } } +/////////////////////////////////////////////////////////////////////////////////////////////////// + pub struct TransportBPM { pub _engine: PhantomData, pub value: f64, @@ -215,156 +249,21 @@ impl Focusable for TransportBPM { self.focused = focused } } - -pub struct TransportQuantize { - pub _engine: PhantomData, - pub value: usize, - pub focused: bool -} -impl Focusable for TransportQuantize { - fn is_focused (&self) -> bool { - self.focused - } - fn set_focused (&mut self, focused: bool) { - self.focused = focused - } -} - -pub struct TransportSync { - pub _engine: PhantomData, - pub value: usize, - pub focused: bool -} -impl Focusable for TransportSync { - fn is_focused (&self) -> bool { - self.focused - } - fn set_focused (&mut self, focused: bool) { - self.focused = focused - } -} - -pub struct TransportClock { - pub _engine: PhantomData, - pub frame: usize, - pub pulse: usize, - pub ppq: usize, - pub usecs: usize, - pub focused: bool, -} -impl Focusable for TransportClock { - fn is_focused (&self) -> bool { - self.focused - } - fn set_focused (&mut self, focused: bool) { - self.focused = focused - } -} - -impl Handle for TransportToolbar { - fn handle (&mut self, from: &Tui) -> Perhaps { - Ok(None) - //Ok( - //from.key(KeyCode::Right).does(||self.focus_next())? - //|| - //from.key(KeyCode::Left).does(||self.focus_prev())? - //|| - //from.key(KeyCode::Char(' ')).does(||self.toggle_play())? - //) - } -} - -impl Handle for TransportPlayPauseButton { - fn handle (&mut self, from: &Tui) -> Perhaps { - Ok(None) - } -} - impl Handle for TransportBPM { fn handle (&mut self, from: &Tui) -> Perhaps { - //TransportFocus::BPM => { - //transport.timebase.bpm.fetch_add(1.0, Ordering::Relaxed); - //}, - //TransportFocus::BPM => { - //transport.timebase.bpm.fetch_sub(1.0, Ordering::Relaxed); - //}, - Ok(None) + match from.event() { + key!(KeyCode::Char(',')) => { + self.bpm().fetch_sub(1.0, Ordering::Relaxed); + Ok(Some(true)) + }, + key!(KeyCode::Char('.')) => { + self.bpm().fetch_add(1.0, Ordering::Relaxed); + Ok(Some(true)) + }, + _ => Ok(None) + } } } - -impl Handle for TransportQuantize { - fn handle (&mut self, from: &Tui) -> Perhaps { - //TransportFocus::Quant => { - //transport.quant.value = next_note_length(transport.quant) - //}, - //TransportFocus::Quant => { - //transport.quant.value = prev_note_length(transport.quant); - //}, - Ok(None) - } -} - -impl Handle for TransportSync { - fn handle (&mut self, from: &Tui) -> Perhaps { - //TransportFocus::Sync => { - //transport.sync.value = next_note_length(transport.sync) - //}, - //TransportFocus::Sync => { - //transport.sync.value = prev_note_length(transport.sync); - //}, - Ok(None) - } -} - -impl Handle for TransportClock { - fn handle (&mut self, from: &Tui) -> Perhaps { - //TransportFocus::Sync => { - //transport.sync.value = next_note_length(transport.sync) - //}, - //TransportFocus::Sync => { - //transport.sync.value = prev_note_length(transport.sync); - //}, - Ok(None) - } -} - -const CORNERS: Corners = Corners(NOT_DIM_GREEN); - -impl Content for TransportToolbar { - type Engine = Tui; - fn content (&self) -> impl Widget { - Split::right(|add|{ - add(&self.playing)?; - add(&self.bpm)?; - add(&self.quant)?; - add(&self.sync)?; - add(&self.clock)?; - Ok(()) - }) - } -} - -impl Content for TransportPlayPauseButton { - type Engine = Tui; - fn content (&self) -> impl Widget { - Layers::new(|add|{ - //add(&self.focused.then_some(CORNERS))?; - add(&Styled(match self.value { - Some(TransportState::Stopped) => Some(GRAY_DIM.bold()), - Some(TransportState::Starting) => Some(GRAY_NOT_DIM_BOLD), - Some(TransportState::Rolling) => Some(WHITE_NOT_DIM_BOLD), - _ => unreachable!(), - }, match self.value { - Some(TransportState::Rolling) => "▶ PLAYING", - Some(TransportState::Starting) => "READY ...", - Some(TransportState::Stopped) => "⏹ STOPPED", - _ => unreachable!(), - }))?; - Ok(()) - }) - } -} - impl Widget for TransportBPM { type Engine = Tui; fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { @@ -389,6 +288,36 @@ impl Widget for TransportBPM { } } +/////////////////////////////////////////////////////////////////////////////////////////////////// + +pub struct TransportQuantize { + pub _engine: PhantomData, + pub value: usize, + pub focused: bool +} +impl Focusable for TransportQuantize { + fn is_focused (&self) -> bool { + self.focused + } + fn set_focused (&mut self, focused: bool) { + self.focused = focused + } +} +impl Handle for TransportQuantize { + fn handle (&mut self, from: &Tui) -> Perhaps { + match from.event() { + key!(KeyCode::Char(',')) => { + transport.quant.value = prev_note_length(transport.quant); + Ok(Some(true)) + }, + key!(KeyCode::Char('.')) => { + transport.quant.value = next_note_length(transport.quant); + Ok(Some(true)) + }, + _ => Ok(None) + } + } +} impl Widget for TransportQuantize { type Engine = Tui; fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { @@ -412,6 +341,36 @@ impl Widget for TransportQuantize { } } +/////////////////////////////////////////////////////////////////////////////////////////////////// + +pub struct TransportSync { + pub _engine: PhantomData, + pub value: usize, + pub focused: bool +} +impl Focusable for TransportSync { + fn is_focused (&self) -> bool { + self.focused + } + fn set_focused (&mut self, focused: bool) { + self.focused = focused + } +} +impl Handle for TransportSync { + fn handle (&mut self, from: &Tui) -> Perhaps { + match from.event() { + key!(KeyCode::Char(',')) => { + transport.sync.value = prev_note_length(transport.quant); + Ok(Some(true)) + }, + key!(KeyCode::Char('.')) => { + transport.sync.value = next_note_length(transport.quant); + Ok(Some(true)) + }, + _ => Ok(None) + } + } +} impl Widget for TransportSync { type Engine = Tui; fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { @@ -435,6 +394,29 @@ impl Widget for TransportSync { } } +/////////////////////////////////////////////////////////////////////////////////////////////////// + +pub struct TransportClock { + pub _engine: PhantomData, + pub frame: usize, + pub pulse: usize, + pub ppq: usize, + pub usecs: usize, + pub focused: bool, +} +impl Focusable for TransportClock { + fn is_focused (&self) -> bool { + self.focused + } + fn set_focused (&mut self, focused: bool) { + self.focused = focused + } +} +impl Handle for TransportClock { + fn handle (&mut self, from: &Tui) -> Perhaps { + Ok(None) + } +} impl Widget for TransportClock { type Engine = Tui; fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { @@ -462,3 +444,34 @@ impl Widget for TransportClock { Ok(Some(area)) } } +impl Handle for TransportPlayPauseButton { + fn handle (&mut self, from: &Tui) -> Perhaps { + match from.event() { + key!(KeyCode::Enter) => { + self.toggle(); + Ok(Some(true)) + } + _ => Ok(None) + } + } +} +impl Content for TransportPlayPauseButton { + type Engine = Tui; + fn content (&self) -> impl Widget { + Layers::new(|add|{ + //add(&self.focused.then_some(CORNERS))?; + add(&Styled(match self.value { + Some(TransportState::Stopped) => Some(GRAY_DIM.bold()), + Some(TransportState::Starting) => Some(GRAY_NOT_DIM_BOLD), + Some(TransportState::Rolling) => Some(WHITE_NOT_DIM_BOLD), + _ => unreachable!(), + }, match self.value { + Some(TransportState::Rolling) => "▶ PLAYING", + Some(TransportState::Starting) => "READY ...", + Some(TransportState::Stopped) => "⏹ STOPPED", + _ => unreachable!(), + }))?; + Ok(()) + }) + } +}