From 0e821e098f3f6f36ad1315b62e322b557c1bba2c Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 5 Jan 2025 22:01:54 +0100 Subject: [PATCH] separate Input and Output impls --- edn/examples/{edn01.rs => edn.rs} | 20 +++++---- edn/examples/edn02.rs | 6 +-- edn/src/edn_view.rs | 64 +++++++++++++++------------ engine/src/{output => }/area.rs | 0 engine/src/{input => }/command.rs | 0 engine/src/{output => }/content.rs | 31 +++++++++---- engine/src/{output => }/coordinate.rs | 0 engine/src/engine.rs | 47 +++++++++++++++----- engine/src/{input => }/event_map.rs | 0 engine/src/handle.rs | 61 +++++++++++++++++++++++++ engine/src/input.rs | 17 ------- engine/src/input/handle.rs | 53 ---------------------- engine/src/lib.rs | 11 ++++- engine/src/output.rs | 24 ---------- engine/src/{output => }/render.rs | 36 +++++++-------- engine/src/{output => }/size.rs | 0 engine/src/{output => }/thunk.rs | 6 +-- examples/demo.rs.fixme | 2 +- examples/demo_bsp.rs.fixme | 19 -------- layout/src/align.rs | 4 +- layout/src/direction.rs | 8 ++-- layout/src/lib.rs | 18 ++++---- layout/src/measure.rs | 32 +++++++------- layout/src/ops.rs | 28 ++++++------ layout/src/transform_xy.rs | 8 ++-- layout/src/transform_xy_unit.rs | 2 +- src/arranger.rs | 8 ++-- src/arranger/arranger_command.rs | 2 +- src/arranger/arranger_mode.rs | 4 +- src/arranger/arranger_v.rs | 2 +- src/arranger/arranger_v_clips.rs | 10 ++--- src/arranger/arranger_v_cursor.rs | 2 +- src/arranger/arranger_v_head.rs | 14 +++--- src/arranger/arranger_v_io.rs | 8 ++-- src/arranger/arranger_v_sep.rs | 4 +- src/clock/clock_tui.rs | 12 ++--- src/field.rs | 8 ++-- src/file.rs | 4 +- src/focus.rs | 2 +- src/groovebox.rs | 16 +++---- src/groovebox/groovebox_command.rs | 2 +- src/groovebox/groovebox_tui.rs | 46 +++++++++---------- src/jack.rs | 2 +- src/lib.rs | 2 +- src/meter.rs | 8 ++-- src/midi/midi_editor.rs | 8 ++-- src/midi/midi_out.rs | 2 +- src/midi/midi_status.rs | 4 +- src/midi/midi_view.rs | 2 +- src/mixer.rs | 14 +++--- src/piano.rs | 2 +- src/piano/piano_h.rs | 4 +- src/piano/piano_h_cursor.rs | 2 +- src/piano/piano_h_keys.rs | 2 +- src/piano/piano_h_notes.rs | 2 +- src/piano/piano_h_time.rs | 2 +- src/plugin.rs | 4 +- src/pool.rs | 2 +- src/pool/clip_length.rs | 2 +- src/pool/clip_select.rs | 2 +- src/pool/pool_tui.rs | 2 +- src/sampler/sample_import.rs | 4 +- src/sampler/sample_list.rs | 2 +- src/sampler/sample_viewer.rs | 2 +- src/sampler/sampler_command.rs | 2 +- src/sampler/sampler_status.rs | 2 +- src/sampler/sampler_tui.rs | 6 +-- src/sequencer.rs | 18 ++++---- src/status.rs | 12 ++--- tui/src/lib.rs | 15 ++++--- tui/src/tui_border.rs | 14 +++--- tui/src/tui_content.rs | 19 ++++++++ tui/src/tui_engine.rs | 8 +--- tui/src/tui_input.rs | 3 +- tui/src/tui_output.rs | 27 +++-------- tui/src/tui_run.rs | 16 +++++-- tui/src/tui_style.rs | 60 ++++++++++++------------- 77 files changed, 465 insertions(+), 454 deletions(-) rename edn/examples/{edn01.rs => edn.rs} (61%) rename engine/src/{output => }/area.rs (100%) rename engine/src/{input => }/command.rs (100%) rename engine/src/{output => }/content.rs (50%) rename engine/src/{output => }/coordinate.rs (100%) rename engine/src/{input => }/event_map.rs (100%) create mode 100644 engine/src/handle.rs delete mode 100644 engine/src/input.rs delete mode 100644 engine/src/input/handle.rs delete mode 100644 engine/src/output.rs rename engine/src/{output => }/render.rs (56%) rename engine/src/{output => }/size.rs (100%) rename engine/src/{output => }/thunk.rs (58%) delete mode 100644 examples/demo_bsp.rs.fixme create mode 100644 tui/src/tui_content.rs diff --git a/edn/examples/edn01.rs b/edn/examples/edn.rs similarity index 61% rename from edn/examples/edn01.rs rename to edn/examples/edn.rs index 42d641c4..d1c306c1 100644 --- a/edn/examples/edn01.rs +++ b/edn/examples/edn.rs @@ -17,23 +17,27 @@ fn main () -> Usually<()> { pub struct Example(usize); impl EdnViewData for &Example { - fn get_content <'a> (&'a self, sym: &'a str) -> RenderBox<'a, Tui> { + fn get_content <'a> (&'a self, sym: EdnItem<&'a str>) -> RenderBox<'a, Tui> { Box::new(Thunk::new(move||match sym { - ":hello-world" => "Hello world!", - ":hello" => "Hello", - ":world" => "world", + EdnItem::Sym(":hello-world") => "Hello world!", + EdnItem::Sym(":hello") => "Hello", + EdnItem::Sym(":world") => "world", _ => "" })) } } -impl Content for Example { - fn content (&self) -> impl Render { - EdnView::new(self, EDN[self.0]).unwrap() +impl Content for Example { + fn content (&self) -> impl Render { + Bsp::a( + &format!("{}", self.0), + EdnView::new(self, EDN[self.0]) + .unwrap_or_else(|e|format!("Failed to render {}: {e}", self.0)) + ) } } -impl Handle for Example { +impl Handle for Example { fn handle (&mut self, input: &TuiIn) -> Perhaps { match input.event() { kpat!(Right) => self.0 = (self.0 + 1) % EDN.len(), diff --git a/edn/examples/edn02.rs b/edn/examples/edn02.rs index 7e85f3ce..4c823884 100644 --- a/edn/examples/edn02.rs +++ b/edn/examples/edn02.rs @@ -22,10 +22,10 @@ impl EdnViewData for &Example { } } -impl Content for Example { - fn content (&self) -> impl Render { +impl Content for Example { + fn content (&self) -> impl Render { EdnView::new(self, EDN).unwrap() } } -impl Handle for Example {} +impl Handle for Example {} diff --git a/edn/src/edn_view.rs b/edn/src/edn_view.rs index 93d9f71c..42ccdaeb 100644 --- a/edn/src/edn_view.rs +++ b/edn/src/edn_view.rs @@ -1,56 +1,62 @@ use crate::*; use std::marker::PhantomData; -use ::tek_layout::{*, tek_engine::{Usually, Content, Render, RenderBox, Engine, Thunk}}; +use ::tek_layout::{*, tek_engine::{Usually, Content, Render, RenderBox, Output, Thunk}}; use EdnItem::*; -pub type EdnCallback<'a, Engine, State> = - dyn Fn(&'a State)-> RenderBox<'a, Engine> + Send + Sync + 'a; +pub type EdnCallback<'a, Output, State> = + dyn Fn(&'a State)-> RenderBox<'a, Output> + Send + Sync + 'a; -pub type EdnRenderCallback<'a, Engine, State> = - Box>; +pub type EdnRenderCallback<'a, Output, State> = + Box>; -pub trait EdnViewData { +pub trait EdnViewData { fn get_bool (&self, _sym: EdnItem<&str>) -> bool { false } fn get_unit (&self, _sym: EdnItem<&str>) -> E::Unit { 0.into() } fn get_usize (&self, _sym: EdnItem<&str>) -> usize { 0 } - fn get_content <'a> (&'a self, _sym: EdnItem<&str>) -> RenderBox<'a, E> { Box::new(()) } + fn get_content <'a> (&'a self, _sym: EdnItem<&'a str>) -> RenderBox<'a, E> { Box::new(()) } } /// Renders from EDN source and context. -pub struct EdnView> { - _engine: PhantomData, - context: T, - layout: EdnItem +pub enum EdnView> { + _Unused(PhantomData), + Ok(T, EdnItem), //render: BoxBox + Send + Sync + 'a> + Send + Sync + 'a> + Err(String) } -impl> EdnView { +impl> EdnView { pub fn new (context: T, source: &str) -> Usually { let layout = EdnItem::read_one(&source)?.0; - Ok(Self { _engine: Default::default(), context, layout, }) + Ok(Self::Ok(context, layout)) } } -impl + Send + Sync> Content for EdnView { +impl + Send + Sync> Content for EdnView { fn content (&self) -> impl Render { use EdnItem::*; - match &self.layout { - Nil => ().boxed(), - Sym(t) => self.context.get_content(Sym(t.as_str())).boxed(), - Key(t) => panic!("todo: add error handling to content() chain. unexpected key {t}"), - Num(n) => panic!("todo: add error handling to content() chain. unexpected num {n}"), - Exp(e) => if let [head, tail @ ..] = e.as_slice() { - let head = &head.to_ref(); - let state = &self.context; - match (head, tail) { - (Key("when"), [c, a]) => When(state.get_bool(c.to_ref()), state.get_content(a.to_ref())).boxed(), - (Key("bsp/s"), [a, b]) => Bsp::s(state.get_content(a.to_ref()), state.get_content(b.to_ref()),).boxed(), - _ => todo!("{:?} {:?}", &head, &tail) - } - } else { - panic!("todo: add error handling to content() chain. invalid expression {e:?}") + match self { + Self::Ok(state, layout) => match layout { + Nil => ().boxed(), + Sym(t) => state.get_content(Sym(t.as_str())).boxed(), + Key(t) => panic!("todo: add error handling to content() chain. unexpected key {t}"), + Num(n) => panic!("todo: add error handling to content() chain. unexpected num {n}"), + Exp(e) => if let [head, tail @ ..] = e.as_slice() { + let head = &head.to_ref(); + match (head, tail) { + (Key("when"), [c, a]) => When(state.get_bool(c.to_ref()), state.get_content(a.to_ref())).boxed(), + (Key("bsp/s"), [a, b]) => Bsp::s(state.get_content(a.to_ref()), state.get_content(b.to_ref()),).boxed(), + _ => todo!("{:?} {:?}", &head, &tail) + } + } else { + panic!("todo: add error handling to content() chain. invalid expression {e:?}") + }, }, + Self::Err(error) => { + Box::new(())//&format!("EdnView error: {error:?}")) + }, + _ => todo!() } + //let items = &self.layout; //if let (Some(first), rest) = (items.get(0).map(EdnItem::to_str), &items[1..]) { //match (first, rest) { diff --git a/engine/src/output/area.rs b/engine/src/area.rs similarity index 100% rename from engine/src/output/area.rs rename to engine/src/area.rs diff --git a/engine/src/input/command.rs b/engine/src/command.rs similarity index 100% rename from engine/src/input/command.rs rename to engine/src/command.rs diff --git a/engine/src/output/content.rs b/engine/src/content.rs similarity index 50% rename from engine/src/output/content.rs rename to engine/src/content.rs index 4487b684..def71540 100644 --- a/engine/src/output/content.rs +++ b/engine/src/content.rs @@ -1,23 +1,22 @@ use crate::*; /// Build a [Render]able out of other [Render]ables, /// then apply optional custom render/layout on top. -pub trait Content: Send + Sync + Sized { +pub trait Content: Send + Sync + Sized { fn content (&self) -> impl Render { () } fn layout (&self, area: E::Area) -> E::Area { self.content().layout(area) } - fn render (&self, output: &mut E::Output) { self.content().render(output) } + fn render (&self, output: &mut E) { self.content().render(output) } } -impl> Content for &C { +impl> Content for &C { fn content (&self) -> impl Render { (*self).content() } fn layout (&self, area: E::Area) -> E::Area { (*self).layout(area) } - fn render (&self, output: &mut E::Output) { (*self).render(output) } + fn render (&self, output: &mut E) { (*self).render(output) } } /// The platonic ideal unit of [Content]: total emptiness at dead center. -impl Content for () { +impl Content for () { fn layout (&self, area: E::Area) -> E::Area { area.center().to_area_pos().into() } - fn render (&self, _: &mut E::Output) {} + fn render (&self, _: &mut E) {} } - -impl> Content for Option { +impl> Content for Option { fn content (&self) -> impl Render { self.as_ref() } @@ -26,8 +25,22 @@ impl> Content for Option { .map(|content|content.layout(area)) .unwrap_or([0.into(), 0.into(), 0.into(), 0.into(),].into()) } - fn render (&self, output: &mut E::Output) { + fn render (&self, output: &mut E) { self.as_ref() .map(|content|content.render(output)); } } +//impl, E: Content> Content for Option { + //fn content (&self) -> impl Render { + //self.as_ref() + //} + //fn layout (&self, area: E::Area) -> E::Area { + //self.as_ref() + //.map(|content|content.layout(area)) + //.unwrap_or([0.into(), 0.into(), 0.into(), 0.into(),].into()) + //} + //fn render (&self, output: &mut E) { + //self.as_ref() + //.map(|content|content.render(output)); + //} +//} diff --git a/engine/src/output/coordinate.rs b/engine/src/coordinate.rs similarity index 100% rename from engine/src/output/coordinate.rs rename to engine/src/coordinate.rs diff --git a/engine/src/engine.rs b/engine/src/engine.rs index b3a862cd..be754e06 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -3,17 +3,9 @@ use crate::*; /// Platform backend. pub trait Engine: Send + Sync + Sized { /// Input event type - type Input: Input; - /// Result of handling input - type Handled; + type Input: Input; /// Render target - type Output: Output; - /// Unit of length - type Unit: Coordinate; - /// Rectangle without offset - type Size: Size; - /// Rectangle with offset - type Area: Area; + type Output: Output; /// Prepare before run fn setup (&mut self) -> Usually<()> { Ok(()) } /// True if done @@ -21,3 +13,38 @@ pub trait Engine: Send + Sync + Sized { /// Clean up after run fn teardown (&mut self) -> Usually<()> { Ok(()) } } + +/// Event source +pub trait Input: Send + Sync + Sized { + /// Type of input event + type Event; + /// Result of handling input + type Handled; + /// Currently handled event + fn event (&self) -> &Self::Event; + /// Whether component should exit + fn is_done (&self) -> bool; + /// Mark component as done + fn done (&self); +} + +/// Render target +pub trait Output: Send + Sync + Sized { + /// Unit of length + type Unit: Coordinate; + /// Rectangle without offset + type Size: Size; + /// Rectangle with offset + type Area: Area; + /// Current output area + fn area (&self) -> Self::Area; + /// Mutable pointer to area + fn area_mut (&mut self) -> &mut Self::Area; + /// Render widget in area + fn place (&mut self, area: Self::Area, content: &impl Render); + #[inline] fn x (&self) -> Self::Unit { self.area().x() } + #[inline] fn y (&self) -> Self::Unit { self.area().y() } + #[inline] fn w (&self) -> Self::Unit { self.area().w() } + #[inline] fn h (&self) -> Self::Unit { self.area().h() } + #[inline] fn wh (&self) -> Self::Size { self.area().wh().into() } +} diff --git a/engine/src/input/event_map.rs b/engine/src/event_map.rs similarity index 100% rename from engine/src/input/event_map.rs rename to engine/src/event_map.rs diff --git a/engine/src/handle.rs b/engine/src/handle.rs new file mode 100644 index 00000000..63b87514 --- /dev/null +++ b/engine/src/handle.rs @@ -0,0 +1,61 @@ +use crate::*; +use std::sync::{Mutex, Arc, RwLock}; + +/// Implement the [Handle] trait. +#[macro_export] macro_rules! handle { + (|$self:ident:$Struct:ty,$input:ident|$handler:expr) => { + impl Handle for $Struct { + fn handle (&mut $self, $input: &E) -> Perhaps { + $handler + } + } + }; + ($E:ty: |$self:ident:$Struct:ty,$input:ident|$handler:expr) => { + impl Handle<$E> for $Struct { + fn handle (&mut $self, $input: &$E) -> Perhaps<<$E as Input>::Handled> { + $handler + } + } + } +} + +/// Handle input +pub trait Handle: Send + Sync { + fn handle (&mut self, _input: &E) -> Perhaps { + Ok(None) + } +} +impl> Handle for &mut H { + fn handle (&mut self, context: &E) -> Perhaps { + (*self).handle(context) + } +} +impl> Handle for Option { + fn handle (&mut self, context: &E) -> Perhaps { + if let Some(ref mut handle) = self { + handle.handle(context) + } else { + Ok(None) + } + } +} +impl Handle for Mutex where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.get_mut().unwrap().handle(context) + } +} +impl Handle for Arc> where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.lock().unwrap().handle(context) + } +} +impl Handle for RwLock where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.write().unwrap().handle(context) + } +} +impl Handle for Arc> where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.write().unwrap().handle(context) + } +} diff --git a/engine/src/input.rs b/engine/src/input.rs deleted file mode 100644 index 90b6dbfe..00000000 --- a/engine/src/input.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::*; - -mod handle; pub use self::handle::*; -mod command; pub use self::command::*; -mod event_map; pub use self::event_map::*; - -/// Current input state -pub trait Input { - /// Type of input event - type Event; - /// Currently handled event - fn event (&self) -> &Self::Event; - /// Whether component should exit - fn is_done (&self) -> bool; - /// Mark component as done - fn done (&self); -} diff --git a/engine/src/input/handle.rs b/engine/src/input/handle.rs deleted file mode 100644 index 751cc7fd..00000000 --- a/engine/src/input/handle.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::*; -use std::sync::{Mutex, Arc, RwLock}; - -#[macro_export] macro_rules! handle { - (<$E:ty>|$self:ident:$Struct:ty,$input:ident|$handler:expr) => { - impl Handle<$E> for $Struct { - fn handle (&mut $self, $input: &<$E as Engine>::Input) -> Perhaps<<$E as Engine>::Handled> { - $handler - } - } - } -} - -/// Handle input -pub trait Handle: Send + Sync { - fn handle (&mut self, _input: &E::Input) -> Perhaps { - Ok(None) - } -} -impl> Handle for &mut H { - fn handle (&mut self, context: &E::Input) -> Perhaps { - (*self).handle(context) - } -} -impl> Handle for Option { - fn handle (&mut self, context: &E::Input) -> Perhaps { - if let Some(ref mut handle) = self { - handle.handle(context) - } else { - Ok(None) - } - } -} -impl Handle for Mutex where H: Handle { - fn handle (&mut self, context: &E::Input) -> Perhaps { - self.get_mut().unwrap().handle(context) - } -} -impl Handle for Arc> where H: Handle { - fn handle (&mut self, context: &E::Input) -> Perhaps { - self.lock().unwrap().handle(context) - } -} -impl Handle for RwLock where H: Handle { - fn handle (&mut self, context: &E::Input) -> Perhaps { - self.write().unwrap().handle(context) - } -} -impl Handle for Arc> where H: Handle { - fn handle (&mut self, context: &E::Input) -> Perhaps { - self.write().unwrap().handle(context) - } -} diff --git a/engine/src/lib.rs b/engine/src/lib.rs index fb142b9d..7115e9e2 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -2,8 +2,15 @@ //mod component; pub use self::component::*; mod engine; pub use self::engine::*; -mod input; pub use self::input::*; -mod output; pub use self::output::*; +mod handle; pub use self::handle::*; +mod command; pub use self::command::*; +mod event_map; pub use self::event_map::*; +mod coordinate; pub use self::coordinate::*; +mod size; pub use self::size::*; +mod area; pub use self::area::*; +mod render; pub use self::render::*; +mod content; pub use self::content::*; +mod thunk; pub use self::thunk::*; pub use std::error::Error; diff --git a/engine/src/output.rs b/engine/src/output.rs deleted file mode 100644 index 70c3ef98..00000000 --- a/engine/src/output.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::*; - -mod coordinate; pub use self::coordinate::*; -mod size; pub use self::size::*; -mod area; pub use self::area::*; - -mod render; pub use self::render::*; -mod content; pub use self::content::*; -mod thunk; pub use self::thunk::*; - -/// Rendering target -pub trait Output { - /// Current output area - fn area (&self) -> E::Area; - /// Mutable pointer to area - fn area_mut (&mut self) -> &mut E::Area; - /// Render widget in area - fn place (&mut self, area: E::Area, content: &impl Render); - #[inline] fn x (&self) -> E::Unit { self.area().x() } - #[inline] fn y (&self) -> E::Unit { self.area().y() } - #[inline] fn w (&self) -> E::Unit { self.area().w() } - #[inline] fn h (&self) -> E::Unit { self.area().h() } - #[inline] fn wh (&self) -> E::Size { self.area().wh().into() } -} diff --git a/engine/src/output/render.rs b/engine/src/render.rs similarity index 56% rename from engine/src/output/render.rs rename to engine/src/render.rs index 202bb43f..22649c7d 100644 --- a/engine/src/output/render.rs +++ b/engine/src/render.rs @@ -2,64 +2,64 @@ use crate::*; use std::ops::Deref; /// Custom layout and rendering. -pub trait Render: Send + Sync { +pub trait Render: Send + Sync { fn layout (&self, area: E::Area) -> E::Area; - fn render (&self, output: &mut E::Output); + fn render (&self, output: &mut E); fn boxed <'a> (self) -> RenderBox<'a, E> where Self: Sized + 'a { Box::new(self) as RenderBox<'a, E> } } -pub type RenderDyn<'a, Engine> = dyn Render + 'a; -impl<'a, E: Engine> Content for &RenderDyn<'a, E> where Self: Sized { +pub type RenderDyn<'a, Output> = dyn Render + 'a; +impl<'a, E: Output> Content for &RenderDyn<'a, E> where Self: Sized { fn content (&self) -> impl Render { *self } fn layout (&self, area: E::Area) -> E::Area { Render::layout(self.deref(), area) } - fn render (&self, output: &mut E::Output) { Render::render(self.deref(), output) } + fn render (&self, output: &mut E) { Render::render(self.deref(), output) } } -pub type RenderBox<'a, E: Engine> = Box>; -impl<'a, E: Engine> Content for RenderBox<'a, E> { +pub type RenderBox<'a, E: Output> = Box>; +impl<'a, E: Output> Content for RenderBox<'a, E> { fn content (&self) -> impl Render { self.deref() } } -impl> Render for C { +impl> Render for C { fn layout (&self, area: E::Area) -> E::Area { Content::layout(self, area) } - fn render (&self, output: &mut E::Output) { Content::render(self, output) } + fn render (&self, output: &mut E) { Content::render(self, output) } } #[macro_export] macro_rules! render { (($self:ident:$Struct:ty) => $content:expr) => { - impl Content for $Struct { + impl Content for $Struct { fn content (&$self) -> impl Render { Some($content) } } }; (|$self:ident:$Struct:ident $(< $($L:lifetime),* $($T:ident $(:$Trait:path)?),* >)?, $to:ident | $render:expr) => { - impl <$($($L),*)? E: Engine, $($T$(:$Trait)?),*> Content + impl <$($($L),*)? E: Output, $($T$(:$Trait)?),*> Content for $Struct $(<$($L),* $($T),*>>)? { - fn render (&$self, $to: &mut E::Output) { $render } + fn render (&$self, $to: &mut E) { $render } } }; - ($Engine:ty: + ($Output:ty: ($self:ident:$Struct:ident $(<$( $($L:lifetime)? $($T:ident)? $(:$Trait:path)? ),+>)?) => $content:expr ) => { - impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> + impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output> for $Struct $(<$($($L)? $($T)?),+>)? { - fn content (&$self) -> impl Render<$Engine> { $content } + fn content (&$self) -> impl Render<$Output> { $content } } }; - ($Engine:ty: + ($Output:ty: |$self:ident : $Struct:ident $(<$( $($L:lifetime)? $($T:ident)? $(:$Trait:path)? ),+>)?, $to:ident| $render:expr ) => { - impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> + impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output> for $Struct $(<$($($L)? $($T)?),+>)? { - fn render (&$self, $to: &mut <$Engine as Engine>::Output) { $render } + fn render (&$self, $to: &mut $Output) { $render } } }; } diff --git a/engine/src/output/size.rs b/engine/src/size.rs similarity index 100% rename from engine/src/output/size.rs rename to engine/src/size.rs diff --git a/engine/src/output/thunk.rs b/engine/src/thunk.rs similarity index 58% rename from engine/src/output/thunk.rs rename to engine/src/thunk.rs index a4bbd303..936114f1 100644 --- a/engine/src/output/thunk.rs +++ b/engine/src/thunk.rs @@ -1,10 +1,10 @@ use crate::*; use std::marker::PhantomData; /// Lazily-evaluated [Render]able. -pub struct Thunk, F: Fn()->T + Send + Sync>(F, PhantomData); -impl, F: Fn()->T + Send + Sync> Thunk { +pub struct Thunk, F: Fn()->T + Send + Sync>(F, PhantomData); +impl, F: Fn()->T + Send + Sync> Thunk { pub fn new (thunk: F) -> Self { Self(thunk, Default::default()) } } -impl, F: Fn()->T + Send + Sync> Content for Thunk { +impl, F: Fn()->T + Send + Sync> Content for Thunk { fn content (&self) -> impl Render { (self.0)() } } diff --git a/examples/demo.rs.fixme b/examples/demo.rs.fixme index ce3c6556..a68d26d7 100644 --- a/examples/demo.rs.fixme +++ b/examples/demo.rs.fixme @@ -104,7 +104,7 @@ impl Content for Demo { } } -impl Handle for Demo { +impl Handle for Demo { fn handle (&mut self, from: &TuiIn) -> Perhaps { use KeyCode::{PageUp, PageDown}; match from.event() { diff --git a/examples/demo_bsp.rs.fixme b/examples/demo_bsp.rs.fixme deleted file mode 100644 index 997956cd..00000000 --- a/examples/demo_bsp.rs.fixme +++ /dev/null @@ -1,19 +0,0 @@ -use tek::*; -use std::sync::{Arc, RwLock}; - -fn main () -> Usually<()> { - Tui::run(Arc::new(RwLock::new(BspDemo(Default::default()))))?; - Ok(()) -} - -pub struct BspDemo(std::marker::PhantomData); - -render!(|self:BspDemo|Fill::xy(Align::c( - Bsp::n(Bsp::s(Bsp::e(Bsp::w("00", "11"), "22"), "33"), "44") -))); - -impl Handle for BspDemo { - fn handle (&mut self, from: &TuiIn) -> Perhaps { - Ok(None) - } -} diff --git a/layout/src/align.rs b/layout/src/align.rs index 419d5aff..530aef63 100644 --- a/layout/src/align.rs +++ b/layout/src/align.rs @@ -19,7 +19,7 @@ impl Align { pub fn se (a: T) -> Self { Self(Alignment::SE, a) } } -impl> Content for Align { +impl> Content for Align { fn content (&self) -> impl Render { &self.1 } @@ -46,7 +46,7 @@ impl> Content for Align { }; [x, y, centered.w(), centered.h()].into() } - fn render (&self, render: &mut E::Output) { + fn render (&self, render: &mut E) { let content = &self.content(); let it = Render::layout(content, render.area()).xywh(); render.place(it.into(), content) diff --git a/layout/src/direction.rs b/layout/src/direction.rs index 78f9f477..d7b22476 100644 --- a/layout/src/direction.rs +++ b/layout/src/direction.rs @@ -20,12 +20,12 @@ impl Direction { pub struct Bsp(Direction, X, Y); -impl, B: Content> Content for Bsp { +impl, B: Content> Content for Bsp { fn layout (&self, outer: E::Area) -> E::Area { let [_, _, c] = self.areas(outer); c } - fn render (&self, to: &mut E::Output) { + fn render (&self, to: &mut E) { let [area_a, area_b, _] = self.areas(to.area()); let (a, b) = self.contents(); match self.0 { @@ -44,7 +44,7 @@ impl Bsp { pub fn b (a: A, b: B) -> Self { Self(Below, a, b) } } -pub trait BspAreas, B: Content> { +pub trait BspAreas, B: Content> { fn direction (&self) -> Direction; fn contents (&self) -> (&A, &B); fn areas (&self, outer: E::Area) -> [E::Area;3] { @@ -95,7 +95,7 @@ pub trait BspAreas, B: Content> { } } -impl, B: Content> BspAreas for Bsp { +impl, B: Content> BspAreas for Bsp { fn direction (&self) -> Direction { self. 0 } fn contents (&self) -> (&A, &B) { (&self.1, &self.2) } } diff --git a/layout/src/lib.rs b/layout/src/lib.rs index b49e877f..57224655 100644 --- a/layout/src/lib.rs +++ b/layout/src/lib.rs @@ -18,17 +18,17 @@ pub(crate) use std::marker::PhantomData; let unit = (); - assert_eq!(Content::::layout(&unit, area), [20, 20, 0, 0]); + assert_eq!(Content::::layout(&unit, area), [20, 20, 0, 0]); - assert_eq!(Fill::::x(unit).layout(area), [10, 20, 20, 0]); - assert_eq!(Fill::::y(unit).layout(area), [20, 10, 0, 20]); - assert_eq!(Fill::::xy(unit).layout(area), area); + assert_eq!(Fill::::x(unit).layout(area), [10, 20, 20, 0]); + assert_eq!(Fill::::y(unit).layout(area), [20, 10, 0, 20]); + assert_eq!(Fill::::xy(unit).layout(area), area); - assert_eq!(Fixed::::x(4, unit).layout(area), [18, 20, 4, 0]); - assert_eq!(Fixed::::y(4, unit).layout(area), [20, 18, 0, 4]); - assert_eq!(Fixed::::xy(4, 4, unit).layout(area), [18, 18, 4, 4]); + assert_eq!(Fixed::::x(4, unit).layout(area), [18, 20, 4, 0]); + assert_eq!(Fixed::::y(4, unit).layout(area), [20, 18, 0, 4]); + assert_eq!(Fixed::::xy(4, 4, unit).layout(area), [18, 18, 4, 4]); - let four = ||Fixed::::xy(4, 4, unit); + let four = ||Fixed::::xy(4, 4, unit); assert_eq!(Align::nw(four()).layout(area), [10, 10, 4, 4]); assert_eq!(Align::n(four()).layout(area), [18, 10, 4, 4]); @@ -39,7 +39,7 @@ pub(crate) use std::marker::PhantomData; assert_eq!(Align::sw(four()).layout(area), [10, 26, 4, 4]); assert_eq!(Align::w(four()).layout(area), [10, 18, 4, 4]); - let two_by_four = ||Fixed::::xy(4, 2, unit); + let two_by_four = ||Fixed::::xy(4, 2, unit); assert_eq!(Align::nw(two_by_four()).layout(area), [10, 10, 4, 2]); assert_eq!(Align::n(two_by_four()).layout(area), [18, 10, 4, 2]); diff --git a/layout/src/measure.rs b/layout/src/measure.rs index da8b3ae1..33eb07ea 100644 --- a/layout/src/measure.rs +++ b/layout/src/measure.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}}; // TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small -pub trait HasSize { +pub trait HasSize { fn size (&self) -> &Measure; } @@ -18,20 +18,20 @@ pub trait HasSize { /// A widget that tracks its render width and height #[derive(Default)] -pub struct Measure { +pub struct Measure { _engine: PhantomData, pub x: Arc, pub y: Arc, } -impl Content for Measure { - fn render (&self, to: &mut E::Output) { +impl Content for Measure { + fn render (&self, to: &mut E) { self.x.store(to.area().w().into(), Relaxed); self.y.store(to.area().h().into(), Relaxed); } } -impl Clone for Measure { +impl Clone for Measure { fn clone (&self) -> Self { Self { _engine: Default::default(), @@ -41,7 +41,7 @@ impl Clone for Measure { } } -impl std::fmt::Debug for Measure { +impl std::fmt::Debug for Measure { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("Measure") .field("width", &self.x) @@ -50,7 +50,7 @@ impl std::fmt::Debug for Measure { } } -impl Measure { +impl Measure { pub fn w (&self) -> usize { self.x.load(Relaxed) } pub fn h (&self) -> usize { self.y.load(Relaxed) } pub fn wh (&self) -> [usize;2] { [self.w(), self.h()] } @@ -73,18 +73,18 @@ impl Measure { ///// A scrollable area. //pub struct Scroll(pub F, pub Direction, pub u64, PhantomData) //where - //E: Engine, + //E: Output, //F: Send + Sync + Fn(&mut dyn FnMut(&dyn Content)->Usually<()>)->Usually<()>; -//pub trait ContentDebug { +//pub trait ContentDebug { //fn debug > (other: W) -> DebugOverlay { //DebugOverlay(Default::default(), other) //} //} -//impl ContentDebug for E {} +//impl ContentDebug for E {} -//impl Render for Measure { +//impl Render for Measure { //fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { //Ok(Some([0u16.into(), 0u16.into()].into())) //} @@ -95,13 +95,13 @@ impl Measure { //} //} -//impl Measure { +//impl Measure { //pub fn debug (&self) -> ShowMeasure { //ShowMeasure(&self) //} //} -//render!(|self: ShowMeasure<'a>|render(|to: &mut TuiOut|Ok({ +//render!(Tui: |self: ShowMeasure<'a>|render(|to: &mut TuiOut|Ok({ //let w = self.0.w(); //let h = self.0.h(); //to.blit(&format!(" {w} x {h} "), to.area.x(), to.area.y(), Some( @@ -109,11 +109,11 @@ impl Measure { //)) //}))); -//pub struct ShowMeasure<'a>(&'a Measure); +//pub struct ShowMeasure<'a>(&'a Measure); -//pub struct DebugOverlay>(PhantomData, pub W); +//pub struct DebugOverlay>(PhantomData, pub W); -//impl> Render for DebugOverlay { +//impl> Render for DebugOverlay { //fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { //self.1.min_size(to) //} diff --git a/layout/src/ops.rs b/layout/src/ops.rs index 89c53d8d..80fca55a 100644 --- a/layout/src/ops.rs +++ b/layout/src/ops.rs @@ -3,7 +3,7 @@ use crate::*; /// Show an item only when a condition is true. pub struct When(pub bool, pub A); -impl> Content for When { +impl> Content for When { fn layout (&self, to: E::Area) -> E::Area { let Self(cond, item) = self; let mut area = E::Area::zero(); @@ -16,7 +16,7 @@ impl> Content for When { } area.into() } - fn render (&self, to: &mut E::Output) { + fn render (&self, to: &mut E) { let Self(cond, item) = self; if *cond { item.render(to) } } @@ -25,12 +25,12 @@ impl> Content for When { /// Show one item if a condition is true and another if the condition is false pub struct Either(pub bool, pub A, pub B); -impl, B: Render> Content for Either { +impl, B: Render> Content for Either { fn layout (&self, to: E::Area) -> E::Area { let Self(cond, a, b) = self; if *cond { a.layout(to) } else { b.layout(to) } } - fn render (&self, to: &mut E::Output) { + fn render (&self, to: &mut E) { let Self(cond, a, b) = self; if *cond { a.render(to) } else { b.render(to) } } @@ -42,7 +42,7 @@ pub struct Map(pub F, pub G) where G: Fn(A, usize)->B + Send + Sync; impl Content for Map where - E: Engine, + E: Output, B: Render, I: Iterator + Send + Sync, F: Fn() -> I + Send + Sync, @@ -67,7 +67,7 @@ impl Content for Map where //[min_x.into(), min_y.into(), w.into(), h.into()].into() area.center_xy([w.into(), h.into()].into()).into() } - fn render (&self, to: &mut E::Output) { + fn render (&self, to: &mut E) { let Self(get_iterator, callback) = self; let mut index = 0; //let area = self.layout(to.area()); @@ -83,7 +83,7 @@ impl Content for Map where /* //pub fn reduce (iterator: I, callback: F) -> Reduce where - //E: Engine, + //E: Output, //I: Iterator + Send + Sync, //R: Render, //F: Fn(R, T, usize) -> R + Send + Sync @@ -91,24 +91,24 @@ impl Content for Map where //Reduce(Default::default(), iterator, callback) //} pub struct Reduce(PhantomData<(E, R)>, I, F) where - E: Engine, + E: Output, I: Iterator + Send + Sync, R: Render, F: Fn(R, T, usize) -> R + Send + Sync; impl Content for Reduce where - E: Engine, + E: Output, I: Iterator + Send + Sync, R: Render, F: Fn(R, T, usize) -> R + Send + Sync { - fn render (&self, to: &mut E::Output) { + fn render (&self, to: &mut E) { todo!() } } */ //macro_rules! define_ops { - //($Trait:ident<$E:ident:$Engine:path> { $( + //($Trait:ident<$E:ident:$Output:path> { $( //$(#[$attr:meta $($attr_args:tt)*])* //( //$fn:ident @@ -117,8 +117,8 @@ impl Content for Reduce where //($($arg:ident:$Arg:ty),*) //) //)* }) => { - //impl<$E: $Engine> $Trait for E {} - //pub trait $Trait<$E: $Engine> { + //impl<$E: $Output> $Trait for E {} + //pub trait $Trait<$E: $Output> { //$( //$(#[$attr $($attr_args)*])* //fn $fn $(<$($G),+>)? @@ -131,7 +131,7 @@ impl Content for Reduce where //} //define_ops! { - //Layout { + //Layout { //(when ,> //When(cond: bool, item: A)) ///// When `cond` is `true`, render `a`, otherwise render `b`. diff --git a/layout/src/transform_xy.rs b/layout/src/transform_xy.rs index 654df17d..d6863218 100644 --- a/layout/src/transform_xy.rs +++ b/layout/src/transform_xy.rs @@ -3,7 +3,7 @@ use crate::*; /// Defines an enum that transforms its content /// along either the X axis, the Y axis, or both. /// -/// The `_Unused` variant wraps the `Engine` type +/// The `_Unused` variant wraps the `Output` type /// using `PhantomData` to permit the double generic. macro_rules! transform_xy { ($self:ident : $Enum:ident |$to:ident|$area:expr) => { @@ -13,15 +13,15 @@ macro_rules! transform_xy { pub fn y (item: T) -> Self { Self::Y(item) } pub fn xy (item: T) -> Self { Self::XY(item) } } - impl> Content for $Enum { + impl> Content for $Enum { fn content (&self) -> impl Render { match self { Self::X(item) => item, Self::Y(item) => item, - Self::XY(item) => item, + Self::XY(item) => item } } - fn layout (&$self, $to: ::Area) -> ::Area { + fn layout (&$self, $to: ::Area) -> ::Area { use $Enum::*; $area } diff --git a/layout/src/transform_xy_unit.rs b/layout/src/transform_xy_unit.rs index a43c786f..51b07885 100644 --- a/layout/src/transform_xy_unit.rs +++ b/layout/src/transform_xy_unit.rs @@ -26,7 +26,7 @@ macro_rules! transform_xy_unit { } } } - impl> Content for $Enum { + impl> Content for $Enum { fn content (&self) -> impl Render { Some(match self { Self::X(_, content) => content, diff --git a/src/arranger.rs b/src/arranger.rs index 481e9d83..3dc9f3b7 100644 --- a/src/arranger.rs +++ b/src/arranger.rs @@ -24,7 +24,7 @@ pub struct ArrangerTui { pub selected: ArrangerSelection, pub mode: ArrangerMode, pub color: ItemPalette, - pub size: Measure, + pub size: Measure, pub note_buf: Vec, pub midi_buf: Vec>>, pub editor: MidiEditor, @@ -97,14 +97,14 @@ from_jack!(|jack| ArrangerTui { } }); impl ArrangerTui { - fn render_mode (state: &Self) -> impl Content + use<'_> { + fn render_mode (state: &Self) -> impl Content + use<'_> { match state.mode { ArrangerMode::H => todo!("horizontal arranger"), ArrangerMode::V(factor) => Self::render_mode_v(state, factor), } } } -render!(Tui: (self: ArrangerTui) => { +render!(TuiOut: (self: ArrangerTui) => { let pool_size = if self.pool.visible { self.splits[1] } else { 0 }; let with_pool = |x|Bsp::w(Fixed::x(pool_size, PoolView(self.pool.visible, &self.pool)), x); let status = ArrangerStatus::from(self); @@ -164,4 +164,4 @@ audio!(|self: ArrangerTui, client, scope|{ has_clock!(|self: ArrangerTui|&self.clock); has_phrases!(|self: ArrangerTui|self.pool.phrases); has_editor!(|self: ArrangerTui|self.editor); -handle!(|self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, input.event())); +handle!(TuiIn: |self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, input.event())); diff --git a/src/arranger/arranger_command.rs b/src/arranger/arranger_command.rs index 283373b5..17bcafd5 100644 --- a/src/arranger/arranger_command.rs +++ b/src/arranger/arranger_command.rs @@ -49,7 +49,7 @@ pub enum ArrangerClipCommand { SetColor(usize, usize, ItemPalette), } -//handle!(|self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, input.event())); +//handle!(TuiIn: |self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, input.event())); //input_to_command!(ArrangerCommand: |state: ArrangerTui, input: Event|{KEYS_ARRANGER.handle(state, input)?}); keymap!(KEYS_ARRANGER = |state: ArrangerTui, input: Event| ArrangerCommand { diff --git a/src/arranger/arranger_mode.rs b/src/arranger/arranger_mode.rs index d1f5b32c..81790e5a 100644 --- a/src/arranger/arranger_mode.rs +++ b/src/arranger/arranger_mode.rs @@ -7,7 +7,7 @@ pub enum ArrangerMode { /// Tracks are rows H, } -impl Content for ArrangerMode {} +impl Content for ArrangerMode {} /// Arranger display mode can be cycled impl ArrangerMode { /// Cycle arranger display mode @@ -21,6 +21,6 @@ impl ArrangerMode { } } } -fn any_size (_: E::Size) -> Perhaps{ +fn any_size (_: E::Size) -> Perhaps{ Ok(Some([0.into(),0.into()].into())) } diff --git a/src/arranger/arranger_v.rs b/src/arranger/arranger_v.rs index 70b92591..6c60b96b 100644 --- a/src/arranger/arranger_v.rs +++ b/src/arranger/arranger_v.rs @@ -3,7 +3,7 @@ use crate::*; pub(crate) const HEADER_H: u16 = 5; pub(crate) const SCENES_W_OFFSET: u16 = 3; impl ArrangerTui { - pub fn render_mode_v (state: &ArrangerTui, factor: usize) -> impl Content + use<'_> { + pub fn render_mode_v (state: &ArrangerTui, factor: usize) -> impl Content + use<'_> { lay!( ArrangerVColSep::from(state), ArrangerVRowSep::from((state, factor)), diff --git a/src/arranger/arranger_v_clips.rs b/src/arranger/arranger_v_clips.rs index 5b0776b2..e3b3ec6f 100644 --- a/src/arranger/arranger_v_clips.rs +++ b/src/arranger/arranger_v_clips.rs @@ -2,7 +2,7 @@ use crate::*; use super::*; pub struct ArrangerVClips<'a> { - size: &'a Measure, + size: &'a Measure, scenes: &'a Vec, tracks: &'a Vec, rows: Vec<(usize, usize)>, @@ -17,8 +17,8 @@ impl<'a> ArrangerVClips<'a> { } } } -impl<'a> Content for ArrangerVClips<'a> { - fn content (&self) -> impl Render { +impl<'a> Content for ArrangerVClips<'a> { + fn content (&self) -> impl Render { let iter = ||self.scenes.iter().zip(self.rows.iter().map(|row|row.0)); let col = Map(iter, |(scene, pulses), i|Self::format_scene(self.tracks, scene, pulses)); Fill::xy(col) @@ -28,7 +28,7 @@ impl<'a> ArrangerVClips<'a> { fn format_scene ( tracks: &'a [ArrangerTrack], scene: &'a ArrangerScene, pulses: usize - ) -> impl Content + use<'a> { + ) -> impl Content + use<'a> { let height = 1.max((pulses / PPQ) as u16); let playing = scene.is_playing(tracks); let icon = Tui::bg( @@ -45,7 +45,7 @@ impl<'a> ArrangerVClips<'a> { fn format_clip ( scene: &'a ArrangerScene, index: usize, track: &'a ArrangerTrack, w: u16, h: u16 - ) -> impl Content + use<'a> { + ) -> impl Content + use<'a> { scene.clips.get(index).map(|clip|clip.as_ref().map(|phrase|{ let phrase = phrase.read().unwrap(); let mut bg = TuiTheme::border_bg(); diff --git a/src/arranger/arranger_v_cursor.rs b/src/arranger/arranger_v_cursor.rs index 3582cd07..87da89ba 100644 --- a/src/arranger/arranger_v_cursor.rs +++ b/src/arranger/arranger_v_cursor.rs @@ -24,7 +24,7 @@ from!(|args:(&ArrangerTui, usize)|ArrangerVCursor = Self { sub_modifier: Modifier::DIM }), }); -impl Content for ArrangerVCursor { +impl Content for ArrangerVCursor { fn render (&self, to: &mut TuiOut) { let area = to.area(); let focused = true; diff --git a/src/arranger/arranger_v_head.rs b/src/arranger/arranger_v_head.rs index cfef2096..8084cab9 100644 --- a/src/arranger/arranger_v_head.rs +++ b/src/arranger/arranger_v_head.rs @@ -15,8 +15,8 @@ from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16, }); -render!(Tui: (self: ArrangerVHead<'a>) => { - fn row > (color: ItemPalette, field: T) -> impl Content { +render!(TuiOut: (self: ArrangerVHead<'a>) => { + fn row > (color: ItemPalette, field: T) -> impl Content { row!(Tui::fg(color.light.rgb, "▎"), Tui::fg(color.lightest.rgb, field)) } Some(Push::x(self.scenes_w, @@ -38,22 +38,22 @@ render!(Tui: (self: ArrangerVHead<'a>) => { impl ArrangerVHead<'_> { /// name and width of track - fn format_name (track: &ArrangerTrack, _w: usize) -> impl Content { + fn format_name (track: &ArrangerTrack, _w: usize) -> impl Content { let name = track.name().read().unwrap().clone(); Tui::bold(true, Tui::fg(track.color.lightest.rgb, name)) } /// input port - fn format_input (track: &ArrangerTrack) -> Usually> { + fn format_input (track: &ArrangerTrack) -> Usually> { Ok(format!(">{}", track.player.midi_ins().first().map(|port|port.short_name()) .transpose()?.unwrap_or("?".into()))) } /// output port - fn format_output (track: &ArrangerTrack) -> Usually> { + fn format_output (track: &ArrangerTrack) -> Usually> { Ok(format!("<{}", track.player.midi_outs().first().map(|port|port.short_name()) .transpose()?.unwrap_or("?".into()))) } /// beats elapsed - fn format_elapsed (track: &ArrangerTrack, timebase: &Arc) -> impl Content { + fn format_elapsed (track: &ArrangerTrack, timebase: &Arc) -> impl Content { let mut result = String::new(); if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() { let length = phrase.read().unwrap().length; @@ -67,7 +67,7 @@ impl ArrangerVHead<'_> { } /// beats until switchover fn format_until_next (track: &ArrangerTrack, current: &Arc) - -> Option> + -> Option> { let timebase = ¤t.timebase; let mut result = String::new(); diff --git a/src/arranger/arranger_v_io.rs b/src/arranger/arranger_v_io.rs index 31c582e0..2d6a5565 100644 --- a/src/arranger/arranger_v_io.rs +++ b/src/arranger/arranger_v_io.rs @@ -2,7 +2,7 @@ use crate::*; use super::*; pub struct ArrangerVIns<'a> { - size: &'a Measure, + size: &'a Measure, tracks: &'a Vec, } @@ -11,10 +11,10 @@ from!(<'a>|args: &'a ArrangerTui|ArrangerVIns<'a> = Self { tracks: &args.tracks, }); -render!(Tui: (self: ArrangerVIns<'a>) => ""); +render!(TuiOut: (self: ArrangerVIns<'a>) => ""); pub struct ArrangerVOuts<'a> { - size: &'a Measure, + size: &'a Measure, tracks: &'a Vec, } @@ -23,4 +23,4 @@ from!(<'a>|args: &'a ArrangerTui|ArrangerVOuts<'a> = Self { tracks: &args.tracks, }); -render!(Tui: (self: ArrangerVOuts<'a>) => ""); +render!(TuiOut: (self: ArrangerVOuts<'a>) => ""); diff --git a/src/arranger/arranger_v_sep.rs b/src/arranger/arranger_v_sep.rs index 7377fbfc..82f49343 100644 --- a/src/arranger/arranger_v_sep.rs +++ b/src/arranger/arranger_v_sep.rs @@ -11,7 +11,7 @@ from!(|state:&ArrangerTui|ArrangerVColSep = Self { cols: ArrangerTrack::widths(&state.tracks), scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16, }); -render!(Tui: |self: ArrangerVColSep, to| { +render!(TuiOut: |self: ArrangerVColSep, to| { let style = Some(Style::default().fg(self.fg)); for x in self.cols.iter().map(|col|col.1) { let x = self.scenes_w + to.area().x() + x as u16; @@ -29,7 +29,7 @@ from!(|args:(&ArrangerTui, usize)|ArrangerVRowSep = Self { fg: TuiTheme::separator_fg(false), rows: ArrangerScene::ppqs(&args.0.scenes, args.1), }); -render!(Tui: |self: ArrangerVRowSep, to|for y in self.rows.iter().map(|row|row.1) { +render!(TuiOut: |self: ArrangerVRowSep, to|for y in self.rows.iter().map(|row|row.1) { let y = to.area().y() + (y / PPQ) as u16 + 1; if y >= to.buffer.area.height { break } for x in to.area().x()..to.area().x2().saturating_sub(2) { diff --git a/src/clock/clock_tui.rs b/src/clock/clock_tui.rs index e7078cd5..ec8d002e 100644 --- a/src/clock/clock_tui.rs +++ b/src/clock/clock_tui.rs @@ -9,7 +9,7 @@ pub struct TransportTui { } has_clock!(|self: TransportTui|&self.clock); audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope)); -render!(Tui: (self: TransportTui) => TransportView { +render!(TuiOut: (self: TransportTui) => TransportView { compact: false, clock: &self.clock }); @@ -25,7 +25,7 @@ impl<'a> TransportView<'a> { Self { compact, clock } } } -render!(Tui: (self: TransportView<'a>) => Outer( +render!(TuiOut: (self: TransportView<'a>) => Outer( Style::default().fg(TuiTheme::g(255)) ).enclose(row!( OutputStats::new(self.compact, self.clock), @@ -36,7 +36,7 @@ render!(Tui: (self: TransportView<'a>) => Outer( ))); pub struct PlayPause { pub compact: bool, pub playing: bool } -render!(Tui: (self: PlayPause) => Tui::bg( +render!(TuiOut: (self: PlayPause) => Tui::bg( if self.playing{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)}, Either(self.compact, Thunk::new(||Fixed::x(9, Either(self.playing, @@ -59,7 +59,7 @@ impl BeatStats { Self { compact, bpm: format!("{:.3}", clock.timebase.bpm.get()), beat, time } } } -render!(Tui: (self: BeatStats) => Either(self.compact, +render!(TuiOut: (self: BeatStats) => Either(self.compact, row!( FieldV(TuiTheme::g(128).into(), "BPM", &self.bpm), FieldV(TuiTheme::g(128).into(), "Beat", &self.beat), @@ -88,7 +88,7 @@ impl OutputStats { } } } -render!(Tui: (self: OutputStats) => Either(self.compact, +render!(TuiOut: (self: OutputStats) => Either(self.compact, row!( FieldV(TuiTheme::g(128).into(), "SR", &self.sample_rate), FieldV(TuiTheme::g(128).into(), "Buf", &self.buffer_size), @@ -100,7 +100,7 @@ render!(Tui: (self: OutputStats) => Either(self.compact, Bsp::e(Tui::fg(TuiTheme::g(255), format!("{:.3}ms", self.latency)), " latency"), ))); -handle!(|self: TransportTui, input|ClockCommand::execute_with_state(self, input.event())); +handle!(TuiIn: |self: TransportTui, input|ClockCommand::execute_with_state(self, input.event())); keymap!(TRANSPORT_KEYS = |state: TransportTui, input: Event| ClockCommand { key(Char(' ')) => if state.clock().is_stopped() { Play(None) } else { Pause(None) }, diff --git a/src/field.rs b/src/field.rs index 7d6ba6e4..81842f81 100644 --- a/src/field.rs +++ b/src/field.rs @@ -3,10 +3,10 @@ use crate::*; pub struct Field(pub ItemPalette, pub T, pub U) where T: AsRef + Send + Sync, U: AsRef + Send + Sync; -impl Content for Field +impl Content for Field where T: AsRef + Send + Sync, U: AsRef + Send + Sync { - fn content (&self) -> impl Render { + fn content (&self) -> impl Render { let ItemPalette { darkest, dark, lighter, lightest, .. } = self.0; row!( Tui::fg_bg(dark.rgb, darkest.rgb, "▐"), @@ -20,10 +20,10 @@ impl Content for Field pub struct FieldV(pub ItemPalette, pub T, pub U) where T: AsRef + Send + Sync, U: AsRef + Send + Sync; -impl Content for FieldV +impl Content for FieldV where T: AsRef + Send + Sync, U: AsRef + Send + Sync { - fn content (&self) -> impl Render { + fn content (&self) -> impl Render { let ItemPalette { darkest, dark, lighter, lightest, .. } = self.0; let sep1 = Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "▐")); let sep2 = Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "▌")); diff --git a/src/file.rs b/src/file.rs index f964e517..942f011b 100644 --- a/src/file.rs +++ b/src/file.rs @@ -8,7 +8,7 @@ pub struct FileBrowser { pub filter: String, pub index: usize, pub scroll: usize, - pub size: Measure + pub size: Measure } /// Commands supported by [FileBrowser] #[derive(Debug, Clone, PartialEq)] @@ -20,7 +20,7 @@ pub enum FileBrowserCommand { Chdir(PathBuf), Filter(String), } -render!(Tui: (self: FileBrowser) => /*Stack::down(|add|{ +render!(TuiOut: (self: FileBrowser) => /*Stack::down(|add|{ let mut i = 0; for (_, name) in self.dirs.iter() { if i >= self.scroll { diff --git a/src/focus.rs b/src/focus.rs index eda38a41..cb1be40d 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -243,7 +243,7 @@ impl FocusOrder for T { } pub trait FocusWrap { - fn wrap > (self, focus: T, content: &'_ W) -> impl Content + '_; + fn wrap > (self, focus: T, content: &'_ W) -> impl Content + '_; } pub fn to_focus_command (input: &TuiIn) -> Option> { diff --git a/src/groovebox.rs b/src/groovebox.rs index 887bdbef..a299edcb 100644 --- a/src/groovebox.rs +++ b/src/groovebox.rs @@ -18,7 +18,7 @@ pub struct Groovebox { pub sampler: Sampler, pub compact: bool, - pub size: Measure, + pub size: Measure, pub status: bool, pub note_buf: Vec, pub midi_buf: Vec>>, @@ -61,7 +61,7 @@ impl Groovebox { has_clock!(|self: Groovebox|self.player.clock()); -impl EdnViewData for &Groovebox { +impl EdnViewData for &Groovebox { fn get_bool (&self, item: EdnItem<&str>) -> bool { todo!() } fn get_unit (&self, item: EdnItem<&str>) -> u16 { use EdnItem::*; @@ -70,13 +70,13 @@ impl EdnViewData for &Groovebox { ":samples-w" => if self.compact { 4 } else { 11 }, ":samples-y" => if self.compact { 1 } else { 0 }, ":pool-w" => if self.compact { 5 } else { - let w = self.size.w(); + let w = self.size.w(); if w > 60 { 20 } else if w > 40 { 15 } else { 10 } }, _ => 0 } } - fn get_content <'a> (&'a self, item: EdnItem<&str>) -> RenderBox<'a, Tui> { + fn get_content <'a> (&'a self, item: EdnItem<&str>) -> RenderBox<'a, TuiOut> { use EdnItem::*; match item.to_str() { ":input-meter-l" => Box::new(Meter("L/", self.sampler.input_meter[0])), @@ -94,7 +94,7 @@ impl EdnViewData for &Groovebox { ":sample-stat" => Box::new(SamplerStatus(&self.sampler, self.editor.note_point())), ":samples-view" => Box::new(SampleList::new(self.compact, &self.sampler, &self.editor)), - _ => Box::new(()) + _ => panic!("{item:?}") } } } @@ -119,12 +119,12 @@ from!(|state: &Groovebox|GrooveboxStatus = { size: format!("{}x{}│", width, state.size.h()), } }); -render!(Tui: (self: GrooveboxStatus) => Fixed::y(2, lay!( +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 { + fn help () -> impl Content { let single = |binding, command|row!(" ", col!( Tui::fg(TuiTheme::yellow(), binding), command @@ -143,7 +143,7 @@ impl GrooveboxStatus { double(("c", "color"), ("", ""),), )) } - fn stats (&self) -> impl Content + use<'_> { + fn stats (&self) -> impl Content + use<'_> { row!(&self.cpu, &self.size) } } diff --git a/src/groovebox/groovebox_command.rs b/src/groovebox/groovebox_command.rs index 25e73973..3c2390f0 100644 --- a/src/groovebox/groovebox_command.rs +++ b/src/groovebox/groovebox_command.rs @@ -46,7 +46,7 @@ command!(|self: GrooveboxCommand, state: Groovebox|match self { }, }); -handle!(|self: Groovebox, input| +handle!(TuiIn: |self: Groovebox, input| GrooveboxCommand::execute_with_state(self, input.event())); keymap!(<'a> KEYS_GROOVEBOX = |state: Groovebox, input: Event| GrooveboxCommand { diff --git a/src/groovebox/groovebox_tui.rs b/src/groovebox/groovebox_tui.rs index 9f29c86a..8f760a25 100644 --- a/src/groovebox/groovebox_tui.rs +++ b/src/groovebox/groovebox_tui.rs @@ -6,28 +6,28 @@ use EdnItem::*; const EDN: &'static str = include_str!("groovebox.edn"); -//impl Content for Groovebox { - //fn content (&self) -> impl Render { - //self.size.of(EdnView::new(self, EDN).expect("failed to build view")) - //} -//} +impl Content for Groovebox { + fn content (&self) -> impl Render { + self.size.of(EdnView::new(self, EDN).expect("failed to build view")) + } +} -render!(Tui: (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))))))))); +//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<'_> { + 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<'_> { + fn selector_view (&self) -> impl Content + use<'_> { row!( ClipSelected::play_phrase(&self.player), ClipSelected::next_phrase(&self.player), @@ -35,23 +35,23 @@ impl Groovebox { MidiEditStatus(&self.editor), ) } - fn sample_view (&self) -> impl Content + use<'_> { + 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<'_> { + 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<'_> { + 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<'_> { + 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( @@ -59,7 +59,7 @@ impl Groovebox { } } -//render!(Tui: (self: Groovebox) => self.size.of( +//render!(TuiOut: (self: Groovebox) => self.size.of( //Bsp::s(self.toolbar_view(), //Bsp::n(self.selector_view(), //Bsp::n(self.sample_view(), @@ -68,8 +68,8 @@ impl Groovebox { //const GROOVEBOX_EDN: &'static str = include_str!("groovebox.edn"); -//impl Content for Groovebox { - //fn content (&self) -> impl Content { +//impl Content for Groovebox { + //fn content (&self) -> impl Content { //EdnView::parse(self.edn.as_slice()) //} //} @@ -119,17 +119,17 @@ impl Groovebox { //} ////impl Groovebox { - ////fn status_view (&self) -> impl Content + use<'_> { + ////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<'_> { + ////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<'_> { + ////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( diff --git a/src/jack.rs b/src/jack.rs index b0862784..5500892e 100644 --- a/src/jack.rs +++ b/src/jack.rs @@ -126,7 +126,7 @@ impl JackConnection { /// * This allows user code to connect to JACK /// * While user code retains clone of the /// [Arc>] that is - /// passed to `init`, the audio engine is running. + /// passed to `init`, the audio engine is running. pub fn activate_with ( self, init: impl FnOnce(&Arc>)->Usually diff --git a/src/lib.rs b/src/lib.rs index 13b9bc1a..3f9d9ef8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ pub mod jack; pub use self::jack::*; pub mod meter; pub use self::meter::*; pub mod midi; pub use self::midi::*; pub mod mixer; pub use self::mixer::*; -pub mod piano; pub use self::piano::*; +pub mod piano; pub use self::piano::*; pub mod plugin; pub use self::plugin::*; pub mod pool; pub use self::pool::*; pub mod sampler; pub use self::sampler::*; diff --git a/src/meter.rs b/src/meter.rs index 659aeeaa..70fc27bd 100644 --- a/src/meter.rs +++ b/src/meter.rs @@ -1,12 +1,11 @@ use crate::*; pub struct Meter<'a>(pub &'a str, pub f32); - -render!(Tui: (self: Meter<'a>) => col!( +render!(TuiOut: (self: Meter<'a>) => col!( Field(TuiTheme::g(128).into(), self.0, format!("{:>+9.3}", self.1)), Fixed::xy(if self.1 >= 0.0 { 13 } else if self.1 >= -1.0 { 12 } - else if self.1 >= -2.0 { 11 } + else if self.1 >= -2.0 { 11 } else if self.1 >= -3.0 { 10 } else if self.1 >= -4.0 { 9 } else if self.1 >= -6.0 { 8 } @@ -22,7 +21,6 @@ render!(Tui: (self: Meter<'a>) => col!( else { Color::Green }, ())))); pub struct Meters<'a>(pub &'a[f32]); - -render!(Tui: (self: Meters<'a>) => col!( +render!(TuiOut: (self: Meters<'a>) => col!( format!("L/{:>+9.3}", self.0[0]), format!("R/{:>+9.3}", self.0[1]))); diff --git a/src/midi/midi_editor.rs b/src/midi/midi_editor.rs index b1439082..7cabd096 100644 --- a/src/midi/midi_editor.rs +++ b/src/midi/midi_editor.rs @@ -16,7 +16,7 @@ pub trait HasEditor { /// Contains state for viewing and editing a phrase pub struct MidiEditor { pub mode: PianoHorizontal, - pub size: Measure + pub size: Measure } from!(|phrase: &Arc>|MidiEditor = { @@ -40,9 +40,9 @@ impl Default for MidiEditor { } } -has_size!(|self: MidiEditor|&self.size); +has_size!(|self: MidiEditor|&self.size); -render!(Tui: (self: MidiEditor) => { +render!(TuiOut: (self: MidiEditor) => { self.autoscroll(); self.autozoom(); Fill::xy(Bsp::b(&self.size, &self.mode)) @@ -147,7 +147,7 @@ pub enum MidiEditCommand { Show(Option>>), } -handle!(|self: MidiEditor, input|MidiEditCommand::execute_with_state(self, input.event())); +handle!(TuiIn: |self: MidiEditor, input|MidiEditCommand::execute_with_state(self, input.event())); keymap!(KEYS_MIDI_EDITOR = |s: MidiEditor, _input: Event| MidiEditCommand { key(Up) => SetNoteCursor(s.note_point() + 1), diff --git a/src/midi/midi_out.rs b/src/midi/midi_out.rs index 0f9f3118..a15d4c88 100644 --- a/src/midi/midi_out.rs +++ b/src/midi/midi_out.rs @@ -111,7 +111,7 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts { phrase: &RwLock, pulse: usize, sample: usize, - note_buf: &mut Vec, + note_buf: &mut Vec, out: &mut [Vec>], notes: &mut [bool;128] ) { diff --git a/src/midi/midi_status.rs b/src/midi/midi_status.rs index b294a04f..35ceca4a 100644 --- a/src/midi/midi_status.rs +++ b/src/midi/midi_status.rs @@ -1,7 +1,7 @@ use crate::*; pub struct MidiEditClip<'a>(pub &'a MidiEditor); -render!(Tui: (self: MidiEditClip<'a>) => { +render!(TuiOut: (self: MidiEditClip<'a>) => { let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) { (phrase.color, phrase.name.clone(), phrase.length, phrase.looped) } else { @@ -14,7 +14,7 @@ render!(Tui: (self: MidiEditClip<'a>) => { }); pub struct MidiEditStatus<'a>(pub &'a MidiEditor); -render!(Tui: (self: MidiEditStatus<'a>) => { +render!(TuiOut: (self: MidiEditStatus<'a>) => { let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) { (phrase.color, phrase.name.clone(), phrase.length, phrase.looped) } else { diff --git a/src/midi/midi_view.rs b/src/midi/midi_view.rs index 211367a4..f9f20e06 100644 --- a/src/midi/midi_view.rs +++ b/src/midi/midi_view.rs @@ -1,6 +1,6 @@ use crate::*; -pub trait MidiViewer: HasSize + MidiRange + MidiPoint + Debug + Send + Sync { +pub trait MidiViewer: HasSize + MidiRange + MidiPoint + Debug + Send + Sync { fn buffer_size (&self, phrase: &MidiClip) -> (usize, usize); fn redraw (&self); fn phrase (&self) -> &Option>>; diff --git a/src/mixer.rs b/src/mixer.rs index 2802705c..94d3afcd 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -96,7 +96,7 @@ pub struct TrackView<'a> { pub entered: bool, } -impl<'a> Content for TrackView<'a> { +impl<'a> Content for TrackView<'a> { fn render (&self, to: &mut TuiOut) { todo!(); //let mut area = to.area(); @@ -127,8 +127,8 @@ impl<'a> Content for TrackView<'a> { } } -//impl Content for Mixer { - //fn content (&self) -> impl Content { +//impl Content for Mixer { + //fn content (&self) -> impl Content { //Stack::right(|add| { //for channel in self.tracks.iter() { //add(channel)?; @@ -138,8 +138,8 @@ impl<'a> Content for TrackView<'a> { //} //} -//impl Content for Track { - //fn content (&self) -> impl Content { +//impl Content for Track { + //fn content (&self) -> impl Content { //TrackView { //chain: Some(&self), //direction: tek_core::Direction::Right, @@ -162,7 +162,7 @@ impl<'a> Content for TrackView<'a> { //} //} -handle!(|self: Mixer, engine|{ +handle!(TuiIn: |self: Mixer, engine|{ if let crossterm::event::Event::Key(event) = engine.event() { match event.code { @@ -210,7 +210,7 @@ handle!(|self: Mixer, engine|{ Ok(None) }); -handle!(|self:MixerTrack,from|{ +handle!(TuiIn: |self:MixerTrack,from|{ match from.event() { //, NONE, "chain_cursor_up", "move cursor up", || { kpat!(KeyCode::Up) => { diff --git a/src/piano.rs b/src/piano.rs index 92a9485a..69e9c3d0 100644 --- a/src/piano.rs +++ b/src/piano.rs @@ -13,7 +13,7 @@ pub struct PianoHorizontal { /// Buffer where the whole phrase is rerendered on change buffer: Arc>, /// Size of actual notes area - size: Measure, + size: Measure, /// The display window range: MidiRangeModel, /// The note cursor diff --git a/src/piano/piano_h.rs b/src/piano/piano_h.rs index 69e5a204..20bbc00f 100644 --- a/src/piano/piano_h.rs +++ b/src/piano/piano_h.rs @@ -5,7 +5,7 @@ pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iter (note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n)) } -render!(Tui: (self: PianoHorizontal) => Bsp::s( +render!(TuiOut: (self: PianoHorizontal) => Bsp::s( Fixed::y(1, Bsp::e( Fixed::x(self.keys_width, ""), Fill::x(PianoHorizontalTimeline(self)), @@ -81,7 +81,7 @@ impl PianoHorizontal { } } -has_size!(|self:PianoHorizontal|&self.size); +has_size!(|self:PianoHorizontal|&self.size); impl TimeRange for PianoHorizontal { fn time_len (&self) -> &AtomicUsize { self.range.time_len() } diff --git a/src/piano/piano_h_cursor.rs b/src/piano/piano_h_cursor.rs index 3a5d6f31..79b7217b 100644 --- a/src/piano/piano_h_cursor.rs +++ b/src/piano/piano_h_cursor.rs @@ -2,7 +2,7 @@ use crate::*; use super::*; pub struct PianoHorizontalCursor<'a>(pub(crate) &'a PianoHorizontal); -render!(Tui: |self: PianoHorizontalCursor<'a>, render|{ +render!(TuiOut: |self: PianoHorizontalCursor<'a>, render|{ let style = Some(Style::default().fg(self.0.color.lightest.rgb)); let note_hi = self.0.note_hi(); let note_len = self.0.note_len(); diff --git a/src/piano/piano_h_keys.rs b/src/piano/piano_h_keys.rs index 96e73575..9c79aeab 100644 --- a/src/piano/piano_h_keys.rs +++ b/src/piano/piano_h_keys.rs @@ -3,7 +3,7 @@ use super::*; pub struct PianoHorizontalKeys<'a>(pub(crate) &'a PianoHorizontal); -render!(Tui: |self: PianoHorizontalKeys<'a>, to|{ +render!(TuiOut: |self: PianoHorizontalKeys<'a>, to|{ let state = self.0; let color = state.color; let note_lo = state.note_lo().get(); diff --git a/src/piano/piano_h_notes.rs b/src/piano/piano_h_notes.rs index ce26f488..373e3176 100644 --- a/src/piano/piano_h_notes.rs +++ b/src/piano/piano_h_notes.rs @@ -3,7 +3,7 @@ use super::*; pub struct PianoHorizontalNotes<'a>(pub(crate) &'a PianoHorizontal); -render!(Tui: |self: PianoHorizontalNotes<'a>, render|{ +render!(TuiOut: |self: PianoHorizontalNotes<'a>, render|{ let time_start = self.0.time_start().get(); let note_axis = self.0.note_axis().get(); let note_lo = self.0.note_lo().get(); diff --git a/src/piano/piano_h_time.rs b/src/piano/piano_h_time.rs index 8f3ccf74..0fbd57e9 100644 --- a/src/piano/piano_h_time.rs +++ b/src/piano/piano_h_time.rs @@ -2,7 +2,7 @@ use crate::*; use super::*; pub struct PianoHorizontalTimeline<'a>(pub(crate) &'a PianoHorizontal); -render!(Tui: |self: PianoHorizontalTimeline<'a>, render|{ +render!(TuiOut: |self: PianoHorizontalTimeline<'a>, render|{ let [x, y, w, h] = render.area(); let style = Some(Style::default().dim()); let length = self.0.phrase.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); diff --git a/src/plugin.rs b/src/plugin.rs index 763cd328..33c4e60d 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -150,7 +150,7 @@ impl Plugin { }) } } -impl Content for Plugin { +impl Content for Plugin { fn render (&self, to: &mut TuiOut) { let area = to.area(); let [x, y, _, height] = area; @@ -198,7 +198,7 @@ fn draw_header (state: &Plugin, to: &mut TuiOut, x: u16, y: u16, w: u16) { //Ok(Rect { x, y, width: w, height: 1 }) } -handle!(|self:Plugin, from|{ +handle!(TuiIn: |self:Plugin, from|{ match from.event() { kpat!(KeyCode::Up) => { self.selected = self.selected.saturating_sub(1); diff --git a/src/pool.rs b/src/pool.rs index 8f456c3a..237019c4 100644 --- a/src/pool.rs +++ b/src/pool.rs @@ -15,7 +15,7 @@ pub struct PoolModel { /// Mode switch pub(crate) mode: Option, /// Rendered size - size: Measure, + size: Measure, /// Scroll offset scroll: usize, } diff --git a/src/pool/clip_length.rs b/src/pool/clip_length.rs index c43f9741..34d5a0fc 100644 --- a/src/pool/clip_length.rs +++ b/src/pool/clip_length.rs @@ -69,7 +69,7 @@ impl PhraseLengthFocus { } } -render!(Tui: (self: PhraseLength) => { +render!(TuiOut: (self: PhraseLength) => { let bars = ||self.bars_string(); let beats = ||self.beats_string(); let ticks = ||self.ticks_string(); diff --git a/src/pool/clip_select.rs b/src/pool/clip_select.rs index 5d07f341..9dd7d991 100644 --- a/src/pool/clip_select.rs +++ b/src/pool/clip_select.rs @@ -7,7 +7,7 @@ pub struct ClipSelected { pub(crate) time: String, } -render!(Tui: (self: ClipSelected) => +render!(TuiOut: (self: ClipSelected) => FieldV(self.color, self.title, format!("{} {}", self.time, self.name))); impl ClipSelected { diff --git a/src/pool/pool_tui.rs b/src/pool/pool_tui.rs index 4fdb8166..c5f27b63 100644 --- a/src/pool/pool_tui.rs +++ b/src/pool/pool_tui.rs @@ -1,7 +1,7 @@ use crate::*; pub struct PoolView<'a>(pub bool, pub &'a PoolModel); -render!(Tui: (self: PoolView<'a>) => { +render!(TuiOut: (self: PoolView<'a>) => { let Self(compact, model) = self; let PoolModel { phrases, mode, .. } = self.1; let color = self.1.phrase().read().unwrap().color; diff --git a/src/sampler/sample_import.rs b/src/sampler/sample_import.rs index adef3b31..6ddc5ef9 100644 --- a/src/sampler/sample_import.rs +++ b/src/sampler/sample_import.rs @@ -170,7 +170,7 @@ fn draw_sample ( Ok(label1.len() + label2.len() + 4) } -impl Content for AddSampleModal { +impl Content for AddSampleModal { fn render (&self, to: &mut TuiOut) { todo!() //let area = to.area(); @@ -207,7 +207,7 @@ impl Content for AddSampleModal { } } -//impl Handle for AddSampleModal { +//impl Handle for AddSampleModal { //fn handle (&mut self, from: &TuiIn) -> Perhaps { //if from.handle_keymap(self, KEYMAP_ADD_SAMPLE)? { //return Ok(Some(true)) diff --git a/src/sampler/sample_list.rs b/src/sampler/sample_list.rs index 8ce01bd7..b8a1e4de 100644 --- a/src/sampler/sample_list.rs +++ b/src/sampler/sample_list.rs @@ -12,7 +12,7 @@ impl<'a> SampleList<'a> { } } -render!(Tui: (self: SampleList<'a>) => { +render!(TuiOut: (self: SampleList<'a>) => { let Self { compact, sampler, editor } = self; let note_lo = editor.note_lo().load(Relaxed); let note_pt = editor.note_point(); diff --git a/src/sampler/sample_viewer.rs b/src/sampler/sample_viewer.rs index 29f75e01..d4d82dcd 100644 --- a/src/sampler/sample_viewer.rs +++ b/src/sampler/sample_viewer.rs @@ -18,7 +18,7 @@ impl SampleViewer { } } -render!(Tui: |self: SampleViewer, to|{ +render!(TuiOut: |self: SampleViewer, to|{ let [x, y, width, height] = to.area(); diff --git a/src/sampler/sampler_command.rs b/src/sampler/sampler_command.rs index 26d4e4aa..5bd81f0f 100644 --- a/src/sampler/sampler_command.rs +++ b/src/sampler/sampler_command.rs @@ -1,6 +1,6 @@ use crate::*; -handle!(|self: SamplerTui, input|SamplerTuiCommand::execute_with_state(self, input.event())); +handle!(TuiIn: |self: SamplerTui, input|SamplerTuiCommand::execute_with_state(self, input.event())); pub enum SamplerTuiCommand { Import(FileBrowserCommand), diff --git a/src/sampler/sampler_status.rs b/src/sampler/sampler_status.rs index 184d8c82..051ae6f5 100644 --- a/src/sampler/sampler_status.rs +++ b/src/sampler/sampler_status.rs @@ -2,7 +2,7 @@ use crate::*; pub struct SamplerStatus<'a>(pub &'a Sampler, pub usize); -render!(Tui: (self: SamplerStatus<'a>) => Tui::bold(true, Tui::fg(TuiTheme::g(224), self.0.mapped[self.1].as_ref().map(|sample|format!( +render!(TuiOut: (self: SamplerStatus<'a>) => Tui::bold(true, Tui::fg(TuiTheme::g(224), self.0.mapped[self.1].as_ref().map(|sample|format!( "Sample {}-{}", sample.read().unwrap().start, sample.read().unwrap().end, diff --git a/src/sampler/sampler_tui.rs b/src/sampler/sampler_tui.rs index 66fb2d12..c343b910 100644 --- a/src/sampler/sampler_tui.rs +++ b/src/sampler/sampler_tui.rs @@ -7,7 +7,7 @@ pub struct SamplerTui { pub editing: Option>>, pub mode: Option, /// Size of actual notes area - pub size: Measure, + pub size: Measure, /// Lowest note displayed pub note_lo: AtomicUsize, pub note_pt: AtomicUsize, @@ -31,7 +31,7 @@ impl SamplerTui { } } -render!(Tui: (self: SamplerTui) => { +render!(TuiOut: (self: SamplerTui) => { let keys_width = 5; let keys = move||"";//SamplerKeys(self); let fg = self.color.base.rgb; @@ -59,7 +59,7 @@ struct SamplesTui { note_pt: usize, height: usize, } -render!(Tui: |self: SamplesTui, render|{ +render!(TuiOut: |self: SamplesTui, render|{ let x = render.area.x(); let bg_base = self.color.darkest.rgb; let bg_selected = self.color.darker.rgb; diff --git a/src/sequencer.rs b/src/sequencer.rs index 3e84f468..d77c7ea9 100644 --- a/src/sequencer.rs +++ b/src/sequencer.rs @@ -12,12 +12,12 @@ pub struct SequencerTui { pub editor: MidiEditor, pub player: MidiPlayer, - pub transport: bool, - pub selectors: bool, + pub transport: bool, + pub selectors: bool, pub compact: bool, pub clock: Clock, - pub size: Measure, + pub size: Measure, pub status: bool, pub note_buf: Vec, pub midi_buf: Vec>>, @@ -47,20 +47,20 @@ from_jack!(|jack|SequencerTui { clock, } }); -render!(Tui: (self: SequencerTui) => self.size.of( +render!(TuiOut: (self: SequencerTui) => self.size.of( Bsp::s(self.toolbar_view(), Bsp::n(self.status_view(), Bsp::w(self.pool_view(), Fill::xy(&self.editor)))))); impl SequencerTui { - fn toolbar_view (&self) -> impl Content + use<'_> { + fn toolbar_view (&self) -> impl Content + use<'_> { self.transport.then(||TransportView::new(true, &self.clock)) } - fn status_view (&self) -> impl Content + use<'_> { + fn status_view (&self) -> impl Content + use<'_> { let edit_clip = MidiEditClip(&self.editor); let selectors = When(self.selectors, Bsp::e(ClipSelected::play_phrase(&self.player), ClipSelected::next_phrase(&self.player))); row!(selectors, edit_clip, MidiEditStatus(&self.editor)) } - fn pool_view (&self) -> impl Content + use<'_> { + fn pool_view (&self) -> impl Content + use<'_> { let w = self.size.w(); let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 }; let pool_w = if self.pool.visible { phrase_w } else { 0 }; @@ -85,11 +85,11 @@ audio!(|self:SequencerTui, client, scope|{ self.perf.update(t0, scope); Control::Continue }); -has_size!(|self:SequencerTui|&self.size); +has_size!(|self:SequencerTui|&self.size); has_clock!(|self:SequencerTui|&self.clock); has_phrases!(|self:SequencerTui|self.pool.phrases); has_editor!(|self:SequencerTui|self.editor); -handle!(|self:SequencerTui,input|SequencerCommand::execute_with_state(self, input.event())); +handle!(TuiIn: |self:SequencerTui,input|SequencerCommand::execute_with_state(self, input.event())); #[derive(Clone, Debug)] pub enum SequencerCommand { Compact(bool), History(isize), diff --git a/src/status.rs b/src/status.rs index d0b3cdbe..fdc49efb 100644 --- a/src/status.rs +++ b/src/status.rs @@ -20,12 +20,12 @@ from!(|state:&SequencerTui|SequencerStatus = { size: format!("{}x{}│", width, state.size.h()), } }); -render!(Tui: (self: SequencerStatus) => Fixed::y(2, lay!( +render!(TuiOut: (self: SequencerStatus) => Fixed::y(2, lay!( Self::help(), Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), ))); impl SequencerStatus { - fn help () -> impl Content { + fn help () -> impl Content { let single = |binding, command|row!(" ", col!( Tui::fg(TuiTheme::yellow(), binding), command @@ -44,7 +44,7 @@ impl SequencerStatus { double(("c", "color"), ("", ""),), )) } - fn stats (&self) -> impl Content + use<'_> { + fn stats (&self) -> impl Content + use<'_> { row!(&self.cpu, &self.size) } } @@ -69,12 +69,12 @@ from!(|state:&ArrangerTui|ArrangerStatus = { size: format!("{}x{}│", width, state.size.h()), } }); -render!(Tui: (self: ArrangerStatus) => Fixed::y(2, lay!( +render!(TuiOut: (self: ArrangerStatus) => Fixed::y(2, lay!( Self::help(), Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), ))); impl ArrangerStatus { - fn help () -> impl Content { + fn help () -> impl Content { let single = |binding, command|row!(" ", col!( Tui::fg(TuiTheme::yellow(), binding), command @@ -95,7 +95,7 @@ impl ArrangerStatus { double(("[]", "phrase"), ("{}", "order"),), )) } - fn stats (&self) -> impl Content + use<'_> { + fn stats (&self) -> impl Content + use<'_> { row!(&self.cpu, &self.size) } } diff --git a/tui/src/lib.rs b/tui/src/lib.rs index b1dd6d92..ce2268be 100644 --- a/tui/src/lib.rs +++ b/tui/src/lib.rs @@ -4,10 +4,11 @@ pub use ::tek_edn; pub(crate) use tek_layout::*; pub(crate) use tek_engine::*; -mod tui_engine; pub use self::tui_engine::*; -mod tui_input; pub use self::tui_input::*; -mod tui_output; pub use self::tui_output::*; -mod tui_run; pub use self::tui_run::*; +mod tui_engine; pub use self::tui_engine::*; +mod tui_content; pub use self::tui_content::*; +mod tui_input; pub use self::tui_input::*; +mod tui_output; pub use self::tui_output::*; +mod tui_run; pub use self::tui_run::*; mod tui_color; pub use self::tui_color::*; mod tui_style; pub use self::tui_style::*; @@ -41,12 +42,12 @@ pub(crate) use ratatui::{ use crate::tui::*; use std::sync::{Arc, RwLock}; struct TestComponent(String); - impl Content for TestComponent { - fn content (&self) -> Option> { + impl Content for TestComponent { + fn content (&self) -> Option> { Some(self.0.as_str()) } } - impl Handle for TestComponent { + impl Handle for TestComponent { fn handle (&mut self, from: &TuiIn) -> Perhaps { Ok(None) } diff --git a/tui/src/tui_border.rs b/tui/src/tui_border.rs index 823c0dfc..96e4ee3c 100644 --- a/tui/src/tui_border.rs +++ b/tui/src/tui_border.rs @@ -1,14 +1,14 @@ use crate::*; -pub struct Bordered>(pub S, pub W); +pub struct Bordered>(pub S, pub W); -render!(Tui: (self: Bordered>) => { +render!(TuiOut: (self: Bordered>) => { Fill::xy(lay!(Border(self.0), Padding::xy(1, 1, &self.1))) }); pub struct Border(pub S); -render!(Tui: |self: Border, to| { +render!(TuiOut: |self: Border, to| { let area = to.area(); if area.w() > 0 && area.y() > 0 { to.blit(&self.0.nw(), area.x(), area.y(), self.0.style()); @@ -27,13 +27,13 @@ render!(Tui: |self: Border, to| { }); pub trait BorderStyle: Send + Sync + Copy { - fn wrap > (self, w: W) -> Bordered { + fn wrap > (self, w: W) -> Bordered { Bordered(self, w) } - fn enclose > (self, w: W) -> impl Content { + fn enclose > (self, w: W) -> impl Content { lay!(Fill::xy(Border(self)), w) } - fn enclose_bg > (self, w: W) -> impl Content { + fn enclose_bg > (self, w: W) -> impl Content { Tui::bg(self.style().unwrap().bg.unwrap_or(Color::Reset), lay!( Fill::xy(Border(self)), w @@ -137,7 +137,7 @@ macro_rules! border { } #[derive(Copy, Clone)] pub struct $T(pub Style); - impl Content for $T { + impl Content for $T { fn render (&self, to: &mut TuiOut) { self.draw(to); } } )+} diff --git a/tui/src/tui_content.rs b/tui/src/tui_content.rs new file mode 100644 index 00000000..0994cc54 --- /dev/null +++ b/tui/src/tui_content.rs @@ -0,0 +1,19 @@ +use crate::*; + +impl Content for &str { + fn layout (&self, to: [u16;4]) -> [u16;4] { + to.center_xy([self.chars().count() as u16, 1]) + } + fn render (&self, to: &mut TuiOut) { + to.blit(self, to.area.x(), to.area.y(), None) + } +} + +impl Content for String { + fn layout (&self, to: [u16;4]) -> [u16;4] { + to.center_xy([self.chars().count() as u16, 1]) + } + fn render (&self, to: &mut TuiOut) { + to.blit(self, to.area.x(), to.area.y(), None) + } +} diff --git a/tui/src/tui_engine.rs b/tui/src/tui_engine.rs index 9ad8c93a..e3e9bed7 100644 --- a/tui/src/tui_engine.rs +++ b/tui/src/tui_engine.rs @@ -8,12 +8,8 @@ pub struct Tui { } impl Engine for Tui { - type Unit = u16; - type Size = [Self::Unit;2]; - type Area = [Self::Unit;4]; - type Input = TuiIn; - type Handled = bool; - type Output = TuiOut; + type Input = TuiIn; + type Output = TuiOut; fn exited (&self) -> bool { self.exited.fetch_and(true, Relaxed) } diff --git a/tui/src/tui_input.rs b/tui/src/tui_input.rs index d27099db..f7df95eb 100644 --- a/tui/src/tui_input.rs +++ b/tui/src/tui_input.rs @@ -5,8 +5,9 @@ use Event as CrosstermEvent; #[derive(Debug, Clone)] pub struct TuiIn(pub Arc, pub CrosstermEvent); -impl Input for TuiIn { +impl Input for TuiIn { type Event = Event; + type Handled = bool; fn event (&self) -> &CrosstermEvent { &self.1 } fn is_done (&self) -> bool { self.0.fetch_and(true, Relaxed) } fn done (&self) { self.0.store(true, Relaxed); } diff --git a/tui/src/tui_output.rs b/tui/src/tui_output.rs index 972bd750..d01c28d0 100644 --- a/tui/src/tui_output.rs +++ b/tui/src/tui_output.rs @@ -5,10 +5,13 @@ pub struct TuiOut { pub area: [u16;4] } -impl Output for TuiOut { +impl Output for TuiOut { + type Unit = u16; + type Size = [Self::Unit;2]; + type Area = [Self::Unit;4]; #[inline] fn area (&self) -> [u16;4] { self.area } #[inline] fn area_mut (&mut self) -> &mut [u16;4] { &mut self.area } - #[inline] fn place (&mut self, area: [u16;4], content: &impl Render) { + #[inline] fn place (&mut self, area: [u16;4], content: &impl Render) { let last = self.area(); *self.area_mut() = area; content.render(self); @@ -65,24 +68,6 @@ impl TuiOut { } } -impl Content for &str { - fn layout (&self, to: [u16;4]) -> [u16;4] { - to.center_xy([self.chars().count() as u16, 1]) - } - fn render (&self, to: &mut TuiOut) { - to.blit(self, to.area.x(), to.area.y(), None) - } -} - -impl Content for String { - fn layout (&self, to: [u16;4]) -> [u16;4] { - to.center_xy([self.chars().count() as u16, 1]) - } - fn render (&self, to: &mut TuiOut) { - to.blit(self, to.area.x(), to.area.y(), None) - } -} - pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) { for row in 0..area.h() { let y = area.y() + row; @@ -113,4 +98,4 @@ pub fn half_block (lower: bool, upper: bool) -> Option { } } -//impl> Render for T {} +//impl> Render for T {} diff --git a/tui/src/tui_run.rs b/tui/src/tui_run.rs index c6040801..683ef72d 100644 --- a/tui/src/tui_run.rs +++ b/tui/src/tui_run.rs @@ -3,7 +3,7 @@ use ratatui::prelude::Size; use std::time::Duration; use std::thread::{spawn, JoinHandle}; -pub trait TuiRun + Handle + Sized + 'static> { +pub trait TuiRun + Handle + Sized + 'static> { /// Run an app in the main loop. fn run (&self, state: &Arc>) -> Usually<()>; /// Spawn the input thread. @@ -12,13 +12,21 @@ pub trait TuiRun + Handle + Sized + 'static> { fn run_output (&self, state: &Arc>, sleep: Duration) -> JoinHandle<()>; } -impl + Handle + Sized + 'static> TuiRun for Arc> { +impl + Handle + Sized + 'static> TuiRun for Arc> { fn run (&self, state: &Arc>) -> Usually<()> { let _input_thread = self.run_input(state, Duration::from_millis(100)); self.write().unwrap().setup()?; let render_thread = self.run_output(state, Duration::from_millis(10)); - render_thread.join().expect("main thread failed"); - self.write().unwrap().teardown()?; + match render_thread.join() { + Ok(result) => { + self.write().unwrap().teardown()?; + println!("\n\rRan successfully: {result:?}\n\r"); + }, + Err(e) => { + self.write().unwrap().teardown()?; + panic!("\n\rRender thread failed.\n\r") + }, + } Ok(()) } fn run_input (&self, state: &Arc>, poll: Duration) -> JoinHandle<()> { diff --git a/tui/src/tui_style.rs b/tui/src/tui_style.rs index 36561bb4..17e9429a 100644 --- a/tui/src/tui_style.rs +++ b/tui/src/tui_style.rs @@ -1,86 +1,84 @@ use crate::*; pub trait TuiStyle { - fn fg > (color: Color, w: R) -> Foreground { + fn fg > (color: Color, w: R) -> Foreground { Foreground(color, w) } - fn bg > (color: Color, w: R) -> Background { + fn bg > (color: Color, w: R) -> Background { Background(color, w) } - fn fg_bg > (fg: Color, bg: Color, w: R) -> Background> { + fn fg_bg > (fg: Color, bg: Color, w: R) -> Background> { Background(bg, Foreground(fg, w)) } - fn bold > (on: bool, w: R) -> Bold { + fn bold > (on: bool, w: R) -> Bold { Bold(on, w) } - fn border , S: BorderStyle> (style: S, w: R) -> Bordered { + fn border , S: BorderStyle> (style: S, w: R) -> Bordered { Bordered(style, w) } } impl TuiStyle for Tui {} -pub struct Bold>(pub bool, R); -impl> Content for Bold { - fn content (&self) -> impl Render { &self.1 } +pub struct Bold>(pub bool, R); +impl> Content for Bold { + fn content (&self) -> impl Render { &self.1 } fn render (&self, to: &mut TuiOut) { to.fill_bold(to.area(), self.0); self.1.render(to) } } -pub struct Foreground>(pub Color, R); -impl> Content for Foreground { - fn content (&self) -> impl Render { &self.1 } +pub struct Foreground>(pub Color, R); +impl> Content for Foreground { + fn content (&self) -> impl Render { &self.1 } fn render (&self, to: &mut TuiOut) { to.fill_fg(to.area(), self.0); self.1.render(to) } } -pub struct Background>(pub Color, R); -impl> Content for Background { - fn content (&self) -> impl Render { &self.1 } +pub struct Background>(pub Color, R); +impl> Content for Background { + fn content (&self) -> impl Render { &self.1 } fn render (&self, to: &mut TuiOut) { to.fill_bg(to.area(), self.0); self.1.render(to) } } -pub struct Styled>(pub Option