collect tek_view, tek_ctrl

This commit is contained in:
i do not exist 2026-09-21 00:16:58 +03:00
parent c5d6ce24b2
commit 186b81f29c
47 changed files with 2665 additions and 2893 deletions

822
src/tek_ctrl.rs Normal file
View file

@ -0,0 +1,822 @@
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<AppCmd> {
self.exit.exit();
Ok(None)
}
/// Cancel current selection.
#[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps<AppCmd> {
todo!("cancel")
}
/// Confirm current selection.
#[command(Confirm = "confirm")] pub fn cmd_confirm (&mut self) -> Perhaps<AppCmd> {
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<AppCmd> {
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<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Project = "session")] pub fn cmd_session (&mut self, command: ProjectCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Axis = "axis")] pub fn cmd_axis (&mut self, command: AxisCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Browse = "browse")] pub fn cmd_browse (&mut self, command: BrowseCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(MidiClip = "clip")] pub fn cmd_midi_clip (&mut self, command: MidiClipCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(MidiEdit = "edit")] pub fn cmd_midi_edit (&mut self, command: MidiEditCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Pool = "pool")] pub fn cmd_pool (&mut self, command: PoolCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Scene = "scene")] pub fn cmd_scene (&mut self, command: SceneCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Scenes = "scenes")] pub fn cmd_scenes (&mut self, command: ScenesCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Track = "track")] pub fn cmd_track (&mut self, command: TrackCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
#[command(Tracks = "tracks")] pub fn cmd_tracks (&mut self, command: TracksCmd) -> Perhaps<AppCmd> {
Ok(command.dispatch(self)?.map(Into::into))
}
}
impl<T: HasProject> ProjectControl for T {}
#[tek_proc::commands(ProjectCmd)] pub trait ProjectControl: HasProject {
#[command(LoadLast = "load-last")] fn load_last (&mut self) -> Perhaps<ProjectCmd> {
todo!()
}
#[command(Load = "load")] fn load (&mut self) -> Perhaps<ProjectCmd> {
todo!()
}
}
impl<T: HasClock + Namespace<u32> + Namespace<f64> + Namespace<Option<u32>>> ClockControl for T {}
#[tek_proc::commands(ClockCmd = "clock")] pub trait ClockControl: HasClock
+ Namespace<u32>
+ Namespace<f64>
+ Namespace<Option<u32>>
{
#[command(SeekUsec = "usec")] fn seek_usec (&mut self, usec: f64) -> Perhaps<ClockCmd> {
self.clock().playhead.update_from_usec(usec);
Ok(None)
}
#[command(SeekSample = "sample")] fn seek_sample (&mut self, sample: f64) -> Perhaps<ClockCmd> {
self.clock().playhead.update_from_sample(sample);
Ok(None)
}
#[command(SeekPulse = "pulse")] fn seek_pulse (&mut self, pulse: f64) -> Perhaps<ClockCmd> {
self.clock().playhead.update_from_pulse(pulse);
Ok(None)
}
#[command(SetBpm = "bpm")] fn set_bpm (&mut self, bpm: f64) -> Perhaps<ClockCmd> {
Ok(Some(ClockCmd::SetBpm {
bpm: self.clock().timebase().bpm.set(bpm)
}))
}
#[command(SetQuant = "quant")] fn set_quant (&mut self, quant: f64) -> Perhaps<ClockCmd> {
Ok(Some(ClockCmd::SetQuant {
quant: self.clock().quant.set(quant)
}))
}
#[command(SetSync = "sync")] fn set_sync (&mut self, sync: f64) -> Perhaps<ClockCmd> {
Ok(Some(ClockCmd::SetSync {
sync: self.clock().sync.set(sync)
}))
}
#[command(Play = "play")] fn play (&mut self, position: Option<u32>) -> Perhaps<ClockCmd> {
self.clock().play_from(position)?;
Ok(None) /* TODO Some(Pause(previousPosition)) */
}
#[command(Pause = "pause")] fn pause (&mut self, position: Option<u32>) -> Perhaps<ClockCmd> {
self.clock().pause_at(position)?;
Ok(None)
}
#[command(TogglePlayback = "toggle")] fn toggle (&mut self, position: u32) -> Perhaps<ClockCmd> {
Ok(if self.clock().is_rolling() {
self.clock().pause_at(Some(position))?;
None
} else {
self.clock().play_from(Some(position))?;
None
})
}
}
impl<T: HasTracks
+ HasScenes
+ HasSelection
+ HasJack<'static>
+ Namespace<usize>
+ Namespace<Arc<[Connect]>>
+ Namespace<Option<usize>>
+ Namespace<Option<Arc<str>>>
+ Namespace<Option<ItemTheme>>
+ Namespace<Option<Arc<[Connect]>>>
+ Namespace<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>>
> TracksControl for T {}
#[tek_proc::commands(TracksCmd)] pub trait TracksControl: HasTracks
+ HasScenes
+ HasSelection
+ HasJack<'static>
+ Namespace<usize>
+ Namespace<Arc<[Connect]>>
+ Namespace<Option<usize>>
+ Namespace<Option<Arc<str>>>
+ Namespace<Option<ItemTheme>>
+ Namespace<Option<Arc<[Connect]>>>
+ Namespace<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>>
{
/// Stop all playing clips
#[command(Stop = "stop")] fn tracks_stop_all (&mut self) -> Perhaps<TracksCmd> {
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<Vec<Option<Arc<RwLock<MidiClip>>>>>
) -> Perhaps<TracksCmd> {
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<TracksCmd>
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<TracksCmd> {
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<TracksCmd> {
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<TracksCmd> {
let select = self.selection_mut().select_track_prev();
*self.selection_mut() = select;
Ok(None)
}
}
impl<T: HasTrack
+ Namespace<usize>
+ Namespace<Arc<str>>
+ Namespace<ItemTheme>
+ Namespace<Option<bool>>
> TrackControl for T {}
#[tek_proc::commands(TrackCmd)] pub trait TrackControl: HasTrack
+ Namespace<usize>
+ Namespace<Arc<str>>
+ Namespace<ItemTheme>
+ Namespace<Option<bool>>
{
#[command(Stop = "track/stop")]
fn track_stop (&mut self) -> Perhaps<TrackCmd> {
self.track_mut().map(|track|track.sequencer.enqueue_next(None));
Ok(None)
}
#[command(SetMute = "track/mute")]
fn track_set_mute (&mut self, _mute: Option<bool>) -> Perhaps<TrackCmd> {
todo!()
}
#[command(SetSolo = "track/solo")]
fn track_set_solo (&mut self, _solo: Option<bool>) -> Perhaps<TrackCmd> {
todo!()
}
#[command(SetSize = "track/size")]
fn track_set_size (&mut self, _size: usize) -> Perhaps<TrackCmd> {
todo!()
}
#[command(SetZoom = "track/zoom")]
fn track_set_zoom (&mut self, _zoom: usize) -> Perhaps<TrackCmd> {
todo!()
}
#[command(SetName = "track/name")]
fn track_set_name (&mut self, name: Arc<str>) -> Perhaps<TrackCmd> {
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<TrackCmd> {
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<bool>) -> Perhaps<TrackCmd> {
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<bool>) -> Perhaps<TrackCmd> {
self.track_mut()
.map(|track|toggle_bool(&mut track.sequencer.monitoring, &mon, |mon|TrackCmd::SetMon { mon }))
.transpose()
.map(Option::flatten)
}
}
impl<T: HasScenes
+ HasTracks
+ HasTrackScroll
+ HasSelection
+ HasJack<'static>
+ Namespace<usize>
+ Namespace<Option<ItemTheme>>
+ Namespace<Option<Arc<str>>>
> ScenesControl for T {}
#[tek_proc::commands(ScenesCmd)] pub trait ScenesControl: HasScenes
+ HasTracks
+ HasTrackScroll
+ HasSelection
+ HasJack<'static>
+ Namespace<usize>
+ Namespace<Option<ItemTheme>>
+ Namespace<Option<Arc<str>>>
{
#[command(Add = "add")] fn scenes_add (&mut self) -> Perhaps<ScenesCmd> {
let (_index, _) = self.scenes_add_one(None, None)?;
Ok(None)
}
#[command(Select = "select")] fn scene_select (&mut self) -> Perhaps<ScenesCmd> {
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<ScenesCmd> {
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<ScenesCmd> {
let select = self.selection_mut().select_scene_prev();
*self.selection_mut() = select;
Ok(None)
}
}
impl<T: HasScene
+ Namespace<usize>
+ Namespace<Arc<str>>
+ Namespace<ItemTheme>
> SceneControl for T {}
#[tek_proc::commands(SceneCmd)] pub trait SceneControl: HasScene
+ Namespace<usize>
+ Namespace<Arc<str>>
+ Namespace<ItemTheme>
{
#[command(SetSize = "size")] fn scene_set_size (&mut self, _size: usize) -> Perhaps<SceneCmd> {
todo!()
}
#[command(SetZoom = "zoom")] fn scene_set_zoom (&mut self, _size: usize) -> Perhaps<SceneCmd> {
todo!()
}
#[command(SetName = "name")] fn scene_set_name (&mut self, name: Arc<str>) -> Perhaps<SceneCmd> {
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<SceneCmd> {
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<usize>
{
#[command(RecordToggle = "rec-toggle")]
fn record_toggle (&mut self, slot: usize) -> Perhaps<SamplerCmd>
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<SamplerCmd> {
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<SamplerCmd> {
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<SamplerCmd> {
self.sampler_mut().recording = None;
Ok(None)
}
#[command(PlaySample = "sample-play")] fn sample_play (&mut self, slot: usize) -> Perhaps<SamplerCmd> {
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<SamplerCmd> {
todo!();
//Ok(None)
}
}
impl<T: HasEditor
+ Namespace<u32>
+ Namespace<f64>
+ Namespace<bool>
+ Namespace<usize>
+ Namespace<Option<u32>>
+ Namespace<Option<Arc<RwLock<MidiClip>>>>
> MidiEditControl for T {}
#[tek_proc::commands(MidiEditCmd)] pub trait MidiEditControl: HasEditor
+ Namespace<u32>
+ Namespace<f64>
+ Namespace<bool>
+ Namespace<usize>
+ Namespace<Option<u32>>
+ Namespace<Option<Arc<RwLock<MidiClip>>>>
{
#[command(Toggle = "toggle")] fn edit_toggle (&mut self) -> Perhaps<MidiEditCmd> {
if self.is_editing() {
*self.editor_mut() = None;
} else {
todo!()
}
Ok(Some(MidiEditCmd::Toggle))
}
#[command(Show = "show")] fn edit_show (&mut self, clip: Option<Arc<RwLock<MidiClip>>>) -> Perhaps<MidiEditCmd> {
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<MidiEditCmd> {
Ok(self.editor_mut().as_mut().map(|editor|{
editor.redraw();
todo!()
}).flatten())
}
#[command(AppendNote = "append")] fn edit_note_append (&mut self, advance: bool) -> Perhaps<MidiEditCmd> {
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<MidiEditCmd> {
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<MidiEditCmd> {
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<MidiEditCmd> {
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<MidiEditCmd> {
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<MidiEditCmd> {
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<MidiEditCmd> {
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<MidiEditCmd> {
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<T: HasPool
+ Namespace<bool>
+ Namespace<usize>
+ Namespace<Arc<str>>
+ Namespace<PathBuf>
+ Namespace<MidiClip>
+ Namespace<ItemColor>
+ Namespace<BrowseCmd>
> PoolControl for T {}
#[tek_proc::commands(PoolCmd = "pool")] pub trait PoolControl: HasPool
+ Namespace<bool>
+ Namespace<usize>
+ Namespace<Arc<str>>
+ Namespace<PathBuf>
+ Namespace<MidiClip>
+ Namespace<ItemColor>
+ Namespace<BrowseCmd>
{
/// Toggle visibility of pool
#[command(Show = "show")] fn show (&mut self, visible: bool) -> Perhaps<PoolCmd> {
self.pool_mut().visible = visible;
Ok(Some(PoolCmd::Show { visible: !visible }))
}
/// Set selected clip
#[command(Select = "select")] fn select (&mut self, index: usize) -> Perhaps<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<str>) -> Perhaps<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<PoolCmd> {
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<str>) -> Perhaps<PoolCmd> {
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<PoolCmd> {
//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<PoolCmd>
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<PoolCmd> {
//Ok(if let Some(browse) = self.pool_mut().browse.as_mut() {
//command.act(browse)?.map(|command|PoolCmd::Export{command})
//} else {
//None
//})
//}
}
impl<T> ModeControl for T where T: HasModeStack
+ Namespace<Vec<Arc<str>>>
+ Namespace<Arc<str>>
+ Namespace<usize>
{}
#[tek_proc::commands(ModeCmd)] pub trait ModeControl: HasModeStack
+ Namespace<Vec<Arc<str>>>
+ Namespace<Arc<str>>
+ Namespace<usize>
{
#[command(Reset = "reset")] fn mode_reset (&mut self, modes: Vec<Arc<str>>) -> Perhaps<ModeCmd> {
*self.modes_mut() = modes.into();
Ok(None)
}
#[command(Push = "push")] fn mode_push (&mut self, mode: Arc<str>) -> Perhaps<ModeCmd> {
self.modes_mut().push(mode);
Ok(Some(ModeCmd::Pop))
}
#[command(Pop = "pop")] fn mode_pop (&mut self) -> Perhaps<ModeCmd> {
let mode = self.modes_mut().pop();
Ok(mode.map(|mode|ModeCmd::Push { mode }))
}
}
impl<T: HasClips + Namespace<Option<bool>> + Namespace<Option<ItemTheme>> > MidiClipControl for T {}
#[tek_proc::commands(MidiClipCmd)] pub trait MidiClipControl: HasClips
+ Namespace<Option<bool>>
+ Namespace<Option<ItemTheme>>
{
/// Create a clip at the current position if it does not already exist.
#[command(Upsert = "upsert")] fn clip_upsert (&mut self) -> Perhaps<MidiClipCmd> {
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<ItemTheme>) -> Perhaps<MidiClipCmd> {
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<bool>) -> Perhaps<MidiClipCmd> {
Ok(self.clip().map(|clip|MidiClipCmd::SetLoop {
looping: Some(clip.write().toggle_loop(looping))
}))
}
}
impl<T: Namespace<usize> + Namespace<PathBuf> + Namespace<Arc<str>>> BrowseControl for T {}
#[tek_proc::commands(BrowseCmd = "browse")] pub trait BrowseControl:
Namespace<usize> +
Namespace<PathBuf> +
Namespace<Arc<str>>
{
/// Toggle visibility of browser
#[command(Show = "show")] fn show (&mut self) -> Perhaps<BrowseCmd> {
todo!()
}
/// Set current directory
#[command(Chdir = "chdir")] fn chdir (&mut self, _path: PathBuf) -> Perhaps<BrowseCmd> {
todo!()
}
/// Set current filter
#[command(SetSearch = "set-search")] fn set_search (&mut self, _filter: Arc<str>) -> Perhaps<BrowseCmd> {
todo!()
}
/// Set selected item
#[command(SetCursor = "set-cursor")] fn set_cursor (&mut self, _index: usize) -> Perhaps<BrowseCmd> {
todo!()
}
}
#[tek_proc::commands(AxisCmd)]
impl App {
/// Increment a given data axis.
#[command(Inc = "inc")]
pub fn inc (&mut self, axis: ControlAxis) -> Perhaps<AxisCmd> {
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<AxisCmd> {
Ok(match (&self.dialog, axis) {
(Dialog::None, _) => None,
(Dialog::Menu(_, _), ControlAxis::Y) => {
AppCmd::Dialog { dialog: self.dialog.menu_prev() }.dispatch(self)?;
None
},
_ => todo!()
})
}
}