From 2f772eceef559b09fb78608fb6810939ad04a68e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 9 Dec 2024 19:15:15 +0100 Subject: [PATCH] wip8 (22e) --- crates/tek/src/api.rs | 466 +---------------------- crates/tek/src/api/jack.rs | 441 +++++++++++++++++++++ crates/tek/src/core.rs | 30 +- crates/tek/src/core/collect.rs | 78 ---- crates/tek/src/core/test.rs | 190 --------- crates/tek/src/layout.rs | 35 +- crates/tek/src/layout/bsp.rs | 18 + crates/tek/src/layout/collect.rs | 79 ++++ crates/tek/src/layout/shrink_grow.rs | 48 +-- crates/tek/src/layout/stack.rs | 23 +- crates/tek/src/lib.rs | 10 +- crates/tek/src/test.rs | 190 +++++++++ crates/tek/src/tui.rs | 81 ++-- crates/tek/src/tui/app_sequencer.rs | 4 +- crates/tek/src/tui/ctrl_arranger.rs | 10 +- crates/tek/src/tui/ctrl_file_browser.rs | 8 +- crates/tek/src/tui/ctrl_phrase_length.rs | 5 +- crates/tek/src/tui/ctrl_phrase_list.rs | 29 +- crates/tek/src/tui/ctrl_sequencer.rs | 10 +- crates/tek/src/tui/ctrl_transport.rs | 6 +- crates/tek/src/tui/jack_arranger.rs | 2 +- crates/tek/src/tui/jack_sequencer.rs | 2 +- crates/tek/src/tui/model_phrase_list.rs | 1 + crates/tek/src/tui/view_file_browser.rs | 36 +- crates/tek/src/tui/view_phrase_editor.rs | 30 +- crates/tek/src/tui/view_transport.rs | 2 +- 26 files changed, 926 insertions(+), 908 deletions(-) delete mode 100644 crates/tek/src/core/test.rs create mode 100644 crates/tek/src/layout/collect.rs diff --git a/crates/tek/src/api.rs b/crates/tek/src/api.rs index 883c0aeb..ce2f87e1 100644 --- a/crates/tek/src/api.rs +++ b/crates/tek/src/api.rs @@ -1,460 +1,10 @@ use crate::*; -submod! { - clip - clock - color - jack - phrase - player - scene - track - - //api_mixer - //api_channel - //api_plugin - //api_plugin_kind - //api_plugin_lv2 - //api_sampler - //api_sampler_sample - //api_sampler_voice -} - -pub trait JackActivate: Sized { - fn activate_with ( - self, - init: impl FnOnce(&Arc>)->Usually - ) - -> Usually>>; -} - -impl JackActivate for JackClient { - fn activate_with ( - self, - init: impl FnOnce(&Arc>)->Usually - ) - -> Usually>> - { - let client = Arc::new(RwLock::new(self)); - let target = Arc::new(RwLock::new(init(&client)?)); - let event = Box::new(move|_|{/*TODO*/}) as Box; - let events = Notifications(event); - let frame = Box::new({ - let target = target.clone(); - move|c: &_, s: &_|if let Ok(mut target) = target.write() { - target.process(c, s) - } else { - Control::Quit - } - }); - let frames = ClosureProcessHandler::new(frame as BoxedAudioHandler); - let mut buffer = Self::Activating; - std::mem::swap(&mut*client.write().unwrap(), &mut buffer); - *client.write().unwrap() = Self::Active(Client::from(buffer).activate_async(events, frames)?); - Ok(target) - } -} - -/// Trait for things that have a JACK process callback. -pub trait Audio: Send + Sync { - fn process(&mut self, _: &Client, _: &ProcessScope) -> Control { - Control::Continue - } - fn callback( - state: &Arc>, client: &Client, scope: &ProcessScope - ) -> Control where Self: Sized { - if let Ok(mut state) = state.write() { - state.process(client, scope) - } else { - Control::Quit - } - } -} - -/// A UI component that may be associated with a JACK client by the `Jack` factory. -pub trait AudioComponent: Component + Audio { - /// Perform type erasure for collecting heterogeneous devices. - fn boxed(self) -> Box> - where - Self: Sized + 'static, - { - Box::new(self) - } -} - -/// All things that implement the required traits can be treated as `AudioComponent`. -impl + Audio> AudioComponent for W {} - -/// Trait for things that may expose JACK ports. -pub trait Ports { - fn audio_ins(&self) -> Usually>> { - Ok(vec![]) - } - fn audio_outs(&self) -> Usually>> { - Ok(vec![]) - } - fn midi_ins(&self) -> Usually>> { - Ok(vec![]) - } - fn midi_outs(&self) -> Usually>> { - Ok(vec![]) - } -} - -fn register_ports( - client: &Client, - names: Vec, - spec: T, -) -> Usually>> { - names - .into_iter() - .try_fold(BTreeMap::new(), |mut ports, name| { - let port = client.register_port(&name, spec)?; - ports.insert(name, port); - Ok(ports) - }) -} - -fn query_ports(client: &Client, names: Vec) -> BTreeMap> { - names.into_iter().fold(BTreeMap::new(), |mut ports, name| { - let port = client.port_by_name(&name).unwrap(); - ports.insert(name, port); - ports - }) -} - -///// A [AudioComponent] bound to a JACK client and a set of ports. -//pub struct JackDevice { - ///// The active JACK client of this device. - //pub client: DynamicAsyncClient, - ///// The device state, encapsulated for sharing between threads. - //pub state: Arc>>>, - ///// Unowned copies of the device's JACK ports, for connecting to the device. - ///// The "real" readable/writable `Port`s are owned by the `state`. - //pub ports: UnownedJackPorts, -//} - -//impl std::fmt::Debug for JackDevice { - //fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - //f.debug_struct("JackDevice") - //.field("ports", &self.ports) - //.finish() - //} -//} - -//impl Render for JackDevice { - //type Engine = E; - //fn min_size(&self, to: E::Size) -> Perhaps { - //self.state.read().unwrap().layout(to) - //} - //fn render(&self, to: &mut E::Output) -> Usually<()> { - //self.state.read().unwrap().render(to) - //} -//} - -//impl Handle for JackDevice { - //fn handle(&mut self, from: &E::Input) -> Perhaps { - //self.state.write().unwrap().handle(from) - //} -//} - -//impl Ports for JackDevice { - //fn audio_ins(&self) -> Usually>> { - //Ok(self.ports.audio_ins.values().collect()) - //} - //fn audio_outs(&self) -> Usually>> { - //Ok(self.ports.audio_outs.values().collect()) - //} - //fn midi_ins(&self) -> Usually>> { - //Ok(self.ports.midi_ins.values().collect()) - //} - //fn midi_outs(&self) -> Usually>> { - //Ok(self.ports.midi_outs.values().collect()) - //} -//} - -//impl JackDevice { - ///// Returns a locked mutex of the state's contents. - //pub fn state(&self) -> LockResult>>> { - //self.state.read() - //} - ///// Returns a locked mutex of the state's contents. - //pub fn state_mut(&self) -> LockResult>>> { - //self.state.write() - //} - //pub fn connect_midi_in(&self, index: usize, port: &Port) -> Usually<()> { - //Ok(self - //.client - //.as_client() - //.connect_ports(port, self.midi_ins()?[index])?) - //} - //pub fn connect_midi_out(&self, index: usize, port: &Port) -> Usually<()> { - //Ok(self - //.client - //.as_client() - //.connect_ports(self.midi_outs()?[index], port)?) - //} - //pub fn connect_audio_in(&self, index: usize, port: &Port) -> Usually<()> { - //Ok(self - //.client - //.as_client() - //.connect_ports(port, self.audio_ins()?[index])?) - //} - //pub fn connect_audio_out(&self, index: usize, port: &Port) -> Usually<()> { - //Ok(self - //.client - //.as_client() - //.connect_ports(self.audio_outs()?[index], port)?) - //} -//} - -///// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut]. -//#[derive(Default, Debug)] -//pub struct JackPorts { - //pub audio_ins: BTreeMap>, - //pub midi_ins: BTreeMap>, - //pub audio_outs: BTreeMap>, - //pub midi_outs: BTreeMap>, -//} - -///// Collection of JACK ports as [Unowned]. -//#[derive(Default, Debug)] -//pub struct UnownedJackPorts { - //pub audio_ins: BTreeMap>, - //pub midi_ins: BTreeMap>, - //pub audio_outs: BTreeMap>, - //pub midi_outs: BTreeMap>, -//} - -//impl JackPorts { - //pub fn clone_unowned(&self) -> UnownedJackPorts { - //let mut unowned = UnownedJackPorts::default(); - //for (name, port) in self.midi_ins.iter() { - //unowned.midi_ins.insert(name.clone(), port.clone_unowned()); - //} - //for (name, port) in self.midi_outs.iter() { - //unowned.midi_outs.insert(name.clone(), port.clone_unowned()); - //} - //for (name, port) in self.audio_ins.iter() { - //unowned.audio_ins.insert(name.clone(), port.clone_unowned()); - //} - //for (name, port) in self.audio_outs.iter() { - //unowned - //.audio_outs - //.insert(name.clone(), port.clone_unowned()); - //} - //unowned - //} -//} - -///// Implement the `Ports` trait. -//#[macro_export] -//macro_rules! ports { - //($T:ty $({ $(audio: { - //$(ins: |$ai_arg:ident|$ai_impl:expr,)? - //$(outs: |$ao_arg:ident|$ao_impl:expr,)? - //})? $(midi: { - //$(ins: |$mi_arg:ident|$mi_impl:expr,)? - //$(outs: |$mo_arg:ident|$mo_impl:expr,)? - //})?})?) => { - //impl Ports for $T {$( - //$( - //$(fn audio_ins <'a> (&'a self) -> Usually>> { - //let cb = |$ai_arg:&'a Self|$ai_impl; - //cb(self) - //})? - //)? - //$( - //$(fn audio_outs <'a> (&'a self) -> Usually>> { - //let cb = (|$ao_arg:&'a Self|$ao_impl); - //cb(self) - //})? - //)? - //)? $( - //$( - //$(fn midi_ins <'a> (&'a self) -> Usually>> { - //let cb = (|$mi_arg:&'a Self|$mi_impl); - //cb(self) - //})? - //)? - //$( - //$(fn midi_outs <'a> (&'a self) -> Usually>> { - //let cb = (|$mo_arg:&'a Self|$mo_impl); - //cb(self) - //})? - //)? - //)?} - //}; -//} - -///// `JackDevice` factory. Creates JACK `Client`s, performs port registration -///// and activation, and encapsulates a `AudioComponent` into a `JackDevice`. -//pub struct Jack { - //pub client: Client, - //pub midi_ins: Vec, - //pub audio_ins: Vec, - //pub midi_outs: Vec, - //pub audio_outs: Vec, -//} - -//impl Jack { - //pub fn new(name: &str) -> Usually { - //Ok(Self { - //midi_ins: vec![], - //audio_ins: vec![], - //midi_outs: vec![], - //audio_outs: vec![], - //client: Client::new(name, ClientOptions::NO_START_SERVER)?.0, - //}) - //} - //pub fn run<'a: 'static, D, E>( - //self, - //state: impl FnOnce(JackPorts) -> Box, - //) -> Usually> - //where - //D: AudioComponent + Sized + 'static, - //E: Engine + 'static, - //{ - //let owned_ports = JackPorts { - //audio_ins: register_ports(&self.client, self.audio_ins, AudioIn::default())?, - //audio_outs: register_ports(&self.client, self.audio_outs, AudioOut::default())?, - //midi_ins: register_ports(&self.client, self.midi_ins, MidiIn::default())?, - //midi_outs: register_ports(&self.client, self.midi_outs, MidiOut::default())?, - //}; - //let midi_outs = owned_ports - //.midi_outs - //.values() - //.map(|p| Ok(p.name()?)) - //.collect::>>()?; - //let midi_ins = owned_ports - //.midi_ins - //.values() - //.map(|p| Ok(p.name()?)) - //.collect::>>()?; - //let audio_outs = owned_ports - //.audio_outs - //.values() - //.map(|p| Ok(p.name()?)) - //.collect::>>()?; - //let audio_ins = owned_ports - //.audio_ins - //.values() - //.map(|p| Ok(p.name()?)) - //.collect::>>()?; - //let state = Arc::new(RwLock::new(state(owned_ports) as Box>)); - //let client = self.client.activate_async( - //Notifications(Box::new({ - //let _state = state.clone(); - //move |_event| { - //// FIXME: this deadlocks - ////state.lock().unwrap().handle(&event).unwrap(); - //} - //}) as Box), - //contrib::ClosureProcessHandler::new(Box::new({ - //let state = state.clone(); - //move |c: &Client, s: &ProcessScope| state.write().unwrap().process(c, s) - //}) as BoxedAudioHandler), - //)?; - //Ok(JackDevice { - //ports: UnownedJackPorts { - //audio_ins: query_ports(&client.as_client(), audio_ins), - //audio_outs: query_ports(&client.as_client(), audio_outs), - //midi_ins: query_ports(&client.as_client(), midi_ins), - //midi_outs: query_ports(&client.as_client(), midi_outs), - //}, - //client, - //state, - //}) - //} - //pub fn audio_in(mut self, name: &str) -> Self { - //self.audio_ins.push(name.to_string()); - //self - //} - //pub fn audio_out(mut self, name: &str) -> Self { - //self.audio_outs.push(name.to_string()); - //self - //} - //pub fn midi_in(mut self, name: &str) -> Self { - //self.midi_ins.push(name.to_string()); - //self - //} - //pub fn midi_out(mut self, name: &str) -> Self { - //self.midi_outs.push(name.to_string()); - //self - //} -//} - -//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::Vertical(factor) = self.mode { - //self.mode = ArrangerEditorMode::Vertical(factor + 1) - //} - //} - //pub fn zoom_out (&mut self) { - //if let ArrangerEditorMode::Vertical(factor) = self.mode { - //self.mode = ArrangerEditorMode::Vertical(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") - //} - //} - -//impl From for Clock { - //fn from (current: Moment) -> Self { - //Self { - //playing: Some(TransportState::Stopped).into(), - //started: None.into(), - //quant: 24.into(), - //sync: (current.timebase.ppq.get() * 4.).into(), - //current, - //} - //} -//} +mod phrase; pub(crate) use phrase::*; +mod jack; pub(crate) use jack::*; +mod clip; pub(crate) use clip::*; +mod color; pub(crate) use color::*; +mod clock; pub(crate) use clock::*; +mod player; pub(crate) use player::*; +mod scene; pub(crate) use scene::*; +mod track; pub(crate) use track::*; diff --git a/crates/tek/src/api/jack.rs b/crates/tek/src/api/jack.rs index e378869f..97ba47d8 100644 --- a/crates/tek/src/api/jack.rs +++ b/crates/tek/src/api/jack.rs @@ -20,3 +20,444 @@ pub trait HasMidiOuts { self.midi_outs().len() > 0 } } + +//////////////////////////////////////////////////////////////////////////////////// + +pub trait JackActivate: Sized { + fn activate_with ( + self, + init: impl FnOnce(&Arc>)->Usually + ) + -> Usually>>; +} + +impl JackActivate for JackClient { + fn activate_with ( + self, + init: impl FnOnce(&Arc>)->Usually + ) + -> Usually>> + { + let client = Arc::new(RwLock::new(self)); + let target = Arc::new(RwLock::new(init(&client)?)); + let event = Box::new(move|_|{/*TODO*/}) as Box; + let events = Notifications(event); + let frame = Box::new({ + let target = target.clone(); + move|c: &_, s: &_|if let Ok(mut target) = target.write() { + target.process(c, s) + } else { + Control::Quit + } + }); + let frames = ClosureProcessHandler::new(frame as BoxedAudioHandler); + let mut buffer = Self::Activating; + std::mem::swap(&mut*client.write().unwrap(), &mut buffer); + *client.write().unwrap() = Self::Active(Client::from(buffer).activate_async(events, frames)?); + Ok(target) + } +} + +/// Trait for things that have a JACK process callback. +pub trait Audio: Send + Sync { + fn process(&mut self, _: &Client, _: &ProcessScope) -> Control { + Control::Continue + } + fn callback( + state: &Arc>, client: &Client, scope: &ProcessScope + ) -> Control where Self: Sized { + if let Ok(mut state) = state.write() { + state.process(client, scope) + } else { + Control::Quit + } + } +} + +/// A UI component that may be associated with a JACK client by the `Jack` factory. +pub trait AudioComponent: Component + Audio { + /// Perform type erasure for collecting heterogeneous devices. + fn boxed(self) -> Box> + where + Self: Sized + 'static, + { + Box::new(self) + } +} + +/// All things that implement the required traits can be treated as `AudioComponent`. +impl + Audio> AudioComponent for W {} + +/// Trait for things that may expose JACK ports. +pub trait Ports { + fn audio_ins(&self) -> Usually>> { + Ok(vec![]) + } + fn audio_outs(&self) -> Usually>> { + Ok(vec![]) + } + fn midi_ins(&self) -> Usually>> { + Ok(vec![]) + } + fn midi_outs(&self) -> Usually>> { + Ok(vec![]) + } +} + +fn register_ports( + client: &Client, + names: Vec, + spec: T, +) -> Usually>> { + names + .into_iter() + .try_fold(BTreeMap::new(), |mut ports, name| { + let port = client.register_port(&name, spec)?; + ports.insert(name, port); + Ok(ports) + }) +} + +fn query_ports(client: &Client, names: Vec) -> BTreeMap> { + names.into_iter().fold(BTreeMap::new(), |mut ports, name| { + let port = client.port_by_name(&name).unwrap(); + ports.insert(name, port); + ports + }) +} + +///// A [AudioComponent] bound to a JACK client and a set of ports. +//pub struct JackDevice { + ///// The active JACK client of this device. + //pub client: DynamicAsyncClient, + ///// The device state, encapsulated for sharing between threads. + //pub state: Arc>>>, + ///// Unowned copies of the device's JACK ports, for connecting to the device. + ///// The "real" readable/writable `Port`s are owned by the `state`. + //pub ports: UnownedJackPorts, +//} + +//impl std::fmt::Debug for JackDevice { + //fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + //f.debug_struct("JackDevice") + //.field("ports", &self.ports) + //.finish() + //} +//} + +//impl Render for JackDevice { + //type Engine = E; + //fn min_size(&self, to: E::Size) -> Perhaps { + //self.state.read().unwrap().layout(to) + //} + //fn render(&self, to: &mut E::Output) -> Usually<()> { + //self.state.read().unwrap().render(to) + //} +//} + +//impl Handle for JackDevice { + //fn handle(&mut self, from: &E::Input) -> Perhaps { + //self.state.write().unwrap().handle(from) + //} +//} + +//impl Ports for JackDevice { + //fn audio_ins(&self) -> Usually>> { + //Ok(self.ports.audio_ins.values().collect()) + //} + //fn audio_outs(&self) -> Usually>> { + //Ok(self.ports.audio_outs.values().collect()) + //} + //fn midi_ins(&self) -> Usually>> { + //Ok(self.ports.midi_ins.values().collect()) + //} + //fn midi_outs(&self) -> Usually>> { + //Ok(self.ports.midi_outs.values().collect()) + //} +//} + +//impl JackDevice { + ///// Returns a locked mutex of the state's contents. + //pub fn state(&self) -> LockResult>>> { + //self.state.read() + //} + ///// Returns a locked mutex of the state's contents. + //pub fn state_mut(&self) -> LockResult>>> { + //self.state.write() + //} + //pub fn connect_midi_in(&self, index: usize, port: &Port) -> Usually<()> { + //Ok(self + //.client + //.as_client() + //.connect_ports(port, self.midi_ins()?[index])?) + //} + //pub fn connect_midi_out(&self, index: usize, port: &Port) -> Usually<()> { + //Ok(self + //.client + //.as_client() + //.connect_ports(self.midi_outs()?[index], port)?) + //} + //pub fn connect_audio_in(&self, index: usize, port: &Port) -> Usually<()> { + //Ok(self + //.client + //.as_client() + //.connect_ports(port, self.audio_ins()?[index])?) + //} + //pub fn connect_audio_out(&self, index: usize, port: &Port) -> Usually<()> { + //Ok(self + //.client + //.as_client() + //.connect_ports(self.audio_outs()?[index], port)?) + //} +//} + +///// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut]. +//#[derive(Default, Debug)] +//pub struct JackPorts { + //pub audio_ins: BTreeMap>, + //pub midi_ins: BTreeMap>, + //pub audio_outs: BTreeMap>, + //pub midi_outs: BTreeMap>, +//} + +///// Collection of JACK ports as [Unowned]. +//#[derive(Default, Debug)] +//pub struct UnownedJackPorts { + //pub audio_ins: BTreeMap>, + //pub midi_ins: BTreeMap>, + //pub audio_outs: BTreeMap>, + //pub midi_outs: BTreeMap>, +//} + +//impl JackPorts { + //pub fn clone_unowned(&self) -> UnownedJackPorts { + //let mut unowned = UnownedJackPorts::default(); + //for (name, port) in self.midi_ins.iter() { + //unowned.midi_ins.insert(name.clone(), port.clone_unowned()); + //} + //for (name, port) in self.midi_outs.iter() { + //unowned.midi_outs.insert(name.clone(), port.clone_unowned()); + //} + //for (name, port) in self.audio_ins.iter() { + //unowned.audio_ins.insert(name.clone(), port.clone_unowned()); + //} + //for (name, port) in self.audio_outs.iter() { + //unowned + //.audio_outs + //.insert(name.clone(), port.clone_unowned()); + //} + //unowned + //} +//} + +///// Implement the `Ports` trait. +//#[macro_export] +//macro_rules! ports { + //($T:ty $({ $(audio: { + //$(ins: |$ai_arg:ident|$ai_impl:expr,)? + //$(outs: |$ao_arg:ident|$ao_impl:expr,)? + //})? $(midi: { + //$(ins: |$mi_arg:ident|$mi_impl:expr,)? + //$(outs: |$mo_arg:ident|$mo_impl:expr,)? + //})?})?) => { + //impl Ports for $T {$( + //$( + //$(fn audio_ins <'a> (&'a self) -> Usually>> { + //let cb = |$ai_arg:&'a Self|$ai_impl; + //cb(self) + //})? + //)? + //$( + //$(fn audio_outs <'a> (&'a self) -> Usually>> { + //let cb = (|$ao_arg:&'a Self|$ao_impl); + //cb(self) + //})? + //)? + //)? $( + //$( + //$(fn midi_ins <'a> (&'a self) -> Usually>> { + //let cb = (|$mi_arg:&'a Self|$mi_impl); + //cb(self) + //})? + //)? + //$( + //$(fn midi_outs <'a> (&'a self) -> Usually>> { + //let cb = (|$mo_arg:&'a Self|$mo_impl); + //cb(self) + //})? + //)? + //)?} + //}; +//} + +///// `JackDevice` factory. Creates JACK `Client`s, performs port registration +///// and activation, and encapsulates a `AudioComponent` into a `JackDevice`. +//pub struct Jack { + //pub client: Client, + //pub midi_ins: Vec, + //pub audio_ins: Vec, + //pub midi_outs: Vec, + //pub audio_outs: Vec, +//} + +//impl Jack { + //pub fn new(name: &str) -> Usually { + //Ok(Self { + //midi_ins: vec![], + //audio_ins: vec![], + //midi_outs: vec![], + //audio_outs: vec![], + //client: Client::new(name, ClientOptions::NO_START_SERVER)?.0, + //}) + //} + //pub fn run<'a: 'static, D, E>( + //self, + //state: impl FnOnce(JackPorts) -> Box, + //) -> Usually> + //where + //D: AudioComponent + Sized + 'static, + //E: Engine + 'static, + //{ + //let owned_ports = JackPorts { + //audio_ins: register_ports(&self.client, self.audio_ins, AudioIn::default())?, + //audio_outs: register_ports(&self.client, self.audio_outs, AudioOut::default())?, + //midi_ins: register_ports(&self.client, self.midi_ins, MidiIn::default())?, + //midi_outs: register_ports(&self.client, self.midi_outs, MidiOut::default())?, + //}; + //let midi_outs = owned_ports + //.midi_outs + //.values() + //.map(|p| Ok(p.name()?)) + //.collect::>>()?; + //let midi_ins = owned_ports + //.midi_ins + //.values() + //.map(|p| Ok(p.name()?)) + //.collect::>>()?; + //let audio_outs = owned_ports + //.audio_outs + //.values() + //.map(|p| Ok(p.name()?)) + //.collect::>>()?; + //let audio_ins = owned_ports + //.audio_ins + //.values() + //.map(|p| Ok(p.name()?)) + //.collect::>>()?; + //let state = Arc::new(RwLock::new(state(owned_ports) as Box>)); + //let client = self.client.activate_async( + //Notifications(Box::new({ + //let _state = state.clone(); + //move |_event| { + //// FIXME: this deadlocks + ////state.lock().unwrap().handle(&event).unwrap(); + //} + //}) as Box), + //contrib::ClosureProcessHandler::new(Box::new({ + //let state = state.clone(); + //move |c: &Client, s: &ProcessScope| state.write().unwrap().process(c, s) + //}) as BoxedAudioHandler), + //)?; + //Ok(JackDevice { + //ports: UnownedJackPorts { + //audio_ins: query_ports(&client.as_client(), audio_ins), + //audio_outs: query_ports(&client.as_client(), audio_outs), + //midi_ins: query_ports(&client.as_client(), midi_ins), + //midi_outs: query_ports(&client.as_client(), midi_outs), + //}, + //client, + //state, + //}) + //} + //pub fn audio_in(mut self, name: &str) -> Self { + //self.audio_ins.push(name.to_string()); + //self + //} + //pub fn audio_out(mut self, name: &str) -> Self { + //self.audio_outs.push(name.to_string()); + //self + //} + //pub fn midi_in(mut self, name: &str) -> Self { + //self.midi_ins.push(name.to_string()); + //self + //} + //pub fn midi_out(mut self, name: &str) -> Self { + //self.midi_outs.push(name.to_string()); + //self + //} +//} + +//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::Vertical(factor) = self.mode { + //self.mode = ArrangerEditorMode::Vertical(factor + 1) + //} + //} + //pub fn zoom_out (&mut self) { + //if let ArrangerEditorMode::Vertical(factor) = self.mode { + //self.mode = ArrangerEditorMode::Vertical(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") + //} + //} + +//impl From for Clock { + //fn from (current: Moment) -> Self { + //Self { + //playing: Some(TransportState::Stopped).into(), + //started: None.into(), + //quant: 24.into(), + //sync: (current.timebase.ppq.get() * 4.).into(), + //current, + //} + //} +//} diff --git a/crates/tek/src/core.rs b/crates/tek/src/core.rs index 9105f901..8a3cd53f 100644 --- a/crates/tek/src/core.rs +++ b/crates/tek/src/core.rs @@ -1,21 +1,13 @@ use crate::*; -submod! { - //tui - audio - color - collect - command - edn - engine - focus - input - output - pitch - space - time -} - -testmod! { - test -} +mod audio; pub(crate) use audio::*; +mod color; pub(crate) use color::*; +mod command; pub(crate) use command::*; +mod edn; pub(crate) use edn::*; +mod engine; pub(crate) use engine::*; +mod focus; pub(crate) use focus::*; +mod input; pub(crate) use input::*; +mod output; pub(crate) use output::*; +mod pitch; pub(crate) use pitch::*; +mod space; pub(crate) use space::*; +mod time; pub(crate) use time::*; diff --git a/crates/tek/src/core/collect.rs b/crates/tek/src/core/collect.rs index 540b9f29..e69de29b 100644 --- a/crates/tek/src/core/collect.rs +++ b/crates/tek/src/core/collect.rs @@ -1,78 +0,0 @@ -use crate::*; - -pub enum Collect<'a, E: Engine, const N: usize> { - Callback(CallbackCollection<'a, E>), - //Iterator(IteratorCollection<'a, E>), - Array(ArrayCollection<'a, E, N>), - Slice(SliceCollection<'a, E>), -} - -impl<'a, E: Engine, const N: usize> Collect<'a, E, N> { - pub fn iter (&'a self) -> CollectIterator<'a, E, N> { - CollectIterator(0, &self) - } -} - -impl<'a, E: Engine, const N: usize> From> for Collect<'a, E, N> { - fn from (callback: CallbackCollection<'a, E>) -> Self { - Self::Callback(callback) - } -} - -impl<'a, E: Engine, const N: usize> From> for Collect<'a, E, N> { - fn from (slice: SliceCollection<'a, E>) -> Self { - Self::Slice(slice) - } -} - -impl<'a, E: Engine, const N: usize> From> for Collect<'a, E, N>{ - fn from (array: ArrayCollection<'a, E, N>) -> Self { - Self::Array(array) - } -} - -type CallbackCollection<'a, E> = - &'a dyn Fn(&'a mut dyn FnMut(&dyn Render)->Usually<()>); - -//type IteratorCollection<'a, E> = - //&'a mut dyn Iterator>; - -type SliceCollection<'a, E> = - &'a [&'a dyn Render]; - -type ArrayCollection<'a, E, const N: usize> = - [&'a dyn Render; N]; - -pub struct CollectIterator<'a, E: Engine, const N: usize>(usize, &'a Collect<'a, E, N>); - -impl<'a, E: Engine, const N: usize> Iterator for CollectIterator<'a, E, N> { - type Item = &'a dyn Render; - fn next (&mut self) -> Option { - match self.1 { - Collect::Callback(callback) => { - todo!() - }, - //Collection::Iterator(iterator) => { - //iterator.next() - //}, - Collect::Array(array) => { - if let Some(item) = array.get(self.0) { - self.0 += 1; - //Some(item) - None - } else { - None - } - } - Collect::Slice(slice) => { - if let Some(item) = slice.get(self.0) { - self.0 += 1; - //Some(item) - None - } else { - None - } - } - } - } -} diff --git a/crates/tek/src/core/test.rs b/crates/tek/src/core/test.rs deleted file mode 100644 index fe6a77b2..00000000 --- a/crates/tek/src/core/test.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::*; - -struct TestEngine([u16;4], Vec>); - -impl Engine for TestEngine { - type Unit = u16; - type Size = [Self::Unit;2]; - type Area = [Self::Unit;4]; - type Input = Self; - type Handled = bool; - fn exited (&self) -> bool { - true - } - fn area (&self) -> Self::Area { - self.0 - } - fn area_mut (&mut self) -> &mut Self::Area { - &mut self.0 - } -} - -#[derive(Copy, Clone)] -struct TestArea(u16, u16); - -impl Render for TestArea { - type Engine = TestEngine; - fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - Ok(Some([to[0], to[1], self.0, self.1])) - } - fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> { - if let Some(layout) = self.layout(to.area())? { - for y in layout.y()..layout.y()+layout.h()-1 { - for x in layout.x()..layout.x()+layout.w()-1 { - to.1[y as usize][x as usize] = '*'; - } - } - Ok(Some(layout)) - } else { - Ok(None) - } - } -} - -#[test] -fn test_plus_minus () -> Usually<()> { - let area = [0, 0, 10, 10]; - let engine = TestEngine(area, vec![vec![' ';10];10]); - let test = TestArea(4, 4); - assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); - assert_eq!(Push::X(1, test).layout(area)?, Some([1, 0, 4, 4])); - Ok(()) -} - -#[test] -fn test_outset_align () -> Usually<()> { - let area = [0, 0, 10, 10]; - let engine = TestEngine(area, vec![vec![' ';10];10]); - let test = TestArea(4, 4); - assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); - assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4])); - assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4])); - assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4])); - assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4])); - Ok(()) -} - -//#[test] -//fn test_misc () -> Usually<()> { - //let area: [u16;4] = [0, 0, 10, 10]; - //let test = TestArea(4, 4); - //assert_eq!(test.layout(area)?, - //Some([0, 0, 4, 4])); - //assert_eq!(Align::Center(test).layout(area)?, - //Some([3, 3, 4, 4])); - //assert_eq!(Align::Center(Stack::down(|add|{ - //add(&test)?; - //add(&test) - //})).layout(area)?, - //Some([3, 1, 4, 8])); - //assert_eq!(Align::Center(Stack::down(|add|{ - //add(&Outset::XY(2, 2, test))?; - //add(&test) - //})).layout(area)?, - //Some([2, 0, 6, 10])); - //assert_eq!(Align::Center(Stack::down(|add|{ - //add(&Outset::XY(2, 2, test))?; - //add(&Inset::XY(2, 2, test)) - //})).layout(area)?, - //Some([2, 1, 6, 8])); - //assert_eq!(Stack::down(|add|{ - //add(&Outset::XY(2, 2, test))?; - //add(&Inset::XY(2, 2, test)) - //}).layout(area)?, - //Some([0, 0, 6, 8])); - //assert_eq!(Stack::right(|add|{ - //add(&Stack::down(|add|{ - //add(&Outset::XY(2, 2, test))?; - //add(&Inset::XY(2, 2, test)) - //}))?; - //add(&Align::Center(TestArea(2 ,2))) - //}).layout(area)?, - //Some([0, 0, 8, 8])); - //Ok(()) -//} - -//#[test] -//fn test_offset () -> Usually<()> { - //let area: [u16;4] = [50, 50, 100, 100]; - //let test = TestArea(3, 3); - //assert_eq!(Push::X(1, test).layout(area)?, Some([51, 50, 3, 3])); - //assert_eq!(Push::Y(1, test).layout(area)?, Some([50, 51, 3, 3])); - //assert_eq!(Push::XY(1, 1, test).layout(area)?, Some([51, 51, 3, 3])); - //Ok(()) -//} - -//#[test] -//fn test_outset () -> Usually<()> { - //let area: [u16;4] = [50, 50, 100, 100]; - //let test = TestArea(3, 3); - //assert_eq!(Outset::X(1, test).layout(area)?, Some([49, 50, 5, 3])); - //assert_eq!(Outset::Y(1, test).layout(area)?, Some([50, 49, 3, 5])); - //assert_eq!(Outset::XY(1, 1, test).layout(area)?, Some([49, 49, 5, 5])); - //Ok(()) -//} - -//#[test] -//fn test_inset () -> Usually<()> { - //let area: [u16;4] = [50, 50, 100, 100]; - //let test = TestArea(3, 3); - //assert_eq!(Inset::X(1, test).layout(area)?, Some([51, 50, 1, 3])); - //assert_eq!(Inset::Y(1, test).layout(area)?, Some([50, 51, 3, 1])); - //assert_eq!(Inset::XY(1, 1, test).layout(area)?, Some([51, 51, 1, 1])); - //Ok(()) -//} - -//#[test] -//fn test_stuff () -> Usually<()> { - //let area: [u16;4] = [0, 0, 100, 100]; - //assert_eq!("1".layout(area)?, - //Some([0, 0, 1, 1])); - //assert_eq!("333".layout(area)?, - //Some([0, 0, 3, 1])); - //assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?, - //Some([0, 0, 3, 1])); - //assert_eq!(Stack::down(|add|{add(&"1")?;add(&"333")}).layout(area)?, - //Some([0, 0, 3, 2])); - //assert_eq!(Stack::right(|add|{add(&"1")?;add(&"333")}).layout(area)?, - //Some([0, 0, 4, 1])); - //assert_eq!(Stack::down(|add|{ - //add(&Stack::right(|add|{add(&"1")?;add(&"333")}))?; - //add(&"55555") - //}).layout(area)?, - //Some([0, 0, 5, 2])); - //let area: [u16;4] = [1, 1, 100, 100]; - //assert_eq!(Outset::X(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, - //Some([0, 1, 6, 1])); - //assert_eq!(Outset::Y(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, - //Some([1, 0, 4, 3])); - //assert_eq!(Outset::XY(1, 1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, - //Some([0, 0, 6, 3])); - //assert_eq!(Stack::down(|add|{ - //add(&Outset::XY(1, 1, "1"))?; - //add(&Outset::XY(1, 1, "333")) - //}).layout(area)?, - //Some([1, 1, 5, 6])); - //let area: [u16;4] = [1, 1, 95, 100]; - //assert_eq!(Align::Center(Stack::down(|add|{ - //add(&Outset::XY(1, 1, "1"))?; - //add(&Outset::XY(1, 1, "333")) - //})).layout(area)?, - //Some([46, 48, 5, 6])); - //assert_eq!(Align::Center(Stack::down(|add|{ - //add(&Layers::new(|add|{ - ////add(&Outset::XY(1, 1, Background(Color::Rgb(0,128,0))))?; - //add(&Outset::XY(1, 1, "1"))?; - //add(&Outset::XY(1, 1, "333"))?; - ////add(&Background(Color::Rgb(0,128,0)))?; - //Ok(()) - //}))?; - //add(&Layers::new(|add|{ - ////add(&Outset::XY(1, 1, Background(Color::Rgb(0,0,128))))?; - //add(&Outset::XY(1, 1, "555"))?; - //add(&Outset::XY(1, 1, "777777"))?; - ////add(&Background(Color::Rgb(0,0,128)))?; - //Ok(()) - //})) - //})).layout(area)?, - //Some([46, 48, 5, 6])); - //Ok(()) -//} diff --git a/crates/tek/src/layout.rs b/crates/tek/src/layout.rs index 11926aa5..168e2022 100644 --- a/crates/tek/src/layout.rs +++ b/crates/tek/src/layout.rs @@ -1,22 +1,17 @@ -// manja s grozde; ikebana s chiaroscuro - use crate::*; -submod! { - align - bsp - cond - debug - fill - fixed - inset_outset - layers - map_reduce - measure - min_max - push_pull - scroll - shrink_grow - split - stack -} +mod align; pub(crate) use align::*; +mod bsp; pub(crate) use bsp::*; +mod cond; pub(crate) use cond::*; +mod debug; pub(crate) use debug::*; +mod fill; pub(crate) use fill::*; +mod fixed; pub(crate) use fixed::*; +mod inset_outset; pub(crate) use inset_outset::*; +mod layers; pub(crate) use layers::*; +mod measure; pub(crate) use measure::*; +mod min_max; pub(crate) use min_max::*; +mod push_pull; pub(crate) use push_pull::*; +mod scroll; pub(crate) use scroll::*; +mod shrink_grow; pub(crate) use shrink_grow::*; +mod split; pub(crate) use split::*; +mod stack; pub(crate) use stack::*; diff --git a/crates/tek/src/layout/bsp.rs b/crates/tek/src/layout/bsp.rs index 3ab5093b..a0c3c07c 100644 --- a/crates/tek/src/layout/bsp.rs +++ b/crates/tek/src/layout/bsp.rs @@ -50,6 +50,24 @@ pub struct ToEast(Option, A, B); pub struct ToWest, B: Render>(Option, A, B); +impl, B: Render> Render for Over { + fn min_size (&self, _: E::Size) -> Perhaps { + todo!(); + } + fn render (&self, _: &mut E::Output) -> Usually<()> { + Ok(()) + } +} + +impl, B: Render> Render for Under { + fn min_size (&self, _: E::Size) -> Perhaps { + todo!(); + } + fn render (&self, _: &mut E::Output) -> Usually<()> { + Ok(()) + } +} + impl, B: Render> Render for ToNorth { fn min_size (&self, _: E::Size) -> Perhaps { todo!(); diff --git a/crates/tek/src/layout/collect.rs b/crates/tek/src/layout/collect.rs new file mode 100644 index 00000000..141992f1 --- /dev/null +++ b/crates/tek/src/layout/collect.rs @@ -0,0 +1,79 @@ +use crate::*; + +pub enum Collect<'a, E: Engine, const N: usize> { + Callback(CallbackCollection<'a, E>), + //Iterator(IteratorCollection<'a, E>), + Array(ArrayCollection<'a, E, N>), + Slice(SliceCollection<'a, E>), +} + +impl<'a, E: Engine, const N: usize> Collect<'a, E, N> { + pub fn iter (&'a self) -> CollectIterator<'a, E, N> { + CollectIterator(0, &self) + } +} + +impl<'a, E: Engine, const N: usize> From> for Collect<'a, E, N> { + fn from (callback: CallbackCollection<'a, E>) -> Self { + Self::Callback(callback) + } +} + +impl<'a, E: Engine, const N: usize> From> for Collect<'a, E, N> { + fn from (slice: SliceCollection<'a, E>) -> Self { + Self::Slice(slice) + } +} + +impl<'a, E: Engine, const N: usize> From> for Collect<'a, E, N>{ + fn from (array: ArrayCollection<'a, E, N>) -> Self { + Self::Array(array) + } +} + +type CallbackCollection<'a, E> = + &'a dyn Fn(&'a mut dyn FnMut(&dyn Render)->Usually<()>); + +//type IteratorCollection<'a, E> = + //&'a mut dyn Iterator>; + +type SliceCollection<'a, E> = + &'a [&'a dyn Render]; + +type ArrayCollection<'a, E, const N: usize> = + [&'a dyn Render; N]; + +pub struct CollectIterator<'a, E: Engine, const N: usize>(usize, &'a Collect<'a, E, N>); + +impl<'a, E: Engine, const N: usize> Iterator for CollectIterator<'a, E, N> { + type Item = &'a dyn Render; + fn next (&mut self) -> Option { + match self.1 { + Collect::Callback(callback) => { + todo!() + }, + //Collection::Iterator(iterator) => { + //iterator.next() + //}, + Collect::Array(array) => { + if let Some(item) = array.get(self.0) { + self.0 += 1; + //Some(item) + None + } else { + None + } + } + Collect::Slice(slice) => { + if let Some(item) = slice.get(self.0) { + self.0 += 1; + //Some(item) + None + } else { + None + } + } + } + } +} + diff --git a/crates/tek/src/layout/shrink_grow.rs b/crates/tek/src/layout/shrink_grow.rs index 9186f724..9c725ef4 100644 --- a/crates/tek/src/layout/shrink_grow.rs +++ b/crates/tek/src/layout/shrink_grow.rs @@ -12,20 +12,19 @@ pub trait LayoutShrinkGrow { fn shrink_xy > (x: E::Unit, y: E::Unit, w: W) -> Shrink { Shrink::XY(x, y, w) } - fn grow_x > (x: E::Unit, w: W) -> Grow { + fn grow_x > (x: E::Unit, w: W) -> Grow { Grow::X(x, w) } - fn grow_y > (y: E::Unit, w: W) -> Grow { + fn grow_y > (y: E::Unit, w: W) -> Grow { Grow::Y(y, w) } - fn grow_xy > (x: E::Unit, y: E::Unit, w: W) -> Grow { + fn grow_xy > (x: E::Unit, y: E::Unit, w: W) -> Grow { Grow::XY(x, y, w) } } /// Shrink drawing area -pub enum Shrink { - _Unused(PhantomData), +pub enum Shrink> { /// Decrease width X(E::Unit, T), /// Decrease height @@ -34,6 +33,16 @@ pub enum Shrink { XY(E::Unit, E::Unit, T), } +/// Expand drawing area +pub enum Grow> { + /// Increase width + X(E::Unit, T), + /// Increase height + Y(E::Unit, T), + /// Increase width and height + XY(E::Unit, E::Unit, T) +} + impl> Shrink { fn inner (&self) -> &T { match self { @@ -45,6 +54,16 @@ impl> Shrink { } } +impl> Grow { + fn inner (&self) -> &T { + match self { + Self::X(_, i) => i, + Self::Y(_, i) => i, + Self::XY(_, _, i) => i, + } + } +} + impl> Render for Shrink { fn min_size (&self, to: E::Size) -> Perhaps { Ok(self.inner().min_size(to)?.map(|to|match *self { @@ -60,7 +79,6 @@ impl> Render for Shrink { if to.w() > w { to.w() - w } else { 0.into() }, if to.h() > h { to.h() - h } else { 0.into() } ], - _ => unreachable!(), }.into())) } fn render (&self, to: &mut E::Output) -> Usually<()> { @@ -70,23 +88,7 @@ impl> Render for Shrink { } } -/// Expand drawing area -pub enum Grow { - /// Increase width - X(N, T), - /// Increase height - Y(N, T), - /// Increase width and height - XY(N, N, T) -} - -impl Grow { - fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -impl> Render for Grow { +impl> Render for Grow { fn min_size (&self, to: E::Size) -> Perhaps { Ok(self.inner().min_size(to)?.map(|to|match *self { Self::X(w, _) => [to.w() + w, to.h()], diff --git a/crates/tek/src/layout/stack.rs b/crates/tek/src/layout/stack.rs index 482afd42..2bae0d1b 100644 --- a/crates/tek/src/layout/stack.rs +++ b/crates/tek/src/layout/stack.rs @@ -1,17 +1,23 @@ use crate::*; #[macro_export] macro_rules! col { - ($(move)?|$add:ident|$expr:expr) => { Stack::down($(move)?|$add|$expr) }; + ($($move:ident)?|$add:ident|$expr:expr) => { + Stack::down($(move)?|$add|$expr) + }; ($pat:pat in $collection:expr => $item:expr) => { Stack::down(move |add|{ for $pat in $collection { add(&$item)?; } Ok(()) }) }; - ($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) }; + ($($expr:expr),* $(,)?) => { + Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) + }; } #[macro_export] macro_rules! col_up { - ($(move)?|$add:ident|$expr:expr) => { Stack::up($(move)?|$add|$expr) }; + ($($move:ident)?|$add:ident|$expr:expr) => { + Stack::up($(move)?|$add|$expr) + }; ($pat:pat in $collection:expr => $item:expr) => { Stack::up(move |add|{ for $pat in $collection { add(&$item)?; } @@ -21,7 +27,7 @@ use crate::*; ($($expr:expr),* $(,)?) => { Stack::up(move|add|{ $(add(&$expr)?;)* Ok(()) }) }; } #[macro_export] macro_rules! row { - ($(move)?|$add:ident|$expr:expr) => { + ($($move:ident)?|$add:ident|$expr:expr) => { Stack::right($(move)?|$add|$expr) }; ($pat:pat in $collection:expr => $item:expr) => { @@ -104,7 +110,7 @@ where (self.0)(&mut |component: &dyn Render| { let max = to.h().minus(h); if max > E::Unit::ZERO() { - let item = Tui::max_y(to.h() - h, component); + let item = E::max_y(to.h() - h, component); let size = item.min_size(to)?.map(|size|size.wh()); if let Some([width, height]) = size { h = h + height.into(); @@ -138,7 +144,7 @@ where Direction::Down => { (self.0)(&mut |item| { if h < area.h() { - let item = Tui::max_y(area.h() - h, Tui::push_y(h, item)); + let item = E::max_y(area.h() - h, E::push_y(h, item)); let show = item.min_size(area.wh().into())?.map(|s|s.wh()); if let Some([width, height]) = show { item.render(to)?; @@ -152,7 +158,7 @@ where Direction::Right => { (self.0)(&mut |item| { if w < area.w() { - let item = Tui::max_x(area.w() - w, Tui::push_x(w, item)); + let item = E::max_x(area.w() - w, E::push_x(w, item)); let show = item.min_size(area.wh().into())?.map(|s|s.wh()); if let Some([width, height]) = show { item.render(to)?; @@ -168,7 +174,8 @@ where if h < area.h() { let show = item.min_size([area.w(), area.h().minus(h)].into())?.map(|s|s.wh()); if let Some([width, height]) = show { - item.push_y(area.h() - height).shrink_y(height).render(to)?; + E::shrink_y(height, E::push_y(area.h() - height, item)) + .render(to)?; h = h + height; if width > w { w = width } }; diff --git a/crates/tek/src/lib.rs b/crates/tek/src/lib.rs index c457e2fe..d8a03be9 100644 --- a/crates/tek/src/lib.rs +++ b/crates/tek/src/lib.rs @@ -73,12 +73,10 @@ pub type Perhaps = Result, Box>; ($($name:ident)*) => { $(#[cfg(test)] mod $name;)* }; } -submod! { - api - core - layout - tui -} +mod core; pub(crate) use core::*; +mod layout; pub(crate) use layout::*; +mod api; pub(crate) use api::*; +mod tui; pub(crate) use tui::*; testmod! { test diff --git a/crates/tek/src/test.rs b/crates/tek/src/test.rs index e69de29b..fe6a77b2 100644 --- a/crates/tek/src/test.rs +++ b/crates/tek/src/test.rs @@ -0,0 +1,190 @@ +use crate::*; + +struct TestEngine([u16;4], Vec>); + +impl Engine for TestEngine { + type Unit = u16; + type Size = [Self::Unit;2]; + type Area = [Self::Unit;4]; + type Input = Self; + type Handled = bool; + fn exited (&self) -> bool { + true + } + fn area (&self) -> Self::Area { + self.0 + } + fn area_mut (&mut self) -> &mut Self::Area { + &mut self.0 + } +} + +#[derive(Copy, Clone)] +struct TestArea(u16, u16); + +impl Render for TestArea { + type Engine = TestEngine; + fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { + Ok(Some([to[0], to[1], self.0, self.1])) + } + fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> { + if let Some(layout) = self.layout(to.area())? { + for y in layout.y()..layout.y()+layout.h()-1 { + for x in layout.x()..layout.x()+layout.w()-1 { + to.1[y as usize][x as usize] = '*'; + } + } + Ok(Some(layout)) + } else { + Ok(None) + } + } +} + +#[test] +fn test_plus_minus () -> Usually<()> { + let area = [0, 0, 10, 10]; + let engine = TestEngine(area, vec![vec![' ';10];10]); + let test = TestArea(4, 4); + assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); + assert_eq!(Push::X(1, test).layout(area)?, Some([1, 0, 4, 4])); + Ok(()) +} + +#[test] +fn test_outset_align () -> Usually<()> { + let area = [0, 0, 10, 10]; + let engine = TestEngine(area, vec![vec![' ';10];10]); + let test = TestArea(4, 4); + assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); + assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4])); + assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4])); + assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4])); + assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4])); + Ok(()) +} + +//#[test] +//fn test_misc () -> Usually<()> { + //let area: [u16;4] = [0, 0, 10, 10]; + //let test = TestArea(4, 4); + //assert_eq!(test.layout(area)?, + //Some([0, 0, 4, 4])); + //assert_eq!(Align::Center(test).layout(area)?, + //Some([3, 3, 4, 4])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&test)?; + //add(&test) + //})).layout(area)?, + //Some([3, 1, 4, 8])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&test) + //})).layout(area)?, + //Some([2, 0, 6, 10])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&Inset::XY(2, 2, test)) + //})).layout(area)?, + //Some([2, 1, 6, 8])); + //assert_eq!(Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&Inset::XY(2, 2, test)) + //}).layout(area)?, + //Some([0, 0, 6, 8])); + //assert_eq!(Stack::right(|add|{ + //add(&Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&Inset::XY(2, 2, test)) + //}))?; + //add(&Align::Center(TestArea(2 ,2))) + //}).layout(area)?, + //Some([0, 0, 8, 8])); + //Ok(()) +//} + +//#[test] +//fn test_offset () -> Usually<()> { + //let area: [u16;4] = [50, 50, 100, 100]; + //let test = TestArea(3, 3); + //assert_eq!(Push::X(1, test).layout(area)?, Some([51, 50, 3, 3])); + //assert_eq!(Push::Y(1, test).layout(area)?, Some([50, 51, 3, 3])); + //assert_eq!(Push::XY(1, 1, test).layout(area)?, Some([51, 51, 3, 3])); + //Ok(()) +//} + +//#[test] +//fn test_outset () -> Usually<()> { + //let area: [u16;4] = [50, 50, 100, 100]; + //let test = TestArea(3, 3); + //assert_eq!(Outset::X(1, test).layout(area)?, Some([49, 50, 5, 3])); + //assert_eq!(Outset::Y(1, test).layout(area)?, Some([50, 49, 3, 5])); + //assert_eq!(Outset::XY(1, 1, test).layout(area)?, Some([49, 49, 5, 5])); + //Ok(()) +//} + +//#[test] +//fn test_inset () -> Usually<()> { + //let area: [u16;4] = [50, 50, 100, 100]; + //let test = TestArea(3, 3); + //assert_eq!(Inset::X(1, test).layout(area)?, Some([51, 50, 1, 3])); + //assert_eq!(Inset::Y(1, test).layout(area)?, Some([50, 51, 3, 1])); + //assert_eq!(Inset::XY(1, 1, test).layout(area)?, Some([51, 51, 1, 1])); + //Ok(()) +//} + +//#[test] +//fn test_stuff () -> Usually<()> { + //let area: [u16;4] = [0, 0, 100, 100]; + //assert_eq!("1".layout(area)?, + //Some([0, 0, 1, 1])); + //assert_eq!("333".layout(area)?, + //Some([0, 0, 3, 1])); + //assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?, + //Some([0, 0, 3, 1])); + //assert_eq!(Stack::down(|add|{add(&"1")?;add(&"333")}).layout(area)?, + //Some([0, 0, 3, 2])); + //assert_eq!(Stack::right(|add|{add(&"1")?;add(&"333")}).layout(area)?, + //Some([0, 0, 4, 1])); + //assert_eq!(Stack::down(|add|{ + //add(&Stack::right(|add|{add(&"1")?;add(&"333")}))?; + //add(&"55555") + //}).layout(area)?, + //Some([0, 0, 5, 2])); + //let area: [u16;4] = [1, 1, 100, 100]; + //assert_eq!(Outset::X(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, + //Some([0, 1, 6, 1])); + //assert_eq!(Outset::Y(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, + //Some([1, 0, 4, 3])); + //assert_eq!(Outset::XY(1, 1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, + //Some([0, 0, 6, 3])); + //assert_eq!(Stack::down(|add|{ + //add(&Outset::XY(1, 1, "1"))?; + //add(&Outset::XY(1, 1, "333")) + //}).layout(area)?, + //Some([1, 1, 5, 6])); + //let area: [u16;4] = [1, 1, 95, 100]; + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Outset::XY(1, 1, "1"))?; + //add(&Outset::XY(1, 1, "333")) + //})).layout(area)?, + //Some([46, 48, 5, 6])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Layers::new(|add|{ + ////add(&Outset::XY(1, 1, Background(Color::Rgb(0,128,0))))?; + //add(&Outset::XY(1, 1, "1"))?; + //add(&Outset::XY(1, 1, "333"))?; + ////add(&Background(Color::Rgb(0,128,0)))?; + //Ok(()) + //}))?; + //add(&Layers::new(|add|{ + ////add(&Outset::XY(1, 1, Background(Color::Rgb(0,0,128))))?; + //add(&Outset::XY(1, 1, "555"))?; + //add(&Outset::XY(1, 1, "777777"))?; + ////add(&Background(Color::Rgb(0,0,128)))?; + //Ok(()) + //})) + //})).layout(area)?, + //Some([46, 48, 5, 6])); + //Ok(()) +//} diff --git a/crates/tek/src/tui.rs b/crates/tek/src/tui.rs index 61a024fb..2263c88d 100644 --- a/crates/tek/src/tui.rs +++ b/crates/tek/src/tui.rs @@ -1,46 +1,55 @@ use crate::*; -submod! { - engine_focus - engine_input - engine_output - engine_style +mod jack_arranger; pub(crate) use app_arranger::*; +mod jack_sequencer; pub(crate) use app_sequencer::*; +mod jack_transport; pub(crate) use app_transport::*; - app_arranger - app_sequencer - app_transport +mod engine_focus; pub(crate) use engine_focus::*; +mod engine_input; pub(crate) use engine_input::*; +mod engine_style; pub(crate) use engine_style::*; +mod engine_output; pub(crate) use engine_output::*; - jack_transport - jack_sequencer - jack_arranger +mod app_arranger; pub(crate) use app_arranger::*; +mod app_sequencer; pub(crate) use app_sequencer::*; +mod app_transport; pub(crate) use app_transport::*; - ctrl_arranger - ctrl_file_browser - ctrl_phrase_editor - ctrl_phrase_length - ctrl_phrase_list - ctrl_phrase_rename - ctrl_sequencer - ctrl_transport +mod view_arranger; pub(crate) use view_arranger::*; +mod view_sequencer; pub(crate) use view_sequencer::*; +mod view_transport; pub(crate) use view_transport::*; - model_arranger - model_clock - model_file_browser - model_phrase_editor - model_phrase_length - model_phrase_list - model_phrase_player +mod ctrl_arranger; pub(crate) use ctrl_arranger::*; +mod ctrl_sequencer; pub(crate) use ctrl_sequencer::*; +mod ctrl_transport; pub(crate) use ctrl_transport::*; - view_arranger - view_file_browser - view_phrase_editor - view_phrase_length - view_phrase_list - view_phrase_selector - view_sequencer - view_status_bar - view_transport -} +mod model_arranger; pub(crate) use model_arranger::*; + +//// + +mod model_clock; pub(crate) use model_clock::*; + +mod view_status_bar; pub(crate) use view_status_bar::*; + +mod model_file_browser; pub(crate) use model_file_browser::*; +mod view_file_browser; pub(crate) use view_file_browser::*; +mod ctrl_file_browser; pub(crate) use ctrl_file_browser::*; + +mod model_phrase_editor; pub(crate) use model_phrase_editor::*; +mod view_phrase_editor; pub(crate) use view_phrase_editor::*; +mod ctrl_phrase_editor; pub(crate) use ctrl_phrase_editor::*; + +mod model_phrase_length; pub(crate) use model_phrase_length::*; +mod view_phrase_length; pub(crate) use view_phrase_length::*; +mod ctrl_phrase_length; pub(crate) use ctrl_phrase_length::*; + +mod model_phrase_list; pub(crate) use model_phrase_list::*; +mod view_phrase_list; pub(crate) use view_phrase_list::*; +mod ctrl_phrase_list; pub(crate) use ctrl_phrase_list::*; + +mod model_phrase_player; pub(crate) use model_phrase_player::*; + +mod view_phrase_selector; pub(crate) use view_phrase_selector::*; + +mod ctrl_phrase_rename; pub(crate) use ctrl_phrase_rename::*; #[macro_export] macro_rules! render { (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { diff --git a/crates/tek/src/tui/app_sequencer.rs b/crates/tek/src/tui/app_sequencer.rs index ebbd47fa..efd328fc 100644 --- a/crates/tek/src/tui/app_sequencer.rs +++ b/crates/tek/src/tui/app_sequencer.rs @@ -1,4 +1,6 @@ use crate::*; +use SequencerFocus::*; +use super::app_transport::TransportFocus::*; /// Root view for standalone `tek_sequencer`. pub struct SequencerTui { @@ -135,8 +137,6 @@ impl StatusBar for SequencerStatusBar { impl From<&SequencerTui> for SequencerStatusBar { fn from (state: &SequencerTui) -> Self { - use SequencerFocus::*; - use TransportFocus::*; let samples = state.clock.chunk.load(Ordering::Relaxed); let rate = state.clock.timebase.sr.get() as f64; let buffer = samples as f64 / rate; diff --git a/crates/tek/src/tui/ctrl_arranger.rs b/crates/tek/src/tui/ctrl_arranger.rs index 7a05492b..63bc6dac 100644 --- a/crates/tek/src/tui/ctrl_arranger.rs +++ b/crates/tek/src/tui/ctrl_arranger.rs @@ -1,4 +1,12 @@ -use crate::*; +use super::model_arranger::ArrangerSelection; +use crate::{ + *, + api::{ + ArrangerTrackCommand, + ArrangerSceneCommand, + ArrangerClipCommand + } +}; impl Handle for ArrangerTui { fn handle (&mut self, i: &TuiInput) -> Perhaps { diff --git a/crates/tek/src/tui/ctrl_file_browser.rs b/crates/tek/src/tui/ctrl_file_browser.rs index fc530b7b..4e60c784 100644 --- a/crates/tek/src/tui/ctrl_file_browser.rs +++ b/crates/tek/src/tui/ctrl_file_browser.rs @@ -1,4 +1,7 @@ use crate::*; +use KeyCode::{Up, Down, Right, Left, Enter, Esc, Char, Backspace}; +use FileBrowserCommand::*; +use super::model_phrase_list::PhrasesMode::{Import, Export}; /// Commands supported by [FileBrowser] #[derive(Debug, Clone, PartialEq)] @@ -13,8 +16,6 @@ pub enum FileBrowserCommand { impl Command for FileBrowserCommand { fn execute (self, state: &mut PhraseListModel) -> Perhaps { - use FileBrowserCommand::*; - use PhrasesMode::{Import, Export}; let mode = state.phrases_mode_mut(); match mode { Some(Import(index, ref mut browser)) => match self { @@ -59,8 +60,6 @@ impl Command for FileBrowserCommand { impl InputToCommand for FileBrowserCommand { fn input_to_command (state: &PhraseListModel, from: &TuiInput) -> Option { - use KeyCode::{Up, Down, Right, Left, Enter, Esc, Char, Backspace}; - use FileBrowserCommand::*; if let Some(PhrasesMode::Import(_index, browser)) = state.phrases_mode() { Some(match from.event() { key!(Up) => Select( @@ -97,7 +96,6 @@ impl InputToCommand for FileBrowserCommand { impl InputToCommand for PhraseLengthCommand { fn input_to_command (state: &PhraseListModel, from: &TuiInput) -> Option { - use KeyCode::{Up, Down, Right, Left, Enter, Esc}; if let Some(PhrasesMode::Length(_, length, _)) = state.phrases_mode() { Some(match from.event() { key!(Up) => Self::Inc, diff --git a/crates/tek/src/tui/ctrl_phrase_length.rs b/crates/tek/src/tui/ctrl_phrase_length.rs index 03290c13..79668c95 100644 --- a/crates/tek/src/tui/ctrl_phrase_length.rs +++ b/crates/tek/src/tui/ctrl_phrase_length.rs @@ -1,4 +1,7 @@ use crate::*; +use super::model_phrase_list::{PhraseListModel, PhrasesMode}; +use super::model_phrase_length::PhraseLengthFocus::*; +use PhraseLengthCommand::*; #[derive(Copy, Clone, Debug, PartialEq)] pub enum PhraseLengthCommand { @@ -13,8 +16,6 @@ pub enum PhraseLengthCommand { impl Command for PhraseLengthCommand { fn execute (self, state: &mut PhraseListModel) -> Perhaps { - use PhraseLengthFocus::*; - use PhraseLengthCommand::*; match state.phrases_mode_mut().clone() { Some(PhrasesMode::Length(phrase, ref mut length, ref mut focus)) => match self { Cancel => { *state.phrases_mode_mut() = None; }, diff --git a/crates/tek/src/tui/ctrl_phrase_list.rs b/crates/tek/src/tui/ctrl_phrase_list.rs index 035880ae..f21c712d 100644 --- a/crates/tek/src/tui/ctrl_phrase_list.rs +++ b/crates/tek/src/tui/ctrl_phrase_list.rs @@ -1,13 +1,21 @@ -use crate::*; +use crate::{ + *, + api::PhrasePoolCommand as Pool, + tui::{ + ctrl_phrase_rename::PhraseRenameCommand as Rename, + ctrl_phrase_length::PhraseLengthCommand as Length, + ctrl_file_browser::FileBrowserCommand as Browse, + } +}; #[derive(Clone, PartialEq, Debug)] pub enum PhrasesCommand { Select(usize), - Phrase(PhrasePoolCommand), - Rename(PhraseRenameCommand), - Length(PhraseLengthCommand), - Import(FileBrowserCommand), - Export(FileBrowserCommand), + Phrase(Pool), + Rename(Rename), + Length(Length), + Import(Browse), + Export(Browse), } impl Command for PhrasesCommand { @@ -72,9 +80,6 @@ impl HasPhrases for PhraseListModel { impl InputToCommand for PhrasesCommand { fn input_to_command (state: &PhraseListModel, input: &TuiInput) -> Option { - use PhraseRenameCommand as Rename; - use PhraseLengthCommand as Length; - use FileBrowserCommand as Browse; Some(match state.phrases_mode() { Some(PhrasesMode::Rename(..)) => Self::Rename(Rename::input_to_command(state, input)?), Some(PhrasesMode::Length(..)) => Self::Length(Length::input_to_command(state, input)?), @@ -87,11 +92,7 @@ impl InputToCommand for PhrasesCommand { fn to_phrases_command (state: &PhraseListModel, input: &TuiInput) -> Option { use KeyCode::{Up, Down, Delete, Char}; - use PhrasesCommand as Cmd; - use PhrasePoolCommand as Pool; - use PhraseRenameCommand as Rename; - use PhraseLengthCommand as Length; - use FileBrowserCommand as Browse; + use PhrasesCommand as Cmd; let index = state.phrase_index(); let count = state.phrases().len(); Some(match input.event() { diff --git a/crates/tek/src/tui/ctrl_sequencer.rs b/crates/tek/src/tui/ctrl_sequencer.rs index 194678c8..5c6c3837 100644 --- a/crates/tek/src/tui/ctrl_sequencer.rs +++ b/crates/tek/src/tui/ctrl_sequencer.rs @@ -1,4 +1,7 @@ -use crate::*; +use crate::{*, api::ClockCommand::{Play, Pause}}; +use super::ctrl_phrase_editor::PhraseCommand::Show; +use KeyCode::{Char, Enter}; +use SequencerCommand::*; impl Handle for SequencerTui { fn handle (&mut self, i: &TuiInput) -> Perhaps { @@ -20,7 +23,6 @@ pub enum SequencerCommand { impl Command for SequencerCommand { fn execute (self, state: &mut SequencerTui) -> Perhaps { - use SequencerCommand::*; Ok(match self { Focus(cmd) => cmd.execute(state)?.map(Focus), Phrases(cmd) => cmd.execute(&mut state.phrases)?.map(Phrases), @@ -50,10 +52,6 @@ impl InputToCommand for SequencerCommand { } pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option { - use SequencerCommand::*; - use PhraseCommand::Show; - use ClockCommand::{Play, Pause}; - use KeyCode::{Char, Enter}; Some(match input.event() { // Play/pause key!(Char(' ')) => Clock( diff --git a/crates/tek/src/tui/ctrl_transport.rs b/crates/tek/src/tui/ctrl_transport.rs index 4ed360c7..97eaf9a0 100644 --- a/crates/tek/src/tui/ctrl_transport.rs +++ b/crates/tek/src/tui/ctrl_transport.rs @@ -1,4 +1,7 @@ use crate::*; +use crate::api::ClockCommand::{SetBpm, SetQuant, SetSync}; +use TransportCommand::{Focus, Clock}; +use KeyCode::{Enter, Left, Right, Char}; impl Handle for TransportTui { fn handle (&mut self, from: &TuiInput) -> Perhaps { @@ -60,9 +63,6 @@ pub fn to_transport_command (state: &T, input: &TuiInput) -> Option Focus(FocusCommand::Prev), key!(Right) => Focus(FocusCommand::Next), diff --git a/crates/tek/src/tui/jack_arranger.rs b/crates/tek/src/tui/jack_arranger.rs index efdb7c5a..1bc9765c 100644 --- a/crates/tek/src/tui/jack_arranger.rs +++ b/crates/tek/src/tui/jack_arranger.rs @@ -1,4 +1,4 @@ -use crate::*; +use crate::{*, tui::ArrangerTui}; impl JackApi for ArrangerTui { fn jack (&self) -> &Arc> { diff --git a/crates/tek/src/tui/jack_sequencer.rs b/crates/tek/src/tui/jack_sequencer.rs index a590564d..bfc7438f 100644 --- a/crates/tek/src/tui/jack_sequencer.rs +++ b/crates/tek/src/tui/jack_sequencer.rs @@ -1,4 +1,4 @@ -use crate::*; +use crate::{*, tui::SequencerTui}; impl JackApi for SequencerTui { fn jack (&self) -> &Arc> { diff --git a/crates/tek/src/tui/model_phrase_list.rs b/crates/tek/src/tui/model_phrase_list.rs index 6786d08b..65e66e58 100644 --- a/crates/tek/src/tui/model_phrase_list.rs +++ b/crates/tek/src/tui/model_phrase_list.rs @@ -1,4 +1,5 @@ use crate::*; +use super::*; #[derive(Debug)] pub struct PhraseListModel { diff --git a/crates/tek/src/tui/view_file_browser.rs b/crates/tek/src/tui/view_file_browser.rs index 2d21e8ea..748907b0 100644 --- a/crates/tek/src/tui/view_file_browser.rs +++ b/crates/tek/src/tui/view_file_browser.rs @@ -1,23 +1,21 @@ use crate::*; -impl Content for FileBrowser { - fn content (&self) -> impl Render { - Stack::down(|add|{ - let mut i = 0; - for (_, name) in self.dirs.iter() { - if i >= self.scroll { - add(&Tui::bold(i == self.index, name.as_str()))?; - } - i += 1; +render!(|self: FileBrowser|{ + Stack::down(|add|{ + let mut i = 0; + for (_, name) in self.dirs.iter() { + if i >= self.scroll { + add(&Tui::bold(i == self.index, name.as_str()))?; } - for (_, name) in self.files.iter() { - if i >= self.scroll { - add(&Tui::bold(i == self.index, name.as_str()))?; - } - i += 1; + i += 1; + } + for (_, name) in self.files.iter() { + if i >= self.scroll { + add(&Tui::bold(i == self.index, name.as_str()))?; } - add(&format!("{}/{i}", self.index))?; - Ok(()) - }) - } -} + i += 1; + } + add(&format!("{}/{i}", self.index))?; + Ok(()) + }) +}); diff --git a/crates/tek/src/tui/view_phrase_editor.rs b/crates/tek/src/tui/view_phrase_editor.rs index c18826e1..b651e67d 100644 --- a/crates/tek/src/tui/view_phrase_editor.rs +++ b/crates/tek/src/tui/view_phrase_editor.rs @@ -124,21 +124,21 @@ render!(|self: PhraseView<'a>|{ ////} //Ok(()) //}; - Tui::layers() - .add(Tui::layers() - .add(Tui::at_nw(Tui::fg(title_color, upper_left))) - .add(Tui::at_sw(Tui::fg(title_color, lower_left))) - .add(Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right))))) - .add(Tui::fill_xy(Tui::at_se(Tui::pull_x(1, Tui::fg(title_color, lower_right)))))) - .add(Tui::bg( - Color::Rgb(40, 50, 30), - Tui::fill_x(Tui::to_east( - Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(2))), keys))), - Tui::fill_x(lay!( - Tui::push_y(1, Tui::fill_x(Widget::new(|to|Ok(Some(to)), notes))), - Tui::push_y(1, Widget::new(|to|Ok(Some(to)), cursor)) - )), - )))) + let indicators = lay!(|add|{ + add(&Tui::at_nw(Tui::fg(title_color, upper_left)))?; + add(&Tui::at_sw(Tui::fg(title_color, lower_left)))?; + add(&Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right)))))?; + add(&Tui::fill_xy(Tui::at_se(Tui::pull_x(1, Tui::fg(title_color, lower_right)))))?; + Ok(()) + }); + let content = Tui::bg(Color::Rgb(40, 50, 30), Tui::fill_x(Tui::to_east( + Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(2))), keys))), + Tui::fill_x(lay!( + Tui::push_y(1, Tui::fill_x(Widget::new(|to|Ok(Some(to)), notes))), + Tui::push_y(1, Widget::new(|to|Ok(Some(to)), cursor)) + )), + ))); + lay!(indicators, content) }); #[derive(Copy, Clone, Debug)] diff --git a/crates/tek/src/tui/view_transport.rs b/crates/tek/src/tui/view_transport.rs index 59fbc597..babdbcf0 100644 --- a/crates/tek/src/tui/view_transport.rs +++ b/crates/tek/src/tui/view_transport.rs @@ -1,4 +1,4 @@ -use crate::*; +use crate::{*, tui::TransportTui}; impl Render for TransportTui { fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {