extract input parse functions

This commit is contained in:
🪞👃🪞 2024-11-23 20:25:53 +01:00
parent 5ccc55a76f
commit a509db7215
3 changed files with 206 additions and 206 deletions

View file

@ -17,6 +17,7 @@ pub enum TransportFocus {
Clock, Clock,
Quant, Quant,
} }
/// Sections in the sequencer app that may be focused /// Sections in the sequencer app that may be focused
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum SequencerFocus { pub enum SequencerFocus {
@ -27,6 +28,7 @@ pub enum SequencerFocus {
/// The phrase editor (sequencer) is focused /// The phrase editor (sequencer) is focused
PhraseEditor, PhraseEditor,
} }
/// Sections in the arranger app that may be focused /// Sections in the arranger app that may be focused
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ArrangerFocus { pub enum ArrangerFocus {
@ -67,27 +69,6 @@ impl FocusWrap<TransportFocus> for Option<TransportFocus> {
} }
} }
impl TransportFocus {
pub fn next (&mut self) {
*self = match self {
Self::PlayPause => Self::Bpm,
Self::Bpm => Self::Quant,
Self::Quant => Self::Sync,
Self::Sync => Self::Clock,
Self::Clock => Self::PlayPause,
}
}
pub fn prev (&mut self) {
*self = match self {
Self::PlayPause => Self::Clock,
Self::Bpm => Self::PlayPause,
Self::Quant => Self::Bpm,
Self::Sync => Self::Quant,
Self::Clock => Self::Sync,
}
}
}
macro_rules! impl_focus { macro_rules! impl_focus {
($Struct:ident $Focus:ident $Grid:expr) => { ($Struct:ident $Focus:ident $Grid:expr) => {
impl HasFocus for $Struct { impl HasFocus for $Struct {
@ -132,24 +113,26 @@ macro_rules! impl_focus {
} }
impl_focus!(TransportTui TransportFocus [ impl_focus!(TransportTui TransportFocus [
&[Menu], //&[Menu],
&[Content(Bpm), Content(Sync), Content(PlayPause), Content(Clock), Content(Quant)], &[Content(Bpm), Content(Sync), Content(PlayPause), Content(Clock), Content(Quant)],
]); ]);
impl_focus!(SequencerTui SequencerFocus [ impl_focus!(SequencerTui SequencerFocus [
//&[
//Menu,
//Menu,
//Menu,
//Menu,
//Menu,
//],
&[ &[
Menu,
Menu,
Menu,
Menu,
Menu,
], &[
Content(Transport(TransportFocus::Bpm)), Content(Transport(TransportFocus::Bpm)),
Content(Transport(TransportFocus::Sync)), Content(Transport(TransportFocus::Sync)),
Content(Transport(TransportFocus::PlayPause)), Content(Transport(TransportFocus::PlayPause)),
Content(Transport(TransportFocus::Clock)), Content(Transport(TransportFocus::Clock)),
Content(Transport(TransportFocus::Quant)) Content(Transport(TransportFocus::Quant))
], &[ ],
&[
Content(Phrases), Content(Phrases),
Content(Phrases), Content(Phrases),
Content(PhraseEditor), Content(PhraseEditor),
@ -159,13 +142,14 @@ impl_focus!(SequencerTui SequencerFocus [
]); ]);
impl_focus!(ArrangerTui ArrangerFocus [ impl_focus!(ArrangerTui ArrangerFocus [
//&[
//Menu,
//Menu,
//Menu,
//Menu,
//Menu,
//],
&[ &[
Menu,
Menu,
Menu,
Menu,
Menu,
], &[
Content(Transport(TransportFocus::Bpm)), Content(Transport(TransportFocus::Bpm)),
Content(Transport(TransportFocus::Sync)), Content(Transport(TransportFocus::Sync)),
Content(Transport(TransportFocus::PlayPause)), Content(Transport(TransportFocus::PlayPause)),

View file

@ -9,7 +9,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for TransportTui {
clock: ClockModel::from(&Arc::new(jack.read().unwrap().transport())), clock: ClockModel::from(&Arc::new(jack.read().unwrap().transport())),
size: Measure::new(), size: Measure::new(),
cursor: (0, 0), cursor: (0, 0),
focus: FocusState::Entered(AppFocus::Content(TransportFocus::PlayPause)) focus: FocusState::Entered(AppFocus::Content(TransportFocus::Bpm))
}) })
} }
} }
@ -30,7 +30,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui {
midi_buf: vec![vec![];65536], midi_buf: vec![vec![];65536],
note_buf: vec![], note_buf: vec![],
clock, clock,
focus: FocusState::Entered(AppFocus::Content(SequencerFocus::Transport(TransportFocus::PlayPause))) focus: FocusState::Entered(AppFocus::Content(SequencerFocus::Transport(TransportFocus::Bpm)))
}) })
} }
} }
@ -58,7 +58,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for ArrangerTui {
status_bar: None, status_bar: None,
midi_buf: vec![vec![];65536], midi_buf: vec![vec![];65536],
note_buf: vec![], note_buf: vec![],
focus: FocusState::Entered(AppFocus::Content(ArrangerFocus::Transport(TransportFocus::PlayPause))) focus: FocusState::Entered(AppFocus::Content(ArrangerFocus::Transport(TransportFocus::Bpm)))
}) })
} }
} }

View file

@ -1,5 +1,26 @@
use crate::*; use crate::*;
impl<T: TransportControl> InputToCommand<Tui, T> for TransportCommand {
fn input_to_command (state: &T, input: &TuiInput) -> Option<Self> {
to_transport_command(state, input)
.or_else(||to_focus_command(input).map(TransportCommand::Focus))
}
}
impl InputToCommand<Tui, SequencerTui> for SequencerCommand {
fn input_to_command (state: &SequencerTui, input: &TuiInput) -> Option<Self> {
to_sequencer_command(state, input)
.or_else(||to_focus_command(input).map(SequencerCommand::Focus))
}
}
impl InputToCommand<Tui, ArrangerTui> for ArrangerCommand {
fn input_to_command (state: &ArrangerTui, input: &TuiInput) -> Option<Self> {
to_arranger_command(state, input)
.or_else(||to_focus_command(input).map(ArrangerCommand::Focus))
}
}
fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> { fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> {
use KeyCode::{Tab, BackTab, Up, Down, Left, Right, Enter, Esc}; use KeyCode::{Tab, BackTab, Up, Down, Left, Right, Enter, Esc};
Some(match input.event() { Some(match input.event() {
@ -17,8 +38,10 @@ fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> {
}) })
} }
impl<T: TransportControl> InputToCommand<Tui, T> for TransportCommand { fn to_transport_command <T> (state: &T, input: &TuiInput) -> Option<TransportCommand>
fn input_to_command (state: &T, input: &TuiInput) -> Option<Self> { where
T: TransportControl
{
use ClockCommand::{SetBpm, SetQuant, SetSync}; use ClockCommand::{SetBpm, SetQuant, SetSync};
use TransportCommand::{Focus, Clock}; use TransportCommand::{Focus, Clock};
use KeyCode::{Enter, Left, Right, Char}; use KeyCode::{Enter, Left, Right, Char};
@ -63,56 +86,55 @@ impl<T: TransportControl> InputToCommand<Tui, T> for TransportCommand {
}, },
} }
}) })
}
} }
impl InputToCommand<Tui, SequencerTui> for SequencerCommand { fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option<SequencerCommand> {
fn input_to_command (state: &SequencerTui, input: &TuiInput) -> Option<Self> { use SequencerCommand as Cmd;
use SequencerCommand::*; if !state.entered() {
Some(if state.entered() { return None
match state.focused() { }
AppFocus::Menu => todo!(), Some(match state.focused() {
AppFocus::Menu => {
todo!()
},
AppFocus::Content(SequencerFocus::Transport(_)) => { AppFocus::Content(SequencerFocus::Transport(_)) => {
use TransportCommand::{Clock, Focus};
match TransportCommand::input_to_command(state, input)? { match TransportCommand::input_to_command(state, input)? {
Clock(_) => { todo!() }, TransportCommand::Clock(_) => { todo!() },
Focus(_) => { todo!() }, TransportCommand::Focus(command) => Cmd::Focus(command),
} }
}, },
AppFocus::Content(SequencerFocus::Phrases) => AppFocus::Content(SequencerFocus::Phrases) => {
Phrases(PhrasesCommand::input_to_command(state, input)?), Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?)
AppFocus::Content(SequencerFocus::PhraseEditor) => },
Editor(PhraseCommand::input_to_command(state, input)?), AppFocus::Content(SequencerFocus::PhraseEditor) => {
} Cmd::Editor(PhraseCommand::input_to_command(state, input)?)
} else if let Some(command) = to_focus_command(input) { },
Self::Focus(command)
} else {
return None
}) })
}
} }
impl InputToCommand<Tui, ArrangerTui> for ArrangerCommand { fn to_arranger_command (state: &ArrangerTui, input: &TuiInput) -> Option<ArrangerCommand> {
fn input_to_command (state: &ArrangerTui, input: &TuiInput) -> Option<Self> { use ArrangerCommand as Cmd;
Some(if state.entered() { if !state.entered() {
match state.focused() { return None
}
Some(match state.focused() {
AppFocus::Menu => todo!(), AppFocus::Menu => todo!(),
AppFocus::Content(ArrangerFocus::Transport(_)) => { AppFocus::Content(ArrangerFocus::Transport(_)) => {
use TransportCommand::{Clock, Focus}; use TransportCommand::{Clock, Focus};
match TransportCommand::input_to_command(state, input)? { match TransportCommand::input_to_command(state, input)? {
Clock(_) => { todo!() }, Clock(_) => { todo!() },
Focus(_) => { todo!() } Focus(command) => Cmd::Focus(command)
} }
}, },
AppFocus::Content(ArrangerFocus::PhraseEditor) => { AppFocus::Content(ArrangerFocus::PhraseEditor) => {
Self::Editor(PhraseCommand::input_to_command(state, input)?) Cmd::Editor(PhraseCommand::input_to_command(state, input)?)
}, },
AppFocus::Content(ArrangerFocus::Phrases) => match input.event() { AppFocus::Content(ArrangerFocus::Phrases) => match input.event() {
key!(KeyCode::Char('e')) => { key!(KeyCode::Char('e')) => {
Self::EditPhrase(state.phrase_editing().clone()) Cmd::EditPhrase(state.phrase_editing().clone())
}, },
_ => { _ => {
Self::Phrases(PhrasesCommand::input_to_command(state, input)?) Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?)
} }
}, },
AppFocus::Content(ArrangerFocus::Arranger) => { AppFocus::Content(ArrangerFocus::Arranger) => {
@ -122,77 +144,71 @@ impl InputToCommand<Tui, ArrangerTui> for ArrangerCommand {
use ArrangerSceneCommand as Scene; use ArrangerSceneCommand as Scene;
use KeyCode::{Char, Up, Down, Left, Right, Enter, Delete}; use KeyCode::{Char, Up, Down, Left, Right, Enter, Delete};
match input.event() { match input.event() {
key!(Char('e')) => Self::EditPhrase(state.phrase_editing().clone()), key!(Char('e')) => Cmd::EditPhrase(state.phrase_editing().clone()),
key!(Char('l')) => Self::Clip(Clip::SetLoop(false)), key!(Char('l')) => Cmd::Clip(Clip::SetLoop(false)),
key!(Char('+')) => Self::Zoom(0), // TODO key!(Char('+')) => Cmd::Zoom(0), // TODO
key!(Char('=')) => Self::Zoom(0), // TODO key!(Char('=')) => Cmd::Zoom(0), // TODO
key!(Char('_')) => Self::Zoom(0), // TODO key!(Char('_')) => Cmd::Zoom(0), // TODO
key!(Char('-')) => Self::Zoom(0), // TODO key!(Char('-')) => Cmd::Zoom(0), // TODO
key!(Char('`')) => { todo!("toggle state mode") }, key!(Char('`')) => { todo!("toggle state mode") },
key!(Ctrl-Char('a')) => Self::Scene(Scene::Add), key!(Ctrl-Char('a')) => Cmd::Scene(Scene::Add),
key!(Ctrl-Char('t')) => Self::Track(Track::Add), key!(Ctrl-Char('t')) => Cmd::Track(Track::Add),
_ => match state.selected() { _ => match state.selected() {
Select::Mix => match input.event() { Select::Mix => match input.event() {
key!(Down) => Self::Select(Select::Scene(0)), key!(Down) => Cmd::Select(Select::Scene(0)),
key!(Right) => Self::Select(Select::Track(0)), key!(Right) => Cmd::Select(Select::Track(0)),
key!(Char(',')) => Self::Zoom(0), key!(Char(',')) => Cmd::Zoom(0),
key!(Char('.')) => Self::Zoom(0), key!(Char('.')) => Cmd::Zoom(0),
key!(Char('<')) => Self::Zoom(0), key!(Char('<')) => Cmd::Zoom(0),
key!(Char('>')) => Self::Zoom(0), key!(Char('>')) => Cmd::Zoom(0),
key!(Delete) => Self::Clear, key!(Delete) => Cmd::Clear,
key!(Char('c')) => Self::Color(ItemColor::random()), key!(Char('c')) => Cmd::Color(ItemColor::random()),
_ => return None _ => return None
}, },
Select::Track(t) => match input.event() { Select::Track(t) => match input.event() {
key!(Down) => Self::Select(Select::Clip(t, 0)), key!(Down) => Cmd::Select(Select::Clip(t, 0)),
key!(Left) => Self::Select(if t > 0 { Select::Track(t - 1) } else { Select::Mix }), key!(Left) => Cmd::Select(if t > 0 { Select::Track(t - 1) } else { Select::Mix }),
key!(Right) => Self::Select(Select::Track(t + 1)), key!(Right) => Cmd::Select(Select::Track(t + 1)),
key!(Char(',')) => Self::Track(Track::Swap(t, t - 1)), key!(Char(',')) => Cmd::Track(Track::Swap(t, t - 1)),
key!(Char('.')) => Self::Track(Track::Swap(t, t + 1)), key!(Char('.')) => Cmd::Track(Track::Swap(t, t + 1)),
key!(Char('<')) => Self::Track(Track::Swap(t, t - 1)), key!(Char('<')) => Cmd::Track(Track::Swap(t, t - 1)),
key!(Char('>')) => Self::Track(Track::Swap(t, t + 1)), key!(Char('>')) => Cmd::Track(Track::Swap(t, t + 1)),
key!(Delete) => Self::Track(Track::Delete(t)), key!(Delete) => Cmd::Track(Track::Delete(t)),
//key!(Char('c')) => Self::Track(Track::Color(t, ItemColor::random())), //key!(Char('c')) => Cmd::Track(Track::Color(t, ItemColor::random())),
_ => return None _ => return None
}, },
Select::Scene(s) => match input.event() { Select::Scene(s) => match input.event() {
key!(Up) => Self::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }), key!(Up) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }),
key!(Down) => Self::Select(Select::Scene(s + 1)), key!(Down) => Cmd::Select(Select::Scene(s + 1)),
key!(Right) => Self::Select(Select::Clip(0, s)), key!(Right) => Cmd::Select(Select::Clip(0, s)),
key!(Char(',')) => Self::Scene(Scene::Swap(s, s - 1)), key!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)),
key!(Char('.')) => Self::Scene(Scene::Swap(s, s + 1)), key!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)),
key!(Char('<')) => Self::Scene(Scene::Swap(s, s - 1)), key!(Char('<')) => Cmd::Scene(Scene::Swap(s, s - 1)),
key!(Char('>')) => Self::Scene(Scene::Swap(s, s + 1)), key!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)),
key!(Enter) => Self::Scene(Scene::Play(s)), key!(Enter) => Cmd::Scene(Scene::Play(s)),
key!(Delete) => Self::Scene(Scene::Delete(s)), key!(Delete) => Cmd::Scene(Scene::Delete(s)),
//key!(Char('c')) => Self::Track(Scene::Color(s, ItemColor::random())), //key!(Char('c')) => Cmd::Track(Scene::Color(s, ItemColor::random())),
_ => return None _ => return None
}, },
Select::Clip(t, s) => match input.event() { Select::Clip(t, s) => match input.event() {
key!(Up) => Self::Select(if s > 0 { Select::Clip(t, s - 1) } else { Select::Track(t) }), key!(Up) => Cmd::Select(if s > 0 { Select::Clip(t, s - 1) } else { Select::Track(t) }),
key!(Down) => Self::Select(Select::Clip(t, s + 1)), key!(Down) => Cmd::Select(Select::Clip(t, s + 1)),
key!(Left) => Self::Select(if t > 0 { Select::Clip(t - 1, s) } else { Select::Scene(s) }), key!(Left) => Cmd::Select(if t > 0 { Select::Clip(t - 1, s) } else { Select::Scene(s) }),
key!(Right) => Self::Select(Select::Clip(t + 1, s)), key!(Right) => Cmd::Select(Select::Clip(t + 1, s)),
key!(Char(',')) => Self::Clip(Clip::Set(t, s, None)), key!(Char(',')) => Cmd::Clip(Clip::Set(t, s, None)),
key!(Char('.')) => Self::Clip(Clip::Set(t, s, None)), key!(Char('.')) => Cmd::Clip(Clip::Set(t, s, None)),
key!(Char('<')) => Self::Clip(Clip::Set(t, s, None)), key!(Char('<')) => Cmd::Clip(Clip::Set(t, s, None)),
key!(Char('>')) => Self::Clip(Clip::Set(t, s, None)), key!(Char('>')) => Cmd::Clip(Clip::Set(t, s, None)),
key!(Delete) => Self::Clip(Clip::Set(t, s, None)), key!(Delete) => Cmd::Clip(Clip::Set(t, s, None)),
//key!(Char('c')) => Self::Clip(Clip::Color(t, s, ItemColor::random())), //key!(Char('c')) => Cmd::Clip(Clip::Color(t, s, ItemColor::random())),
//key!(Char('g')) => Self::Clip(Clip(Clip::Get(t, s))), //key!(Char('g')) => Cmd::Clip(Clip(Clip::Get(t, s))),
//key!(Char('s')) => Self::Clip(Clip(Clip::Set(t, s))), //key!(Char('s')) => Cmd::Clip(Clip(Clip::Set(t, s))),
_ => return None _ => return None
}, },
} }
} }
} }
}
} else if let Some(command) = to_focus_command(input) {
Self::Focus(command)
} else {
return None
}) })
}
} }
impl<T: PhrasesControl> InputToCommand<Tui, T> for PhrasesCommand { impl<T: PhrasesControl> InputToCommand<Tui, T> for PhrasesCommand {