down to 28e, sane ones

This commit is contained in:
🪞👃🪞 2024-12-31 15:50:53 +01:00
parent 46609855eb
commit 16e6a0397c
15 changed files with 91 additions and 87 deletions

View file

@ -1,4 +1,5 @@
use crate::*; use crate::*;
use std::marker::PhantomData;
//use std::sync::{Arc, Mutex, RwLock}; //use std::sync::{Arc, Mutex, RwLock};
/// Rendering target /// Rendering target
@ -42,54 +43,52 @@ impl<E: Engine, T: Content<E>> Content<E> for Option<T> {}
impl<E: Engine, T: Content<E>> Content<E> for Vec<T> {} impl<E: Engine, T: Content<E>> Content<E> for Vec<T> {}
pub struct Thunk<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync>(F, PhantomData<E>);
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Thunk<E, T, F> {
pub fn new (thunk: F) -> Self {
Self(thunk, Default::default())
}
}
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Content<E> for Thunk<E, T, F> {
fn content (&self) -> impl Content<E> {
(self.0)()
}
}
#[macro_export] macro_rules! render { #[macro_export] macro_rules! render {
(($self:ident:$Struct:ty) => $content:expr) => { (($self:ident:$Struct:ty) => $content:expr) => {
impl <E: Engine> Content<E> for $Struct { impl <E: Engine> Content<E> for $Struct {
fn content (&$self) -> Option<impl Content<E>> { fn content (&$self) -> impl Content<E> { Some($content) }
Some($content)
}
} }
}; };
(|$self:ident:$Struct:ident $(< (|$self:ident:$Struct:ident $(<
$($L:lifetime),* $($L:lifetime),* $($T:ident $(:$Trait:path)?),*
$($T:ident $(:$Trait:path)?),*
>)?, $to:ident | $render:expr) => { >)?, $to:ident | $render:expr) => {
impl <$($($L),*)? E: Engine, $($T$(:$Trait)?),*> Content<E> impl <$($($L),*)? E: Engine, $($T$(:$Trait)?),*> Content<E>
for $Struct $(<$($L),* $($T),*>>)? { for $Struct $(<$($L),* $($T),*>>)? {
fn render (&$self, $to: &mut E::Output) { fn render (&$self, $to: &mut E::Output) { $render }
Some($render)
}
} }
}; };
($Engine:ty: ($Engine:ty:
($self:ident:$Struct:ident $(<$( ($self:ident:$Struct:ident $(<$(
$($L:lifetime)? $($L:lifetime)? $($T:ident)? $(:$Trait:path)?
$($T:ident)?
$(:$Trait:path)?
),+>)?) => $content:expr ),+>)?) => $content:expr
) => { ) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine>
for $Struct $(<$($($L)? $($T)?),+>)? for $Struct $(<$($($L)? $($T)?),+>)? {
{ fn content (&$self) -> impl Content<$Engine> { $content }
fn content (&$self) -> Option<impl Content<$Engine>> {
Some($content)
}
} }
}; };
($Engine:ty: ($Engine:ty:
|$self:ident : $Struct:ident $(<$( |$self:ident : $Struct:ident $(<$(
$($L:lifetime)? $($L:lifetime)? $($T:ident)? $(:$Trait:path)?
$($T:ident)?
$(:$Trait:path)?
),+>)?, $to:ident| $render:expr ),+>)?, $to:ident| $render:expr
) => { ) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine>
for $Struct $(<$($($L)? $($T)?),+>)? for $Struct $(<$($($L)? $($T)?),+>)? {
{ fn render (&$self, $to: &mut <$Engine as Engine>::Output) { $render }
fn render (&$self, $to: &mut <$Engine as Engine>::Output) {
Some($render)
}
} }
}; };
} }

View file

