diff --git a/.scratch.rs b/.scratch.rs index f7c9cee7..4eead468 100644 --- a/.scratch.rs +++ b/.scratch.rs @@ -120,3 +120,194 @@ //PhraseView, //PhraseEdit, //} + + //let focused = true; + //let _tracks = view.tracks(); + //lay!( + //focused.then_some(Background(TuiTheme::border_bg())), + //row!( + //// name + //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ + //todo!() + ////let Self(tracks, selected) = self; + ////let yellow = Some(Style::default().yellow().bold().not_dim()); + ////let white = Some(Style::default().white().bold().not_dim()); + ////let area = to.area(); + ////let area = [area.x(), area.y(), 3 + 5.max(track_name_max_len(tracks)) as u16, area.h()]; + ////let offset = 0; // track scroll offset + ////for y in 0..area.h() { + ////if y == 0 { + ////to.blit(&"Mixer", area.x() + 1, area.y() + y, Some(DIM))?; + ////} else if y % 2 == 0 { + ////let index = (y as usize - 2) / 2 + offset; + ////if let Some(track) = tracks.get(index) { + ////let selected = selected.track() == Some(index); + ////let style = if selected { yellow } else { white }; + ////to.blit(&format!(" {index:>02} "), area.x(), area.y() + y, style)?; + ////to.blit(&*track.name.read().unwrap(), area.x() + 4, area.y() + y, style)?; + ////} + ////} + ////} + ////Ok(Some(area)) + //}), + //// monitor + //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ + //todo!() + ////let Self(tracks) = self; + ////let mut area = to.area(); + ////let on = Some(Style::default().not_dim().green().bold()); + ////let off = Some(DIM); + ////area.x += 1; + ////for y in 0..area.h() { + ////if y == 0 { + //////" MON ".blit(to.buffer, area.x, area.y + y, style2)?; + ////} else if y % 2 == 0 { + ////let index = (y as usize - 2) / 2; + ////if let Some(track) = tracks.get(index) { + ////let style = if track.monitoring { on } else { off }; + ////to.blit(&" MON ", area.x(), area.y() + y, style)?; + ////} else { + ////area.height = y; + ////break + ////} + ////} + ////} + ////area.width = 4; + ////Ok(Some(area)) + //}), + //// record + //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ + //todo!() + ////let Self(tracks) = self; + ////let mut area = to.area(); + ////let on = Some(Style::default().not_dim().red().bold()); + ////let off = Some(Style::default().dim()); + ////area.x += 1; + ////for y in 0..area.h() { + ////if y == 0 { + //////" REC ".blit(to.buffer, area.x, area.y + y, style2)?; + ////} else if y % 2 == 0 { + ////let index = (y as usize - 2) / 2; + ////if let Some(track) = tracks.get(index) { + ////let style = if track.recording { on } else { off }; + ////to.blit(&" REC ", area.x(), area.y() + y, style)?; + ////} else { + ////area.height = y; + ////break + ////} + ////} + ////} + ////area.width = 4; + ////Ok(Some(area)) + //}), + //// overdub + //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ + //todo!() + ////let Self(tracks) = self; + ////let mut area = to.area(); + ////let on = Some(Style::default().not_dim().yellow().bold()); + ////let off = Some(Style::default().dim()); + ////area.x = area.x + 1; + ////for y in 0..area.h() { + ////if y == 0 { + //////" OVR ".blit(to.buffer, area.x, area.y + y, style2)?; + ////} else if y % 2 == 0 { + ////let index = (y as usize - 2) / 2; + ////if let Some(track) = tracks.get(index) { + ////to.blit(&" OVR ", area.x(), area.y() + y, if track.overdub { + ////on + ////} else { + ////off + ////})?; + ////} else { + ////area.height = y; + ////break + ////} + ////} + ////} + ////area.width = 4; + ////Ok(Some(area)) + //}), + //// erase + //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ + //todo!() + ////let Self(tracks) = self; + ////let mut area = to.area(); + ////let off = Some(Style::default().dim()); + ////area.x = area.x + 1; + ////for y in 0..area.h() { + ////if y == 0 { + //////" DEL ".blit(to.buffer, area.x, area.y + y, style2)?; + ////} else if y % 2 == 0 { + ////let index = (y as usize - 2) / 2; + ////if let Some(_) = tracks.get(index) { + ////to.blit(&" DEL ", area.x(), area.y() + y, off)?; + ////} else { + ////area.height = y; + ////break + ////} + ////} + ////} + ////area.width = 4; + ////Ok(Some(area)) + //}), + //// gain + //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ + //todo!() + ////let Self(tracks) = self; + ////let mut area = to.area(); + ////let off = Some(Style::default().dim()); + ////area.x = area.x() + 1; + ////for y in 0..area.h() { + ////if y == 0 { + //////" GAIN ".blit(to.buffer, area.x, area.y + y, style2)?; + ////} else if y % 2 == 0 { + ////let index = (y as usize - 2) / 2; + ////if let Some(_) = tracks.get(index) { + ////to.blit(&" +0.0 ", area.x(), area.y() + y, off)?; + ////} else { + ////area.height = y; + ////break + ////} + ////} + ////} + ////area.width = 7; + ////Ok(Some(area)) + //}), + //// scenes + //Widget::new(|_|{todo!()}, |to: &mut TuiOutput|{ + //let [x, y, _, height] = to.area(); + //let mut x2 = 0; + //Ok(for (scene_index, scene) in view.scenes().iter().enumerate() { + //let active_scene = view.selected.scene() == Some(scene_index); + //let sep = Some(if active_scene { + //Style::default().yellow().not_dim() + //} else { + //Style::default().dim() + //}); + //for y in y+1..y+height { + //to.blit(&"│", x + x2, y, sep); + //} + //let name = scene.name.read().unwrap(); + //let mut x3 = name.len() as u16; + //to.blit(&*name, x + x2, y, sep); + //for (i, clip) in scene.clips.iter().enumerate() { + //let active_track = view.selected.track() == Some(i); + //if let Some(clip) = clip { + //let y2 = y + 2 + i as u16 * 2; + //let label = format!("{}", clip.read().unwrap().name); + //to.blit(&label, x + x2, y2, Some(if active_track && active_scene { + //Style::default().not_dim().yellow().bold() + //} else { + //Style::default().not_dim() + //})); + //x3 = x3.max(label.len() as u16) + //} + //} + //x2 = x2 + x3 + 1; + //}) + //}), + //) + //) +//} + diff --git a/crates/tek/src/midi.rs b/crates/tek/src/midi.rs index 22300e80..4e54d012 100644 --- a/crates/tek/src/midi.rs +++ b/crates/tek/src/midi.rs @@ -6,6 +6,7 @@ pub(crate) mod midi_note; pub(crate) use midi_note::*; pub(crate) mod midi_out; pub(crate) use midi_out::*; pub(crate) mod midi_phrase; pub(crate) use midi_phrase::*; pub(crate) mod midi_play; pub(crate) use midi_play::*; +pub(crate) mod midi_pool; pub(crate) use midi_pool::*; pub(crate) mod midi_rec; pub(crate) use midi_rec::*; /// Add "all notes off" to the start of a buffer. diff --git a/crates/tek/src/midi/midi_phrase.rs b/crates/tek/src/midi/midi_phrase.rs index d0d18322..1c1f66dd 100644 --- a/crates/tek/src/midi/midi_phrase.rs +++ b/crates/tek/src/midi/midi_phrase.rs @@ -1,19 +1,5 @@ use crate::*; -pub trait HasPhrases { - fn phrases (&self) -> &Vec>>; - fn phrases_mut (&mut self) -> &mut Vec>>; -} - -#[macro_export] macro_rules! has_phrases { - (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { - impl $(<$($L),*$($T $(: $U)?),*>)? HasPhrases for $Struct $(<$($L),*$($T),*>)? { - fn phrases (&$self) -> &Vec>> { &$cb } - fn phrases_mut (&mut $self) -> &mut Vec>> { &mut$cb } - } - } -} - pub trait HasPhrase { fn phrase (&self) -> &Arc>; } @@ -26,84 +12,6 @@ pub trait HasPhrase { } } -#[derive(Clone, Debug, PartialEq)] -pub enum PhrasePoolCommand { - Add(usize, Phrase), - Delete(usize), - Swap(usize, usize), - Import(usize, PathBuf), - Export(usize, PathBuf), - SetName(usize, String), - SetLength(usize, usize), - SetColor(usize, ItemColor), -} - -impl Command for PhrasePoolCommand { - fn execute (self, model: &mut T) -> Perhaps { - use PhrasePoolCommand::*; - Ok(match self { - Add(mut index, phrase) => { - let phrase = Arc::new(RwLock::new(phrase)); - let phrases = model.phrases_mut(); - if index >= phrases.len() { - index = phrases.len(); - phrases.push(phrase) - } else { - phrases.insert(index, phrase); - } - Some(Self::Delete(index)) - }, - Delete(index) => { - let phrase = model.phrases_mut().remove(index).read().unwrap().clone(); - Some(Self::Add(index, phrase)) - }, - Swap(index, other) => { - model.phrases_mut().swap(index, other); - Some(Self::Swap(index, other)) - }, - Import(index, path) => { - 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 phrase = Phrase::new("imported", true, t as usize + 1, None, None); - for event in events.iter() { - phrase.notes[event.0 as usize].push(event.2); - } - Self::Add(index, phrase).execute(model)? - }, - Export(_index, _path) => { - todo!("export phrase to midi file"); - }, - SetName(index, name) => { - let mut phrase = model.phrases()[index].write().unwrap(); - let old_name = phrase.name.clone(); - phrase.name = name; - Some(Self::SetName(index, old_name)) - }, - SetLength(index, length) => { - let mut phrase = model.phrases()[index].write().unwrap(); - let old_len = phrase.length; - phrase.length = length; - Some(Self::SetLength(index, old_len)) - }, - SetColor(index, color) => { - let mut color = ItemPalette::from(color); - std::mem::swap(&mut color, &mut model.phrases()[index].write().unwrap().color); - Some(Self::SetColor(index, color.base)) - }, - }) - } -} - /// A MIDI sequence. #[derive(Debug, Clone)] pub struct Phrase { diff --git a/crates/tek/src/midi/midi_pool.rs b/crates/tek/src/midi/midi_pool.rs new file mode 100644 index 00000000..555059be --- /dev/null +++ b/crates/tek/src/midi/midi_pool.rs @@ -0,0 +1,93 @@ +use crate::*; + +pub trait HasPhrases { + fn phrases (&self) -> &Vec>>; + fn phrases_mut (&mut self) -> &mut Vec>>; +} + +#[macro_export] macro_rules! has_phrases { + (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { + impl $(<$($L),*$($T $(: $U)?),*>)? HasPhrases for $Struct $(<$($L),*$($T),*>)? { + fn phrases (&$self) -> &Vec>> { &$cb } + fn phrases_mut (&mut $self) -> &mut Vec>> { &mut$cb } + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum PhrasePoolCommand { + Add(usize, Phrase), + Delete(usize), + Swap(usize, usize), + Import(usize, PathBuf), + Export(usize, PathBuf), + SetName(usize, String), + SetLength(usize, usize), + SetColor(usize, ItemColor), +} + +impl Command for PhrasePoolCommand { + fn execute (self, model: &mut T) -> Perhaps { + use PhrasePoolCommand::*; + Ok(match self { + Add(mut index, phrase) => { + let phrase = Arc::new(RwLock::new(phrase)); + let phrases = model.phrases_mut(); + if index >= phrases.len() { + index = phrases.len(); + phrases.push(phrase) + } else { + phrases.insert(index, phrase); + } + Some(Self::Delete(index)) + }, + Delete(index) => { + let phrase = model.phrases_mut().remove(index).read().unwrap().clone(); + Some(Self::Add(index, phrase)) + }, + Swap(index, other) => { + model.phrases_mut().swap(index, other); + Some(Self::Swap(index, other)) + }, + Import(index, path) => { + 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 phrase = Phrase::new("imported", true, t as usize + 1, None, None); + for event in events.iter() { + phrase.notes[event.0 as usize].push(event.2); + } + Self::Add(index, phrase).execute(model)? + }, + Export(_index, _path) => { + todo!("export phrase to midi file"); + }, + SetName(index, name) => { + let mut phrase = model.phrases()[index].write().unwrap(); + let old_name = phrase.name.clone(); + phrase.name = name; + Some(Self::SetName(index, old_name)) + }, + SetLength(index, length) => { + let mut phrase = model.phrases()[index].write().unwrap(); + let old_len = phrase.length; + phrase.length = length; + Some(Self::SetLength(index, old_len)) + }, + SetColor(index, color) => { + let mut color = ItemPalette::from(color); + std::mem::swap(&mut color, &mut model.phrases()[index].write().unwrap().color); + Some(Self::SetColor(index, color.base)) + }, + }) + } +} diff --git a/crates/tek/src/tui/app_arranger.rs b/crates/tek/src/tui/app_arranger.rs index 958edcb4..eaa8ab48 100644 --- a/crates/tek/src/tui/app_arranger.rs +++ b/crates/tek/src/tui/app_arranger.rs @@ -192,58 +192,55 @@ input_to_command!(ArrangerCommand: |state: ArrangerTui, input|{ key_pat!(Ctrl-Char('k')) => { todo!("keyboard") }, // Transport: Play/pause key_pat!(Char(' ')) => - Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }), + Self::Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }), // Transport: Play from start or rewind to start key_pat!(Shift-Char(' ')) => - Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }), + Self::Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }), key_pat!(Char('e')) => - Editor(PhraseCommand::Show(Some(state.phrases.phrase().clone()))), + Self::Editor(PhraseCommand::Show(Some(state.phrases.phrase().clone()))), key_pat!(Char('l')) => - Clip(ArrangerClipCommand::SetLoop(false)), + Self::Clip(ArrangerClipCommand::SetLoop(false)), key_pat!(Ctrl-Char('a')) => - Scene(ArrangerSceneCommand::Add), + Self::Scene(ArrangerSceneCommand::Add), key_pat!(Ctrl-Char('t')) => - Track(ArrangerTrackCommand::Add), + Self::Track(ArrangerTrackCommand::Add), key_pat!(Char('0')) => match state.selected() { Selected::Mix => StopAll, Selected::Track(t) => return None, Selected::Scene(s) => return None, Selected::Clip(t, s) => return None, }, - key_pat!(Char('q')) => match state.selected() { - Selected::Mix => return None, - Selected::Track(t) => return None, - Selected::Scene(s) => return None, - Selected::Clip(t, s) => return None, + key_pat!(Char('g')) => if let Selected::Clip(t, s) = state.selected() { + Self::Phrases(PhrasesCommand::Select(0)) + } else { + return None }, - key_pat!(Char('g')) => match state.selected() { - Selected::Mix => return None, - Selected::Track(t) => return None, - Selected::Scene(s) => return None, - Selected::Clip(t, s) => return None, + key_pat!(Char('p')) => if let Selected::Clip(t, s) = state.selected() { + Self::Clip(ArrangerClipCommand::Select(0)) + } else { + return None }, - key_pat!(Char('p')) => match state.selected() { - Selected::Mix => return None, - Selected::Track(t) => return None, - Selected::Scene(s) => return None, - Selected::Clip(t, s) => return None, + key_pat!(Char('q')) => if let Selected::Clip(t, s) = state.selected() { + todo!("enqueue clip") + } else { + return None }, // Tab: Toggle visibility of phrase pool column key_pat!(Tab) => - ShowPool(!state.show_pool), - _ => match state.selected() { - Selected::Mix => to_arranger_mix_command(input), - Selected::Track(t) => to_arranger_track_command(input, - t, state.tracks.len()), - Selected::Scene(s) => to_arranger_scene_command(input, - s, state.scenes.len()), - Selected::Clip(t, s) => to_arranger_clip_command(input, - t, state.tracks.len(), - s, state.scenes.len()), + Self::ShowPool(!state.show_pool), + _ => { + let t_len = state.tracks.len(); + let s_len = state.scenes.len(); + match state.selected() { + Selected::Mix => to_arranger_mix_command(input), + Selected::Track(t) => to_arranger_track_command(input, t, t_len), + Selected::Scene(s) => to_arranger_scene_command(input, s, s_len), + Selected::Clip(t, s) => to_arranger_clip_command(input, t, t_len, s, s_len), + } }.or_else(||if let Some(command) = PhraseCommand::input_to_command(&state.editor, input) { - Some(Editor(command)) + Some(Self::Editor(command)) } else if let Some(command) = PhrasesCommand::input_to_command(&state.phrases, input) { - Some(Phrases(command)) + Some(Self::Phrases(command)) } else { None })? @@ -368,264 +365,3 @@ impl ArrangerMode { fn any_size (_: E::Size) -> Perhaps{ Ok(Some([0.into(),0.into()].into())) } - -//impl Command for ArrangerClipCommand { - //fn execute (self, state: &mut T) -> Perhaps { - //match self { - //_ => todo!() - //} - //Ok(None) - //} -//} - //let focused = true; - //let _tracks = view.tracks(); - //lay!( - //focused.then_some(Background(TuiTheme::border_bg())), - //row!( - //// name - //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ - //todo!() - ////let Self(tracks, selected) = self; - ////let yellow = Some(Style::default().yellow().bold().not_dim()); - ////let white = Some(Style::default().white().bold().not_dim()); - ////let area = to.area(); - ////let area = [area.x(), area.y(), 3 + 5.max(track_name_max_len(tracks)) as u16, area.h()]; - ////let offset = 0; // track scroll offset - ////for y in 0..area.h() { - ////if y == 0 { - ////to.blit(&"Mixer", area.x() + 1, area.y() + y, Some(DIM))?; - ////} else if y % 2 == 0 { - ////let index = (y as usize - 2) / 2 + offset; - ////if let Some(track) = tracks.get(index) { - ////let selected = selected.track() == Some(index); - ////let style = if selected { yellow } else { white }; - ////to.blit(&format!(" {index:>02} "), area.x(), area.y() + y, style)?; - ////to.blit(&*track.name.read().unwrap(), area.x() + 4, area.y() + y, style)?; - ////} - ////} - ////} - ////Ok(Some(area)) - //}), - //// monitor - //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ - //todo!() - ////let Self(tracks) = self; - ////let mut area = to.area(); - ////let on = Some(Style::default().not_dim().green().bold()); - ////let off = Some(DIM); - ////area.x += 1; - ////for y in 0..area.h() { - ////if y == 0 { - //////" MON ".blit(to.buffer, area.x, area.y + y, style2)?; - ////} else if y % 2 == 0 { - ////let index = (y as usize - 2) / 2; - ////if let Some(track) = tracks.get(index) { - ////let style = if track.monitoring { on } else { off }; - ////to.blit(&" MON ", area.x(), area.y() + y, style)?; - ////} else { - ////area.height = y; - ////break - ////} - ////} - ////} - ////area.width = 4; - ////Ok(Some(area)) - //}), - //// record - //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ - //todo!() - ////let Self(tracks) = self; - ////let mut area = to.area(); - ////let on = Some(Style::default().not_dim().red().bold()); - ////let off = Some(Style::default().dim()); - ////area.x += 1; - ////for y in 0..area.h() { - ////if y == 0 { - //////" REC ".blit(to.buffer, area.x, area.y + y, style2)?; - ////} else if y % 2 == 0 { - ////let index = (y as usize - 2) / 2; - ////if let Some(track) = tracks.get(index) { - ////let style = if track.recording { on } else { off }; - ////to.blit(&" REC ", area.x(), area.y() + y, style)?; - ////} else { - ////area.height = y; - ////break - ////} - ////} - ////} - ////area.width = 4; - ////Ok(Some(area)) - //}), - //// overdub - //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ - //todo!() - ////let Self(tracks) = self; - ////let mut area = to.area(); - ////let on = Some(Style::default().not_dim().yellow().bold()); - ////let off = Some(Style::default().dim()); - ////area.x = area.x + 1; - ////for y in 0..area.h() { - ////if y == 0 { - //////" OVR ".blit(to.buffer, area.x, area.y + y, style2)?; - ////} else if y % 2 == 0 { - ////let index = (y as usize - 2) / 2; - ////if let Some(track) = tracks.get(index) { - ////to.blit(&" OVR ", area.x(), area.y() + y, if track.overdub { - ////on - ////} else { - ////off - ////})?; - ////} else { - ////area.height = y; - ////break - ////} - ////} - ////} - ////area.width = 4; - ////Ok(Some(area)) - //}), - //// erase - //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ - //todo!() - ////let Self(tracks) = self; - ////let mut area = to.area(); - ////let off = Some(Style::default().dim()); - ////area.x = area.x + 1; - ////for y in 0..area.h() { - ////if y == 0 { - //////" DEL ".blit(to.buffer, area.x, area.y + y, style2)?; - ////} else if y % 2 == 0 { - ////let index = (y as usize - 2) / 2; - ////if let Some(_) = tracks.get(index) { - ////to.blit(&" DEL ", area.x(), area.y() + y, off)?; - ////} else { - ////area.height = y; - ////break - ////} - ////} - ////} - ////area.width = 4; - ////Ok(Some(area)) - //}), - //// gain - //Widget::new(|_|{todo!()}, |_: &mut TuiOutput|{ - //todo!() - ////let Self(tracks) = self; - ////let mut area = to.area(); - ////let off = Some(Style::default().dim()); - ////area.x = area.x() + 1; - ////for y in 0..area.h() { - ////if y == 0 { - //////" GAIN ".blit(to.buffer, area.x, area.y + y, style2)?; - ////} else if y % 2 == 0 { - ////let index = (y as usize - 2) / 2; - ////if let Some(_) = tracks.get(index) { - ////to.blit(&" +0.0 ", area.x(), area.y() + y, off)?; - ////} else { - ////area.height = y; - ////break - ////} - ////} - ////} - ////area.width = 7; - ////Ok(Some(area)) - //}), - //// scenes - //Widget::new(|_|{todo!()}, |to: &mut TuiOutput|{ - //let [x, y, _, height] = to.area(); - //let mut x2 = 0; - //Ok(for (scene_index, scene) in view.scenes().iter().enumerate() { - //let active_scene = view.selected.scene() == Some(scene_index); - //let sep = Some(if active_scene { - //Style::default().yellow().not_dim() - //} else { - //Style::default().dim() - //}); - //for y in y+1..y+height { - //to.blit(&"│", x + x2, y, sep); - //} - //let name = scene.name.read().unwrap(); - //let mut x3 = name.len() as u16; - //to.blit(&*name, x + x2, y, sep); - //for (i, clip) in scene.clips.iter().enumerate() { - //let active_track = view.selected.track() == Some(i); - //if let Some(clip) = clip { - //let y2 = y + 2 + i as u16 * 2; - //let label = format!("{}", clip.read().unwrap().name); - //to.blit(&label, x + x2, y2, Some(if active_track && active_scene { - //Style::default().not_dim().yellow().bold() - //} else { - //Style::default().not_dim() - //})); - //x3 = x3.max(label.len() as u16) - //} - //} - //x2 = x2 + x3 + 1; - //}) - //}), - //) - //) -//} - -//impl Command for ArrangerSceneCommand { -//} - //Edit(phrase) => { state.state.phrase = phrase.clone() }, - //ToggleViewMode => { state.state.mode.to_next(); }, - //Delete => { state.state.delete(); }, - //Activate => { state.state.activate(); }, - //ZoomIn => { state.state.zoom_in(); }, - //ZoomOut => { state.state.zoom_out(); }, - //MoveBack => { state.state.move_back(); }, - //MoveForward => { state.state.move_forward(); }, - //RandomColor => { state.state.randomize_color(); }, - //Put => { state.state.phrase_put(); }, - //Get => { state.state.phrase_get(); }, - //AddScene => { state.state.scene_add(None, None)?; }, - //AddTrack => { state.state.track_add(None, None)?; }, - //ToggleLoop => { state.state.toggle_loop() }, - //pub fn zoom_in (&mut self) { - //if let ArrangerEditorMode::V(factor) = self.mode { - //self.mode = ArrangerEditorMode::V(factor + 1) - //} - //} - //pub fn zoom_out (&mut self) { - //if let ArrangerEditorMode::V(factor) = self.mode { - //self.mode = ArrangerEditorMode::V(factor.saturating_sub(1)) - //} - //} - //pub fn move_back (&mut self) { - //match self.selected { - //ArrangerEditorFocus::Scene(s) => { - //if s > 0 { - //self.scenes.swap(s, s - 1); - //self.selected = ArrangerEditorFocus::Scene(s - 1); - //} - //}, - //ArrangerEditorFocus::Track(t) => { - //if t > 0 { - //self.tracks.swap(t, t - 1); - //self.selected = ArrangerEditorFocus::Track(t - 1); - //// FIXME: also swap clip order in scenes - //} - //}, - //_ => todo!("arrangement: move forward") - //} - //} - //pub fn move_forward (&mut self) { - //match self.selected { - //ArrangerEditorFocus::Scene(s) => { - //if s < self.scenes.len().saturating_sub(1) { - //self.scenes.swap(s, s + 1); - //self.selected = ArrangerEditorFocus::Scene(s + 1); - //} - //}, - //ArrangerEditorFocus::Track(t) => { - //if t < self.tracks.len().saturating_sub(1) { - //self.tracks.swap(t, t + 1); - //self.selected = ArrangerEditorFocus::Track(t + 1); - //// FIXME: also swap clip order in scenes - //} - //}, - //_ => todo!("arrangement: move forward") - //} - //} diff --git a/crates/tek/src/tui/arranger_scene.rs b/crates/tek/src/tui/arranger_scene.rs index f8a4f3e7..2b4d95a0 100644 --- a/crates/tek/src/tui/arranger_scene.rs +++ b/crates/tek/src/tui/arranger_scene.rs @@ -123,3 +123,65 @@ impl ArrangerTui { self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten() } } +//impl Command for ArrangerSceneCommand { +//} + //Edit(phrase) => { state.state.phrase = phrase.clone() }, + //ToggleViewMode => { state.state.mode.to_next(); }, + //Delete => { state.state.delete(); }, + //Activate => { state.state.activate(); }, + //ZoomIn => { state.state.zoom_in(); }, + //ZoomOut => { state.state.zoom_out(); }, + //MoveBack => { state.state.move_back(); }, + //MoveForward => { state.state.move_forward(); }, + //RandomColor => { state.state.randomize_color(); }, + //Put => { state.state.phrase_put(); }, + //Get => { state.state.phrase_get(); }, + //AddScene => { state.state.scene_add(None, None)?; }, + //AddTrack => { state.state.track_add(None, None)?; }, + //ToggleLoop => { state.state.toggle_loop() }, + //pub fn zoom_in (&mut self) { + //if let ArrangerEditorMode::V(factor) = self.mode { + //self.mode = ArrangerEditorMode::V(factor + 1) + //} + //} + //pub fn zoom_out (&mut self) { + //if let ArrangerEditorMode::V(factor) = self.mode { + //self.mode = ArrangerEditorMode::V(factor.saturating_sub(1)) + //} + //} + //pub fn move_back (&mut self) { + //match self.selected { + //ArrangerEditorFocus::Scene(s) => { + //if s > 0 { + //self.scenes.swap(s, s - 1); + //self.selected = ArrangerEditorFocus::Scene(s - 1); + //} + //}, + //ArrangerEditorFocus::Track(t) => { + //if t > 0 { + //self.tracks.swap(t, t - 1); + //self.selected = ArrangerEditorFocus::Track(t - 1); + //// FIXME: also swap clip order in scenes + //} + //}, + //_ => todo!("arrangement: move forward") + //} + //} + //pub fn move_forward (&mut self) { + //match self.selected { + //ArrangerEditorFocus::Scene(s) => { + //if s < self.scenes.len().saturating_sub(1) { + //self.scenes.swap(s, s + 1); + //self.selected = ArrangerEditorFocus::Scene(s + 1); + //} + //}, + //ArrangerEditorFocus::Track(t) => { + //if t < self.tracks.len().saturating_sub(1) { + //self.tracks.swap(t, t + 1); + //self.selected = ArrangerEditorFocus::Track(t + 1); + //// FIXME: also swap clip order in scenes + //} + //}, + //_ => todo!("arrangement: move forward") + //} + //} diff --git a/crates/tek/src/tui/status_bar.rs b/crates/tek/src/tui/status_bar.rs index bb1fcadb..600a5f6e 100644 --- a/crates/tek/src/tui/status_bar.rs +++ b/crates/tek/src/tui/status_bar.rs @@ -104,7 +104,7 @@ from!(|state:&ArrangerTui|ArrangerStatus = { }); render!(|self: ArrangerStatus|Fixed::h(2, lay!([ Self::help(), - Fill::wh(Align::se({Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats())})), + Fill::wh(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), ]))); impl ArrangerStatus { fn help () -> impl Render { @@ -120,9 +120,10 @@ impl ArrangerStatus { single("SPACE", "play/pause"), single(" Ctrl", " scroll"), single(" wsad", " cell"), + double(("p", "put"), ("g", "get")), double(("q", "enqueue"), ("e", "edit")), single(" ▲▼▶◀", " note"), - double(("a", "append"), ("s", "set note"),), + double(("a", "append"), ("s", "set"),), double((",.", "length"), ("<>", "triplet"),), double(("[]", "phrase"), ("{}", "order"),), ]))