reorganize more

This commit is contained in:
i do not exist 2026-07-06 20:40:57 +03:00
parent b9e7b9732e
commit 2d64f63741
12 changed files with 117 additions and 145 deletions

View file

@ -59,7 +59,7 @@ impl App {
/// Create a new application instance from a backend, project, config, and mode /// Create a new application instance from a backend, project, config, and mode
/// ///
/// ``` /// ```
/// let jack = tek::tengri::sing::Jack::new(&"test_tek").expect("failed to connect to jack"); /// let jack = tek::tengri::Jack::new(&"test_tek").expect("failed to connect to jack");
/// let proj = tek::Arrangement::default(); /// let proj = tek::Arrangement::default();
/// let mut conf = tek::Config::default(); /// let mut conf = tek::Config::default();
/// conf.add("(mode hello)"); /// conf.add("(mode hello)");

View file

@ -50,7 +50,7 @@ pub(crate) fn load_bind (binds: &Binds, name: &impl AsRef<str>, body: &impl Lang
/// ///
/// ``` /// ```
/// let lang = "(@x (nop)) (@y (nop) (nop))"; /// let lang = "(@x (nop)) (@y (nop) (nop))";
/// let bind = tek::Bind::<tek::tengri::term::TuiEvent, std::sync::Arc<str>>::load(&lang).unwrap(); /// let bind = tek::Bind::<tek::tengri::TuiEvent, std::sync::Arc<str>>::load(&lang).unwrap();
/// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1)); /// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1));
/// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2)); /// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2));
/// ``` /// ```

View file

@ -10,7 +10,7 @@ impl View<Tui> for App {
thunk(|to: &mut Tui|{ thunk(|to: &mut Tui|{
let xywh = to.area().into(); let xywh = to.area().into();
if let Some(e) = self.error.read().unwrap().as_ref() { if let Some(e) = self.error.read().unwrap().as_ref() {
to.show(Layout::XYWH(xywh, e.as_ref()))?; to.show(area(xywh, e.as_ref()))?;
} }
for (index, dsl) in self.mode.view.iter().enumerate() { for (index, dsl) in self.mode.view.iter().enumerate() {
if let Err(e) = self.interpret(to, dsl) { if let Err(e) = self.interpret(to, dsl) {
@ -18,39 +18,31 @@ impl View<Tui> for App {
break; break;
} }
} }
Ok(xywh) Ok(Some(xywh))
}) })
} }
} }
impl Interpret<Tui, XYWH<u16>> for App { impl Interpret<Tui, Option<XYWH<u16>>> for App {
fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
tek_draw_expr(self, to, lang) tek_draw_expr(self, to, lang)
} }
fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
tek_draw_word(self, to, lang) tek_draw_word(self, to, lang)
} }
} }
fn tek_draw_expr (state: &App, to: &mut Tui, lang: &impl Expression) fn tek_draw_expr (state: &App, to: &mut Tui, lang: &impl Expression) -> Drawn<u16> {
-> Usually<XYWH<u16>> Ok(Some(if let Some(area) = eval_view(state, to, lang)? {
{ area
if let Some(area) = eval_view(state, to, lang)? {
Ok(area)
} else if let Some(area) = eval_view_tui(state, to, lang)? { } else if let Some(area) = eval_view_tui(state, to, lang)? {
Ok(area) area
} else { } else {
Err(format!("App::interpret_expr: unexpected: {lang:?}").into()) return Err(format!("App::interpret_expr: unexpected: {lang:?}").into())
} }))
} }
fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression) fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
let mut frags = dsl.src()?.unwrap().split("/"); let mut frags = dsl.src()?.unwrap().split("/");
match frags.next() { match frags.next() {
Some(":logo") => view_logo().draw(to), Some(":logo") => view_logo().draw(to),
@ -79,32 +71,26 @@ fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression)
} }
} }
pub fn draw_meter_section (to: &mut Tui, mut frags: std::str::Split<&str>) pub fn draw_meter_section (to: &mut Tui, mut frags: std::str::Split<&str>) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
match frags.next() { match frags.next() {
Some("input") => bg(Rgb(30, 30, 30), h_full(origin_s("Input Meters"))).draw(to), Some("input") => bg(Rgb(30, 30, 30), h_full(align_s("Input Meters"))).draw(to),
Some("output") => bg(Rgb(30, 30, 30), h_full(origin_s("Output Meters"))).draw(to), Some("output") => bg(Rgb(30, 30, 30), h_full(align_s("Output Meters"))).draw(to),
_ => panic!() _ => panic!()
} }
} }
pub fn draw_tracks (to: &mut Tui, mut frags: std::str::Split<&str>, state: &App) pub fn draw_tracks (to: &mut Tui, mut frags: std::str::Split<&str>, state: &App) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
match frags.next() { match frags.next() {
None => "TODO tracks".draw(to), None => "TODO tracks".draw(to),
Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), w_full(origin_w("Track Names")))), Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), w_full(align_w("Track Names")))),
Some("inputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Inputs"))).draw(to), Some("inputs") => bg(Rgb(40, 40, 40), w_full(align_w("Track Inputs"))).draw(to),
Some("devices") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Devices"))).draw(to), Some("devices") => bg(Rgb(40, 40, 40), w_full(align_w("Track Devices"))).draw(to),
Some("outputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Outputs"))).draw(to), Some("outputs") => bg(Rgb(40, 40, 40), w_full(align_w("Track Outputs"))).draw(to),
_ => panic!() _ => panic!()
} }
} }
pub fn draw_scenes (to: &mut Tui, mut frags: std::str::Split<&str>) pub fn draw_scenes (to: &mut Tui, mut frags: std::str::Split<&str>) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
match frags.next() { match frags.next() {
None => "TODO Scenes".draw(to), None => "TODO Scenes".draw(to),
Some(":scenes/names") => "TODO Scene Names".draw(to), Some(":scenes/names") => "TODO Scene Names".draw(to),
@ -113,8 +99,7 @@ pub fn draw_scenes (to: &mut Tui, mut frags: std::str::Split<&str>)
} }
pub fn draw_dialog ( pub fn draw_dialog (
to: &mut Tui, mut frags: std::str::Split<&str>, state: &App, dsl: &impl Expression to: &mut Tui, mut frags: std::str::Split<&str>, state: &App, dsl: &impl Expression) -> Drawn<u16> {
) -> Usually<XYWH<u16>> {
match frags.next() { match frags.next() {
Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog { Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog {
let items = items.clone(); let items = items.clone();
@ -124,10 +109,10 @@ pub fn draw_dialog (
y_push((2 * index) as u16,fg_bg( y_push((2 * index) as u16,fg_bg(
if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) }, if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) },
if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) }, if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) },
h_exact(2, origin_n(w_full(item))) h_exact(2, align_n(w_full(item)))
)).draw(to)?; )).draw(to)?;
} }
Ok(to.area().into()) Ok(Some(to.area().into()))
}))) })))
} else { } else {
None None
@ -136,9 +121,7 @@ pub fn draw_dialog (
} }
} }
pub fn draw_templates (to: &mut Tui, frags: std::str::Split<&str>, state: &App) pub fn draw_templates (to: &mut Tui, frags: std::str::Split<&str>, state: &App) -> Drawn<u16> {
-> Usually<XYWH<u16>>
{
let height = (state.config.modes.len() * 2) as u16; let height = (state.config.modes.len() * 2) as u16;
h_exact(height, w_min(Some(30), thunk(move |to: &mut Tui|{ h_exact(height, w_min(Some(30), thunk(move |to: &mut Tui|{
let mut index = 0; let mut index = 0;
@ -148,9 +131,9 @@ pub fn draw_templates (to: &mut Tui, frags: std::str::Split<&str>, state: &App)
let info = profile.info.get(0).map(|x|x.as_ref()).unwrap_or("<no info>"); let info = profile.info.get(0).map(|x|x.as_ref()).unwrap_or("<no info>");
let fg1 = Rgb(224, 192, 128); let fg1 = Rgb(224, 192, 128);
let fg2 = Rgb(224, 128, 32); let fg2 = Rgb(224, 128, 32);
let field_name = w_full(origin_w(fg(fg1, name))); let field_name = w_full(align_w(fg(fg1, name)));
let field_id = w_full(origin_e(fg(fg2, id))); let field_id = w_full(align_e(fg(fg2, id)));
let field_info = w_full(origin_w(info)); let field_info = w_full(align_w(info));
let _ = y_push((2 * index) as u16, let _ = y_push((2 * index) as u16,
h_exact(2, w_full(bg(b, south( h_exact(2, w_full(bg(b, south(
above(field_name, field_id), above(field_name, field_id),
@ -158,7 +141,7 @@ pub fn draw_templates (to: &mut Tui, frags: std::str::Split<&str>, state: &App)
))))).draw(to); ))))).draw(to);
index += 1; index += 1;
}); });
Ok(to.area().into()) Ok(Some(to.area().into()))
}))).draw(to) }))).draw(to)
} }
@ -183,8 +166,8 @@ pub fn view_logo () -> impl Draw<Tui> {
pub fn view_transport (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw<Tui> { pub fn view_transport (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw<Tui> {
let theme = ItemTheme::G[96]; let theme = ItemTheme::G[96];
bg(Black, east!(above( bg(Black, east!(above(
wh_full(origin_w(button_play_pause(play, false))), wh_full(align_w(button_play_pause(play, false))),
wh_full(origin_e(east!( wh_full(align_e(east!(
field_h(theme, "BPM", bpm), field_h(theme, "BPM", bpm),
field_h(theme, "Beat", beat), field_h(theme, "Beat", beat),
field_h(theme, "Time", time), field_h(theme, "Time", time),
@ -203,8 +186,8 @@ pub fn view_status (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl D
let buf = field_h(theme, "Buf", buf); let buf = field_h(theme, "Buf", buf);
let lat = field_h(theme, "Lat", lat); let lat = field_h(theme, "Lat", lat);
bg(Black, east!(above( bg(Black, east!(above(
wh_full(origin_w(sel.map(|sel|field_h(theme, "Selected", sel)))), wh_full(align_w(sel.map(|sel|field_h(theme, "Selected", sel)))),
wh_full(origin_e(east!(sr, buf, lat))), wh_full(align_e(east!(sr, buf, lat))),
))) )))
} }
@ -235,8 +218,8 @@ pub fn button_play_pause (playing: bool, compact: bool) -> impl Draw<Tui> {
button_add: impl Draw<Tui>, button_add: impl Draw<Tui>,
content: impl Draw<Tui>, content: impl Draw<Tui>,
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
west(h_full(w_exact(4, origin_nw(button_add))), west(h_full(w_exact(4, align_nw(button_add))),
east(w_exact(20, h_full(origin_nw(button))), wh_full(origin_c(content)))) east(w_exact(20, h_full(align_nw(button))), wh_full(align_c(content))))
} }
/// ``` /// ```
@ -302,12 +285,12 @@ pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tu
let sample = sample.unwrap().read().unwrap(); let sample = sample.unwrap().read().unwrap();
let theme = sample.color; let theme = sample.color;
w_exact(20, south!( w_exact(20, south!(
w_full(origin_w(field_h(theme, "Name ", format!("{:<10}", sample.name.clone())))), w_full(align_w(field_h(theme, "Name ", format!("{:<10}", sample.name.clone())))),
w_full(origin_w(field_h(theme, "Length", format!("{:<8}", sample.channels[0].len())))), w_full(align_w(field_h(theme, "Length", format!("{:<8}", sample.channels[0].len())))),
w_full(origin_w(field_h(theme, "Start ", format!("{:<8}", sample.start)))), w_full(align_w(field_h(theme, "Start ", format!("{:<8}", sample.start)))),
w_full(origin_w(field_h(theme, "End ", format!("{:<8}", sample.end)))), w_full(align_w(field_h(theme, "End ", format!("{:<8}", sample.end)))),
w_full(origin_w(field_h(theme, "Trans ", "0"))), w_full(align_w(field_h(theme, "Trans ", "0"))),
w_full(origin_w(field_h(theme, "Gain ", format!("{}", sample.gain)))), w_full(align_w(field_h(theme, "Gain ", format!("{}", sample.gain)))),
)).draw(to) )).draw(to)
}); });
@ -330,7 +313,7 @@ pub fn view_sample_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tu
} }
pub fn view_track_header (theme: ItemTheme, content: impl Draw<Tui>) -> impl Draw<Tui> { pub fn view_track_header (theme: ItemTheme, content: impl Draw<Tui>) -> impl Draw<Tui> {
w_exact(12, bg(theme.darker.term, w_full(origin_e(content)))) w_exact(12, bg(theme.darker.term, w_full(align_e(content))))
} }
pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, ports: &'a [T]) pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, ports: &'a [T])
@ -339,7 +322,7 @@ pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, po
let ins = ports.len() as u16; let ins = ports.len() as u16;
let frame = Outer(true, Style::default().fg(g(96))); let frame = Outer(true, Style::default().fg(g(96)));
let iter = move||ports.iter(); let iter = move||ports.iter();
let names = iter_south(iter, move|port, index|h_full(origin_w(format!(" {index} {}", port.port_name())))); let names = iter_south(iter, move|port, index|h_full(align_w(format!(" {index} {}", port.port_name()))));
let field = field_v(theme, title, names); let field = field_v(theme, title, names);
wh_exact(Some(20), Some(1 + ins), border(true, frame, wh_exact(Some(20), Some(1 + ins), field))) wh_exact(Some(20), Some(1 + ins), border(true, frame, wh_exact(Some(20), Some(1 + ins), field)))
} }
@ -350,9 +333,9 @@ pub fn view_io_ports <'a, T: PortsSizes<'a>> (
type Item<'a> = (usize, &'a Arc<str>, &'a [Connect], usize, usize); type Item<'a> = (usize, &'a Arc<str>, &'a [Connect], usize, usize);
iter(items, move|(_index, name, connections, y, y2): Item<'a>, _| { iter(items, move|(_index, name, connections, y, y2): Item<'a>, _| {
y_push(y as u16, h_exact((y2-y) as u16, y_push(y as u16, h_exact((y2-y) as u16,
south(h_full(bold(true, fg_bg(fg, bg, origin_w(east(" 󰣲 ", name))))), south(h_full(bold(true, fg_bg(fg, bg, align_w(east(" 󰣲 ", name))))),
iter(||connections.iter(), move|connect: &'a Connect, index|y_push( iter(||connections.iter(), move|connect: &'a Connect, index|y_push(
index as u16, h_exact(1, origin_w(bold(false, fg_bg(fg, bg, &connect.info)))) index as u16, h_exact(1, align_w(bold(false, fg_bg(fg, bg, &connect.info))))
))))) )))))
}) })
} }
@ -365,7 +348,7 @@ pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> (
size: &Sizer, size: &Sizer,
editing: bool, editing: bool,
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
let status = wh_full(origin_se(fg(Green, format!("{}x{}", size.w(), size.h())))); let status = wh_full(align_se(fg(Green, format!("{}x{}", size.w(), size.h()))));
let tracks = iter_once(tracks, move|(track_index, track, _, _), _| { let tracks = iter_once(tracks, move|(track_index, track, _, _), _| {
let scenes = iter_once(scenes(), move|(scene_index, scene, _, _), _| { let scenes = iter_once(scenes(), move|(scene_index, scene, _, _), _| {
let (name, theme): (Arc<str>, ItemTheme) = scene_name_theme(scene, track_index); let (name, theme): (Arc<str>, ItemTheme) = scene_name_theme(scene, track_index);
@ -379,7 +362,7 @@ pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> (
wh_full(below( wh_full(below(
below( below(
fg_bg(o, b, wh_full("")), fg_bg(o, b, wh_full("")),
wh_full(origin_nw(fg_bg(f, b, bold(true, name)))), wh_full(align_nw(fg_bg(f, b, bold(true, name)))),
), ),
wh_full(when(is_selected, editor.map(|e|e.view()))))))) wh_full(when(is_selected, editor.map(|e|e.view())))))))
}); });
@ -460,12 +443,12 @@ pub fn view_track_names (
track.color.light.term track.color.light.term
} else { } else {
track.color.base.term track.color.base.term
}, south(w_full(origin_nw(east( }, south(w_full(align_nw(east(
format!("·t{index:02} "), format!("·t{index:02} "),
fg(Rgb(255, 255, 255), bold(true, &track.name)) fg(Rgb(255, 255, 255), bold(true, &track.name))
))), ""))) ).draw(to)?; ))), ""))) ).draw(to)?;
} }
Ok(XYWH(0, 0, 0, 0)) Ok(Some(XYWH(0, 0, 0, 0)))
})))) }))))
} }
@ -473,24 +456,24 @@ pub fn view_track_outputs (
theme: ItemTheme, tracks: impl TracksSizes<'_>, midi_outs: impl Iterator<Item = &MidiOutput>, theme: ItemTheme, tracks: impl TracksSizes<'_>, midi_outs: impl Iterator<Item = &MidiOutput>,
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
view_track_row_section(theme, view_track_row_section(theme,
south(w_full(origin_w(button_2("o", "utput", false))), south(w_full(align_w(button_2("o", "utput", false))),
thunk(|to: &mut Tui|{ thunk(|to: &mut Tui|{
for port in midi_outs { for port in midi_outs {
w_full(origin_w(port.port_name())).draw(to); w_full(align_w(port.port_name())).draw(to);
} }
Ok(XYWH(0, 0, 0, 0)) Ok(Some(XYWH(0, 0, 0, 0)))
})), })),
button_2("O", "+", false), button_2("O", "+", false),
bg(theme.darker.term, origin_w(thunk(|to: &mut Tui|{ bg(theme.darker.term, align_w(thunk(|to: &mut Tui|{
for (index, track, _x1, _x2) in tracks { for (index, track, _x1, _x2) in tracks {
let iter = ||track.sequencer.midi_outs.iter(); let iter = ||track.sequencer.midi_outs.iter();
let draw = |port: &MidiOutput, _|fg(Rgb(255, 255, 255), let draw = |port: &MidiOutput, _|fg(Rgb(255, 255, 255),
h_exact(1, bg(track.color.dark.term, w_full(origin_w( h_exact(1, bg(track.color.dark.term, w_full(align_w(
format!("·o{index:02} {}", port.port_name())))))); format!("·o{index:02} {}", port.port_name()))))));
w_exact(track_width(index, track), w_exact(track_width(index, track),
origin_nw(h_full(iter_south(iter, draw)))).draw(to)?; align_nw(h_full(iter_south(iter, draw)))).draw(to)?;
} }
Ok(XYWH(0, 0, 0, 0)) Ok(Some(XYWH(0, 0, 0, 0)))
})))) }))))
} }
@ -498,22 +481,22 @@ pub fn view_track_inputs (
theme: ItemTheme, tracks: impl TracksSizes<'_>, height: u16, theme: ItemTheme, tracks: impl TracksSizes<'_>, height: u16,
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
view_track_row_section(theme, button_2("i", "nput", false), button_2("I", "+", false), view_track_row_section(theme, button_2("i", "nput", false), button_2("I", "+", false),
bg(theme.darker.term, origin_w(thunk(move|to: &mut Tui|{ bg(theme.darker.term, align_w(thunk(move|to: &mut Tui|{
for (index, track, _x1, _x2) in tracks { for (index, track, _x1, _x2) in tracks {
wh_exact(Some(track_width(index, track)), Some(height + 1), wh_exact(Some(track_width(index, track)), Some(height + 1),
origin_nw(south( align_nw(south(
bg(track.color.base.term, bg(track.color.base.term,
w_full(origin_w(east!( w_full(align_w(east!(
either(track.sequencer.monitoring, fg(Green, "●mon "), "·mon "), either(track.sequencer.monitoring, fg(Green, "●mon "), "·mon "),
either(track.sequencer.recording, fg(Red, "●rec "), "·rec "), either(track.sequencer.recording, fg(Red, "●rec "), "·rec "),
either(track.sequencer.overdub, fg(Yellow, "●dub "), "·dub "), either(track.sequencer.overdub, fg(Yellow, "●dub "), "·dub "),
)))), )))),
iter_south(||track.sequencer.midi_ins.iter(), iter_south(||track.sequencer.midi_ins.iter(),
|port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term, |port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term,
w_full(origin_w(format!("·i{index:02} {}", port.port_name())))))))) w_full(align_w(format!("·i{index:02} {}", port.port_name()))))))))
.draw(to)?; .draw(to)?;
} }
Ok(XYWH(0, 0, 0, 0)) Ok(Some(XYWH(0, 0, 0, 0)))
})))) }))))
} }
@ -527,7 +510,7 @@ pub fn view_scenes_names (
for (index, scene, ..) in scenes { for (index, scene, ..) in scenes {
view_scene_name(select, editor, index, scene, editing).draw(to)?; view_scene_name(select, editor, index, scene, editing).draw(to)?;
} }
Ok(XYWH(1, 1, 1, 1)) Ok(Some(XYWH(1, 1, 1, 1)))
})) }))
} }
@ -543,10 +526,10 @@ pub fn view_scene_name (
} else { } else {
H_SCENE as u16 H_SCENE as u16
}; };
let a = w_full(origin_w(east(format!("·s{index:02} "), let a = w_full(align_w(east(format!("·s{index:02} "),
fg(g(255), bold(true, &scene.name))))); fg(g(255), bold(true, &scene.name)))));
let b = when(select.scene() == Some(index) && editing, let b = when(select.scene() == Some(index) && editing,
wh_full(origin_nw(south( wh_full(align_nw(south(
editor.as_ref().map(|e|e.clip_status()), editor.as_ref().map(|e|e.clip_status()),
editor.as_ref().map(|e|e.edit_status()))))); editor.as_ref().map(|e|e.edit_status())))));
let c = if select.scene() == Some(index) { let c = if select.scene() == Some(index) {
@ -554,7 +537,7 @@ pub fn view_scene_name (
} else { } else {
scene.color.base.term scene.color.base.term
}; };
wh_exact(Some(20), Some(h), bg(c, origin_nw(south(a, b)))) wh_exact(Some(20), Some(h), bg(c, align_nw(south(a, b))))
} }
pub fn view_midi_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<Tui> { pub fn view_midi_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<Tui> {
@ -590,21 +573,21 @@ pub fn view_per_track () -> impl Draw<Tui> {}
pub fn view_per_track_top () -> impl Draw<Tui> {} pub fn view_per_track_top () -> impl Draw<Tui> {}
pub fn view_inputs (tracks: impl TracksSizes<'_>, midi_ins: &[MidiInput]) -> impl Draw<Tui> { pub fn view_inputs (tracks: impl TracksSizes<'_>, midi_ins: &[MidiInput]) -> impl Draw<Tui> {
let title_1 = wh_exact(Some(20), Some(1), origin_w(button_3("i", "nput ", format!("{}", midi_ins.len()), false))); let title_1 = wh_exact(Some(20), Some(1), align_w(button_3("i", "nput ", format!("{}", midi_ins.len()), false)));
let title_2 = wh_exact(Some(4), Some(1), w_exact(4, button_2("I", "+", false))); let title_2 = wh_exact(Some(4), Some(1), w_exact(4, button_2("I", "+", false)));
east(title_1, west(title_2, thunk(move|to: &mut Tui|{ east(title_1, west(title_2, thunk(move|to: &mut Tui|{
for (_index, track, x1, _x2) in tracks { for (_index, track, x1, _x2) in tracks {
south( south(
x_push(x1 as u16, bg(track.color.dark.term, origin_w(w_exact(track.width as u16, east!( x_push(x1 as u16, bg(track.color.dark.term, align_w(w_exact(track.width as u16, east!(
either(track.sequencer.monitoring, fg(Green, "mon "), "mon "), either(track.sequencer.monitoring, fg(Green, "mon "), "mon "),
either(track.sequencer.recording, fg(Red, "rec "), "rec "), either(track.sequencer.recording, fg(Red, "rec "), "rec "),
either(track.sequencer.overdub, fg(Yellow, "dub "), "dub "), either(track.sequencer.overdub, fg(Yellow, "dub "), "dub "),
))))), ))))),
thunk(move |to: &mut Tui|{ thunk(move |to: &mut Tui|{
for (index, port) in midi_ins.iter().enumerate() { for (index, port) in midi_ins.iter().enumerate() {
x_push(index as u16 * 10, h_exact(1, east(w_exact(20, origin_w(east("", bold(true, fg(Rgb(255,255,255), port.port_name()))))), x_push(index as u16 * 10, h_exact(1, east(w_exact(20, align_w(east("", bold(true, fg(Rgb(255,255,255), port.port_name()))))),
west(w_exact(4, ()), thunk(move|to: &mut Tui|{ west(w_exact(4, ()), thunk(move|to: &mut Tui|{
bg(track.color.darker.term, origin_w(w_exact(track.width as u16, east!( bg(track.color.darker.term, align_w(w_exact(track.width as u16, east!(
either(track.sequencer.monitoring, fg(Green, ""), " · "), either(track.sequencer.monitoring, fg(Green, ""), " · "),
either(track.sequencer.recording, fg(Red, ""), " · "), either(track.sequencer.recording, fg(Red, ""), " · "),
either(track.sequencer.overdub, fg(Yellow, ""), " · "), either(track.sequencer.overdub, fg(Yellow, ""), " · "),
@ -628,18 +611,18 @@ pub fn view_outputs (
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
let list = south( let list = south(
h_exact(1, w_full(origin_w(button_3( h_exact(1, w_full(align_w(button_3(
"o", "utput", format!("{}", midi_outs.len()), false "o", "utput", format!("{}", midi_outs.len()), false
)))), )))),
h_exact(height - 1, wh_full(origin_nw(thunk(|to: &mut Tui|{ h_exact(height - 1, wh_full(align_nw(thunk(|to: &mut Tui|{
for (_index, port) in midi_outs.iter().enumerate() { for (_index, port) in midi_outs.iter().enumerate() {
h_exact(1,w_full(east( h_exact(1,w_full(east(
origin_w(east("", fg(Rgb(255,255,255), bold(true, port.port_name())))), align_w(east("", fg(Rgb(255,255,255), bold(true, port.port_name())))),
w_full(origin_e(format!("{}/{} ", w_full(align_e(format!("{}/{} ",
port.port().get_connections().len(), port.port().get_connections().len(),
port.connections.len())))))).draw(to)?; port.connections.len())))))).draw(to)?;
for (index, conn) in port.connections.iter().enumerate() { for (index, conn) in port.connections.iter().enumerate() {
h_exact(1, w_full(origin_w(format!(" c{index:02}{}", conn.info())))) h_exact(1, w_full(align_w(format!(" c{index:02}{}", conn.info()))))
.draw(to)?; .draw(to)?;
} }
} }
@ -648,17 +631,17 @@ pub fn view_outputs (
); );
h_exact(height, view_track_row_section(theme, list, button_2("O", "+", false), h_exact(height, view_track_row_section(theme, list, button_2("O", "+", false),
bg(theme.darker.term, origin_w(w_full( bg(theme.darker.term, align_w(w_full(
thunk(|to: &mut Tui|{ thunk(|to: &mut Tui|{
for (index, track, _x1, _x2) in tracks { for (index, track, _x1, _x2) in tracks {
w_exact(track_width(index, track), w_exact(track_width(index, track),
thunk(|to: &mut Tui|{ thunk(|to: &mut Tui|{
h_exact(1, origin_w(east( h_exact(1, align_w(east(
either(true, fg(Green, "play "), "play "), either(true, fg(Green, "play "), "play "),
either(false, fg(Yellow, "solo "), "solo "), either(false, fg(Yellow, "solo "), "solo "),
))).draw(to)?; ))).draw(to)?;
for (_index, port) in midi_outs.iter().enumerate() { for (_index, port) in midi_outs.iter().enumerate() {
h_exact(1, origin_w(east( h_exact(1, align_w(east(
either(true, fg(Green, ""), " · "), either(true, fg(Green, ""), " · "),
either(false, fg(Yellow, ""), " · "), either(false, fg(Yellow, ""), " · "),
))).draw(to)?; ))).draw(to)?;
@ -688,12 +671,12 @@ pub fn view_track_devices (
iter_once(tracks, move|(_, track, _x1, _x2), index| wh_exact( iter_once(tracks, move|(_, track, _x1, _x2), index| wh_exact(
Some(track_width(index, track)), Some(track_width(index, track)),
Some(h + 1), Some(h + 1),
bg(track.color.dark.term, origin_nw(iter_south(move||0..h, bg(track.color.dark.term, align_nw(iter_south(move||0..h,
|_, _index|wh_exact(Some(track.width as u16), Some(2), |_, _index|wh_exact(Some(track.width as u16), Some(2),
fg_bg( fg_bg(
ItemTheme::G[32].lightest.term, ItemTheme::G[32].lightest.term,
ItemTheme::G[32].dark.term, ItemTheme::G[32].dark.term,
origin_nw(format!(" · {}", "--")) align_nw(format!(" · {}", "--"))
) )
))))))) )))))))
} }
@ -702,14 +685,14 @@ pub fn per_track <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> (
tracks: impl Fn() -> U + Send + Sync + 'a, tracks: impl Fn() -> U + Send + Sync + 'a,
callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Draw<Tui> + 'a { ) -> impl Draw<Tui> + 'a {
per_track_top(tracks, move|index, track|h_full(origin_y(callback(index, track)))) per_track_top(tracks, move|index, track|h_full(align_y(callback(index, track))))
} }
pub fn per_track_top <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> ( pub fn per_track_top <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> (
tracks: impl Fn() -> U + Send + Sync + 'a, tracks: impl Fn() -> U + Send + Sync + 'a,
callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Draw<Tui> + 'a { ) -> impl Draw<Tui> + 'a {
origin_x(bg(Reset, iter_east(tracks, align_x(bg(Reset, iter_east(tracks,
move|(index, track, x1, x2): (usize, &'a Track, usize, usize), _|{ move|(index, track, x1, x2): (usize, &'a Track, usize, usize), _|{
w_exact((x2 - x1) as u16, fg_bg( w_exact((x2 - x1) as u16, fg_bg(
track.color.lightest.term, track.color.lightest.term,
@ -732,14 +715,14 @@ pub fn view_sessions () -> impl Draw<Tui> {
let b = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) }; let b = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) };
let y = (2 * index) as u16; let y = (2 * index) as u16;
let h = 2; let h = 2;
y_push(y, h_exact(h, w_full(bg(b, origin_w(fg(f, *name)))))).draw(to)?; y_push(y, h_exact(h, w_full(bg(b, align_w(fg(f, *name)))))).draw(to)?;
} }
Ok(to.area().into()) Ok(Some(to.area().into()))
}))) })))
} }
pub fn view_browse_title (state: &App) -> impl Draw<Tui> { pub fn view_browse_title (state: &App) -> impl Draw<Tui> {
w_full(origin_w(field_v(ItemTheme::default(), w_full(align_w(field_v(ItemTheme::default(),
match state.dialog.browser_target().unwrap() { match state.dialog.browser_target().unwrap() {
BrowseTarget::SaveProject => "Save project:", BrowseTarget::SaveProject => "Save project:",
BrowseTarget::LoadProject => "Load project:", BrowseTarget::LoadProject => "Load project:",

View file

@ -6,7 +6,7 @@ pub(crate) use ::xdg::BaseDirectories;
pub(crate) use ::midly::{Smf, TrackEventKind, MidiMessage, Error as MidiError, num::*, live::*}; pub(crate) use ::midly::{Smf, TrackEventKind, MidiMessage, Error as MidiError, num::*, live::*};
pub(crate) use tengri::{ pub(crate) use tengri::{
*, lang::*, exit::*, eval::*, sing::*, time::*, draw::*, term::*, color::*, task::*, *, lang::*,
crossterm::event::{Event, KeyEvent}, crossterm::event::{Event, KeyEvent},
ratatui::{ ratatui::{
self, self,

View file

@ -1,7 +1,6 @@
use crate::*; use crate::*;
use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}}; use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}};
use ::atomic_float::AtomicF64; use ::atomic_float::AtomicF64;
use ::tengri::{draw::*, term::*};
/// A point in time in all time scales (microsecond, sample, MIDI pulse) /// A point in time in all time scales (microsecond, sample, MIDI pulse)
/// ///

View file

@ -1,7 +1,6 @@
use crate::*; use crate::*;
use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}}; use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}};
use ::atomic_float::AtomicF64; use ::atomic_float::AtomicF64;
use ::tengri::{draw::*, term::*};
/// Iterator that emits subsequent ticks within a range. /// Iterator that emits subsequent ticks within a range.
/// ///

View file

@ -1,7 +1,6 @@
use crate::*; use crate::*;
use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}}; use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}};
use ::atomic_float::AtomicF64; use ::atomic_float::AtomicF64;
use ::tengri::{draw::*, term::*};
/// Temporal resolutions: sample rate, tempo, MIDI pulses per quaver (beat) /// Temporal resolutions: sample rate, tempo, MIDI pulses per quaver (beat)
/// ///

View file

@ -156,7 +156,7 @@ impl PianoHorizontal {
} }
} }
} }
Ok(xywh) Ok(Some(xywh))
}) })
} }
@ -190,7 +190,7 @@ impl PianoHorizontal {
break break
} }
} }
Ok(xywh) Ok(Some(xywh))
}) })
} }
@ -217,7 +217,7 @@ impl PianoHorizontal {
to.blit(&note_pitch_to_name(note), x, screen_y, off_style) to.blit(&note_pitch_to_name(note), x, screen_y, off_style)
}; };
} }
Ok(xywh) Ok(Some(xywh))
}))) })))
} }
@ -233,7 +233,7 @@ impl PianoHorizontal {
to.blit(&"|", screen_x, y, style); to.blit(&"|", screen_x, y, style);
} }
} }
Ok(xywh) Ok(Some(xywh))
}))) })))
} }
} }

View file

@ -11,8 +11,7 @@ pub struct Log10Meter(pub f32);
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct RmsMeter(pub f32); pub struct RmsMeter(pub f32);
impl Draw<Tui> for RmsMeter { impl_draw!(|self: RmsMeter, to: Tui|{
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
let XYWH(x, y, w, h) = to.area().into(); let XYWH(x, y, w, h) = to.area().into();
let signal = f32::max(0.0, f32::min(100.0, self.0.abs())); let signal = f32::max(0.0, f32::min(100.0, self.0.abs()));
let v = (signal * h as f32).ceil() as u16; let v = (signal * h as f32).ceil() as u16;
@ -23,12 +22,10 @@ impl Draw<Tui> for RmsMeter {
to.blit(&"", x, y2.saturating_sub(y), Some(Style::default().green())); to.blit(&"", x, y2.saturating_sub(y), Some(Style::default().green()));
} }
} }
Ok(to.area().into()) Ok(Some(to.area().into()))
} });
}
impl Draw<Tui> for Log10Meter { impl_draw!(|self: Log10Meter, to: Tui| {
fn draw(self, to: &mut Tui) -> Usually<XYWH<u16>> {
let XYWH(x, y, w, h) = to.area().into(); let XYWH(x, y, w, h) = to.area().into();
let signal = 100.0 - f32::max(0.0, f32::min(100.0, self.0.abs())); let signal = 100.0 - f32::max(0.0, f32::min(100.0, self.0.abs()));
let v = (signal * h as f32 / 100.0).ceil() as u16; let v = (signal * h as f32 / 100.0).ceil() as u16;
@ -39,9 +36,8 @@ impl Draw<Tui> for Log10Meter {
to.blit(&"", x, y2 - y, Some(Style::default().green())); to.blit(&"", x, y2 - y, Some(Style::default().green()));
} }
} }
Ok(to.area().into()) Ok(Some(to.area().into()))
} });
}
fn draw_meters (meters: &[f32]) -> impl Draw<Tui> + use<'_> { fn draw_meters (meters: &[f32]) -> impl Draw<Tui> + use<'_> {
bg(Black, w_exact(2, iter_east_fixed(1, ||meters.iter(), |value, _index|{ bg(Black, w_exact(2, iter_east_fixed(1, ||meters.iter(), |value, _index|{

View file

@ -314,7 +314,7 @@ fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_
}) })
.render(area, to.as_mut()); .render(area, to.as_mut());
} }
Ok(xywh) Ok(Some(xywh))
}) })
} }

View file

@ -12,6 +12,8 @@ use crate::{*, device::sampler::*};
pub _search: Option<String>, pub _search: Option<String>,
} }
impl_draw!(|self: SampleAdd, to: Tui|{ todo!() });
impl SampleAdd { impl SampleAdd {
fn exited (&self) -> bool { fn exited (&self) -> bool {
self.exited self.exited
@ -118,9 +120,3 @@ impl SampleAdd {
return Ok(false) return Ok(false)
} }
} }
impl Draw<Tui> for SampleAdd {
fn draw (self, _to: &mut Tui) -> Usually<XYWH<u16>> {
todo!()
}
}

2
tengri

@ -1 +1 @@
Subproject commit 0b9e9c06962e5cd55b639d9c0a7cef6f11405d81 Subproject commit 1f60b43f616ff49ddd8187bcca8d31e9b6597cec