@ -121,8 +121,8 @@ impl<E: Engine, X: Content<E>, Y: Content<E>> Default for Bsp<E, X, Y> {
impl<E: Engine, X: Content<E>, Y: Content<E>> Content<E> for Bsp<E, X, Y> { impl<E: Engine, X: Content<E>, Y: Content<E>> Content<E> for Bsp<E, X, Y> {
fn render (&self, to: &mut E::Output) { fn render (&self, to: &mut E::Output) {
let n = E::Size::zero(); let _n = E::Size::zero();
let s = to.wh(); let _s = to.wh();
match self { match self {
Self::Null(_) => {}, Self::Null(_) => {},
//Self::S(p, a, b) => { //Self::S(p, a, b) => {

View file

@ -25,13 +25,13 @@ macro_rules! transform_xy {
pub fn xy (item: T) -> Self { Self::XY(item) } pub fn xy (item: T) -> Self { Self::XY(item) }
} }
impl<E: Engine, T: Content<E>> Content<E> for $Enum<E, T> { impl<E: Engine, T: Content<E>> Content<E> for $Enum<E, T> {
fn content (&self) -> Option<impl Content<E>> { fn content (&self) -> impl Content<E> {
Some(match self { match self {
Self::X(item) => item, Self::X(item) => item,
Self::Y(item) => item, Self::Y(item) => item,
Self::XY(item) => item, Self::XY(item) => item,
_ => unreachable!() _ => unreachable!()
}) }
} }
fn area (&$self, $to: <E as Engine>::Area) -> <E as Engine>::Area { fn area (&$self, $to: <E as Engine>::Area) -> <E as Engine>::Area {
$area $area
@ -42,7 +42,7 @@ macro_rules! transform_xy {
transform_xy!(self: Fill |to|{ transform_xy!(self: Fill |to|{
let [x0, y0, wmax, hmax] = to.xywh(); let [x0, y0, wmax, hmax] = to.xywh();
let [x, y, w, h] = self.content().unwrap().area(to).xywh(); let [x, y, w, h] = self.content().area(to).xywh();
return match self { return match self {
Self::X(_) => [x0, y, wmax, h], Self::X(_) => [x0, y, wmax, h],
Self::Y(_) => [x, y0, w, hmax], Self::Y(_) => [x, y0, w, hmax],
@ -78,7 +78,7 @@ macro_rules! transform_xy_unit {
} }
} }
impl<E: Engine, T: Content<E>> Content<E> for $Enum<E, T> { impl<E: Engine, T: Content<E>> Content<E> for $Enum<E, T> {
fn content (&self) -> Option<impl Content<E>> { fn content (&self) -> impl Content<E> {
Some(match self { Some(match self {
Self::X(_, content) => content, Self::X(_, content) => content,
Self::Y(_, content) => content, Self::Y(_, content) => content,

View file

@ -72,11 +72,16 @@ impl Content<Tui> for ArrangerVCursor {
to.fill_ul([area.x(), y - 1, area.w(), 1], bg); to.fill_ul([area.x(), y - 1, area.w(), 1], bg);
to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg); to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
} }
Ok(if focused { if focused {
to.render_in(if let Some(clip_area) = clip_area { clip_area } to.place(if let Some(clip_area) = clip_area {
else if let Some(track_area) = track_area { track_area.clip_h(HEADER_H) } clip_area
else if let Some(scene_area) = scene_area { scene_area.clip_w(self.scenes_w) } } else if let Some(track_area) = track_area {
else { area.clip_w(self.scenes_w).clip_h(HEADER_H) }, &self.reticle)? track_area.clip_h(HEADER_H)
}) } else if let Some(scene_area) = scene_area {
scene_area.clip_w(self.scenes_w)
} else {
area.clip_w(self.scenes_w).clip_h(HEADER_H)
}, &self.reticle)
};
} }
} }

View file

@ -24,7 +24,6 @@ render!(Tui: |self: Border<S: BorderStyle>, to| {
to.blit(&self.0.e(), area.x() + area.w() - 1, y, self.0.style()); to.blit(&self.0.e(), area.x() + area.w() - 1, y, self.0.style());
} }
} }
Ok(())
}); });
pub trait BorderStyle: Send + Sync + Copy { pub trait BorderStyle: Send + Sync + Copy {
@ -130,7 +129,7 @@ macro_rules! border {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct $T(pub Style); pub struct $T(pub Style);
impl Content<Tui> for $T { impl Content<Tui> for $T {
fn render (&self, to: &mut TuiOutput) { self.draw(to) } fn render (&self, to: &mut TuiOutput) { self.draw(to); }
} }
)+} )+}
} }

View file

@ -149,13 +149,14 @@ render!(Tui: (self: Groovebox) => {
struct EditStatus<'a, T: Content<Tui>>(&'a Sampler, &'a MidiEditor, usize, T); struct EditStatus<'a, T: Content<Tui>>(&'a Sampler, &'a MidiEditor, usize, T);
impl<'a, T: Content<Tui>> Content<Tui> for EditStatus<'a, T> { impl<'a, T: Content<Tui>> Content<Tui> for EditStatus<'a, T> {
fn content (&self) -> Option<impl Content<Tui>> { fn content (&self) -> impl Content<Tui> {
Some(Split::n(false, 9, col!( Split::n(false, 9, col!(
row!( row!(
Cond::opt( self.0.mapped[self.2].as_ref().map(|sample|format!(
&self.0.mapped[self.2], "Sample {}-{}",
|sample|format!("Sample {}", sample.read().unwrap().end) sample.read().unwrap().start,
), sample.read().unwrap().end,
)),
MidiEditStatus(&self.1), MidiEditStatus(&self.1),
), ),
lay!( lay!(
@ -168,7 +169,7 @@ impl<'a, T: Content<Tui>> Content<Tui> for EditStatus<'a, T> {
SampleViewer(None) SampleViewer(None)
})), })),
), ),
), &self.3)) ), &self.3)
} }
} }
@ -177,7 +178,7 @@ render!(Tui: (self: GrooveboxSamples<'a>) => {
let note_lo = self.0.editor.note_lo().load(Relaxed); let note_lo = self.0.editor.note_lo().load(Relaxed);
let note_pt = self.0.editor.note_point(); let note_pt = self.0.editor.note_point();
let note_hi = self.0.editor.note_hi(); let note_hi = self.0.editor.note_hi();
Fill::xy(Coll::map((note_lo..=note_hi).rev(), |note, i| { Fill::xy(Coll::map((note_lo..=note_hi).rev(), move|note, i| {
let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset }; let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset };
let mut fg = TuiTheme::g(160); let mut fg = TuiTheme::g(160);
if let Some((index, _)) = self.0.sampler.recording { if let Some((index, _)) = self.0.sampler.recording {
@ -188,7 +189,7 @@ render!(Tui: (self: GrooveboxSamples<'a>) => {
} else if self.0.sampler.mapped[note].is_some() { } else if self.0.sampler.mapped[note].is_some() {
fg = TuiTheme::g(224); fg = TuiTheme::g(224);
} }
Push::y(i, Tui::bg(bg, if let Some(sample) = &self.0.sampler.mapped[note] { Push::y(i as u16, Tui::bg(bg, if let Some(sample) = &self.0.sampler.mapped[note] {
Tui::fg(fg, format!("{note:3} ?????? ")) Tui::fg(fg, format!("{note:3} ?????? "))
} else { } else {
Tui::fg(fg, format!("{note:3} (none) ")) Tui::fg(fg, format!("{note:3} (none) "))

View file

@ -9,7 +9,7 @@ pub(crate) use ::tek_layout::{
tek_engine::{ tek_engine::{
Usually, Perhaps, Usually, Perhaps,
Engine, Size, Area, Engine, Size, Area,
Output, Content, render, Output, Content, Thunk, render,
Input, Handle, handle, Input, Handle, handle,
kexp, key_pat, key_event_pat, key_event_expr, kexp, key_pat, key_event_pat, key_event_expr,
tui::{ tui::{

View file

@ -3,6 +3,6 @@ use crate::*;
pub struct Meters<'a>(pub &'a[f32]); pub struct Meters<'a>(pub &'a[f32]);
render!(Tui: (self: Meters<'a>) => col!( render!(Tui: (self: Meters<'a>) => col!(
&format!("L/{:>+9.3}", self.0[0]), format!("L/{:>+9.3}", self.0[0]),
&format!("R/{:>+9.3}", self.0[1]), format!("R/{:>+9.3}", self.0[1]),
)); ));

View file

@ -97,7 +97,7 @@ pub struct TrackView<'a> {
} }
impl<'a> Content<Tui> for TrackView<'a> { impl<'a> Content<Tui> for TrackView<'a> {
fn render (&self, to: &mut TuiOutput) -> Usually<()> { fn render (&self, to: &mut TuiOutput) {
todo!(); todo!();
//let mut area = to.area(); //let mut area = to.area();
//if let Some(chain) = self.chain { //if let Some(chain) = self.chain {

View file

@ -5,14 +5,14 @@ pub struct PianoHorizontalKeys<'a>(pub(crate) &'a PianoHorizontal);
render!(Tui: |self: PianoHorizontalKeys<'a>, to|{ render!(Tui: |self: PianoHorizontalKeys<'a>, to|{
let state = self.0; let state = self.0;
let color = state.color(); let color = state.color;
let note_lo = state.note_lo().get(); let note_lo = state.note_lo().get();
let note_hi = state.note_hi(); let note_hi = state.note_hi();
let note_point = state.note_point(); let note_point = state.note_point();
let [x, y0, w, h] = to.area().xywh(); let [x, y0, w, h] = to.area().xywh();
let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0))); let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0)));
let off_style = Some(Style::default().fg(TuiTheme::g(160))); let off_style = Some(Style::default().fg(TuiTheme::g(160)));
let on_style = Some(Style::default().fg(TuiTheme::g(255)).bg(color.rgb).bold()); let on_style = Some(Style::default().fg(TuiTheme::g(255)).bg(color.base.rgb).bold());
for (area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) { for (area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
to.blit(&to_key(note), x, screen_y, key_style); to.blit(&to_key(note), x, screen_y, key_style);
if note > 127 { if note > 127 {

View file

@ -171,7 +171,7 @@ fn draw_sample (
} }
impl Content<Tui> for AddSampleModal { impl Content<Tui> for AddSampleModal {
fn render (&self, to: &mut TuiOutput) -> Usually<()> { fn render (&self, to: &mut TuiOutput) {
todo!() todo!()
//let area = to.area(); //let area = to.area();
//to.make_dim(); //to.make_dim();

View file

@ -52,6 +52,4 @@ render!(Tui: |self: SampleViewer, to|{
.y_bounds(y_bounds) .y_bounds(y_bounds)
.paint(|ctx| { for line in lines.iter() { ctx.draw(line) } }) .paint(|ctx| { for line in lines.iter() { ctx.draw(line) } })
.render(area, &mut to.buffer); .render(area, &mut to.buffer);
Ok(())
}); });

View file

@ -82,7 +82,7 @@ render!(Tui: |self: SamplesTui, render|{
let note = self.note_hi - y as usize; let note = self.note_hi - y as usize;
let bg = if note == self.note_pt { bg_selected } else { bg_base }; let bg = if note == self.note_pt { bg_selected } else { bg_base };
let style = Some(style_empty.bg(bg)); let style = Some(style_empty.bg(bg));
render.blit(&" (no sample) ", x, render.area.y() + y as u16, style) render.blit(&" (no sample) ", x, render.area.y() + y as u16, style);
} }
}); });

View file

@ -23,7 +23,7 @@ impl TuiStyle for Tui {}
pub struct Bold<W: Content<Tui>>(pub bool, W); pub struct Bold<W: Content<Tui>>(pub bool, W);
impl<W: Content<Tui>> Content<Tui> for Bold<W> { impl<W: Content<Tui>> Content<Tui> for Bold<W> {
fn content (&self) -> Option<impl Content<Tui>> { fn content (&self) -> impl Content<Tui> {
Some(&self.1) Some(&self.1)
} }
fn render (&self, to: &mut TuiOutput) { fn render (&self, to: &mut TuiOutput) {
@ -35,7 +35,7 @@ impl<W: Content<Tui>> Content<Tui> for Bold<W> {
pub struct Foreground<W: Content<Tui>>(pub Color, W); pub struct Foreground<W: Content<Tui>>(pub Color, W);
impl<W: Content<Tui>> Content<Tui> for Foreground<W> { impl<W: Content<Tui>> Content<Tui> for Foreground<W> {
fn content (&self) -> Option<impl Content<Tui>> { fn content (&self) -> impl Content<Tui> {
Some(&self.1) Some(&self.1)
} }
fn render (&self, to: &mut TuiOutput) { fn render (&self, to: &mut TuiOutput) {
@ -47,7 +47,7 @@ impl<W: Content<Tui>> Content<Tui> for Foreground<W> {
pub struct Background<W: Content<Tui>>(pub Color, W); pub struct Background<W: Content<Tui>>(pub Color, W);
impl<W: Content<Tui>> Content<Tui> for Background<W> { impl<W: Content<Tui>> Content<Tui> for Background<W> {
fn content (&self) -> Option<impl Content<Tui>> { fn content (&self) -> impl Content<Tui> {
Some(&self.1) Some(&self.1)
} }
fn render (&self, to: &mut TuiOutput) { fn render (&self, to: &mut TuiOutput) {
@ -59,14 +59,14 @@ impl<W: Content<Tui>> Content<Tui> for Background<W> {
pub struct Styled<T: Content<Tui>>(pub Option<Style>, pub T); pub struct Styled<T: Content<Tui>>(pub Option<Style>, pub T);
impl Content<Tui> for Styled<&str> { impl Content<Tui> for Styled<&str> {
fn content (&self) -> Option<impl Content<Tui>> { fn content (&self) -> impl Content<Tui> {
Some(&self.1) Some(&self.1)
} }
fn render (&self, to: &mut TuiOutput) { fn render (&self, to: &mut TuiOutput) {
// FIXME // FIXME
let [x, y, ..] = to.area(); let [x, y, ..] = to.area();
//let [w, h] = self.min_size(to.area().wh())?.unwrap(); //let [w, h] = self.min_size(to.area().wh())?.unwrap();
Ok(to.blit(&self.1, x, y, None)) to.blit(&self.1, x, y, None)
} }
} }

View file

@ -89,23 +89,29 @@ impl TransportView {
} }
render!(Tui: (self: TransportView) => { render!(Tui: (self: TransportView) => {
let color = self.color; let color = self.color;
let transport_field = move|label, value|row!(
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Tui::bold(true, label)),
Tui::fg_bg(color.base.rgb, color.darkest.rgb, ""),
Tui::fg_bg(color.lightest.rgb, color.darkest.rgb, format!("{:>10}", value)),
Tui::fg_bg(color.darkest.rgb, color.base.rgb, ""),
);
Fixed::y(3, Tui::bg(color.base.rgb, Fill::x(row!( Fixed::y(3, Tui::bg(color.base.rgb, Fill::x(row!(
col!( Thunk::new(move||col!(
TransportField(" Beat", self.beat.as_str(), &color), transport_field(" Beat", self.beat.as_str()),
TransportField(" Time", format!("{:.1}s", self.current_second).as_str(), &color), transport_field(" Time", format!("{:.1}s", self.current_second).as_str()),
TransportField(" BPM", self.bpm.as_str(), &color), transport_field(" BPM", self.bpm.as_str()),
), )),
col!( Thunk::new(move||col!(
TransportField(" Rate", format!("{}", self.sr).as_str(), &color), transport_field(" Rate", format!("{}", self.sr).as_str()),
TransportField(" Chunk", format!("{}", self.chunk).as_str(), &color), transport_field(" Chunk", format!("{}", self.chunk).as_str()),
TransportField(" Lag", format!("{:.3}ms", self.latency).as_str(), &color), transport_field(" Lag", format!("{:.3}ms", self.latency).as_str()),
), )),
col!( col!(
//Field(" CPU%", format!("{:.1}ms", self.perf).as_str(), &color), //Field(" CPU%", format!("{:.1}ms", self.perf).as_str(), &color),
), ),
)))) ))))
}); });
struct TransportField<'a>(&'a str, &'a str, &'a ItemPalette); struct TransportField<'a>(&'a str, &'a str, ItemPalette);
render!(Tui: (self: TransportField<'a>) => row!( render!(Tui: (self: TransportField<'a>) => row!(
Tui::fg_bg(self.2.lightest.rgb, self.2.base.rgb, Tui::bold(true, self.0)), Tui::fg_bg(self.2.lightest.rgb, self.2.base.rgb, Tui::bold(true, self.0)),
Tui::fg_bg(self.2.base.rgb, self.2.darkest.rgb, ""), Tui::fg_bg(self.2.base.rgb, self.2.darkest.rgb, ""),
@ -115,17 +121,13 @@ render!(Tui: (self: TransportField<'a>) => row!(
pub struct PlayPause(pub bool); pub struct PlayPause(pub bool);
render!(Tui: (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::x(5, col!(|add|if self.0 { Fixed::x(5, Cond::either(self.0, Tui::fg(Color::Rgb(0, 255, 0), col!(
add(&Tui::fg(Color::Rgb(0, 255, 0), col!( " 🭍🭑🬽 ",
" 🭍🭑🬽 ", " 🭞🭜🭘 ",
" 🭞🭜🭘 ", )), Tui::fg(Color::Rgb(255, 128, 0), col!(
))) " ▗▄▖ ",
} else { " ▝▀▘ ",
add(&Tui::fg(Color::Rgb(255, 128, 0), col!( ))))
" ▗▄▖ ",
" ▝▀▘ ",
)))
}))
)); ));
impl HasFocus for TransportTui { impl HasFocus for TransportTui {
type Item = TransportFocus; type Item = TransportFocus;
@ -152,7 +154,7 @@ impl FocusWrap<TransportFocus> for TransportFocus {
let focused = focus == self; let focused = focus == self;
let corners = focused.then_some(CORNERS); let corners = focused.then_some(CORNERS);
//let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50))); //let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50)));
lay!(corners, /*highlight,*/ *content) lay!(corners, /*highlight,*/ content)
} }
} }
impl FocusWrap<TransportFocus> for Option<TransportFocus> { impl FocusWrap<TransportFocus> for Option<TransportFocus> {
@ -162,7 +164,7 @@ impl FocusWrap<TransportFocus> for Option<TransportFocus> {
let focused = Some(focus) == self; let focused = Some(focus) == self;
let corners = focused.then_some(CORNERS); let corners = focused.then_some(CORNERS);
//let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50))); //let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50)));
lay!(corners, /*highlight,*/ *content) lay!(corners, /*highlight,*/ content)
} }
} }
pub trait TransportControl<T>: HasClock + { pub trait TransportControl<T>: HasClock + {