use those macros in some places, a few more to go

This commit is contained in:
🪞👃🪞 2024-12-17 18:35:01 +01:00
parent fdafd15a01
commit 17efdb9b8e
3 changed files with 192 additions and 193 deletions

View file

@ -218,23 +218,16 @@ pub enum TransportCommand {
Clock(ClockCommand), Clock(ClockCommand),
} }
impl Command<TransportTui> for TransportCommand { command!(|self:TransportCommand,state:TransportTui|match self {
fn execute (self, state: &mut TransportTui) -> Perhaps<Self> { //Self::Focus(cmd) => cmd.execute(state)?.map(Self::Focus),
Ok(match self { Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock),
Self::Focus(cmd) => cmd.execute(state)?.map(Self::Focus), _ => unreachable!(),
Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock), });
})
}
}
impl Command<TransportTui> for FocusCommand<TransportFocus> { //command!(|self:TransportFocus,state:TransportTui|{
fn execute (self, state: &mut TransportTui) -> Perhaps<FocusCommand<TransportFocus>> { //if let FocusCommand::Set(to) = self { state.set_focused(to); }
if let FocusCommand::Set(to) = self { //Ok(None)
state.set_focused(to); //});
}
Ok(None)
}
}
impl InputToCommand<Tui, TransportTui> for TransportCommand { impl InputToCommand<Tui, TransportTui> for TransportCommand {
fn input_to_command (state: &TransportTui, input: &TuiInput) -> Option<Self> { fn input_to_command (state: &TransportTui, input: &TuiInput) -> Option<Self> {
@ -262,34 +255,10 @@ where
Pause(Some(0)) Pause(Some(0))
}), }),
_ => match state.transport_focused().unwrap() { _ => match state.transport_focused().unwrap() {
TransportFocus::Bpm => match input.event() { TransportFocus::Bpm => to_bpm_command(input, state.clock().bpm().get())?,
key_pat!(Char(',')) => Clock(SetBpm(state.clock().bpm().get() - 1.0)), TransportFocus::Quant => to_quant_command(input, &state.clock().quant)?,
key_pat!(Char('.')) => Clock(SetBpm(state.clock().bpm().get() + 1.0)), TransportFocus::Sync => to_sync_command(input, &state.clock().sync)?,
key_pat!(Char('<')) => Clock(SetBpm(state.clock().bpm().get() - 0.001)), TransportFocus::Clock => to_seek_command(input)?,
key_pat!(Char('>')) => Clock(SetBpm(state.clock().bpm().get() + 0.001)),
_ => return None,
},
TransportFocus::Quant => match input.event() {
key_pat!(Char(',')) => Clock(SetQuant(state.clock().quant.prev())),
key_pat!(Char('.')) => Clock(SetQuant(state.clock().quant.next())),
key_pat!(Char('<')) => Clock(SetQuant(state.clock().quant.prev())),
key_pat!(Char('>')) => Clock(SetQuant(state.clock().quant.next())),
_ => return None,
},
TransportFocus::Sync => match input.event() {
key_pat!(Char(',')) => Clock(SetSync(state.clock().sync.prev())),
key_pat!(Char('.')) => Clock(SetSync(state.clock().sync.next())),
key_pat!(Char('<')) => Clock(SetSync(state.clock().sync.prev())),
key_pat!(Char('>')) => Clock(SetSync(state.clock().sync.next())),
_ => return None,
},
TransportFocus::Clock => match input.event() {
key_pat!(Char(',')) => todo!("transport seek bar"),
key_pat!(Char('.')) => todo!("transport seek bar"),
key_pat!(Char('<')) => todo!("transport seek beat"),
key_pat!(Char('>')) => todo!("transport seek beat"),
_ => return None,
},
TransportFocus::PlayPause => match input.event() { TransportFocus::PlayPause => match input.event() {
key_pat!(Enter) => Clock( key_pat!(Enter) => Clock(
if state.clock().is_stopped() { if state.clock().is_stopped() {
@ -310,3 +279,43 @@ where
} }
}) })
} }
fn to_bpm_command (input: &TuiInput, bpm: f64) -> Option<TransportCommand> {
Some(match input.event() {
key_pat!(Char(',')) => Clock(SetBpm(bpm - 1.0)),
key_pat!(Char('.')) => Clock(SetBpm(bpm + 1.0)),
key_pat!(Char('<')) => Clock(SetBpm(bpm - 0.001)),
key_pat!(Char('>')) => Clock(SetBpm(bpm + 0.001)),
_ => return None,
})
}
fn to_quant_command (input: &TuiInput, quant: &Quantize) -> Option<TransportCommand> {
Some(match input.event() {
key_pat!(Char(',')) => Clock(SetQuant(quant.prev())),
key_pat!(Char('.')) => Clock(SetQuant(quant.next())),
key_pat!(Char('<')) => Clock(SetQuant(quant.prev())),
key_pat!(Char('>')) => Clock(SetQuant(quant.next())),
_ => return None,
})
}
fn to_sync_command (input: &TuiInput, sync: &LaunchSync) -> Option<TransportCommand> {
Some(match input.event() {
key_pat!(Char(',')) => Clock(SetSync(sync.prev())),
key_pat!(Char('.')) => Clock(SetSync(sync.next())),
key_pat!(Char('<')) => Clock(SetSync(sync.prev())),
key_pat!(Char('>')) => Clock(SetSync(sync.next())),
_ => return None,
})
}
fn to_seek_command (input: &TuiInput) -> Option<TransportCommand> {
Some(match input.event() {
key_pat!(Char(',')) => todo!("transport seek bar"),
key_pat!(Char('.')) => todo!("transport seek bar"),
key_pat!(Char('<')) => todo!("transport seek beat"),
key_pat!(Char('>')) => todo!("transport seek beat"),
_ => return None,
})
}

