From 449615eea87ea274a7033913d3e88b827853827b Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 12 Jul 2024 13:23:32 +0300 Subject: [PATCH] make transport focusable --- src/control.rs | 2 + src/main.rs | 1 + src/model.rs | 12 +++-- src/model/sampler.rs | 75 +++++++++++++++++++++++++++++- src/model/track.rs | 13 +----- src/view.rs | 3 +- src/view/arranger.rs | 91 +++--------------------------------- src/view/border.rs | 9 ++++ src/view/chain.rs | 14 ++++-- src/view/sampler.rs | 78 ------------------------------- src/view/sequencer.rs | 10 ++-- src/view/split.rs | 0 src/view/theme.rs | 45 ++++++++++++++++++ src/view/transport.rs | 104 ++++++++++++++++++++++-------------------- 14 files changed, 220 insertions(+), 237 deletions(-) delete mode 100644 src/view/sampler.rs create mode 100644 src/view/split.rs create mode 100644 src/view/theme.rs diff --git a/src/control.rs b/src/control.rs index e2eaefbc..ee10b8e9 100644 --- a/src/control.rs +++ b/src/control.rs @@ -24,6 +24,8 @@ handle!{ fn handle_focused (state: &mut App, e: &AppEvent) -> Usually { match state.section { + AppSection::Transport => + Ok(false), AppSection::Arranger => handle_keymap(state, e, crate::control::arranger::KEYMAP_ARRANGER), AppSection::Sequencer => diff --git a/src/main.rs b/src/main.rs index 530c1471..1687eb3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ //#![feature(fn_traits)] //#![feature(unboxed_closures)] #![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)] +#![allow(ambiguous_glob_reexports)] extern crate clap; extern crate jack as _jack; diff --git a/src/model.rs b/src/model.rs index 6289b68c..b5466570 100644 --- a/src/model.rs +++ b/src/model.rs @@ -217,21 +217,23 @@ impl App { } #[derive(PartialEq, Clone, Copy)] -pub enum AppSection { Arranger, Sequencer, Chain, } +pub enum AppSection { Transport, Arranger, Sequencer, Chain, } impl Default for AppSection { fn default () -> Self { Self::Arranger } } impl AppSection { pub fn prev (&mut self) { *self = match self { - Self::Arranger => Self::Chain, + Self::Transport => Self::Chain, + Self::Arranger => Self::Transport, Self::Sequencer => Self::Arranger, - Self::Chain => Self::Sequencer, + Self::Chain => Self::Sequencer, } } pub fn next (&mut self) { *self = match self { - Self::Arranger => Self::Sequencer, + Self::Transport => Self::Arranger, + Self::Arranger => Self::Sequencer, Self::Sequencer => Self::Chain, - Self::Chain => Self::Arranger, + Self::Chain => Self::Transport, } } } diff --git a/src/model/sampler.rs b/src/model/sampler.rs index d36778b2..d5a5cde6 100644 --- a/src/model/sampler.rs +++ b/src/model/sampler.rs @@ -9,8 +9,36 @@ pub struct Sampler { pub buffer: Vec>, pub output_gain: f32 } +render!(Sampler |self, buf, area| { + let Rect { x, y, height, .. } = area; + let style = Style::default().gray(); + let title = format!(" {} ({})", self.name, self.voices.len()); + title.blit(buf, x+1, y, Some(style.white().bold().not_dim()))?; + let mut width = title.len() + 2; + for (i, (note, sample)) in self.samples.iter().enumerate() { + let style = if i == self.cursor.0 { + Style::default().green() + } else { + Style::default() + }; + let i = i as u16; + let y1 = y+1+i; + if y1 >= y + height { + break + } + if i as usize == self.cursor.0 { + "⯈".blit(buf, x+1, y1, Some(style.bold()))?; + } + let label1 = format!("{note:3} {:12}", sample.name); + let label2 = format!("{:>6} {:>6} +0.0", sample.start, sample.end); + label1.blit(buf, x+2, y1, Some(style.bold()))?; + label2.blit(buf, x+3+label1.len()as u16, y1, Some(style))?; + width = width.max(label1.len() + label2.len() + 4); + } + let height = ((2 + self.samples.len()) as u16).min(height); + Ok(Rect { x, y, width: (width as u16).min(area.width), height }) +}); -render!(Sampler = crate::view::sampler::render); handle!(Sampler = crate::control::sampler::handle); //jack!(Sampler { //process = Sampler::process, @@ -184,3 +212,48 @@ impl Iterator for Voice { None } } + +//fn render_table ( + //self: &mut Sampler, + //stdout: &mut Stdout, + //offset: (u16, u16), +//) -> Result<(), Box> { + //let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row); + //stdout.queue(move_to(0, 3))?.queue( + //Print(" Name Rate Trigger Route") + //)?; + //for (i, sample) in self.samples.lock().unwrap().iter().enumerate() { + //let row = 4 + i as u16; + //for (j, (column, field)) in [ + //(0, format!(" {:7} ", sample.name)), + //(9, format!(" {:.1}Hz ", sample.rate)), + //(18, format!(" MIDI C{} {} ", sample.trigger.0, sample.trigger.1)), + //(33, format!(" {:.1}dB -> Output ", sample.gain)), + //(50, format!(" {} ", sample.playing.unwrap_or(0))), + //].into_iter().enumerate() { + //stdout.queue(move_to(column, row))?; + //if self.selected_sample == i && self.selected_column == j { + //stdout.queue(PrintStyledContent(field.to_string().bold().reverse()))?; + //} else { + //stdout.queue(PrintStyledContent(field.to_string().bold()))?; + //} + //} + //} + //Ok(()) +//} + +//fn render_meters ( + //self: &mut Sampler, + //stdout: &mut Stdout, + //offset: (u16, u16), +//) -> Result<(), Box> { + //let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row); + //for (i, sample) in self.samples.lock().iter().enumerate() { + //let row = 4 + i as u16; + //stdout.queue(move_to(32, row))?.queue( + //PrintStyledContent("▁".green()) + //)?; + //} + //Ok(()) +//} + diff --git a/src/model/track.rs b/src/model/track.rs index ffde2874..47dfaef1 100644 --- a/src/model/track.rs +++ b/src/model/track.rs @@ -20,17 +20,6 @@ impl App { Ok(&mut self.tracks[self.track_cursor - 1]) } - fn add_track_with_cb ( - &mut self, name: Option<&str>, init: impl FnOnce(&Client, &mut Track)->Usually<()>, - ) -> Usually<&mut Track> { - let name = name.ok_or_else(||self.new_track_name())?; - let mut track = Track::new(&name, None, None)?; - init(self.client(), &mut track)?; - self.tracks.push(track); - self.track_cursor = self.tracks.len(); - Ok(&mut self.tracks[self.track_cursor - 1]) - } - pub fn track (&self) -> Option<(usize, &Track)> { match self.track_cursor { 0 => None, _ => { let id = self.track_cursor as usize - 1; @@ -61,6 +50,7 @@ pub struct Track { pub sequence: Option, /// Output from current sequence. pub midi_out: Option>, + /// MIDI output buffer midi_out_buf: Vec>>, /// Device chain pub devices: Vec, @@ -74,6 +64,7 @@ pub struct Track { /// Highlight keys on piano roll. pub notes_out: [bool;128], } + impl Track { fn new ( name: &str, diff --git a/src/view.rs b/src/view.rs index 963fd197..0c1f4ed7 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,12 +1,13 @@ pub mod chain; pub mod arranger; -pub mod sampler; pub mod sequencer; pub mod transport; pub mod plugin; pub mod border; +pub mod theme; pub use self::border::*; +pub use self::theme::*; pub use self::transport::TransportView; pub use self::arranger::*; pub use self::chain::ChainView; diff --git a/src/view/arranger.rs b/src/view/arranger.rs index eaba3ac0..167cecce 100644 --- a/src/view/arranger.rs +++ b/src/view/arranger.rs @@ -24,37 +24,6 @@ impl<'a> ArrangerView<'a> { vertical } } - fn track_names (&self) -> Vec<&'a str> { - let mut track_names = vec!["Mix"]; - for track in self.tracks.iter() { - track_names.push(track.name.as_str()); - } - track_names - } - fn track_widths (&self) -> Vec { - self.track_names() - .iter() - .map(|name|(name.len() as u16).max(10) + 3) - .collect() - } - fn bg_color_lo (&self) -> Color { - if self.focused && self.entered { - Color::Rgb(25, 60, 15) - } else if self.focused { - Color::Rgb(20, 45, 5) - } else { - Color::Reset - } - } - fn bg_color_hi (&self) -> Color { - if self.focused && self.entered { - Color::Rgb(30, 90, 25) - } else if self.focused { - Color::Rgb(25, 60, 15) - } else { - Color::Reset - } - } } impl<'a> Render for ArrangerView<'a> { @@ -64,7 +33,7 @@ impl<'a> Render for ArrangerView<'a> { } else { self.tracks.len() as u16 * 2 }); - fill_bg(buf, area, self.bg_color_lo()); + fill_bg(buf, area, Nord::bg_lo(self.focused, self.entered)); area = if self.vertical { self.draw_vertical(buf, area) } else { @@ -73,7 +42,7 @@ impl<'a> Render for ArrangerView<'a> { if self.focused { //HELP.blit(buf, area.x + 2, area.y + area.height - 1, Some(Style::default().dim()))?; if self.entered { - QuarterV(Style::default().green().dim()).draw(buf, area)?; + Corners(Style::default().green().not_dim()).draw(buf, area)?; } } Ok(area) @@ -82,45 +51,6 @@ impl<'a> Render for ArrangerView<'a> { impl<'a> ArrangerView<'a> { - fn vertical_clips (&self, buf: &mut Buffer, x: u16, y: u16, height: u16, track: usize) -> Usually { - let mut index = 0; - let mut width = 10; - loop { - if index >= self.scenes.len() { - break - } - if y + index as u16 >= height { - break - } - width = 10.max(if let Some(scene) = self.scenes.get(index) { - let hi = (track + 1 == self.cursor.0) && - (index + 1 == self.cursor.1); - let style = Some(highlight(self.focused, hi)); - let clip = scene.clips.get(track); - let index = index as u16; - let label = if let Some(Some(clip)) = clip { - if let Some(phrase) = self.tracks[track].phrases.get(*clip) { - format!("{} {}", if self.tracks[track].sequence == Some(*clip) { - "" - } else { - " " - }, phrase.name) - } else { - format!(" ??? ") - } - } else { - format!(" ·········") - }; - label.blit(buf, x, y + index, style)?; - label.len() as u16 - } else { - 0u16 - }); - index = index + 1; - } - Ok(width) - } - fn draw_vertical (&self, buf: &mut Buffer, area: Rect) -> Usually { return Split::right([ @@ -140,7 +70,7 @@ impl<'a> ArrangerView<'a> { "⯈".blit(buf, x+1, y, style)?; scene.name.blit(buf, x + 2, y, style)?; } - let width = 2+self.scenes.iter() + let width = 2 + self.scenes.iter() .map(|x|&x.name).fold(0, |x,y|x.max(y.len() as u16+1)); Ok(Rect { width, ..area }) }, @@ -180,20 +110,13 @@ impl<'a> ArrangerView<'a> { //width = width.max(2label.len() as u16 + 3); } if track_index + 1 == self.cursor.0 { + let bg = Nord::bg_hi(self.focused, self.entered); if self.cursor.1 == 0 { let y = area.y; - fill_bg(buf, Rect { x, y, width, height: 1 }, if self.focused { - Color::Rgb(30, 90, 25) - } else { - Color::Rgb(25, 60, 15) - }) + fill_bg(buf, Rect { x, y, width, height: 1 }, bg) } else { let y = 1 + area.y + 2 * (self.cursor.1 as u16 - 1); - fill_bg(buf, Rect { x, y, width, height: 2 }, if self.focused { - Color::Rgb(30, 90, 25) - } else { - Color::Rgb(25, 60, 15) - }) + fill_bg(buf, Rect { x, y, width, height: 2 }, bg) } }; x = x + width as u16; @@ -202,9 +125,7 @@ impl<'a> ArrangerView<'a> { } ]).render(buf, area); } -} -impl<'a> ArrangerView<'a> { fn draw_horizontal (&self, buf: &mut Buffer, area: Rect) -> Usually { let style1 = Some(Style::default().bold().not_dim()); let style2 = Some(Style::default().not_dim()); diff --git a/src/view/border.rs b/src/view/border.rs index 670337ae..51262214 100644 --- a/src/view/border.rs +++ b/src/view/border.rs @@ -99,6 +99,7 @@ pub struct LozengeDotted(pub Style); pub struct Quarter(pub Style); pub struct QuarterV(pub Style); pub struct Chamfer(pub Style); +pub struct Corners(pub Style); border! { Lozenge { @@ -148,5 +149,13 @@ border! { fn style (&self) -> Option