parameterize render! macro

This commit is contained in:
🪞👃🪞 2024-12-17 20:02:47 +01:00
parent 914b569839
commit 3e4d75ea40
17 changed files with 176 additions and 65 deletions

120
crates/tek/examples/bsp.rs Normal file
View file

@ -0,0 +1,120 @@
use tek_core::*;
use tek_core::jack::*;
fn main () -> Usually<()> {
Tui::run(Arc::new(RwLock::new(Demo::new())))?;
Ok(())
}
pub struct BspDemo<E: Engine>;
impl Content for Demo<Tui> {
type Engine = Tui;
fn content (&self) -> dyn Render<Engine = Tui> {
let border_style = Style::default().fg(Color::Rgb(0,0,0));
Align::Center(Layers::new(move|add|{
add(&Background(Color::Rgb(0,128,128)))?;
add(&Outset::XY(1, 1, Stack::down(|add|{
add(&Layers::new(|add|{
add(&Background(Color::Rgb(128,96,0)))?;
add(&Border(Square(border_style)))?;
add(&Outset::XY(2, 1, "..."))?;
Ok(())
}).debug())?;
add(&Layers::new(|add|{
add(&Background(Color::Rgb(128,64,0)))?;
add(&Border(Lozenge(border_style)))?;
add(&Outset::XY(4, 2, "---"))?;
Ok(())
}).debug())?;
add(&Layers::new(|add|{
add(&Background(Color::Rgb(96,64,0)))?;
add(&Border(SquareBold(border_style)))?;
add(&Outset::XY(6, 3, "~~~"))?;
Ok(())
}).debug())?;
Ok(())
})).debug())?;
Ok(())
}))
//Align::Center(Outset::X(1, Layers::new(|add|{
//add(&Background(Color::Rgb(128,0,0)))?;
//add(&Stack::down(|add|{
//add(&Outset::Y(1, Layers::new(|add|{
//add(&Background(Color::Rgb(0,128,0)))?;
//add(&Align::Center("12345"))?;
//add(&Align::Center("FOO"))
//})))?;
//add(&Outset::XY(1, 1, Layers::new(|add|{
//add(&Align::Center("1234567"))?;
//add(&Align::Center("BAR"))?;
//add(&Background(Color::Rgb(0,0,128)))
//})))
//}))
//})))
//Align::Y(Layers::new(|add|{
//add(&Background(Color::Rgb(128,0,0)))?;
//add(&Outset::X(1, Align::Center(Stack::down(|add|{
//add(&Align::X(Outset::Y(1, Layers::new(|add|{
//add(&Background(Color::Rgb(0,128,0)))?;
//add(&Align::Center("12345"))?;
//add(&Align::Center("FOO"))
//})))?;
//add(&Outset::XY(1, 1, Layers::new(|add|{
//add(&Align::Center("1234567"))?;
//add(&Align::Center("BAR"))?;
//add(&Background(Color::Rgb(0,0,128)))
//})))?;
//Ok(())
//})))))
//}))
}
}
impl Handle<Tui> for Demo<Tui> {
fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> {
match from.event() {
key!(KeyCode::PageUp) => {
self.index = (self.index + 1) % self.items.len();
},
key!(KeyCode::PageDown) => {
self.index = if self.index > 1 {
self.index - 1
} else {
self.items.len() - 1
};
},
_ => return Ok(None)
}
Ok(Some(true))
}
}
//lisp!(CONTENT Demo (LET
//(BORDER-STYLE (STYLE (FG (RGB 0 0 0))))
//(BG-COLOR-0 (RGB 0 128 128))
//(BG-COLOR-1 (RGB 128 96 0))
//(BG-COLOR-2 (RGB 128 64 0))
//(BG-COLOR-3 (RGB 96 64 0))
//(CENTER (LAYERS
//(BACKGROUND BG-COLOR-0)
//(OUTSET-XY 1 1 (SPLIT-DOWN
//(LAYERS (BACKGROUND BG-COLOR-1)
//(BORDER SQUARE BORDER-STYLE)
//(OUTSET-XY 2 1 "..."))
//(LAYERS (BACKGROUND BG-COLOR-2)
//(BORDER LOZENGE BORDER-STYLE)
//(OUTSET-XY 4 2 "---"))
//(LAYERS (BACKGROUND BG-COLOR-3)
//(BORDER SQUARE-BOLD BORDER-STYLE)
//(OUTSET-XY 2 1 "~~~"))))))))

