diff --git a/crates/tek_tui/src/lib.rs b/crates/tek_tui/src/lib.rs index 576ba8a1..92af2e72 100644 --- a/crates/tek_tui/src/lib.rs +++ b/crates/tek_tui/src/lib.rs @@ -238,14 +238,6 @@ impl Debug for PhrasePlayerModel { } } -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum AppFocus { - /// The menu bar is focused - Menu, - /// The app content is focused - Content(T) -} - pub trait FocusWrap { fn wrap <'a, W: Widget> (self, focus: T, content: &'a W) -> impl Widget + 'a; @@ -254,7 +246,7 @@ pub trait FocusWrap { #[macro_export] macro_rules! impl_focus { ($Struct:ident $Focus:ident $Grid:expr) => { impl HasFocus for $Struct { - type Item = AppFocus<$Focus>; + type Item = $Focus; /// Get the currently focused item. fn focused (&self) -> Self::Item { self.focus.inner() @@ -285,8 +277,7 @@ pub trait FocusWrap { fn focus_cursor_mut (&mut self) -> &mut (usize, usize) { &mut self.cursor } - fn focus_layout (&self) -> &[&[AppFocus<$Focus>]] { - use AppFocus::*; + fn focus_layout (&self) -> &[&[$Focus]] { use $Focus::*; &$Grid } diff --git a/crates/tek_tui/src/tui_app_arranger.rs b/crates/tek_tui/src/tui_app_arranger.rs index 99d85670..a8704680 100644 --- a/crates/tek_tui/src/tui_app_arranger.rs +++ b/crates/tek_tui/src/tui_app_arranger.rs @@ -21,7 +21,7 @@ pub struct ArrangerTui { pub note_buf: Vec, pub midi_buf: Vec>>, pub editor: PhraseEditorModel, - pub focus: FocusState>, + pub focus: FocusState, pub perf: PerfModel, } @@ -49,9 +49,7 @@ impl TryFrom<&Arc>> for ArrangerTui { midi_buf: vec![vec![];65536], note_buf: vec![], perf: PerfModel::default(), - focus: FocusState::Entered( - AppFocus::Content(ArrangerFocus::Transport(TransportFocus::PlayPause)) - ), + focus: FocusState::Entered(ArrangerFocus::Transport(TransportFocus::PlayPause)), }) } } @@ -78,23 +76,23 @@ impl_focus!(ArrangerTui ArrangerFocus [ //Menu, //], &[ - Content(Transport(TransportFocus::PlayPause)), - Content(Transport(TransportFocus::Bpm)), - Content(Transport(TransportFocus::Sync)), - Content(Transport(TransportFocus::Quant)), - Content(Transport(TransportFocus::Clock)), + Transport(TransportFocus::PlayPause), + Transport(TransportFocus::Bpm), + Transport(TransportFocus::Sync), + Transport(TransportFocus::Quant), + Transport(TransportFocus::Clock), ], &[ - Content(Arranger), - Content(Arranger), - Content(Arranger), - Content(Arranger), - Content(Arranger), + Arranger, + Arranger, + Arranger, + Arranger, + Arranger, ], &[ - Content(Phrases), - Content(Phrases), - Content(PhraseEditor), - Content(PhraseEditor), - Content(PhraseEditor), + Phrases, + Phrases, + PhraseEditor, + PhraseEditor, + PhraseEditor, ], ]); diff --git a/crates/tek_tui/src/tui_app_sequencer.rs b/crates/tek_tui/src/tui_app_sequencer.rs index 9af929de..50fa62df 100644 --- a/crates/tek_tui/src/tui_app_sequencer.rs +++ b/crates/tek_tui/src/tui_app_sequencer.rs @@ -13,7 +13,7 @@ pub struct SequencerTui { pub entered: bool, pub note_buf: Vec, pub midi_buf: Vec>>, - pub focus: FocusState>, + pub focus: FocusState, pub perf: PerfModel, } @@ -22,21 +22,19 @@ impl TryFrom<&Arc>> for SequencerTui { fn try_from (jack: &Arc>) -> Usually { let clock = ClockModel::from(&Arc::new(jack.read().unwrap().transport())); Ok(Self { - jack: jack.clone(), - phrases: PhrasesModel::default(), - player: PhrasePlayerModel::from(&clock), - editor: PhraseEditorModel::default(), - size: Measure::new(), - cursor: (0, 0), - entered: false, - split: 20, - midi_buf: vec![vec![];65536], - note_buf: vec![], + jack: jack.clone(), + phrases: PhrasesModel::default(), + player: PhrasePlayerModel::from(&clock), + editor: PhraseEditorModel::default(), + size: Measure::new(), + cursor: (0, 0), + entered: false, + split: 20, + midi_buf: vec![vec![];65536], + note_buf: vec![], clock, - perf: PerfModel::default(), - focus: FocusState::Entered( - AppFocus::Content(SequencerFocus::Transport(TransportFocus::PlayPause)) - ), + perf: PerfModel::default(), + focus: FocusState::Focused(SequencerFocus::Transport(TransportFocus::PlayPause)) }) } } @@ -47,9 +45,12 @@ pub enum SequencerFocus { /// The transport (toolbar) is focused Transport(TransportFocus), /// The phrase list (pool) is focused - Phrases, + PhraseList, /// The phrase editor (sequencer) is focused PhraseEditor, + + PhrasePlay, + PhraseNext, } impl_focus!(SequencerTui SequencerFocus [ @@ -61,18 +62,32 @@ impl_focus!(SequencerTui SequencerFocus [ //Menu, //], &[ - Content(Transport(TransportFocus::PlayPause)), - Content(Transport(TransportFocus::Bpm)), - Content(Transport(TransportFocus::Sync)), - Content(Transport(TransportFocus::Quant)), - Content(Transport(TransportFocus::Clock)), + Transport(TransportFocus::PlayPause), + Transport(TransportFocus::Bpm), + Transport(TransportFocus::Sync), + Transport(TransportFocus::Quant), + Transport(TransportFocus::Clock), ], &[ - Content(Phrases), - Content(Phrases), - Content(PhraseEditor), - Content(PhraseEditor), - Content(PhraseEditor), + PhrasePlay, + PhrasePlay, + PhraseEditor, + PhraseEditor, + PhraseEditor, + ], + &[ + PhraseNext, + PhraseNext, + PhraseEditor, + PhraseEditor, + PhraseEditor, + ], + &[ + PhraseList, + PhraseList, + PhraseEditor, + PhraseEditor, + PhraseEditor, ], ]); diff --git a/crates/tek_tui/src/tui_app_transport.rs b/crates/tek_tui/src/tui_app_transport.rs index 330c3eaa..d8ad4ae5 100644 --- a/crates/tek_tui/src/tui_app_transport.rs +++ b/crates/tek_tui/src/tui_app_transport.rs @@ -6,7 +6,7 @@ pub struct TransportTui { pub clock: ClockModel, pub size: Measure, pub cursor: (usize, usize), - pub focus: FocusState>, + pub focus: FocusState, } /// Create app state from JACK handle. @@ -18,9 +18,7 @@ impl TryFrom<&Arc>> for TransportTui { clock: ClockModel::from(&Arc::new(jack.read().unwrap().transport())), size: Measure::new(), cursor: (0, 0), - focus: FocusState::Entered( - AppFocus::Content(TransportFocus::PlayPause) - ) + focus: FocusState::Entered(TransportFocus::PlayPause) }) } } @@ -60,11 +58,11 @@ impl FocusWrap for Option { impl_focus!(TransportTui TransportFocus [ //&[Menu], &[ - Content(PlayPause), - Content(Bpm), - Content(Quant), - Content(Sync), - Content(Clock), + PlayPause, + Bpm, + Quant, + Sync, + Clock, ], ]); diff --git a/crates/tek_tui/src/tui_control_arranger.rs b/crates/tek_tui/src/tui_control_arranger.rs index d61cdc04..40bbb187 100644 --- a/crates/tek_tui/src/tui_control_arranger.rs +++ b/crates/tek_tui/src/tui_control_arranger.rs @@ -142,37 +142,34 @@ fn to_arranger_command (state: &ArrangerTui, input: &TuiInput) -> Option Cmd::Editor(PhraseCommand::Show(state.phrase_to_edit().clone())), _ => match state.focused() { - AppFocus::Menu => { todo!() }, - AppFocus::Content(focused) => match focused { - ArrangerFocus::Transport(_) => { - match TransportCommand::input_to_command(state, input)? { - TransportCommand::Clock(command) => Cmd::Clock(command), - _ => return None, - } - }, - ArrangerFocus::PhraseEditor => { - Cmd::Editor(PhraseCommand::input_to_command(state, input)?) - }, - ArrangerFocus::Phrases => { - Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?) - }, - ArrangerFocus::Arranger => { - use ArrangerSelection::*; - match input.event() { - key!(Char('l')) => Cmd::Clip(ArrangerClipCommand::SetLoop(false)), - key!(Char('+')) => Cmd::Zoom(0), // TODO - key!(Char('=')) => Cmd::Zoom(0), // TODO - key!(Char('_')) => Cmd::Zoom(0), // TODO - key!(Char('-')) => Cmd::Zoom(0), // TODO - key!(Char('`')) => { todo!("toggle state mode") }, - key!(Ctrl-Char('a')) => Cmd::Scene(ArrangerSceneCommand::Add), - key!(Ctrl-Char('t')) => Cmd::Track(ArrangerTrackCommand::Add), - _ => match state.selected() { - Mix => to_arranger_mix_command(input)?, - Track(t) => to_arranger_track_command(input, t)?, - Scene(s) => to_arranger_scene_command(input, s)?, - Clip(t, s) => to_arranger_clip_command(input, t, s)?, - } + ArrangerFocus::Transport(_) => { + match TransportCommand::input_to_command(state, input)? { + TransportCommand::Clock(command) => Cmd::Clock(command), + _ => return None, + } + }, + ArrangerFocus::PhraseEditor => { + Cmd::Editor(PhraseCommand::input_to_command(state, input)?) + }, + ArrangerFocus::Phrases => { + Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?) + }, + ArrangerFocus::Arranger => { + use ArrangerSelection::*; + match input.event() { + key!(Char('l')) => Cmd::Clip(ArrangerClipCommand::SetLoop(false)), + key!(Char('+')) => Cmd::Zoom(0), // TODO + key!(Char('=')) => Cmd::Zoom(0), // TODO + key!(Char('_')) => Cmd::Zoom(0), // TODO + key!(Char('-')) => Cmd::Zoom(0), // TODO + key!(Char('`')) => { todo!("toggle state mode") }, + key!(Ctrl-Char('a')) => Cmd::Scene(ArrangerSceneCommand::Add), + key!(Ctrl-Char('t')) => Cmd::Track(ArrangerTrackCommand::Add), + _ => match state.selected() { + Mix => to_arranger_mix_command(input)?, + Track(t) => to_arranger_track_command(input, t)?, + Scene(s) => to_arranger_scene_command(input, s)?, + Clip(t, s) => to_arranger_clip_command(input, t, s)?, } } } diff --git a/crates/tek_tui/src/tui_control_phrase_editor.rs b/crates/tek_tui/src/tui_control_phrase_editor.rs index 5cbc86d3..8eb91a52 100644 --- a/crates/tek_tui/src/tui_control_phrase_editor.rs +++ b/crates/tek_tui/src/tui_control_phrase_editor.rs @@ -172,12 +172,12 @@ macro_rules! impl_phrase_editor_control { } } impl_phrase_editor_control!(SequencerTui - [AppFocus::Content(SequencerFocus::PhraseEditor)] + [SequencerFocus::PhraseEditor] [self: Some(self.phrases.phrases[self.phrases.phrase.load(Ordering::Relaxed)].clone())] [self, phrase: self.editor.show(phrase)] ); impl_phrase_editor_control!(ArrangerTui - [AppFocus::Content(ArrangerFocus::PhraseEditor)] + [ArrangerFocus::PhraseEditor] [self: todo!()] [self, phrase: todo!()] ); diff --git a/crates/tek_tui/src/tui_control_sequencer.rs b/crates/tek_tui/src/tui_control_sequencer.rs index 1312b73e..b2403116 100644 --- a/crates/tek_tui/src/tui_control_sequencer.rs +++ b/crates/tek_tui/src/tui_control_sequencer.rs @@ -64,21 +64,19 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option match state.focused() { - AppFocus::Menu => { todo!() }, - AppFocus::Content(focused) => match focused { - SequencerFocus::Transport(_) => { - match TransportCommand::input_to_command(state, input)? { - TransportCommand::Clock(command) => Clock(command), - _ => return None, - } - }, - SequencerFocus::Phrases => Phrases( - PhrasesCommand::input_to_command(state, input)? - ), - SequencerFocus::PhraseEditor => Editor( - PhraseCommand::input_to_command(state, input)? - ), - } + SequencerFocus::Transport(_) => { + match TransportCommand::input_to_command(state, input)? { + TransportCommand::Clock(command) => Clock(command), + _ => return None, + } + }, + SequencerFocus::PhraseList => Phrases( + PhrasesCommand::input_to_command(state, input)? + ), + SequencerFocus::PhraseEditor => Editor( + PhraseCommand::input_to_command(state, input)? + ), + _ => todo!() } }) } diff --git a/crates/tek_tui/src/tui_control_transport.rs b/crates/tek_tui/src/tui_control_transport.rs index 1ba73743..f59f750a 100644 --- a/crates/tek_tui/src/tui_control_transport.rs +++ b/crates/tek_tui/src/tui_control_transport.rs @@ -34,30 +34,24 @@ pub trait TransportControl: ClockApi + FocusGrid + HasEnter { impl TransportControl for TransportTui { fn transport_focused (&self) -> Option { - if let AppFocus::Content(focus) = self.focus.inner() { - Some(focus) - } else { - None - } + Some(self.focus.inner()) } } impl TransportControl for SequencerTui { fn transport_focused (&self) -> Option { - if let AppFocus::Content(SequencerFocus::Transport(focus)) = self.focus.inner() { - Some(focus) - } else { - None + match self.focus.inner() { + SequencerFocus::Transport(focus) => Some(focus), + _ => None } } } impl TransportControl for ArrangerTui { fn transport_focused (&self) -> Option { - if let AppFocus::Content(ArrangerFocus::Transport(focus)) = self.focus.inner() { - Some(focus) - } else { - None + match self.focus.inner() { + ArrangerFocus::Transport(focus) => Some(focus), + _ => None } } } diff --git a/crates/tek_tui/src/tui_model_phrase_editor.rs b/crates/tek_tui/src/tui_model_phrase_editor.rs index 906676d1..c66090de 100644 --- a/crates/tek_tui/src/tui_model_phrase_editor.rs +++ b/crates/tek_tui/src/tui_model_phrase_editor.rs @@ -64,7 +64,7 @@ impl HasEditor for SequencerTui { &self.editor } fn editor_focused (&self) -> bool { - self.focused() == AppFocus::Content(SequencerFocus::PhraseEditor) + self.focused() == SequencerFocus::PhraseEditor } fn editor_entered (&self) -> bool { self.entered() && self.editor_focused() @@ -76,7 +76,7 @@ impl HasEditor for ArrangerTui { &self.editor } fn editor_focused (&self) -> bool { - self.focused() == AppFocus::Content(ArrangerFocus::PhraseEditor) + self.focused() == ArrangerFocus::PhraseEditor } fn editor_entered (&self) -> bool { self.entered() && self.editor_focused() diff --git a/crates/tek_tui/src/tui_model_phrase_list.rs b/crates/tek_tui/src/tui_model_phrase_list.rs index 1434a338..a1fe0d7e 100644 --- a/crates/tek_tui/src/tui_model_phrase_list.rs +++ b/crates/tek_tui/src/tui_model_phrase_list.rs @@ -45,7 +45,7 @@ pub trait HasPhraseList: HasPhrases { impl HasPhraseList for SequencerTui { fn phrases_focused (&self) -> bool { - self.focused() == AppFocus::Content(SequencerFocus::Phrases) + self.focused() == SequencerFocus::PhraseList } fn phrases_entered (&self) -> bool { self.entered() && self.phrases_focused() @@ -60,7 +60,7 @@ impl HasPhraseList for SequencerTui { impl HasPhraseList for ArrangerTui { fn phrases_focused (&self) -> bool { - self.focused() == AppFocus::Content(ArrangerFocus::Phrases) + self.focused() == ArrangerFocus::Phrases } fn phrases_entered (&self) -> bool { self.entered() && self.phrases_focused() diff --git a/crates/tek_tui/src/tui_view_arranger.rs b/crates/tek_tui/src/tui_view_arranger.rs index 7dbdaa0a..5795bdf6 100644 --- a/crates/tek_tui/src/tui_view_arranger.rs +++ b/crates/tek_tui/src/tui_view_arranger.rs @@ -71,7 +71,7 @@ pub trait ArrangerViewState { } impl ArrangerViewState for ArrangerTui { fn arranger_focused (&self) -> bool { - self.focused() == AppFocus::Content(ArrangerFocus::Arranger) + self.focused() == ArrangerFocus::Arranger } } diff --git a/crates/tek_tui/src/tui_view_phrase_list.rs b/crates/tek_tui/src/tui_view_phrase_list.rs index 770b0809..8105a71a 100644 --- a/crates/tek_tui/src/tui_view_phrase_list.rs +++ b/crates/tek_tui/src/tui_view_phrase_list.rs @@ -55,7 +55,7 @@ impl<'a> Content for PhraseListView<'a> { }; let row2 = TuiStyle::bold(row2, true); add(&col!(row1, row2).fill_x().bg(color.base.rgb))?; - if *focused && i == *index { + if *entered && i == *index { add(&CORNERS)?; } Ok(()) diff --git a/crates/tek_tui/src/tui_view_phrase_selector.rs b/crates/tek_tui/src/tui_view_phrase_selector.rs index 4f420151..818bc34f 100644 --- a/crates/tek_tui/src/tui_view_phrase_selector.rs +++ b/crates/tek_tui/src/tui_view_phrase_selector.rs @@ -47,10 +47,9 @@ impl<'a> Content for PhraseSelector<'a> { let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color)); let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border); let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)}; - let upper_left = format!("[{}] {title}", if *entered {"■"} else {" "}); lay!( content, - TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(), + TuiStyle::fg(*title, title_color).push_x(1).align_nw().fill_xy(), ) } } diff --git a/crates/tek_tui/src/tui_view_transport.rs b/crates/tek_tui/src/tui_view_transport.rs index a4415031..b52bbb1a 100644 --- a/crates/tek_tui/src/tui_view_transport.rs +++ b/crates/tek_tui/src/tui_view_transport.rs @@ -76,17 +76,14 @@ where impl From<&TransportTui> for Option { fn from (state: &TransportTui) -> Self { - match state.focus.inner() { - AppFocus::Content(focus) => Some(focus), - _ => None - } + Some(state.focus.inner()) } } impl From<&SequencerTui> for Option { fn from (state: &SequencerTui) -> Self { match state.focus.inner() { - AppFocus::Content(SequencerFocus::Transport(focus)) => Some(focus), + SequencerFocus::Transport(focus) => Some(focus), _ => None } } @@ -95,7 +92,7 @@ impl From<&SequencerTui> for Option { impl From<&ArrangerTui> for Option { fn from (state: &ArrangerTui) -> Self { match state.focus.inner() { - AppFocus::Content(ArrangerFocus::Transport(focus)) => Some(focus), + ArrangerFocus::Transport(focus) => Some(focus), _ => None } }