use crate::*; use super::*; use std::marker::ConstParamTy; use EdnItem::*; const EDN: &'static str = include_str!("groovebox.edn"); //impl Content for Groovebox { //fn content (&self) -> impl Render { //self.size.of(EdnView::from_source(self, EDN)) //} //} // this works: render!(TuiOut: (self: Groovebox) => self.size.of( Bsp::s(self.toolbar_view(), Bsp::n(self.selector_view(), Bsp::n(self.sample_view(), Bsp::n(self.status_view(), Bsp::w(self.pool_view(), Fill::xy(Bsp::e(self.sampler_view(), &self.editor))))))))); impl Groovebox { fn toolbar_view (&self) -> impl Content + use<'_> { Fill::x(Fixed::y(2, lay!( Align::w(Meter("L/", self.sampler.input_meter[0])), Align::e(Meter("R/", self.sampler.input_meter[1])), Align::x(TransportView::new(true, &self.player.clock)), ))) } fn selector_view (&self) -> impl Content + use<'_> { row!( ClipSelected::play_phrase(&self.player), ClipSelected::next_phrase(&self.player), MidiEditClip(&self.editor), MidiEditStatus(&self.editor), ) } fn sample_view (&self) -> impl Content + use<'_> { let note_pt = self.editor.note_point(); let sample_h = if self.compact { 0 } else { 5 }; Max::y(sample_h, Fill::xy( SampleViewer::from_sampler(&self.sampler, note_pt))) } fn status_view (&self) -> impl Content + use<'_> { let note_pt = self.editor.note_point(); Align::w(Fixed::y(1, SamplerStatus(&self.sampler, note_pt))) } fn pool_view (&self) -> impl Content + use<'_> { let w = self.size.w(); let pool_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 }; Fixed::x(if self.compact { 5 } else { pool_w }, PoolView(self.compact, &self.pool)) } fn sampler_view (&self) -> impl Content + use<'_> { let sampler_w = if self.compact { 4 } else { 11 }; let sampler_y = if self.compact { 1 } else { 0 }; Fixed::x(sampler_w, Push::y(sampler_y, Fill::y( SampleList::new(self.compact, &self.sampler, &self.editor)))) } } ///// Status bar for sequencer app //#[derive(Clone)] //pub struct GrooveboxStatus { //pub(crate) width: usize, //pub(crate) cpu: Option, //pub(crate) size: String, //pub(crate) playing: bool, //} //from!(|state: &Groovebox|GrooveboxStatus = { //let samples = state.clock().chunk.load(Relaxed); //let rate = state.clock().timebase.sr.get(); //let buffer = samples as f64 / rate; //let width = state.size.w(); //Self { //width, //playing: state.clock().is_rolling(), //cpu: state.perf.percentage().map(|cpu|format!("│{cpu:.01}%")), //size: format!("{}x{}│", width, state.size.h()), //} //}); //render!(TuiOut: (self: GrooveboxStatus) => Fixed::y(2, lay!( //Self::help(), //Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), //))); //impl GrooveboxStatus { //fn help () -> impl Content { //let single = |binding, command|row!(" ", col!( //Tui::fg(TuiTheme::yellow(), binding), //command //)); //let double = |(b1, c1), (b2, c2)|col!( //row!(" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,), //row!(" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,), //); //Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!( //single("SPACE", "play/pause"), //double(("▲▼▶◀", "cursor"), ("Ctrl", "scroll"), ), //double(("a", "append"), ("s", "set note"),), //double((",.", "length"), ("<>", "triplet"), ), //double(("[]", "phrase"), ("{}", "order"), ), //double(("q", "enqueue"), ("e", "edit"), ), //double(("c", "color"), ("", ""),), //)) //} //fn stats (&self) -> impl Content + use<'_> { //row!(&self.cpu, &self.size) //} //} //render!(TuiOut: (self: Groovebox) => self.size.of( //Bsp::s(self.toolbar_view(), //Bsp::n(self.selector_view(), //Bsp::n(self.sample_view(), //Bsp::n(self.status_view(), //Bsp::w(self.pool_view(), Fill::xy(Bsp::e(self.sampler_view(), &self.editor))))))))); //const GROOVEBOX_EDN: &'static str = include_str!("groovebox.edn"); //impl Content for Groovebox { //fn content (&self) -> impl Content { //EdnView::parse(self.edn.as_slice()) //} //} //macro_rules! edn_context { //($Struct:ident |$l:lifetime, $state:ident| { //$($key:literal = $field:ident: $Type:ty => $expr:expr,)* //}) => { //#[derive(Default)] //pub struct EdnView<$l> { $($field: Option<$Type>),* } //impl<$l> EdnView<$l> { //pub fn parse <'e> (edn: &[Edn<'e>]) -> impl Fn(&$Struct) + use<'e> { //let imports = Self::imports_all(edn); //move |state| { //let mut context = EdnView::default(); //for import in imports.iter() { //context.import(state, import) //} //} //} //fn imports_all <'e> (edn: &[Edn<'e>]) -> Vec<&'e str> { //let mut imports = vec![]; //for edn in edn.iter() { //for import in Self::imports_one(edn) { //imports.push(import); //} //} //imports //} //fn imports_one <'e> (edn: &Edn<'e>) -> Vec<&'e str> { //match edn { //Edn::Symbol(import) => vec![import], //Edn::List(edn) => Self::imports_all(edn.as_slice()), //_ => vec![], //} //} //pub fn import (&mut self, $state: &$l$Struct, key: &str) { //match key { //$($key => self.$field = Some($expr),)* //_ => {} //} //} //} //} //} ////impl Groovebox { ////fn status_view (&self) -> impl Content + use<'_> { ////let note_pt = self.editor.note_point(); ////Align::w(Fixed::y(1, )) ////} ////fn pool_view (&self) -> impl Content + use<'_> { ////let w = self.size.w(); ////let pool_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 }; ////Fixed::x(if self.compact { 5 } else { pool_w }, ////) ////} ////fn sampler_view (&self) -> impl Content + use<'_> { ////let sampler_w = if self.compact { 4 } else { 11 }; ////let sampler_y = if self.compact { 1 } else { 0 }; ////Fixed::x(sampler_w, Push::y(sampler_y, Fill::y( ////SampleList::new(self.compact, &self.sampler, &self.editor)))) ////} ////}