diff --git a/src/device/launcher.rs b/src/device/launcher.rs index f5991873..47f54a56 100644 --- a/src/device/launcher.rs +++ b/src/device/launcher.rs @@ -5,7 +5,7 @@ pub struct Launcher { cursor: (usize, usize), tracks: Vec>, chains: Vec>, - rows: usize, + scenes: Vec, show_help: bool, view: LauncherView, } @@ -14,6 +14,18 @@ pub enum LauncherView { Sequencer, Chains } +pub struct Scene { + name: String, + clips: Vec>, +} +impl Scene { + pub fn new (name: impl AsRef, clips: impl AsRef<[Option]>) -> Self { + Self { + name: name.as_ref().into(), + clips: clips.as_ref().iter().map(|x|x.clone()).collect() + } + } +} impl Launcher { pub fn new ( name: &str, @@ -23,8 +35,17 @@ impl Launcher { name: name.into(), view: LauncherView::Tracks, timebase: timebase.clone(), - cursor: (0, 0), - rows: 8, + cursor: (1, 2), + scenes: vec![ + Scene::new(&"Scene#01", &[Some(0), None, None, None]), + Scene::new(&"Scene#02", &[None, None, None, None]), + Scene::new(&"Scene#03", &[None, None, None, None]), + Scene::new(&"Scene#04", &[None, None, None, None]), + Scene::new(&"Scene#05", &[None, None, None, None]), + Scene::new(&"Scene#06", &[None, None, None, None]), + Scene::new(&"Scene#07", &[None, None, None, None]), + Scene::new(&"Scene#08", &[None, None, None, None]), + ], tracks: vec![ Sequencer::new("Drum", timebase)?, Sequencer::new("Bass", timebase)?, @@ -69,7 +90,7 @@ impl Launcher { } } fn rows (&self) -> usize { - (self.rows + 2) as usize + (self.scenes.len() + 2) as usize } fn row (&self) -> usize { self.cursor.1 as usize @@ -137,28 +158,26 @@ pub fn render (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually } Ok(area) } - fn draw_scenes ( state: &Launcher, buf: &mut Buffer, x: u16, y: u16, ) -> Rect { let style = Style::default().not_dim().bold(); let row = state.row() as u16; let col = state.col() as u16; + let green = |r: u16, c: u16| if row == r && col == c { + Style::default().green() + } else { + Style::default() + }; let mut width = 8u16; let mut height = 6u16; - format!("{} | ", state.name).blit(buf, x+2, y+1, Some( - if row == 0 && col == 0 { Style::default().green() } else { Style::default() } - )); - format!("Sync 1/1").blit(buf, x+2, y+3, Some( - if row == 1 && col == 0 { Style::default().green() } else { Style::default() } - )); - for j in 0..=7 { - let y = y + 5 + j as u16 * 2; - let label = format!("▶ Scene {j}"); - width = width.max(label.len() as u16 + 3); - label.blit(buf, x + 2, y, Some( - if row == j + 2 && col == 0 { Style::default().green() } else { Style::default() } - )); + format!("{} | ", state.name).blit(buf, x+2, y+1, Some(green(0, 0))); + format!("Sync 1/1").blit(buf, x+2, y+3, Some(green(1, 0))); + for (scene_index, scene) in state.scenes.iter().enumerate() { + let y = y + 5 + scene_index as u16 * 2; + let label = format!("▶ {}", &scene.name); + width = width.max(label.len() as u16 + 2); + label.blit(buf, x + 2, y, Some(green(scene_index as u16 + 2, 0))); height = height + 2; } Rect { x, y, width, height } @@ -182,45 +201,52 @@ fn draw_tracks ( fn draw_track ( state: &Launcher, buf: &mut Buffer, x: u16, y: u16, i: u16, track: &Sequencer ) -> u16 { - let mut width = track.name.len() as u16 + 3; + let mut width = 11.max(track.name.len() as u16 + 3); let row = state.row() as u16; let col = state.col() as u16; - track.name.blit(buf, x, y + 1, Some( if row == 0 && col == i + 1 { Style::default().green() } else { Style::default() } )); - "(global)".blit(buf, x, y + 3, Some( if row == 1 && col == i + 1 { Style::default().green() } else { Style::default().dim() } )); - "┊".blit(buf, x - 2, y + 3, Some( Style::default().dim() )); - - for j in 0..=7 { - let y = y + 5 + j as u16 * 2; - if let Some(sequence) = track.sequences.get(j) { - let label = format!("▶ {}", &sequence.name); - width = width.max(label.len() as u16 + 1); - let style = if j + 2 == row as usize && i + 1 == col { - Style::default().green().bold() - } else { - Style::default() - }; - buf.set_string(x - 0, y + 0, &label, style); - buf.set_string(x - 2, y + 0, &"┊", style.dim()); - buf.set_string(x - 2, y + 1, &"┊", style.dim()); - buf.set_string(x + width - 2, y + 0, &"┊", style.dim()); - buf.set_string(x + width - 2, y + 1, &"┊", style.dim()); + let green = |r: u16, c: u16| if row == r && col == c { + Style::default().green() + } else { + Style::default() + }; + for (scene_index, scene) in state.scenes.iter().enumerate() { + let y = y + 5 + scene_index as u16 * 2; + //let label = format!("▶ {}", &scene.name); + //width = width.max(label.len() as u16 + 2); + //label.blit(buf, x + 2, y, Some(green(scene_index as u16 + 2, 0))); + //height = height + 2; + let style = if scene_index + 2 == row as usize && i + 1 == col { + Style::default().green().bold() } else { - buf.set_string(x - 2, y as u16, - format!("┊ {}", &"·".repeat(track.name.len())), - Style::default().dim() - ); + Style::default().dim() + }; + if let Some(Some(sequence_index)) = scene.clips.get(i as usize) { + if let Some(sequence) = track.sequences.get(*sequence_index) { + let label = format!("▶ {}", &sequence.name); + width = width.max(label.len() as u16 + 1); + label.blit(buf, x, y, Some(style)); + } else { + format!("┊ {}", &"?".repeat(track.name.len())) + .blit(buf, x - 2, y as u16, Some(Style::default().dim())); + } + } else { + "····".blit(buf, x, y, Some(style.dim())); } + let style = Some(style.dim()); + "┊".blit(buf, x - 2, y + 0, style); + "┊".blit(buf, x - 2, y + 1, style); + "┊".blit(buf, x + width - 2, y + 0, style); + "┊".blit(buf, x + width - 2, y + 1, style); } - width } fn draw_crossings (state: &Launcher, buf: &mut Buffer, x: u16, y: u16) { @@ -282,10 +308,12 @@ pub const KEYMAP: &'static [KeyBinding] = keymap!(Launcher { [Tab, NONE, "focus_next", "focus next area", focus_next], }); pub const KEYMAP_TRACKS: &'static [KeyBinding] = keymap!(Launcher { - [Up, NONE, "cursor_up", "move cursor up", cursor_up], - [Down, NONE, "cursor_down", "move cursor down", cursor_down], - [Left, NONE, "cursor_left", "move cursor left", cursor_left], - [Right, NONE, "cursor_right", "move cursor right", cursor_right], + [Up, NONE, "cursor_up", "move cursor up", cursor_up], + [Down, NONE, "cursor_down", "move cursor down", cursor_down], + [Left, NONE, "cursor_left", "move cursor left", cursor_left], + [Right, NONE, "cursor_right", "move cursor right", cursor_right], + [Char('.'), NONE, "clip_next", "set clip to next phrase", clip_next], + [Char(','), NONE, "clip_next", "set clip to last phrase", clip_prev], }); fn rename (_: &mut Launcher) -> Usually { Ok(true) @@ -326,3 +354,35 @@ fn focus_prev (state: &mut Launcher) -> Usually { }; Ok(true) } +fn clip_next (state: &mut Launcher) -> Usually { + if state.cursor.0 >= 1 && state.cursor.1 >= 2 { + let scene_id = state.cursor.1 - 2; + let clip_id = state.cursor.0 - 1; + let scene = &mut state.scenes[scene_id]; + scene.clips[clip_id] = match scene.clips[clip_id] { + None => Some(0), + Some(i) => if i >= state.tracks[clip_id].state().sequences.len().saturating_sub(1) { + None + } else { + Some(i + 1) + } + }; + } + Ok(true) +} +fn clip_prev (state: &mut Launcher) -> Usually { + if state.cursor.0 >= 1 && state.cursor.1 >= 2 { + let scene_id = state.cursor.1 - 2; + let clip_id = state.cursor.0 - 1; + let scene = &mut state.scenes[scene_id]; + scene.clips[clip_id] = match scene.clips[clip_id] { + None => Some(state.tracks[clip_id].state().sequences.len().saturating_sub(1)), + Some(i) => if i == 0 { + None + } else { + Some(i - 1) + } + }; + } + Ok(true) +}