use crate::*; impl_from!(AppCmd: |x: AxisCmd| AppCmd::Axis { command: x }); impl_from!(AppCmd: |x: BrowseCmd| AppCmd::Browse { command: x }); impl_from!(AppCmd: |x: MidiClipCmd| AppCmd::MidiClip { command: x }); impl_from!(AppCmd: |x: MidiEditCmd| AppCmd::MidiEdit { command: x }); impl_from!(AppCmd: |x: ModeCmd| AppCmd::Mode { command: x }); impl_from!(AppCmd: |x: PoolCmd| AppCmd::Pool { command: x }); impl_from!(AppCmd: |x: ProjectCmd| AppCmd::Project { command: x }); impl_from!(AppCmd: |x: SceneCmd| AppCmd::Scene { command: x }); impl_from!(AppCmd: |x: ScenesCmd| AppCmd::Scenes { command: x }); impl_from!(AppCmd: |x: TrackCmd| AppCmd::Track { command: x }); impl_from!(AppCmd: |x: TracksCmd| AppCmd::Tracks { command: x }); #[tek_proc::commands(AppCmd)] impl App { /// Exit the application. #[command(Exit = "exit")] pub fn cmd_exit (&mut self) -> Perhaps { self.exit.exit(); Ok(None) } /// Cancel current selection. #[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps { todo!("cancel") } /// Confirm current selection. #[command(Confirm = "confirm")] pub fn cmd_confirm (&mut self) -> Perhaps { Ok(match self.dialog.clone() { Dialog::Menu(index, items) => { for command in items[index].1.iter() { App::cmd_dispatch(self, command.clone())?; } None } _ => todo!(), }) } /// Swap currently active modal dialog. /// /// ``` /// let _ = tek::App::default().cmd_dialog(tek::Dialog::welcome()); /// ``` #[command(Dialog = "dialog")] pub fn cmd_dialog (&mut self, dialog: Dialog) -> Perhaps { let mut dialog = dialog.clone(); std::mem::swap(&mut self.dialog, &mut dialog); Ok(Some(AppCmd::Dialog { dialog })) } #[command(Mode = "mode")] pub fn cmd_mode (&mut self, command: ModeCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Project = "session")] pub fn cmd_session (&mut self, command: ProjectCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Axis = "axis")] pub fn cmd_axis (&mut self, command: AxisCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Browse = "browse")] pub fn cmd_browse (&mut self, command: BrowseCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(MidiClip = "clip")] pub fn cmd_midi_clip (&mut self, command: MidiClipCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(MidiEdit = "edit")] pub fn cmd_midi_edit (&mut self, command: MidiEditCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Pool = "pool")] pub fn cmd_pool (&mut self, command: PoolCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Scene = "scene")] pub fn cmd_scene (&mut self, command: SceneCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Scenes = "scenes")] pub fn cmd_scenes (&mut self, command: ScenesCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Track = "track")] pub fn cmd_track (&mut self, command: TrackCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } #[command(Tracks = "tracks")] pub fn cmd_tracks (&mut self, command: TracksCmd) -> Perhaps { Ok(command.dispatch(self)?.map(Into::into)) } } impl ProjectControl for T {} #[tek_proc::commands(ProjectCmd)] pub trait ProjectControl: HasProject { #[command(LoadLast = "load-last")] fn load_last (&mut self) -> Perhaps { todo!() } #[command(Load = "load")] fn load (&mut self) -> Perhaps { todo!() } } impl + Namespace + Namespace>> ClockControl for T {} #[tek_proc::commands(ClockCmd = "clock")] pub trait ClockControl: HasClock + Namespace + Namespace + Namespace> { #[command(SeekUsec = "usec")] fn seek_usec (&mut self, usec: f64) -> Perhaps { self.clock().playhead.update_from_usec(usec); Ok(None) } #[command(SeekSample = "sample")] fn seek_sample (&mut self, sample: f64) -> Perhaps { self.clock().playhead.update_from_sample(sample); Ok(None) } #[command(SeekPulse = "pulse")] fn seek_pulse (&mut self, pulse: f64) -> Perhaps { self.clock().playhead.update_from_pulse(pulse); Ok(None) } #[command(SetBpm = "bpm")] fn set_bpm (&mut self, bpm: f64) -> Perhaps { Ok(Some(ClockCmd::SetBpm { bpm: self.clock().timebase().bpm.set(bpm) })) } #[command(SetQuant = "quant")] fn set_quant (&mut self, quant: f64) -> Perhaps { Ok(Some(ClockCmd::SetQuant { quant: self.clock().quant.set(quant) })) } #[command(SetSync = "sync")] fn set_sync (&mut self, sync: f64) -> Perhaps { Ok(Some(ClockCmd::SetSync { sync: self.clock().sync.set(sync) })) } #[command(Play = "play")] fn play (&mut self, position: Option) -> Perhaps { self.clock().play_from(position)?; Ok(None) /* TODO Some(Pause(previousPosition)) */ } #[command(Pause = "pause")] fn pause (&mut self, position: Option) -> Perhaps { self.clock().pause_at(position)?; Ok(None) } #[command(TogglePlayback = "toggle")] fn toggle (&mut self, position: u32) -> Perhaps { Ok(if self.clock().is_rolling() { self.clock().pause_at(Some(position))?; None } else { self.clock().play_from(Some(position))?; None }) } } impl + Namespace + Namespace> + Namespace> + Namespace>> + Namespace> + Namespace>> + Namespace>>>>> > TracksControl for T {} #[tek_proc::commands(TracksCmd)] pub trait TracksControl: HasTracks + HasScenes + HasSelection + HasJack<'static> + Namespace + Namespace> + Namespace> + Namespace>> + Namespace> + Namespace>> + Namespace>>>>> { /// Stop all playing clips #[command(Stop = "stop")] fn tracks_stop_all (&mut self) -> Perhaps { for track in self.tracks_mut().iter_mut() { track.sequencer.enqueue_next(None); } Ok(None) } /// Launch multiple clips #[command(Launch = "launch")] fn tracks_launch ( &mut self, clips: Option>>>> ) -> Perhaps { if let Some(clips) = clips { for (clip, track) in clips.iter().zip(self.tracks_mut()) { track.sequencer.enqueue_next(clip.as_ref()); } } else { for track in self.tracks_mut().iter_mut() { track.sequencer.enqueue_next(None); } } Ok(None) } #[command(Add = "add")] fn tracks_add (&mut self) -> Perhaps where Self: HasScenes + HasJack<'static> { let (_index, _) = self.tracks_add_one(None, None, [].into(), [].into())?; Ok(None) } #[command(Select = "select")] fn track_select (&mut self) -> Perhaps { let tracks = self.tracks().len(); let select = self.selection_mut().select_track(tracks); *self.selection_mut() = select; Ok(None) } #[command(Next = "next")] fn track_select_next (&mut self) -> Perhaps { let tracks = self.tracks().len(); let select = self.selection().select_track_next(tracks); *self.selection_mut() = select; Ok(None) } #[command(Prev = "prev")] fn track_select_prev (&mut self) -> Perhaps { let select = self.selection_mut().select_track_prev(); *self.selection_mut() = select; Ok(None) } } impl + Namespace> + Namespace + Namespace> > TrackControl for T {} #[tek_proc::commands(TrackCmd)] pub trait TrackControl: HasTrack + Namespace + Namespace> + Namespace + Namespace> { #[command(Stop = "track/stop")] fn track_stop (&mut self) -> Perhaps { self.track_mut().map(|track|track.sequencer.enqueue_next(None)); Ok(None) } #[command(SetMute = "track/mute")] fn track_set_mute (&mut self, _mute: Option) -> Perhaps { todo!() } #[command(SetSolo = "track/solo")] fn track_set_solo (&mut self, _solo: Option) -> Perhaps { todo!() } #[command(SetSize = "track/size")] fn track_set_size (&mut self, _size: usize) -> Perhaps { todo!() } #[command(SetZoom = "track/zoom")] fn track_set_zoom (&mut self, _zoom: usize) -> Perhaps { todo!() } #[command(SetName = "track/name")] fn track_set_name (&mut self, name: Arc) -> Perhaps { self.track_mut() .map(|track|swap_value(&mut track.name, &name, |name|TrackCmd::SetName { name })) .transpose() .map(Option::flatten) } #[command(SetColor = "track/color")] fn track_set_color (&mut self, color: ItemTheme) -> Perhaps { self.track_mut() .map(|track|swap_value(&mut track.color, &color, |color|TrackCmd::SetColor { color })) .transpose() .map(Option::flatten) } #[command(SetRec = "track/rec")] fn track_set_rec (&mut self, rec: Option) -> Perhaps { self.track_mut() .map(|track|toggle_bool(&mut track.sequencer.recording, &rec, |rec|TrackCmd::SetRec { rec })) .transpose() .map(Option::flatten) } #[command(SetMon = "track/mon")] fn track_set_mon (&mut self, mon: Option) -> Perhaps { self.track_mut() .map(|track|toggle_bool(&mut track.sequencer.monitoring, &mon, |mon|TrackCmd::SetMon { mon })) .transpose() .map(Option::flatten) } } impl + Namespace + Namespace> + Namespace>> > ScenesControl for T {} #[tek_proc::commands(ScenesCmd)] pub trait ScenesControl: HasScenes + HasTracks + HasTrackScroll + HasSelection + HasJack<'static> + Namespace + Namespace> + Namespace>> { #[command(Add = "add")] fn scenes_add (&mut self) -> Perhaps { let (_index, _) = self.scenes_add_one(None, None)?; Ok(None) } #[command(Select = "select")] fn scene_select (&mut self) -> Perhaps { let scenes = self.scenes().len(); let select = self.selection_mut().select_scene(scenes); *self.selection_mut() = select; Ok(None) } #[command(Next = "next")] fn scene_select_next (&mut self) -> Perhaps { let scenes = self.scenes().len(); let select = self.selection().select_scene_next(scenes); *self.selection_mut() = select; Ok(None) } #[command(Prev = "prev")] fn scene_select_prev (&mut self) -> Perhaps { let select = self.selection_mut().select_scene_prev(); *self.selection_mut() = select; Ok(None) } } impl + Namespace> + Namespace > SceneControl for T {} #[tek_proc::commands(SceneCmd)] pub trait SceneControl: HasScene + Namespace + Namespace> + Namespace { #[command(SetSize = "size")] fn scene_set_size (&mut self, _size: usize) -> Perhaps { todo!() } #[command(SetZoom = "zoom")] fn scene_set_zoom (&mut self, _size: usize) -> Perhaps { todo!() } #[command(SetName = "name")] fn scene_set_name (&mut self, name: Arc) -> Perhaps { Ok(self.scene_mut().map(|scene|swap_value( &mut scene.name, &name, |name|SceneCmd::SetName { name } )).transpose()?.flatten()) } #[command(SetColor = "color")] fn scene_set_color (&mut self, color: ItemTheme) -> Perhaps { Ok(self.scene_mut().map(|scene|swap_value( &mut scene.color, &color, |color|SceneCmd::SetColor { color } )).transpose()?.flatten()) } } #[tek_proc::commands(SamplerCmd = "sampler")] pub trait SamplerControl: HasSampler + Namespace { #[command(RecordToggle = "rec-toggle")] fn record_toggle (&mut self, slot: usize) -> Perhaps where Self: Sized { let sampler = self.sampler_mut(); let recording = sampler.recording.as_ref().map(|x|x.0); let _ = SamplerCmd::RecordFinish.dispatch(self)?; // autoslice: continue recording at next slot if recording != Some(slot) { SamplerCmd::RecordBegin { slot }.dispatch(self) } else { Ok(None) } } #[command(RecordBegin = "rec-begin")] fn record_begin (&mut self, slot: usize) -> Perhaps { let sampler = self.sampler_mut(); sampler.recording = Some(( slot, Some(Arc::new(RwLock::new(Sample::new( "Sample", 0, 0, vec![vec![]; sampler.audio_ins.len()] )))) )); Ok(None) } #[command(RecordFinish = "rec-finish")] fn record_finish (&mut self) -> Perhaps { let sampler = self.sampler_mut(); let _prev_sample = sampler.recording.as_mut().map(|(index, sample)|{ std::mem::swap(sample, &mut sampler.samples.0[*index]); sample }); // TODO: undo Ok(None) } #[command(RecordCancel = "rec-cancel")] fn record_cancel (&mut self) -> Perhaps { self.sampler_mut().recording = None; Ok(None) } #[command(PlaySample = "sample-play")] fn sample_play (&mut self, slot: usize) -> Perhaps { let sampler = self.sampler_mut(); if let Some(ref sample) = sampler.samples.0[slot] { sampler.voices.try_write().unwrap().push(Sample::play(sample, 0, &u7::from(128))); } Ok(None) } #[command(StopSample = "sample-stop")] fn sample_stop (&mut self, slot: usize) -> Perhaps { todo!(); //Ok(None) } } impl + Namespace + Namespace + Namespace + Namespace> + Namespace>>> > MidiEditControl for T {} #[tek_proc::commands(MidiEditCmd)] pub trait MidiEditControl: HasEditor + Namespace + Namespace + Namespace + Namespace + Namespace> + Namespace>>> { #[command(Toggle = "toggle")] fn edit_toggle (&mut self) -> Perhaps { if self.is_editing() { *self.editor_mut() = None; } else { todo!() } Ok(Some(MidiEditCmd::Toggle)) } #[command(Show = "show")] fn edit_show (&mut self, clip: Option>>) -> Perhaps { Ok(self.editor_mut().as_mut().map(|mut editor|{ editor.set_clip(clip.as_ref()); editor.redraw(); None }).flatten()) } #[command(DeleteNote = "delete")] fn edit_note_delete (&mut self) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.redraw(); todo!() }).flatten()) } #[command(AppendNote = "append")] fn edit_note_append (&mut self, advance: bool) -> Perhaps { Ok(self.editor_mut().as_mut().map(|mut editor|{ editor.put_note(advance); editor.redraw(); None }).flatten()) } #[command(SetNotePos = "note-pos")] fn edit_note_set_pos (&mut self, pos: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_note_pos((pos).min(127)); editor.redraw(); None }).flatten()) } #[command(SetNoteLen = "note-len")] fn edit_note_set_len (&mut self, len: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_note_len(len); editor.redraw(); None }).flatten()) } #[command(SetNoteScroll = "note-scroll")] fn edit_note_set_scroll (&mut self, scroll: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_note_lo((scroll).min(127)); editor.redraw(); None }).flatten()) } #[command(SetTimePos = "time-pos")] fn edit_time_set_pos (&mut self, pos: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_pos(pos); editor.redraw(); None }).flatten()) } #[command(SetTimeScroll = "time-scroll")] fn edit_time_set_scroll (&mut self, scroll: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_start(scroll); editor.redraw(); None }).flatten()) } #[command(SetTimeZoom = "time-zoom")] fn edit_time_set_zoom (&mut self, zoom: usize) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_zoom(zoom); editor.redraw(); None }).flatten()) } #[command(SetTimeLock = "time-lock")] fn edit_time_set_lock (&mut self, lock: bool) -> Perhaps { Ok(self.editor_mut().as_mut().map(|editor|{ editor.set_time_lock(lock); editor.redraw(); None }).flatten()) } // TODO: 1-9 seek markers that by default start every 8th of the clip } impl + Namespace + Namespace> + Namespace + Namespace + Namespace + Namespace > PoolControl for T {} #[tek_proc::commands(PoolCmd = "pool")] pub trait PoolControl: HasPool + Namespace + Namespace + Namespace> + Namespace + Namespace + Namespace + Namespace { /// Toggle visibility of pool #[command(Show = "show")] fn show (&mut self, visible: bool) -> Perhaps { self.pool_mut().visible = visible; Ok(Some(PoolCmd::Show { visible: !visible })) } /// Set selected clip #[command(Select = "select")] fn select (&mut self, index: usize) -> Perhaps { self.pool_mut().set_clip_index(index); Ok(None) } /// Delete a clip from the pool #[command(Delete = "delete")] fn delete (&mut self, index: usize) -> Perhaps { let clip = self.pool_mut().clips_mut().remove(index).try_read().unwrap().clone(); Ok(Some(PoolCmd::Add { index, clip })) } /// Switch places of two clips in pool #[command(Swap = "swap")] fn swap (&mut self, index: usize, other: usize) -> Perhaps { self.pool_mut().clips_mut().swap(index, other); Ok(Some(PoolCmd::Swap { index, other })) } /// Add clip to pool #[command(Add = "add")] fn clip_add (&mut self, index: usize, clip: MidiClip) -> Perhaps { let mut index = index; let clip = Arc::new(RwLock::new(clip.clone())); let mut clips = self.pool_mut().clips_mut(); if index >= clips.len() { index = clips.len(); clips.push(clip) } else { clips.insert(index, clip); } Ok(Some(PoolCmd::Delete { index })) } /// Set name of clip #[command(SetName = "set-name")] fn clip_set_name (&mut self, index: usize, name: Arc) -> Perhaps { let clip = &mut self.pool_mut().clips_mut()[index]; let old_name = clip.try_read().unwrap().name.clone(); clip.try_write().unwrap().name = name.clone(); Ok(Some(PoolCmd::SetName { index, name: old_name })) } /// Set length of clip #[command(SetLength = "set-length")] fn clip_set_length (&mut self, index: usize, length: usize) -> Perhaps { let clip = &mut self.pool_mut().clips_mut()[index]; let old_len = clip.try_read().unwrap().length; clip.try_write().unwrap().length = length; Ok(Some(PoolCmd::SetLength { index, length: old_len })) } /// Set color of clip #[command(SetColor = "set-color")] fn clip_set_color (&mut self, index: usize, color: ItemColor) -> Perhaps { let mut color = ItemTheme::from(color); std::mem::swap(&mut color, &mut self.pool().clips()[index].try_write().unwrap().color); Ok(Some(PoolCmd::SetColor { index, color: color.base })) } /// Enter crop mode #[command(CropBegin = "crop/begin")] fn crop_begin (&mut self) -> Perhaps { let index = self.pool().clip_index(); let length = self.pool().clips()[index].try_read().unwrap().length; *self.pool_mut().mode_mut() = Some(PoolMode::Length(index, length, ClipLengthFocus::Bar)); Ok(None) } /// Exit crop mode, discard #[command(CropCancel = "crop/cancel")] fn crop_cancel (&mut self) -> Perhaps { if let Some(PoolMode::Length(..)) = self.pool_mut().mode_mut().clone() { *self.pool_mut().mode_mut() = None; } Ok(None) } #[command(CropSet = "crop/set")] fn crop_set (&mut self, _length: usize) -> Perhaps { if let Some(PoolMode::Length(clip, ref mut length, ref mut _focus)) = self.pool_mut().mode_mut().clone() { let old_length; { let clip = self.pool().clips()[clip].clone();//.try_write().unwrap(); old_length = Some(clip.try_read().unwrap().length); clip.try_write().unwrap().length = *length; } *self.pool_mut().mode_mut() = None; return Ok(old_length.map(|l|PoolCmd::CropSet { _length: l })) } Ok(None) } #[command(CropNext = "crop/next")] fn crop_next (&mut self) -> Perhaps { if let Some(PoolMode::Length( _clip, ref mut _length, ref mut focus )) = self.pool_mut().mode_mut().clone() { focus.next() }; Ok(None) } #[command(CropPrev = "crop/prev")] fn crop_prev (&mut self) -> Perhaps { if let Some(PoolMode::Length( _clip, ref mut _length, ref mut focus )) = self.pool_mut().mode_mut().clone() { focus.prev() }; Ok(None) } #[command(CropInc = "crop/inc")] fn crop_inc (&mut self) -> Perhaps { if let Some(PoolMode::Length( _clip, ref mut length, ref mut focus )) = self.pool_mut().mode_mut().clone() { match focus { ClipLengthFocus::Bar => { *length += 4 * PPQ }, ClipLengthFocus::Beat => { *length += PPQ }, ClipLengthFocus::Tick => { *length += 1 }, } } Ok(None) } #[command(CropDec = "crop/dec")] fn crop_dec (&mut self) -> Perhaps { if let Some(PoolMode::Length( _clip, ref mut length, ref mut focus )) = self.pool_mut().mode_mut().clone() { match focus { ClipLengthFocus::Bar => { *length = length.saturating_sub(4 * PPQ) }, ClipLengthFocus::Beat => { *length = length.saturating_sub(PPQ) }, ClipLengthFocus::Tick => { *length = length.saturating_sub(1) }, } } Ok(None) } /// Enter rename mode #[command(RenameBegin = "rename/begin")] fn rename_begin (&mut self) -> Perhaps { let index = self.pool().clip_index(); let name = self.pool().clips()[index].try_read().unwrap().name.clone(); *self.pool_mut().mode_mut() = Some(PoolMode::Rename(index, name)); Ok(None) } /// Exit rename mode, discard #[command(RenameCancel = "rename/cancel")] fn rename_cancel (&mut self) -> Perhaps { if let Some(PoolMode::Rename(clip, ref mut old_name)) = self.pool_mut().mode_mut().clone() { self.pool().clips()[clip].try_write().unwrap().name = old_name.clone().into(); } Ok(None) } /// Exit rename mode, update name #[command(RenameConfirm = "rename/confirm")] fn rename_confirm (&mut self) -> Perhaps { Ok(if let Some(PoolMode::Rename(_clip, ref mut old_name)) = self.pool_mut().mode_mut().clone() { let old_name = old_name.clone(); *self.pool_mut().mode_mut() = None; Some(PoolCmd::RenameSet { value: old_name }) } else { None }) } #[command(RenameSet = "rename/set")] fn rename_set (&mut self, value: Arc) -> Perhaps { if let Some(PoolMode::Rename(clip, ref mut _old_name)) = self.pool_mut().mode_mut().clone() { self.pool().clips()[clip].try_write().unwrap().name = value.clone(); } Ok(None) } ///// Import from file //#[command(Browse = "browse")] //fn browse (&mut self, command: BrowseCmd) -> Perhaps { //Ok(if let Some(browse) = self.pool_mut().browse.as_mut() { //command.act(browse)?.map(|command|PoolCmd::Browse{command}) //} else { //None //}) //} /// Import clip to pool from file #[command(Import = "import")] fn clip_import (&mut self, index: usize, path: PathBuf) -> Perhaps where Self: Sized { let bytes = std::fs::read(&path)?; let smf = Smf::parse(bytes.as_slice())?; let mut t = 0u32; let mut events = vec![]; for track in smf.tracks.iter() { for event in track.iter() { t += event.delta.as_int(); if let TrackEventKind::Midi { channel, message } = event.kind { events.push((t, channel.as_int(), message)); } } } let mut clip = MidiClip::new("imported", true, t as usize + 1, None, None); for event in events.iter() { clip.notes[event.0 as usize].push(event.2); } Ok(PoolCmd::Add { index, clip }.dispatch(self)?) } ///// Export to file //#[command(Export = "export")] //fn export (&mut self, command: BrowseCmd) -> Perhaps { //Ok(if let Some(browse) = self.pool_mut().browse.as_mut() { //command.act(browse)?.map(|command|PoolCmd::Export{command}) //} else { //None //}) //} } impl ModeControl for T where T: HasModeStack + Namespace>> + Namespace> + Namespace {} #[tek_proc::commands(ModeCmd)] pub trait ModeControl: HasModeStack + Namespace>> + Namespace> + Namespace { #[command(Reset = "reset")] fn mode_reset (&mut self, modes: Vec>) -> Perhaps { *self.modes_mut() = modes.into(); Ok(None) } #[command(Push = "push")] fn mode_push (&mut self, mode: Arc) -> Perhaps { self.modes_mut().push(mode); Ok(Some(ModeCmd::Pop)) } #[command(Pop = "pop")] fn mode_pop (&mut self) -> Perhaps { let mode = self.modes_mut().pop(); Ok(mode.map(|mode|ModeCmd::Push { mode })) } } impl> + Namespace> > MidiClipControl for T {} #[tek_proc::commands(MidiClipCmd)] pub trait MidiClipControl: HasClips + Namespace> + Namespace> { /// Create a clip at the current position if it does not already exist. #[command(Upsert = "upsert")] fn clip_upsert (&mut self) -> Perhaps { let clip = self.clip(); //let old = self.scenes[scene].clips[track].clone(); //self.scenes[scene].clips[track] = clip; //old todo!() } #[command(SetColor = "color")] fn clip_set_color (&mut self, color: Option) -> Perhaps { Ok(self.clip().map(|clip|MidiClipCmd::SetColor { color: Some(clip.write().set_color(color)) })) } /// Toggle looping for the active clip #[command(SetLoop = "loop")] fn clip_toggle_loop (&mut self, looping: Option) -> Perhaps { Ok(self.clip().map(|clip|MidiClipCmd::SetLoop { looping: Some(clip.write().toggle_loop(looping)) })) } } impl + Namespace + Namespace>> BrowseControl for T {} #[tek_proc::commands(BrowseCmd = "browse")] pub trait BrowseControl: Namespace + Namespace + Namespace> { /// Toggle visibility of browser #[command(Show = "show")] fn show (&mut self) -> Perhaps { todo!() } /// Set current directory #[command(Chdir = "chdir")] fn chdir (&mut self, _path: PathBuf) -> Perhaps { todo!() } /// Set current filter #[command(SetSearch = "set-search")] fn set_search (&mut self, _filter: Arc) -> Perhaps { todo!() } /// Set selected item #[command(SetCursor = "set-cursor")] fn set_cursor (&mut self, _index: usize) -> Perhaps { todo!() } } #[tek_proc::commands(AxisCmd)] impl App { /// Increment a given data axis. #[command(Inc = "inc")] pub fn inc (&mut self, axis: ControlAxis) -> Perhaps { Ok(match (&self.dialog, axis) { (Dialog::None, _) => todo!(), (Dialog::Menu(_, _), ControlAxis::Y) => { AppCmd::Dialog { dialog: self.dialog.menu_next() }.dispatch(self)?; None }, _ => todo!() }) } /// Decrement a given data axis. #[command(Dec = "dec")] pub fn dec (&mut self, axis: ControlAxis) -> Perhaps { Ok(match (&self.dialog, axis) { (Dialog::None, _) => None, (Dialog::Menu(_, _), ControlAxis::Y) => { AppCmd::Dialog { dialog: self.dialog.menu_prev() }.dispatch(self)?; None }, _ => todo!() }) } }