View file

@ -95,100 +95,94 @@ pub enum FileBrowserCommand {
Filter(String), Filter(String),
} }
impl Command<PhraseListModel> for FileBrowserCommand { command!(|self: FileBrowserCommand, state: PhraseListModel|{
fn execute (self, state: &mut PhraseListModel) -> Perhaps<Self> { let mode = state.phrases_mode_mut();
let mode = state.phrases_mode_mut(); match mode {
match mode { Some(Import(index, ref mut browser)) => match self {
Some(Import(index, ref mut browser)) => match self { Cancel => {
Cancel => { *mode = None;
*mode = None;
},
Chdir(cwd) => {
*mode = Some(Import(*index, FileBrowser::new(Some(cwd))?));
},
Select(index) => {
browser.index = index;
},
Confirm => {
if browser.is_file() {
let index = *index;
let path = browser.path();
*mode = None;
PhrasePoolCommand::Import(index, path).execute(state)?;
} else if browser.is_dir() {
*mode = Some(Import(*index, browser.chdir()?));
}
},
_ => todo!(),
}, },
Some(PhraseListMode::Export(index, ref mut browser)) => match self { Chdir(cwd) => {
Cancel => { *mode = Some(Import(*index, FileBrowser::new(Some(cwd))?));
*mode = None;
},
Chdir(cwd) => {
*mode = Some(PhraseListMode::Export(*index, FileBrowser::new(Some(cwd))?));
},
Select(index) => {
browser.index = index;
},
_ => unreachable!()
}, },
_ => unreachable!(), Select(index) => {
}; browser.index = index;
Ok(None) },
} Confirm => {
} if browser.is_file() {
let index = *index;
let path = browser.path();
*mode = None;
PhrasePoolCommand::Import(index, path).execute(state)?;
} else if browser.is_dir() {
*mode = Some(Import(*index, browser.chdir()?));
}
},
_ => todo!(),
},
Some(PhraseListMode::Export(index, ref mut browser)) => match self {
Cancel => {
*mode = None;
},
Chdir(cwd) => {
*mode = Some(PhraseListMode::Export(*index, FileBrowser::new(Some(cwd))?));
},
Select(index) => {
browser.index = index;
},
_ => unreachable!()
},
_ => unreachable!(),
};
None
});
impl InputToCommand<Tui, PhraseListModel> for FileBrowserCommand { input_to_command!(FileBrowserCommand:<Tui>|state:PhraseListModel,from|{
fn input_to_command (state: &PhraseListModel, from: &TuiInput) -> Option<Self> { if let Some(PhraseListMode::Import(_index, browser)) = state.phrases_mode() {
if let Some(PhraseListMode::Import(_index, browser)) = state.phrases_mode() { Some(match from.event() {
Some(match from.event() { key_pat!(Up) => Select(
key_pat!(Up) => Select( browser.index.overflowing_sub(1).0.min(browser.len().saturating_sub(1))
browser.index.overflowing_sub(1).0.min(browser.len().saturating_sub(1)) ),
), key_pat!(Down) => Select(
key_pat!(Down) => Select( browser.index.saturating_add(1) % browser.len()
browser.index.saturating_add(1) % browser.len() ),
), key_pat!(Right) => Chdir(browser.cwd.clone()),
key_pat!(Right) => Chdir(browser.cwd.clone()), key_pat!(Left) => Chdir(browser.cwd.clone()),
key_pat!(Left) => Chdir(browser.cwd.clone()), key_pat!(Enter) => Confirm,
key_pat!(Enter) => Confirm, key_pat!(Char(_)) => { todo!() },
key_pat!(Char(_)) => { todo!() }, key_pat!(Backspace) => { todo!() },
key_pat!(Backspace) => { todo!() }, key_pat!(Esc) => Self::Cancel,
key_pat!(Esc) => Self::Cancel, _ => return None
_ => return None })
}) } else if let Some(PhraseListMode::Export(_index, browser)) = state.phrases_mode() {
} else if let Some(PhraseListMode::Export(_index, browser)) = state.phrases_mode() { Some(match from.event() {
Some(match from.event() { key_pat!(Up) => Select(browser.index.overflowing_sub(1).0.min(browser.len())),
key_pat!(Up) => Select(browser.index.overflowing_sub(1).0.min(browser.len())), key_pat!(Down) => Select(browser.index.saturating_add(1) % browser.len()),
key_pat!(Down) => Select(browser.index.saturating_add(1) % browser.len()), key_pat!(Right) => Chdir(browser.cwd.clone()),
key_pat!(Right) => Chdir(browser.cwd.clone()), key_pat!(Left) => Chdir(browser.cwd.clone()),
key_pat!(Left) => Chdir(browser.cwd.clone()), key_pat!(Enter) => Confirm,
key_pat!(Enter) => Confirm, key_pat!(Char(_)) => { todo!() },
key_pat!(Char(_)) => { todo!() }, key_pat!(Backspace) => { todo!() },
key_pat!(Backspace) => { todo!() }, key_pat!(Esc) => Self::Cancel,
key_pat!(Esc) => Self::Cancel, _ => return None
_ => return None })
}) } else {
} else { unreachable!()
unreachable!()
}
} }
} });
impl InputToCommand<Tui, PhraseListModel> for PhraseLengthCommand { input_to_command!(PhraseLengthCommand:<Tui>|state:PhraseListModel,from|{
fn input_to_command (state: &PhraseListModel, from: &TuiInput) -> Option<Self> { if let Some(PhraseListMode::Length(_, length, _)) = state.phrases_mode() {
if let Some(PhraseListMode::Length(_, length, _)) = state.phrases_mode() { Some(match from.event() {
Some(match from.event() { key_pat!(Up) => Self::Inc,
key_pat!(Up) => Self::Inc, key_pat!(Down) => Self::Dec,
key_pat!(Down) => Self::Dec, key_pat!(Right) => Self::Next,
key_pat!(Right) => Self::Next, key_pat!(Left) => Self::Prev,
key_pat!(Left) => Self::Prev, key_pat!(Enter) => Self::Set(*length),
key_pat!(Enter) => Self::Set(*length), key_pat!(Esc) => Self::Cancel,
key_pat!(Esc) => Self::Cancel, _ => return None
_ => return None })
}) } else {
} else { unreachable!()
unreachable!()
}
} }
} });

