use crate::*; use std::path::PathBuf; type MaybeClip = Option>>; macro_rules! ns { ($C:ty, $s:expr, $a:expr, $W:expr) => { <$C>::try_from_expr($s, $a).map($W) } } macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; } macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; } handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.command(self, input) { let undo = command.execute(self)?; if let Some(undo) = undo { self.history.push(undo); } Some(true) } else { None })); #[tengri_proc::command(App)] impl AppCommand { fn dialog (app: &mut App, dialog: Option) -> Perhaps { app.toggle_dialog(dialog); Ok(None) } fn cancel_dialog (app: &mut App) -> Perhaps { app.toggle_dialog(None); Ok(None) } fn toggle_editor (app: &mut App, value: bool) -> Perhaps { app.toggle_editor(Some(value)); Ok(None) } //fn color (app: &mut App, theme: ItemTheme) -> Perhaps { //Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme})) //} fn enqueue (app: &mut App, clip: Option>>) -> Perhaps { todo!() } fn history (app: &mut App, delta: isize) -> Perhaps { todo!() } fn zoom (app: &mut App, zoom: usize) -> Perhaps { todo!() } //fn launch (app: &mut App) -> Perhaps { //app.project.launch(); //Ok(None) //} fn select (app: &mut App, selection: Selection) -> Perhaps { *app.project.selection_mut() = selection; if let Some(ref mut editor) = app.editor { editor.set_clip(match app.project.selection() { Selection::TrackClip { track, scene } if let Some(Some(Some(clip))) = app .project .scenes.get(*scene) .map(|s|s.clips.get(*track)) => Some(clip), _ => None }); } Ok(None) //("select" [t: usize, s: usize] Some(match (t.expect("no track"), s.expect("no scene")) { //(0, 0) => Self::Select(Selection::Mix), //(t, 0) => Self::Select(Selection::Track(t)), //(0, s) => Self::Select(Selection::Scene(s)), //(t, s) => Self::Select(Selection::TrackClip { track: t, scene: s }) }))) // autoedit: load focused clip in editor. } fn stop_all (app: &mut App) -> Perhaps { app.tracks_stop_all(); Ok(None) } fn sampler (app: &mut App, command: SamplerCommand) -> Perhaps { Ok(app.project.sampler_mut() .map(|s|command.delegate(s, |command|Self::Sampler{command})) .transpose()? .flatten()) } fn project (app: &mut App, command: ArrangementCommand) -> Perhaps { Ok(command.delegate(&mut app.project, |command|Self::Project{command})?) } fn clock (app: &mut App, command: ClockCommand) -> Perhaps { Ok(command.execute(app.clock_mut())?.map(|command|Self::Clock{command})) } fn message (app: &mut App, command: MessageCommand) -> Perhaps { Ok(command.delegate(app, |command|Self::Message{command})?) } fn editor (app: &mut App, command: MidiEditCommand) -> Perhaps { Ok(if let Some(editor) = app.editor.as_mut() { let undo = command.clone().delegate(editor, |command|AppCommand::Editor{command})?; // update linked sampler after editor action app.project.sampler_mut().map(|sampler|match command { // autoselect: automatically select sample in sampler MidiEditCommand::SetNotePos { pos } => { sampler.set_note_pos(pos); }, _ => {} }); undo } else { None }) } fn pool (app: &mut App, command: PoolCommand) -> Perhaps { let undo = command.clone().delegate( &mut app.project.pool, |command|AppCommand::Pool{command} )?; // update linked editor after pool action app.editor.as_mut().map(|editor|match command { // autoselect: automatically load selected clip in editor PoolCommand::Select { .. } | // autocolor: update color in all places simultaneously PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } => editor.set_clip(app.project.pool.clip().as_ref()), _ => {} }); Ok(undo) } } impl<'state> Context<'state, ClockCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { Context::get(&self.clock(), iter) } } impl<'state> Context<'state, MidiEditCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.editor().map(|e|Context::get(e, iter)).flatten() } } impl<'state> Context<'state, PoolCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { Context::get(&self.project.pool, iter) } } impl<'state> Context<'state, SamplerCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.project.sampler().map(|p|Context::get(p, iter)).flatten() } } impl<'state> Context<'state, ArrangementCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { Context::get(&self.project, iter) } } #[tengri_proc::command(App)] impl MessageCommand { fn dismiss (app: &mut App) -> Perhaps { app.dialog = None; Ok(None) } }