diff --git a/crates/tek_core/src/focus.rs b/crates/tek_core/src/focus.rs index 495e3271..e65e3293 100644 --- a/crates/tek_core/src/focus.rs +++ b/crates/tek_core/src/focus.rs @@ -12,7 +12,7 @@ pub enum FocusCommand { Exit } -impl Command for FocusCommand { +impl Command for FocusCommand { fn execute (self, state: &mut F) -> Perhaps { use FocusCommand::*; match self { @@ -46,6 +46,12 @@ pub trait HasFocus { self.focus_next() } } + /// Enter the focused item + fn focus_enter (&mut self) {} + /// Exit the focused item + fn focus_exit (&mut self) {} + /// Return the focused item, if any + fn focus_entered (&self) -> Option { None } } /// Trait for things that implement directional focus. @@ -94,7 +100,7 @@ pub trait FocusGrid { impl HasFocus for U where T: Copy + PartialEq + Debug, - U: FocusGrid + FocusEnter, + U: FocusGrid { type Item = T; fn focused (&self) -> Self::Item { @@ -134,11 +140,3 @@ where self.focus_update(); } } - -/// Trait for things that can be focused into. -pub trait FocusEnter { - type Item: Copy + PartialEq + Debug; - fn focus_enter (&mut self) {} - fn focus_exit (&mut self) {} - fn focus_entered (&self) -> Option; -} diff --git a/crates/tek_tui/src/tui_apps.rs b/crates/tek_tui/src/tui_apps.rs index 97216b12..af4767d4 100644 --- a/crates/tek_tui/src/tui_apps.rs +++ b/crates/tek_tui/src/tui_apps.rs @@ -19,6 +19,10 @@ pub struct SequencerTui { pub(crate) cursor: (usize, usize), pub(crate) split: u16, pub(crate) entered: bool, + /// MIDI output buffer + pub(crate) note_buf: Vec, + /// MIDI output buffer + pub(crate) midi_buf: Vec>>, } /// Root view for standalone `tek_arranger` @@ -35,10 +39,12 @@ pub struct ArrangerTui { pub(crate) color: ItemColor, pub(crate) entered: bool, pub(crate) size: Measure, - pub(crate) note_buf: Vec, - pub(crate) midi_buf: Vec>>, pub(crate) cursor: (usize, usize), pub(crate) menu_bar: Option>, pub(crate) status_bar: Option, pub(crate) history: Vec, + /// MIDI output buffer + pub(crate) note_buf: Vec, + /// MIDI output buffer + pub(crate) midi_buf: Vec>>, } diff --git a/crates/tek_tui/src/tui_command.rs b/crates/tek_tui/src/tui_command.rs index 7233775a..072ea264 100644 --- a/crates/tek_tui/src/tui_command.rs +++ b/crates/tek_tui/src/tui_command.rs @@ -38,8 +38,7 @@ pub enum SequencerCommand { impl Command for SequencerCommand where - T: PhrasesControl + PhraseEditorControl + PlayheadApi - + FocusGrid + FocusEnter + T: PhrasesControl + PhraseEditorControl + PlayheadApi + FocusGrid { fn execute (self, state: &mut T) -> Perhaps { use SequencerCommand::*; @@ -70,7 +69,7 @@ pub enum ArrangerCommand { Clip(ArrangerClipCommand), Select(ArrangerSelection), Zoom(usize), - Phrases(PhrasePoolCommand), + Phrases(PhrasesCommand), Editor(PhraseCommand), EditPhrase(Option>>), } @@ -263,10 +262,7 @@ pub enum PhraseCommand { TimeZoomSet(usize), } -impl Command for PhraseCommand -where - T: PhraseEditorControl + FocusEnter -{ +impl Command for PhraseCommand { fn execute (self, state: &mut T) -> Perhaps { use PhraseCommand::*; Ok(match self { diff --git a/crates/tek_tui/src/tui_content.rs b/crates/tek_tui/src/tui_content.rs index 693fa946..abcb8358 100644 --- a/crates/tek_tui/src/tui_content.rs +++ b/crates/tek_tui/src/tui_content.rs @@ -123,9 +123,9 @@ impl<'a, T: PhrasesViewState> Content for PhrasesView<'a, T> { type Engine = Tui; fn content (&self) -> impl Widget { let focused = self.0.phrases_focused(); - let entered = self.0.entered(); + let entered = self.0.phrases_entered(); let phrases = self.0.phrases(); - let selected_phrase = self.0.phrase(); + let selected_phrase = self.0.phrase_index(); let mode = self.0.phrase_mode(); let content = col!( (i, phrase) in phrases.iter().enumerate() => Layers::new(|add|{ @@ -173,7 +173,7 @@ impl<'a, T: PhraseViewState> Content for PhraseView<'a, T> { let phrase = self.0.phrase(); let size = self.0.size(); let focused = self.0.phrase_focused(); - let entered = self.0.entered(); + let entered = self.0.phrase_editor_entered(); let keys = self.0.keys(); let buffer = self.0.buffer(); let note_len = self.0.note_len(); diff --git a/crates/tek_tui/src/tui_control.rs b/crates/tek_tui/src/tui_control.rs index e35eaf25..d34f87a4 100644 --- a/crates/tek_tui/src/tui_control.rs +++ b/crates/tek_tui/src/tui_control.rs @@ -1,6 +1,26 @@ use crate::*; -pub trait TransportControl: ClockApi {} +pub trait TransportControl: ClockApi { + fn transport_focused (&self) -> TransportFocus; +} + +impl TransportControl for TransportTui { + fn transport_focused (&self) -> TransportFocus { + self.state.focus + } +} + +impl TransportControl for SequencerTui { + fn transport_focused (&self) -> TransportFocus { + self.transport.focus + } +} + +impl TransportControl for ArrangerTui { + fn transport_focused (&self) -> TransportFocus { + self.transport.focus + } +} pub trait SequencerControl: TransportControl {} @@ -50,7 +70,7 @@ pub trait PhrasesControl: HasPhrases { } } -pub trait PhraseEditorControl { +pub trait PhraseEditorControl: HasFocus { fn edit_phrase (&self, phrase: &Option>>); fn editing_phrase (&self) -> &Option>>; fn phrase_editor_entered (&self) -> bool; @@ -67,12 +87,6 @@ pub trait PhraseEditorControl { } } -impl TransportControl for TransportTui {} - -impl TransportControl for SequencerTui {} - -impl TransportControl for ArrangerTui {} - impl SequencerControl for SequencerTui {} impl ArrangerControl for ArrangerTui { diff --git a/crates/tek_tui/src/tui_focus.rs b/crates/tek_tui/src/tui_focus.rs index ab6e7b83..56e24cf6 100644 --- a/crates/tek_tui/src/tui_focus.rs +++ b/crates/tek_tui/src/tui_focus.rs @@ -68,27 +68,6 @@ impl TransportFocus { } } -//impl HasFocus for TransportTui { - //type Item = TransportFocus; -//} - -//impl FocusEnter for TransportTui { - //type Item = TransportFocus; - //fn focus_enter (&mut self) { - //self.entered = true; - //} - //fn focus_exit (&mut self) { - //self.entered = false; - //} - //fn focus_entered (&self) -> Option { - //if self.entered { - //Some(self.focused()) - //} else { - //None - //} - //} -//} - impl FocusGrid for TransportTui { type Item = TransportFocus; fn focus_cursor (&self) -> (usize, usize) { @@ -113,29 +92,29 @@ impl FocusGrid for TransportTui { //type Item = SequencerFocus; //} -impl FocusEnter for SequencerTui { - type Item = SequencerFocus; - fn focus_enter (&mut self) { - let focused = self.focused(); - if !self.entered { - self.entered = true; - // TODO - } - } - fn focus_exit (&mut self) { - if self.entered { - self.entered = false; - // TODO - } - } - fn focus_entered (&self) -> Option { - if self.entered { - Some(self.focused()) - } else { - None - } - } -} +//impl FocusEnter for SequencerTui { + //type Item = SequencerFocus; + //fn focus_enter (&mut self) { + //let focused = self.focused(); + //if !self.entered { + //self.entered = true; + //// TODO + //} + //} + //fn focus_exit (&mut self) { + //if self.entered { + //self.entered = false; + //// TODO + //} + //} + //fn focus_entered (&self) -> Option { + //if self.entered { + //Some(self.focused()) + //} else { + //None + //} + //} +//} impl FocusGrid for SequencerTui { type Item = SequencerFocus; @@ -158,34 +137,34 @@ impl FocusGrid for SequencerTui { } } -impl FocusEnter for ArrangerTui { - type Item = ArrangerFocus; - fn focus_enter (&mut self) { - self.entered = true; - //use ArrangerFocus::*; - //let focused = self.focused(); - //if !self.entered { - //self.entered = focused == Arranger; - //self.editor.entered = focused == PhraseEditor; - //self.phrases.entered = focused == Phrases; - //} - } - fn focus_exit (&mut self) { - self.entered = false; +//impl FocusEnter for ArrangerTui { + //type Item = ArrangerFocus; + //fn focus_enter (&mut self) { + //self.entered = true; + ////use ArrangerFocus::*; + ////let focused = self.focused(); + ////if !self.entered { + ////self.entered = focused == Arranger; + ////self.editor.entered = focused == PhraseEditor; + ////self.phrases.entered = focused == Phrases; + ////} + //} + //fn focus_exit (&mut self) { + //self.entered = false; + ////if self.entered { + ////self.entered = false; + ////self.editor.entered = false; + ////self.phrases.entered = false; + ////} + //} + //fn focus_entered (&self) -> Option { //if self.entered { - //self.entered = false; - //self.editor.entered = false; - //self.phrases.entered = false; + //Some(self.focused()) + //} else { + //None //} - } - fn focus_entered (&self) -> Option { - if self.entered { - Some(self.focused()) - } else { - None - } - } -} + //} +//} /// Focus layout of arranger app impl FocusGrid for ArrangerTui { diff --git a/crates/tek_tui/src/tui_handle.rs b/crates/tek_tui/src/tui_handle.rs index 3befacc4..51623103 100644 --- a/crates/tek_tui/src/tui_handle.rs +++ b/crates/tek_tui/src/tui_handle.rs @@ -15,13 +15,13 @@ impl Handle for ArrangerTui { ArrangerCommand::execute_with_state(self, i) } } -impl Handle for PhrasesModel { - fn handle (&mut self, from: &TuiInput) -> Perhaps { - PhrasesCommand::execute_with_state(self, from) - } -} -impl Handle for PhraseEditorModel { - fn handle (&mut self, from: &TuiInput) -> Perhaps { - PhraseCommand::execute_with_state(self, from) - } -} +//impl Handle for PhrasesModel { + //fn handle (&mut self, from: &TuiInput) -> Perhaps { + //PhrasesCommand::execute_with_state(self, from) + //} +//} +//impl Handle for PhraseEditorModel { + //fn handle (&mut self, from: &TuiInput) -> Perhaps { + //PhraseCommand::execute_with_state(self, from) + //} +//} diff --git a/crates/tek_tui/src/tui_impls.rs b/crates/tek_tui/src/tui_impls.rs index 755a14e7..33473a4f 100644 --- a/crates/tek_tui/src/tui_impls.rs +++ b/crates/tek_tui/src/tui_impls.rs @@ -152,6 +152,7 @@ impl_has_phrase!(SequencerTui::player); impl_has_phrase!(ArrangerTrack::player); impl_has_phrase!(PhrasePlayerModel); impl_midi_player!(ArrangerTrack); +impl_midi_player!(PhrasePlayerModel); impl HasScenes for ArrangerTui { fn scenes (&self) -> &Vec { diff --git a/crates/tek_tui/src/tui_init.rs b/crates/tek_tui/src/tui_init.rs index e460a3c7..75c25c1d 100644 --- a/crates/tek_tui/src/tui_init.rs +++ b/crates/tek_tui/src/tui_init.rs @@ -17,15 +17,17 @@ impl TryFrom<&Arc>> for SequencerTui { type Error = Box; fn try_from (jack: &Arc>) -> Usually { Ok(Self { - jack: jack.clone(), - transport: TransportModel::from(jack.read().unwrap().transport()), - phrases: PhrasesModel::default(), - player: PhrasePlayerModel::default(), - editor: PhraseEditorModel::default(), - size: Measure::new(), - cursor: (0, 0), - entered: false, - split: 20, + jack: jack.clone(), + transport: TransportModel::from(jack.read().unwrap().transport()), + phrases: PhrasesModel::default(), + player: PhrasePlayerModel::default(), + editor: PhraseEditorModel::default(), + size: Measure::new(), + cursor: (0, 0), + entered: false, + split: 20, + midi_buf: vec![], + note_buf: vec![], }) } } @@ -34,24 +36,24 @@ impl TryFrom<&Arc>> for ArrangerTui { type Error = Box; fn try_from (jack: &Arc>) -> Usually { Ok(Self { - jack: jack.clone(), - transport: TransportModel::from(jack.read().unwrap().transport()), - phrases: PhrasesModel::default(), - selected: ArrangerSelection::Clip(0, 0), - scenes: vec![], - tracks: vec![], - color: Color::Rgb(28, 35, 25).into(), - history: vec![], - midi_buf: vec![], - note_buf: vec![], - mode: ArrangerMode::Vertical(2), - name: Arc::new(RwLock::new(String::new())), - size: Measure::new(), - cursor: (0, 0), - splits: [20, 20], - entered: false, - menu_bar: None, - status_bar: None, + jack: jack.clone(), + transport: TransportModel::from(jack.read().unwrap().transport()), + phrases: PhrasesModel::default(), + selected: ArrangerSelection::Clip(0, 0), + scenes: vec![], + tracks: vec![], + color: Color::Rgb(28, 35, 25).into(), + history: vec![], + mode: ArrangerMode::Vertical(2), + name: Arc::new(RwLock::new(String::new())), + size: Measure::new(), + cursor: (0, 0), + splits: [20, 20], + entered: false, + menu_bar: None, + status_bar: None, + midi_buf: vec![], + note_buf: vec![], }) } } diff --git a/crates/tek_tui/src/tui_input.rs b/crates/tek_tui/src/tui_input.rs index 41064696..5325a8db 100644 --- a/crates/tek_tui/src/tui_input.rs +++ b/crates/tek_tui/src/tui_input.rs @@ -1,17 +1,12 @@ use crate::*; -impl InputToCommand for TransportCommand -where - T: TransportControl - + HasFocus - + FocusEnter -{ +impl InputToCommand for TransportCommand { fn input_to_command (state: &T, input: &TuiInput) -> Option { use KeyCode::Char; use ClockCommand::{SetBpm, SetQuant, SetSync}; use TransportFocus as Focused; use TransportCommand::{Focus, Clock, Playhead}; - let focused = state.focused(); + let focused = state.transport_focused(); Some(match input.event() { key!(Left) => Focus(FocusCommand::Prev), key!(Right) => Focus(FocusCommand::Next), @@ -57,7 +52,6 @@ where T: SequencerControl + TransportControl + PhrasesControl + PhraseEditorControl + PlayheadApi + HasFocus + FocusGrid - + FocusEnter { fn input_to_command (state: &T, input: &TuiInput) -> Option { use FocusCommand::*; @@ -73,14 +67,11 @@ where key!(KeyCode::Right) => Some(Self::Focus(Right)), _ => Some(match state.focused() { SequencerFocus::Transport => { - use TransportCommand::{Clock, Playhead}; + use TransportCommand::{Clock, Playhead, Focus}; match TransportCommand::input_to_command(state, input)? { - Clock(command) => { - todo!() - }, - Playhead(command) => { - todo!() - }, + Clock(command) => { todo!() }, + Playhead(command) => { todo!() }, + Focus(command) => { todo!() }, } }, SequencerFocus::Phrases => @@ -110,23 +101,21 @@ impl InputToCommand for ArrangerCommand { key!(KeyCode::Esc) => Self::Focus(Exit), key!(KeyCode::Char(' ')) => Self::Playhead(PlayheadCommand::Play(None)), _ => match state.focused() { + ArrangerFocus::Menu => { todo!() }, ArrangerFocus::Transport => { - use TransportCommand::{Clock, Playhead}; + use TransportCommand::{Clock, Playhead, Focus}; match TransportCommand::input_to_command(state, input)? { - Clock(command) => { - todo!() - }, - Playhead(command) => { - todo!() - }, + Clock(command) => { todo!() }, + Playhead(command) => { todo!() }, + Focus(command) => { todo!() } } }, ArrangerFocus::PhraseEditor => Editor( PhraseCommand::input_to_command(state, input)? ), ArrangerFocus::Phrases => match input.event() { - key!(KeyCode::Char('e')) => EditPhrase(Some(state.phrase().clone())), - _ => Phrases(PhrasePoolCommand::input_to_command(state, input)?) + key!(KeyCode::Char('e')) => EditPhrase(state.phrase().clone()), + _ => Phrases(PhrasesCommand::input_to_command(state, input)?) }, ArrangerFocus::Arranger => { use ArrangerSelection as Select; @@ -134,7 +123,7 @@ impl InputToCommand for ArrangerCommand { use ArrangerClipCommand as Clip; use ArrangerSceneCommand as Scene; match input.event() { - key!(KeyCode::Char('e')) => EditPhrase(state.phrase()), + key!(KeyCode::Char('e')) => EditPhrase(state.phrase().clone()), _ => match input.event() { // FIXME: boundary conditions @@ -361,10 +350,7 @@ impl InputToCommand for PhraseRenameCommand { } } -impl InputToCommand for PhraseCommand -where - T: PhraseEditorControl + FocusEnter -{ +impl InputToCommand for PhraseCommand { fn input_to_command (state: &T, from: &TuiInput) -> Option { use PhraseCommand::*; Some(match from.event() { diff --git a/crates/tek_tui/src/tui_jack.rs b/crates/tek_tui/src/tui_jack.rs index c515751a..8d318aa4 100644 --- a/crates/tek_tui/src/tui_jack.rs +++ b/crates/tek_tui/src/tui_jack.rs @@ -11,7 +11,11 @@ impl Audio for SequencerTui { if PlayheadAudio(self).process(client, scope) == Control::Quit { return Control::Quit } - if PlayerAudio(self.player).process(client, scope) == Control::Quit { + if PlayerAudio( + &mut self.player, + &mut self.note_buf, + &mut self.midi_buf, + ).process(client, scope) == Control::Quit { return Control::Quit } Control::Continue @@ -39,14 +43,14 @@ impl Audio for ArrangerTui { let pulse = self.current().pulse.get(); let start = started_at.pulse.get(); let now = (pulse - start) % phrase.length as f64; - self.now.set(now); + self.now().set(now); return Control::Continue } } } } } - self.now.set(0.); + self.now().set(0.); return Control::Continue } } diff --git a/crates/tek_tui/src/tui_model.rs b/crates/tek_tui/src/tui_model.rs index 4887ec7d..8a250618 100644 --- a/crates/tek_tui/src/tui_model.rs +++ b/crates/tek_tui/src/tui_model.rs @@ -56,10 +56,6 @@ pub struct PhrasePlayerModel { pub(crate) midi_ins: Vec>, /// Play from current sequence to MIDI ports pub(crate) midi_outs: Vec>, - /// MIDI output buffer - pub(crate) note_buf: Vec, - /// MIDI output buffer - pub(crate) midi_buf: Vec>>, /// Notes currently held at input pub(crate) notes_in: Arc>, /// Notes currently held at output @@ -79,8 +75,6 @@ impl Default for PhrasePlayerModel { next_phrase: None, notes_in: RwLock::new([false;128]).into(), notes_out: RwLock::new([false;128]).into(), - note_buf: vec![], - midi_buf: vec![], } } } @@ -127,7 +121,7 @@ impl Default for PhraseEditorModel { mode: false, notes_in: RwLock::new([false;128]).into(), notes_out: RwLock::new([false;128]).into(), - now: Instant::default().into(), + now: Pulse::default().into(), size: Measure::new(), note_axis: RwLock::new(FixedAxis { start: 12, @@ -301,7 +295,7 @@ impl PhrasesModel { pub fn new (phrases: Vec>>) -> Self { Self { scroll: 0, - phrase: 0, + phrase: 0.into(), mode: None, focused: false, entered: false, diff --git a/crates/tek_tui/src/tui_status.rs b/crates/tek_tui/src/tui_status.rs index 1680cd23..3a5036b8 100644 --- a/crates/tek_tui/src/tui_status.rs +++ b/crates/tek_tui/src/tui_status.rs @@ -102,7 +102,7 @@ impl StatusBar for ArrangerStatus { ArrangerSelection::Scene(_) => ArrangerStatus::ArrangerScene, ArrangerSelection::Clip(_, _) => ArrangerStatus::ArrangerClip, }, - ArrangerFocus::PhrasePool => ArrangerStatus::PhrasePool, + ArrangerFocus::Phrases => ArrangerStatus::PhrasePool, ArrangerFocus::PhraseEditor => match entered { true => ArrangerStatus::PhraseEdit, false => ArrangerStatus::PhraseView, diff --git a/crates/tek_tui/src/tui_view.rs b/crates/tek_tui/src/tui_view.rs index 17429073..4eb2b765 100644 --- a/crates/tek_tui/src/tui_view.rs +++ b/crates/tek_tui/src/tui_view.rs @@ -30,9 +30,9 @@ pub trait ArrangerViewState { pub trait PhrasesViewState: Send + Sync { fn phrases_focused (&self) -> bool; - fn entered (&self) -> bool; + fn phrases_entered (&self) -> bool; fn phrases (&self) -> Vec>>; - fn phrase (&self) -> usize; + fn phrase_index (&self) -> usize; fn phrase_mode (&self) -> &Option; } @@ -40,7 +40,7 @@ pub trait PhraseViewState: Send + Sync { fn phrase (&self) -> &Option>>; fn phrase_focused (&self) -> bool; fn phrase_editor_size (&self) -> &Measure; - fn entered (&self) -> bool; + fn phrase_editor_entered (&self) -> bool; fn keys (&self) -> &Buffer; fn buffer (&self) -> &BigBuffer; fn note_len (&self) -> usize; @@ -96,13 +96,13 @@ impl PhrasesViewState for PhrasesModel { fn phrases_focused (&self) -> bool { todo!() } - fn entered (&self) -> bool { + fn phrases_entered (&self) -> bool { todo!() } fn phrases (&self) -> Vec>> { todo!() } - fn phrase (&self) -> usize { + fn phrase_index (&self) -> usize { todo!() } fn phrase_mode (&self) -> &Option { @@ -114,13 +114,13 @@ impl PhrasesViewState for SequencerTui { fn phrases_focused (&self) -> bool { todo!() } - fn entered (&self) -> bool { + fn phrases_entered (&self) -> bool { todo!() } fn phrases (&self) -> Vec>> { todo!() } - fn phrase (&self) -> usize { + fn phrase_index (&self) -> usize { todo!() } fn phrase_mode (&self) -> &Option { @@ -132,13 +132,13 @@ impl PhrasesViewState for ArrangerTui { fn phrases_focused (&self) -> bool { todo!() } - fn entered (&self) -> bool { + fn phrases_entered (&self) -> bool { todo!() } fn phrases (&self) -> Vec>> { todo!() } - fn phrase (&self) -> usize { + fn phrase_index (&self) -> usize { todo!() } fn phrase_mode (&self) -> &Option { @@ -156,7 +156,7 @@ impl PhraseViewState for PhraseEditorModel { fn phrase_editor_size (&self) -> &Measure { todo!() } - fn entered (&self) -> bool { + fn phrase_editor_entered (&self) -> bool { self.entered } fn keys (&self) -> &Buffer { @@ -192,7 +192,7 @@ impl PhraseViewState for SequencerTui { fn phrase_editor_size (&self) -> &Measure { todo!() } - fn entered (&self) -> bool { + fn phrase_editor_entered (&self) -> bool { todo!() } fn keys (&self) -> &Buffer { @@ -228,7 +228,7 @@ impl PhraseViewState for ArrangerTui { fn phrase_editor_size (&self) -> &Measure { todo!() } - fn entered (&self) -> bool { + fn phrase_editor_entered (&self) -> bool { todo!() } fn keys (&self) -> &Buffer {