View file

@ -1,5 +1,18 @@
use crate::*; use crate::*;
#[macro_export] macro_rules! render {
(<$E:ty>|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? Render<$E> for $Struct $(<$($L),*$($T),*>)? {
fn min_size (&$self, to: <$E as Engine>::Size) -> Perhaps<<$E as Engine>::Size> {
$cb.min_size(to)
}
fn render (&$self, to: &mut <$E as Engine>::Output) -> Usually<()> {
$cb.render(to)
}
}
}
}
/// Rendering target /// Rendering target
pub trait Output<E: Engine> { pub trait Output<E: Engine> {
/// Current output area /// Current output area

View file

@ -67,28 +67,28 @@ impl<E: Engine, X: Render<E>, Y: Render<E>> Render<E> for Bsp<E, X, Y> {
Self::Null(_) => {}, Self::Null(_) => {},
Self::S(a, b) => { Self::S(a, b) => {
let s_a = a.min_size(s)?.unwrap_or(n); let s_a = a.min_size(s)?.unwrap_or(n);
//let s_b = b.min_size(s)?.unwrap_or(n); let _ = b.min_size(s)?.unwrap_or(n);
let h = s_a.h().into(); let h = s_a.h().into();
to.render_in(to.area().clip_h(h).into(), a)?; to.render_in(to.area().clip_h(h).into(), a)?;
to.render_in(to.area().push_y(h).shrink_y(h).into(), b)?; to.render_in(to.area().shrink_y(h).push_y(h).into(), b)?;
}, },
Self::E(a, b) => { Self::E(a, b) => {
let s_a = a.min_size(s)?.unwrap_or(n); let s_a = a.min_size(s)?.unwrap_or(n);
//let s_b = b.min_size(s)?.unwrap_or(n); let _ = b.min_size(s)?.unwrap_or(n);
let w = s_a.w().into(); let w = s_a.w().into();
to.render_in(to.area().clip_w(w).into(), a)?; to.render_in(to.area().clip_w(w).into(), a)?;
to.render_in(to.area().push_x(w).shrink_x(w).into(), b)?; to.render_in(to.area().push_x(w).shrink_x(w).into(), b)?;
}, },
Self::W(a, b) => { Self::W(a, b) => {
let s_a = a.min_size(s)?.unwrap_or(n); let s_a = a.min_size(s)?.unwrap_or(n);
//let s_b = b.min_size(s)?.unwrap_or(n); let _ = b.min_size(s)?.unwrap_or(n);
let w = (to.area().w() - s_a.w()).into(); let w = (to.area().w() - s_a.w()).into();
to.render_in(to.area().push_x(w).into(), a)?; to.render_in(to.area().push_x(w).into(), a)?;
to.render_in(to.area().shrink_x(w).into(), b)?; to.render_in(to.area().shrink_x(w).into(), b)?;
}, },
Self::N(a, b) => { Self::N(a, b) => {
let s_a = a.min_size(s)?.unwrap_or(n); let s_a = a.min_size(s)?.unwrap_or(n);
//let s_b = b.min_size(s)?.unwrap_or(n); let _ = b.min_size(s)?.unwrap_or(n);
let h = to.area().h() - s_a.h(); let h = to.area().h() - s_a.h();
to.render_in(to.area().push_y(h).into(), a)?; to.render_in(to.area().push_y(h).into(), a)?;
to.render_in(to.area().shrink_y(h).into(), b)?; to.render_in(to.area().shrink_y(h).into(), b)?;

View file

@ -84,7 +84,7 @@ impl Measure<Tui> {
} }
pub struct ShowMeasure<'a>(&'a Measure<Tui>); pub struct ShowMeasure<'a>(&'a Measure<Tui>);
render!(|self: ShowMeasure<'a>|render(|to|Ok({ render!(<Tui>|self: ShowMeasure<'a>|render(|to|Ok({
let w = self.0.w(); let w = self.0.w();
let h = self.0.h(); let h = self.0.h();
to.blit(&format!(" {w} x {h} "), to.area.x(), to.area.y(), Some( to.blit(&format!(" {w} x {h} "), to.area.x(), to.area.y(), Some(

View file

@ -27,19 +27,6 @@ mod port_select; pub(crate) use port_select::*;
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
#[macro_export] macro_rules! render {
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? Render<Tui> for $Struct $(<$($L),*$($T),*>)? {
fn min_size (&$self, to: [u16;2]) -> Perhaps<[u16;2]> {
$cb.min_size(to)
}
fn render (&$self, to: &mut TuiOutput) -> Usually<()> {
$cb.render(to)
}
}
}
}
pub fn render <F: Fn(&mut TuiOutput)->Usually<()>+Send+Sync> (render: F) -> impl Render<Tui> { pub fn render <F: Fn(&mut TuiOutput)->Usually<()>+Send+Sync> (render: F) -> impl Render<Tui> {
Widget::new(|_|Ok(Some([0u16,0u16].into())), render) Widget::new(|_|Ok(Some([0u16,0u16].into())), render)
} }

View file

@ -60,7 +60,7 @@ has_clock!(|self:ArrangerTui|&self.clock);
has_phrases!(|self:ArrangerTui|self.phrases.phrases); has_phrases!(|self:ArrangerTui|self.phrases.phrases);
has_editor!(|self:ArrangerTui|self.editor); has_editor!(|self:ArrangerTui|self.editor);
handle!(<Tui>|self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, input)); handle!(<Tui>|self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, input));
render!(|self: ArrangerTui|{ render!(<Tui>|self: ArrangerTui|{
let arranger_focused = self.arranger_focused(); let arranger_focused = self.arranger_focused();
let transport_focused = if let ArrangerFocus::Transport(_) = self.focus.inner() { let transport_focused = if let ArrangerFocus::Transport(_) = self.focus.inner() {
true true
@ -506,7 +506,7 @@ impl StatusBar for ArrangerStatus {
} }
} }
render!(|self: ArrangerStatus|{ render!(<Tui>|self: ArrangerStatus|{
let label = match self { let label = match self {
Self::Transport => "TRANSPORT", Self::Transport => "TRANSPORT",
@ -674,7 +674,7 @@ impl From<&ArrangerTui> for ArrangerVerticalColumnSeparator {
} }
} }
} }
render!(|self: ArrangerVerticalColumnSeparator|render(move|to: &mut TuiOutput|{ render!(<Tui>|self: ArrangerVerticalColumnSeparator|render(move|to: &mut TuiOutput|{
let style = Some(Style::default().fg(self.sep_fg)); let style = Some(Style::default().fg(self.sep_fg));
Ok(for x in self.cols.iter().map(|col|col.1) { Ok(for x in self.cols.iter().map(|col|col.1) {
let x = self.scenes_w + to.area().x() + x as u16; let x = self.scenes_w + to.area().x() + x as u16;
@ -697,7 +697,7 @@ impl From<(&ArrangerTui, usize)> for ArrangerVerticalRowSeparator {
} }
} }
render!(|self: ArrangerVerticalRowSeparator|render(move|to: &mut TuiOutput|{ render!(<Tui>|self: ArrangerVerticalRowSeparator|render(move|to: &mut TuiOutput|{
Ok(for y in self.rows.iter().map(|row|row.1) { Ok(for y in self.rows.iter().map(|row|row.1) {
let y = to.area().y() + (y / PPQ) as u16 + 1; let y = to.area().y() + (y / PPQ) as u16 + 1;
if y >= to.buffer.area.height { break } if y >= to.buffer.area.height { break }
@ -731,7 +731,7 @@ impl From<(&ArrangerTui, usize)> for ArrangerVerticalCursor {
} }
} }
} }
render!(|self: ArrangerVerticalCursor|render(move|to: &mut TuiOutput|{ render!(<Tui>|self: ArrangerVerticalCursor|render(move|to: &mut TuiOutput|{
let area = to.area(); let area = to.area();
let focused = self.focused; let focused = self.focused;
let selected = self.selected; let selected = self.selected;
@ -810,7 +810,7 @@ impl<'a> From<&'a ArrangerTui> for ArrangerVerticalHeader<'a> {
} }
} }
} }
render!(|self: ArrangerVerticalHeader<'a>|row!( render!(<Tui>|self: ArrangerVerticalHeader<'a>|row!(
(track, w) in self.tracks.iter().zip(self.cols.iter().map(|col|col.0)) => { (track, w) in self.tracks.iter().zip(self.cols.iter().map(|col|col.0)) => {
// name and width of track // name and width of track
let name = track.name().read().unwrap(); let name = track.name().read().unwrap();
@ -877,7 +877,7 @@ impl<'a> From<(&'a ArrangerTui, usize)> for ArrangerVerticalContent<'a> {
} }
} }
} }
render!(|self: ArrangerVerticalContent<'a>|Fixed::h( render!(<Tui>|self: ArrangerVerticalContent<'a>|Fixed::h(
(self.size.h() as u16).saturating_sub(self.header_h), (self.size.h() as u16).saturating_sub(self.header_h),
col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => { col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => {
let height = 1.max((pulses / PPQ) as u16); let height = 1.max((pulses / PPQ) as u16);

View file

@ -26,7 +26,7 @@ pub enum GrooveboxCommand {
Sampler(SamplerCommand), Sampler(SamplerCommand),
} }
render!(|self:GrooveboxTui|Bsp::n( render!(<Tui>|self:GrooveboxTui|Bsp::n(
Fixed::h(2, SequencerStatusBar::from(&self.sequencer)), Fixed::h(2, SequencerStatusBar::from(&self.sequencer)),
Bsp::s(Fixed::h(self.split, &self.sequencer), &self.sampler), Bsp::s(Fixed::h(self.split, &self.sequencer), &self.sampler),
)); ));

View file

@ -65,7 +65,7 @@ pub enum SamplerFocus {
} }
audio!(|self: SamplerTui, _client, _scope|Control::Continue); audio!(|self: SamplerTui, _client, _scope|Control::Continue);
render!(|self: SamplerTui|{ render!(<Tui>|self: SamplerTui|{
Fill::wh(lay!([ Fill::wh(lay!([
Fill::wh(render(|to|{ // border Fill::wh(render(|to|{ // border

View file

@ -136,7 +136,7 @@ has_size!(<Tui>|self:SequencerTui|&self.size);
has_clock!(|self:SequencerTui|&self.clock); has_clock!(|self:SequencerTui|&self.clock);
has_phrases!(|self:SequencerTui|self.phrases.phrases); has_phrases!(|self:SequencerTui|self.phrases.phrases);
has_editor!(|self:SequencerTui|self.editor); has_editor!(|self:SequencerTui|self.editor);
render!(|self: SequencerTui|{ render!(<Tui>|self: SequencerTui|{
let w = self.size.w(); let w = self.size.w();
let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 }; let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
let pool_w = if self.show_pool { phrase_w } else { 0 }; let pool_w = if self.show_pool { phrase_w } else { 0 };
@ -225,7 +225,7 @@ impl From<&SequencerTui> for SequencerStatusBar {
} }
} }
render!(|self: SequencerStatusBar|Fixed::h(2, lay!([ render!(<Tui>|self: SequencerStatusBar|Fixed::h(2, lay!([
{ {
let single = |binding, command|row!([" ", col!([ let single = |binding, command|row!([" ", col!([
Tui::fg(TuiTheme::yellow(), binding), Tui::fg(TuiTheme::yellow(), binding),

View file

@ -40,7 +40,7 @@ impl std::fmt::Debug for TransportTui {
has_clock!(|self:TransportTui|&self.clock); has_clock!(|self:TransportTui|&self.clock);
audio!(|self:TransportTui,client,scope|ClockAudio(self).process(client, scope)); audio!(|self:TransportTui,client,scope|ClockAudio(self).process(client, scope));
handle!(<Tui>|self:TransportTui,from|TransportCommand::execute_with_state(self, from)); handle!(<Tui>|self:TransportTui,from|TransportCommand::execute_with_state(self, from));
render!(|self: TransportTui|TransportView::from((self, None, true))); render!(<Tui>|self: TransportTui|TransportView::from((self, None, true)));
pub struct TransportView { pub struct TransportView {
color: ItemPalette, color: ItemPalette,
@ -97,12 +97,12 @@ impl<T: HasClock> From<(&T, Option<ItemPalette>, bool)> for TransportView {
} }
render!(|self: TransportView|{ render!(<Tui>|self: TransportView|{
let color = self.color; let color = self.color;
struct Field<'a>(&'a str, &'a str, &'a ItemPalette); struct Field<'a>(&'a str, &'a str, &'a ItemPalette);
render!(|self: Field<'a>|row!([ render!(<Tui>|self: Field<'a>|row!([
Tui::fg_bg(self.2.lightest.rgb, self.2.darkest.rgb, Tui::bold(true, self.0)), Tui::fg_bg(self.2.lightest.rgb, self.2.darkest.rgb, Tui::bold(true, self.0)),
Tui::fg_bg(self.2.lighter.rgb, self.2.darkest.rgb, ""), Tui::fg_bg(self.2.lighter.rgb, self.2.darkest.rgb, ""),
Tui::fg_bg(self.2.lighter.rgb, self.2.base.rgb, format!("{:>10}", self.1)), Tui::fg_bg(self.2.lighter.rgb, self.2.base.rgb, format!("{:>10}", self.1)),
@ -124,7 +124,7 @@ render!(|self: TransportView|{
}); });
pub struct PlayPause(pub bool); pub struct PlayPause(pub bool);
render!(|self: PlayPause|Tui::bg( render!(<Tui>|self: PlayPause|Tui::bg(
if self.0{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)}, if self.0{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)},
Fixed::w(5, col!(|add|if self.0 { Fixed::w(5, col!(|add|if self.0 {
add(&Tui::fg(Color::Rgb(0, 255, 0), col!([ add(&Tui::fg(Color::Rgb(0, 255, 0), col!([
@ -200,7 +200,7 @@ impl StatusBar for TransportStatusBar {
} }
} }
render!(|self: TransportStatusBar|"todo"); render!(<Tui>|self: TransportStatusBar|"todo");
pub trait TransportControl<T>: HasClock + { pub trait TransportControl<T>: HasClock + {
fn transport_focused (&self) -> Option<TransportFocus>; fn transport_focused (&self) -> Option<TransportFocus>;

View file

@ -15,7 +15,7 @@ pub struct FileBrowser {
pub size: Measure<Tui> pub size: Measure<Tui>
} }
render!(|self: FileBrowser|{ render!(<Tui>|self: FileBrowser|{
Stack::down(|add|{ Stack::down(|add|{
let mut i = 0; let mut i = 0;
for (_, name) in self.dirs.iter() { for (_, name) in self.dirs.iter() {

View file

@ -119,8 +119,8 @@ impl Default for PhraseEditorModel {
} }
has_size!(<Tui>|self:PhraseEditorModel|&self.size); has_size!(<Tui>|self:PhraseEditorModel|&self.size);
render!(|self: PhraseEditorModel|&self.mode); render!(<Tui>|self: PhraseEditorModel|&self.mode);
//render!(|self: PhraseEditorModel|lay!(|add|{add(&self.size)?;add(self.mode)}));//bollocks //render!(<Tui>|self: PhraseEditorModel|lay!(|add|{add(&self.size)?;add(self.mode)}));//bollocks
pub trait PhraseViewMode: Render<Tui> + HasSize<Tui> + MidiRange + MidiPoint + Debug + Send + Sync { pub trait PhraseViewMode: Render<Tui> + HasSize<Tui> + MidiRange + MidiPoint + Debug + Send + Sync {
fn buffer_size (&self, phrase: &Phrase) -> (usize, usize); fn buffer_size (&self, phrase: &Phrase) -> (usize, usize);
@ -231,7 +231,7 @@ impl std::fmt::Debug for PhraseEditorModel {
} }
pub struct PhraseEditStatus<'a>(pub &'a PhraseEditorModel); pub struct PhraseEditStatus<'a>(pub &'a PhraseEditorModel);
render!(|self:PhraseEditStatus<'a>|row!(|add|{ render!(<Tui>|self:PhraseEditStatus<'a>|row!(|add|{
let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) { 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) (phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
} else { } else {

View file

@ -68,8 +68,7 @@ impl PhraseLengthFocus {
} }
} }
render!(<Tui>|self: PhraseLength|{
render!(|self: PhraseLength|{
let bars = ||self.bars_string(); let bars = ||self.bars_string();
let beats = ||self.beats_string(); let beats = ||self.beats_string();
let ticks = ||self.ticks_string(); let ticks = ||self.ticks_string();

View file

@ -206,7 +206,7 @@ pub trait HasPhraseList: HasPhrases {
pub struct PhraseListView<'a>(pub(crate) &'a PhraseListModel); pub struct PhraseListView<'a>(pub(crate) &'a PhraseListModel);
// TODO: Display phrases always in order of appearance // TODO: Display phrases always in order of appearance
render!(|self: PhraseListView<'a>|{ render!(<Tui>|self: PhraseListView<'a>|{
let PhraseListModel { phrases, mode, .. } = self.0; let PhraseListModel { phrases, mode, .. } = self.0;
let bg = TuiTheme::g(32); let bg = TuiTheme::g(32);
let title_color = TuiTheme::ti1(); let title_color = TuiTheme::ti1();
@ -263,7 +263,7 @@ pub struct PhraseSelector {
} }
// TODO: Display phrases always in order of appearance // TODO: Display phrases always in order of appearance
render!(|self: PhraseSelector|Fixed::wh(24, 1, row!([ render!(<Tui>|self: PhraseSelector|Fixed::wh(24, 1, row!([
Tui::fg(self.color.lightest.rgb, Tui::bold(true, &self.title)), Tui::fg(self.color.lightest.rgb, Tui::bold(true, &self.title)),
Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!([ Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!([
format!("{:8}", &self.name[0..8.min(self.name.len())]), format!("{:8}", &self.name[0..8.min(self.name.len())]),

View file

@ -59,32 +59,24 @@ impl PianoHorizontal {
} }
} }
render!(|self: PianoHorizontal|{ render!(<Tui>|self: PianoHorizontal|{
let color = self.color; let color = self.color;
let keys = move||PianoHorizontalKeys(&self); let keys = move||PianoHorizontalKeys(&self);
let timeline = move||PianoHorizontalTimeline(&self); let timeline = move||PianoHorizontalTimeline(&self);
let notes = move||PianoHorizontalNotes(&self); let notes = move||PianoHorizontalNotes(&self);
let cursor = move||PianoHorizontalCursor(&self); let cursor = move||PianoHorizontalCursor(&self);
let keys_width = 5; let keys_width = 5;
Fill::wh(Tui::bg(color.darker.rgb, Tui::bg(color.darker.rgb, Fill::wh(Bsp::s(
Bsp::s( Fixed::h(1, Bsp::e(Fixed::w(keys_width, ""), Fill::w(timeline()),)),
Fixed::h(1, Bsp::e(
Fixed::w(keys_width, ""),
Fill::w(timeline()),
)),
Bsp::e( Bsp::e(
Fixed::w(keys_width, keys()), Fixed::w(keys_width, keys()),
Fill::wh(lay!([&self.size, Fill::wh(lay!([ Fill::wh(lay!([&self.size, Fill::wh(lay!([Fill::wh(notes()), Fill::wh(cursor()),]))])),
Fill::wh(notes()),
Fill::wh(cursor()),
]))])),
), ),
) )))
))
}); });
pub struct PianoHorizontalTimeline<'a>(&'a PianoHorizontal); pub struct PianoHorizontalTimeline<'a>(&'a PianoHorizontal);
render!(|self: PianoHorizontalTimeline<'a>|render(|to|{ render!(<Tui>|self: PianoHorizontalTimeline<'a>|render(|to|{
let [x, y, w, h] = to.area(); let [x, y, w, h] = to.area();
let style = Some(Style::default().dim()); let style = Some(Style::default().dim());
let length = self.0.phrase.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); let length = self.0.phrase.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
@ -103,7 +95,7 @@ render!(|self: PianoHorizontalTimeline<'a>|render(|to|{
//)); //));
pub struct PianoHorizontalKeys<'a>(&'a PianoHorizontal); pub struct PianoHorizontalKeys<'a>(&'a PianoHorizontal);
render!(|self: PianoHorizontalKeys<'a>|render(|to|Ok({ render!(<Tui>|self: PianoHorizontalKeys<'a>|render(|to|Ok({
let color = self.0.color; let color = self.0.color;
let note_lo = self.0.note_lo(); let note_lo = self.0.note_lo();
let note_hi = self.0.note_hi(); let note_hi = self.0.note_hi();
@ -136,7 +128,7 @@ render!(|self: PianoHorizontalKeys<'a>|render(|to|Ok({
}))); })));
pub struct PianoHorizontalCursor<'a>(&'a PianoHorizontal); pub struct PianoHorizontalCursor<'a>(&'a PianoHorizontal);
render!(|self: PianoHorizontalCursor<'a>|render(|to|Ok({ render!(<Tui>|self: PianoHorizontalCursor<'a>|render(|to|Ok({
let note_hi = self.0.note_hi(); let note_hi = self.0.note_hi();
let note_len = self.0.note_len(); let note_len = self.0.note_len();
let note_lo = self.0.note_lo(); let note_lo = self.0.note_lo();
@ -167,7 +159,7 @@ render!(|self: PianoHorizontalCursor<'a>|render(|to|Ok({
}))); })));
pub struct PianoHorizontalNotes<'a>(&'a PianoHorizontal); pub struct PianoHorizontalNotes<'a>(&'a PianoHorizontal);
render!(|self: PianoHorizontalNotes<'a>|render(|to|Ok({ render!(<Tui>|self: PianoHorizontalNotes<'a>|render(|to|Ok({
let time_start = self.0.time_start(); let time_start = self.0.time_start();
let note_hi = self.0.note_hi(); let note_hi = self.0.note_hi();
let note_lo = self.0.note_lo(); let note_lo = self.0.note_lo();

View file

@ -4,4 +4,4 @@ pub struct PortSelector {
pub(crate) title: &'static str, pub(crate) title: &'static str,
} }
render!(|self: PortSelector|{}); render!(<Tui>|self: PortSelector|{});

View file

@ -2,7 +2,7 @@ use crate::*;
pub struct Bordered<S: BorderStyle, W: Render<Tui>>(pub S, pub W); pub struct Bordered<S: BorderStyle, W: Render<Tui>>(pub S, pub W);
render!(|self: Bordered<S: BorderStyle, W: Render<Tui>>|{ render!(<Tui>|self: Bordered<S: BorderStyle, W: Render<Tui>>|{
Fill::wh(lay!([Border(self.0), Tui::inset_xy(1, 1, widget(&self.1))])) Fill::wh(lay!([Border(self.0), Tui::inset_xy(1, 1, widget(&self.1))]))
}); });