View file

@ -50,68 +50,64 @@ pub enum PhrasesCommand {
Export(Browse), Export(Browse),
} }
impl Command<PhraseListModel> for PhrasesCommand { command!(|self:PhrasesCommand, state:PhraseListModel|{
fn execute (self, state: &mut PhraseListModel) -> Perhaps<Self> { use PhrasesCommand::*;
use PhrasesCommand::*; match self {
Ok(match self { Phrase(command) => command.execute(state)?.map(Phrase),
Phrase(command) => command.execute(state)?.map(Phrase), Rename(command) => match command {
Rename(command) => match command { PhraseRenameCommand::Begin => {
PhraseRenameCommand::Begin => { let length = state.phrases()[state.phrase_index()].read().unwrap().length;
let length = state.phrases()[state.phrase_index()].read().unwrap().length; *state.phrases_mode_mut() = Some(
*state.phrases_mode_mut() = Some( PhraseListMode::Length(state.phrase_index(), length, PhraseLengthFocus::Bar)
PhraseListMode::Length(state.phrase_index(), length, PhraseLengthFocus::Bar) );
);
None
},
_ => command.execute(state)?.map(Rename)
},
Length(command) => match command {
PhraseLengthCommand::Begin => {
let name = state.phrases()[state.phrase_index()].read().unwrap().name.clone();
*state.phrases_mode_mut() = Some(
PhraseListMode::Rename(state.phrase_index(), name)
);
None
},
_ => command.execute(state)?.map(Length)
},
Import(command) => match command {
FileBrowserCommand::Begin => {
*state.phrases_mode_mut() = Some(
PhraseListMode::Import(state.phrase_index(), FileBrowser::new(None)?)
);
None
},
_ => command.execute(state)?.map(Import)
},
Export(command) => match command {
FileBrowserCommand::Begin => {
*state.phrases_mode_mut() = Some(
PhraseListMode::Export(state.phrase_index(), FileBrowser::new(None)?)
);
None
},
_ => command.execute(state)?.map(Export)
},
Select(phrase) => {
state.set_phrase_index(phrase);
None None
}, },
}) _ => command.execute(state)?.map(Rename)
},
Length(command) => match command {
PhraseLengthCommand::Begin => {
let name = state.phrases()[state.phrase_index()].read().unwrap().name.clone();
*state.phrases_mode_mut() = Some(
PhraseListMode::Rename(state.phrase_index(), name)
);
None
},
_ => command.execute(state)?.map(Length)
},
Import(command) => match command {
FileBrowserCommand::Begin => {
*state.phrases_mode_mut() = Some(
PhraseListMode::Import(state.phrase_index(), FileBrowser::new(None)?)
);
None
},
_ => command.execute(state)?.map(Import)
},
Export(command) => match command {
FileBrowserCommand::Begin => {
*state.phrases_mode_mut() = Some(
PhraseListMode::Export(state.phrase_index(), FileBrowser::new(None)?)
);
None
},
_ => command.execute(state)?.map(Export)
},
Select(phrase) => {
state.set_phrase_index(phrase);
None
},
} }
} });
impl InputToCommand<Tui, PhraseListModel> for PhrasesCommand { input_to_command!(PhrasesCommand:<Tui>|state:PhraseListModel,input|{
fn input_to_command (state: &PhraseListModel, input: &TuiInput) -> Option<Self> { Some(match state.phrases_mode() {
Some(match state.phrases_mode() { Some(PhraseListMode::Rename(..)) => Self::Rename(Rename::input_to_command(state, input)?),
Some(PhraseListMode::Rename(..)) => Self::Rename(Rename::input_to_command(state, input)?), Some(PhraseListMode::Length(..)) => Self::Length(Length::input_to_command(state, input)?),
Some(PhraseListMode::Length(..)) => Self::Length(Length::input_to_command(state, input)?), Some(PhraseListMode::Import(..)) => Self::Import(Browse::input_to_command(state, input)?),
Some(PhraseListMode::Import(..)) => Self::Import(Browse::input_to_command(state, input)?), Some(PhraseListMode::Export(..)) => Self::Export(Browse::input_to_command(state, input)?),
Some(PhraseListMode::Export(..)) => Self::Export(Browse::input_to_command(state, input)?), _ => to_phrases_command(state, input)?
_ => to_phrases_command(state, input)? })
}) });
}
}
fn to_phrases_command (state: &PhraseListModel, input: &TuiInput) -> Option<PhrasesCommand> { fn to_phrases_command (state: &PhraseListModel, input: &TuiInput) -> Option<PhrasesCommand> {
use KeyCode::{Up, Down, Delete, Char}; use KeyCode::{Up, Down, Delete, Char};