From d8a767326cadb276183f388c3d3cc8d9244bb4d8 Mon Sep 17 00:00:00 2001 From: i do not exist Date: Tue, 7 Jul 2026 16:35:52 +0300 Subject: [PATCH] convert to layout suffixes --- src/app/draw.rs | 387 +++++++++++++++++++------------------ src/device/browse.rs | 18 +- src/device/editor.rs | 44 ++--- src/device/editor/piano.rs | 18 +- src/device/meter.rs | 6 +- tengri | 2 +- 6 files changed, 245 insertions(+), 230 deletions(-) diff --git a/src/app/draw.rs b/src/app/draw.rs index dd161ce0..f21fbba2 100644 --- a/src/app/draw.rs +++ b/src/app/draw.rs @@ -54,9 +54,9 @@ fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Drawn view_sessions().draw(to), Some(":browse/title") => view_browse_title(state).draw(to), Some(":device") => view_device(state).draw(to), - Some(":status") => h_exact(1, "TODO: Status Bar").draw(to), + Some(":status") => "TODO: Status Bar".exact_h(1).draw(to), Some(":editor") => "TODO Editor".draw(to), - Some(":debug") => h_exact(1, format!("[{:?}]", to.area())).draw(to), + Some(":debug") => format!("[{:?}]", to.area()).exact_h(1).draw(to), Some(_) => { let views = state.config.views.read().unwrap(); if let Some(dsl) = views.get(dsl.src()?.unwrap()) { @@ -73,8 +73,8 @@ fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Drawn) -> Drawn { match frags.next() { - Some("input") => bg(Rgb(30, 30, 30), h_full(align_s("Input Meters"))).draw(to), - Some("output") => bg(Rgb(30, 30, 30), h_full(align_s("Output Meters"))).draw(to), + Some("input") => bg(Rgb(30, 30, 30), align_s("Input Meters").full_h()).draw(to), + Some("output") => bg(Rgb(30, 30, 30), align_s("Output Meters").full_h()).draw(to), _ => panic!() } } @@ -82,10 +82,10 @@ pub fn draw_meter_section (to: &mut Tui, mut frags: std::str::Split<&str>) -> Dr pub fn draw_tracks (to: &mut Tui, mut frags: std::str::Split<&str>, state: &App) -> Drawn { match frags.next() { None => "TODO tracks".draw(to), - 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(align_w("Track Inputs"))).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(align_w("Track Outputs"))).draw(to), + Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), full_w(align_w("Track Names")))), + Some("inputs") => bg(Rgb(40, 40, 40), align_w("Track Inputs").full_w()).draw(to), + Some("devices") => bg(Rgb(40, 40, 40), align_w("Track Devices").full_w()).draw(to), + Some("outputs") => bg(Rgb(40, 40, 40), align_w("Track Outputs").full_w()).draw(to), _ => panic!() } } @@ -104,16 +104,15 @@ pub fn draw_dialog ( Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog { let items = items.clone(); let selected = selected; - Some(wh_full(thunk(move|to: &mut Tui|{ + Some(thunk(move|to: &mut Tui|{ for (index, MenuItem(item, _)) in items.0.iter().enumerate() { - y_push((2 * index) as u16,fg_bg( - if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) }, - if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) }, - h_exact(2, align_n(w_full(item))) - )).draw(to)?; + let f = if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) }; + let b = if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) }; + fg_bg(f, b, align_n(item.full_w()).exact_h(2)) + .push_y((2 * index) as u16).draw(to)?; } Ok(Some(to.area().into())) - }))) + }).full_wh()) } else { None }.draw(to), @@ -123,7 +122,7 @@ pub fn draw_dialog ( pub fn draw_templates (to: &mut Tui, frags: std::str::Split<&str>, state: &App) -> Drawn { let height = (state.config.modes.len() * 2) as u16; - h_exact(height, w_min(Some(30), thunk(move |to: &mut Tui|{ + thunk(move |to: &mut Tui|{ let mut index = 0; state.config.modes.for_each(|id, profile| { let b = if index == 0 { Rgb(70,70,70) } else { Rgb(50,50,50) }; @@ -131,31 +130,28 @@ 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(""); let fg1 = Rgb(224, 192, 128); let fg2 = Rgb(224, 128, 32); - let field_name = w_full(align_w(fg(fg1, name))); - let field_id = w_full(align_e(fg(fg2, id))); - let field_info = w_full(align_w(info)); - let _ = y_push((2 * index) as u16, - h_exact(2, w_full(bg(b, south( - above(field_name, field_id), - field_info - ))))).draw(to); + let field_name = align_w(fg(fg1, name)).full_w(); + let field_id = align_e(fg(fg2, id)).full_w(); + let field_info = align_w(info).full_w(); + let _ = bg(b, south(above(field_name, field_id), field_info)) + .full_w().exact_h(2).push_y((2 * index) as u16).draw(to); index += 1; }); Ok(Some(to.area().into())) - }))).draw(to) + }).min_w(30).exact_h(height).draw(to) } /// ``` /// let _ = tek::view_logo(); /// ``` pub fn view_logo () -> impl Draw { - wh_exact(Some(32), Some(7), bold(true, fg(Rgb(240, 200, 180), south!{ - h_exact(1, ""), - h_exact(1, ""), - h_exact(1, "~~ ╓─╥─╖ ╓──╖ ╥ ╖ ~~~~~~~~~~~~"), - h_exact(1, east("~~~~ ║ ~ ╟─╌ ~╟─< ~~ ", east(fg(Rgb(230,100,40), "v0.3.0"), " ~~"))), - h_exact(1, "~~~~ ╨ ~ ╙──╜ ╨ ╜ ~~~~~~~~~~~~"), - }))) + bold(true, fg(Rgb(240, 200, 180), south!{ + "".exact_h(1), + "".exact_h(1), + "~~ ╓─╥─╖ ╓──╖ ╥ ╖ ~~~~~~~~~~~~".exact_h(1), + east("~~~~ ║ ~ ╟─╌ ~╟─< ~~ ", east(fg(Rgb(230,100,40), "v0.3.0"), " ~~")).exact_h(1), + "~~~~ ╨ ~ ╙──╜ ╨ ╜ ~~~~~~~~~~~~".exact_h(1), + })).exact_wh(32, 7) } /// ``` @@ -166,12 +162,12 @@ pub fn view_logo () -> impl Draw { pub fn view_transport (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw { let theme = ItemTheme::G[96]; bg(Black, east!(above( - wh_full(align_w(button_play_pause(play, false))), - wh_full(align_e(east!( + align_w(button_play_pause(play, false)).full_wh(), + align_e(east!( field_h(theme, "BPM", bpm), field_h(theme, "Beat", beat), field_h(theme, "Time", time), - ))) + )).full_wh() ))) } @@ -186,8 +182,8 @@ pub fn view_status (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl D let buf = field_h(theme, "Buf", buf); let lat = field_h(theme, "Lat", lat); bg(Black, east!(above( - wh_full(align_w(sel.map(|sel|field_h(theme, "Selected", sel)))), - wh_full(align_e(east!(sr, buf, lat))), + align_w(sel.map(|sel|field_h(theme, "Selected", sel))).full_wh(), + align_e(east!(sr, buf, lat)).full_wh(), ))) } @@ -200,14 +196,14 @@ pub fn view_status (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl D pub fn button_play_pause (playing: bool, compact: bool) -> impl Draw { bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) }, either(compact, - thunk(move|to: &mut Tui|w_exact(9, either(playing, + thunk(move|to: &mut Tui|either(playing, fg(Rgb(0, 255, 0), " PLAYING "), - fg(Rgb(255, 128, 0), " STOPPED ")) - ).draw(to)), - thunk(move|to: &mut Tui|w_exact(5, either(playing, + fg(Rgb(255, 128, 0), " STOPPED "), + ).exact_w(9).draw(to)), + thunk(move|to: &mut Tui|either(playing, fg(Rgb(0, 255, 0), south(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)), - fg(Rgb(255, 128, 0), south(" ▗▄▖ ", " ▝▀▘ ",))) - ).draw(to)), + fg(Rgb(255, 128, 0), south(" ▗▄▖ ", " ▝▀▘ ",)), + ).exact_w(5).draw(to)), ) ) } @@ -218,8 +214,13 @@ pub fn button_play_pause (playing: bool, compact: bool) -> impl Draw { button_add: impl Draw, content: impl Draw, ) -> impl Draw { - west(h_full(w_exact(4, align_nw(button_add))), - east(w_exact(20, h_full(align_nw(button))), wh_full(align_c(content)))) + west( + align_nw(button_add).exact_w(4).full_h(), + east( + align_nw(button).full_h().exact_w(20), + align_c(content).full_wh() + ) + ) } /// ``` @@ -228,8 +229,8 @@ pub fn button_play_pause (playing: bool, compact: bool) -> impl Draw { /// let _ = tek::view_wrap(bg, fg, "and then blue, too!"); /// ``` pub fn view_wrap (bg: Color, fg: Color, content: impl Draw) -> impl Draw { - let left = fg_bg(bg, Reset, w_exact(1, y_repeat("▐"))); - let right = fg_bg(bg, Reset, w_exact(1, y_repeat("▌"))); + let left = fg_bg(bg, Reset, y_repeat("▐").exact_w(1)); + let right = fg_bg(bg, Reset, y_repeat("▌").exact_w(1)); east(left, west(right, fg_bg(fg, bg, content))) } @@ -256,7 +257,7 @@ pub fn view_meter <'a> (label: &'a str, value: f32) -> impl Draw + 'a { let c = if value >= 0.0 { Red } else if value >= -3.0 { Yellow } else { Green }; - south!(f, wh_exact(Some(w), Some(1), bg(c, ()))) + south!(f, bg(c, ()).exact_wh(w, 1)) } pub fn view_meters (values: &[f32;2]) -> impl Draw + use<'_> { @@ -284,14 +285,14 @@ pub fn view_sample_info_v (sample: Option<&Arc>>) -> impl Draw>>) -> impl Draw) -> impl Draw { - w_exact(12, bg(theme.darker.term, w_full(align_e(content)))) + bg(theme.darker.term, align_e(content).full_w()).exact_w(12) } pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, ports: &'a [T]) @@ -322,22 +323,22 @@ pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, po let ins = ports.len() as u16; let frame = Outer(true, Style::default().fg(g(96))); let iter = move||ports.iter(); - let names = iter_south(iter, move|port, index|h_full(align_w(format!(" {index} {}", port.port_name())))); + let names = iter_south(iter, move|port, index|align_w(format!(" {index} {}", port.port_name())).full_h()); 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))) + border(true, frame, field.exact_wh(20, 1 + ins)).exact_wh(20, 1 + ins) } pub fn view_io_ports <'a, T: PortsSizes<'a>> ( fg: Color, bg: Color, items: impl Fn()->T + Send + Sync + 'a ) -> impl Draw + 'a { type Item<'a> = (usize, &'a Arc, &'a [Connect], usize, usize); - iter(items, move|(_index, name, connections, y, y2): Item<'a>, _| { - y_push(y as u16, h_exact((y2-y) as u16, - south(h_full(bold(true, fg_bg(fg, bg, align_w(east(" 󰣲 ", name))))), - iter(||connections.iter(), move|connect: &'a Connect, index|y_push( - index as u16, h_exact(1, align_w(bold(false, fg_bg(fg, bg, &connect.info)))) - ))))) - }) + iter(items, + move|(_index, name, connections, y, y2): Item<'a>, _| south( + bold(true, fg_bg(fg, bg, align_w(east(" 󰣲 ", name)))).full_h(), + iter(||connections.iter(), move|connect: &'a Connect, index|{ + align_w(bold(false, fg_bg(fg, bg, &connect.info)).exact_h(1)).push_y(index as u16) + }) + ).exact_h((y2 - y) as u16).push_y(y as u16)) } pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> ( @@ -348,7 +349,7 @@ pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> ( size: &Sizer, editing: bool, ) -> impl Draw { - let status = wh_full(align_se(fg(Green, format!("{}x{}", size.w(), size.h())))); + let status = align_se(fg(Green, format!("{}x{}", size.w(), size.h()))).full_wh(); let tracks = iter_once(tracks, move|(track_index, track, _, _), _| { let scenes = iter_once(scenes(), move|(scene_index, scene, _, _), _| { let (name, theme): (Arc, ItemTheme) = scene_name_theme(scene, track_index); @@ -357,19 +358,21 @@ pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> ( let w = scene_w(track, select, track_index, editor); let y = scene_y(select, scene_index, editor); let is_selected = scene_sel(select, track_index, scene_index, editing); - wh_exact(Some(w), Some(y), below( - wh_full(Outer(true, Style::default().fg(o))), - wh_full(below( + below( + Outer(true, Style::default().fg(o)).full_wh(), + below( below( - fg_bg(o, b, wh_full("")), - wh_full(align_nw(fg_bg(f, b, bold(true, name)))), + fg_bg(o, b, "".full_wh()), + align_nw(fg_bg(f, b, bold(true, name))).full_wh(), ), - wh_full(when(is_selected, editor.map(|e|e.view()))))))) + when(is_selected, editor.map(|e|e.view())).full_wh() + ).full_wh() + ).exact_wh(w, y) }); - w_exact(track.width as u16, h_full(scenes)) + scenes.full_h().exact_w(track.width as u16) }); - return size.of(wh_full(above(status, tracks))); + return size.of(above(status, tracks).full_wh()); fn scene_name_theme (scene: &Scene, track_index: usize) -> (Arc, ItemTheme) { if let Some(Some(clip)) = &scene.clips.get(track_index) { @@ -436,42 +439,48 @@ pub fn view_track_names ( button_2("T", "+", false), button_2("S", "+", false)); view_track_row_section(theme, button, button_2, bg(theme.darker.term, - h_exact(2, thunk(|to: &mut Tui|{ + thunk(|to: &mut Tui|{ for (index, track, x1, _x2) in tracks { - x_push(x1 as u16, w_exact(track_width(index, track), - bg(if selected.track() == Some(index) { - track.color.light.term - } else { - track.color.base.term - }, south(w_full(align_nw(east( - format!("·t{index:02} "), - fg(Rgb(255, 255, 255), bold(true, &track.name)) - ))), ""))) ).draw(to)?; + let b = if selected.track() == Some(index) { + track.color.light.term + } else { + track.color.base.term + }; + bg(b, south(align_nw(east( + format!("·t{index:02} "), + fg(Rgb(255, 255, 255), bold(true, &track.name)) + )).full_w(), "")) + .exact_w(track_width(index, track)) + .push_x(x1 as u16) + .draw(to)?; } Ok(Some(XYWH(0, 0, 0, 0))) - })))) + }).exact_h(2))) } pub fn view_track_outputs ( theme: ItemTheme, tracks: impl TracksSizes<'_>, midi_outs: impl Iterator, ) -> impl Draw { view_track_row_section(theme, - south(w_full(align_w(button_2("o", "utput", false))), + south(align_w(button_2("o", "utput", false)).full_w(), thunk(|to: &mut Tui|{ for port in midi_outs { - w_full(align_w(port.port_name())).draw(to); + align_w(port.port_name()).full_w().draw(to); } Ok(Some(XYWH(0, 0, 0, 0))) })), button_2("O", "+", false), bg(theme.darker.term, align_w(thunk(|to: &mut Tui|{ for (index, track, _x1, _x2) in tracks { + let f = Rgb(255, 255, 255); + let b = track.color.dark.term; let iter = ||track.sequencer.midi_outs.iter(); - let draw = |port: &MidiOutput, _|fg(Rgb(255, 255, 255), - h_exact(1, bg(track.color.dark.term, w_full(align_w( - format!("·o{index:02} {}", port.port_name())))))); - w_exact(track_width(index, track), - align_nw(h_full(iter_south(iter, draw)))).draw(to)?; + let draw = |port: &MidiOutput, _|fg(f, bg(b, align_w( + format!("·o{index:02} {}", port.port_name()).full_w() + )).exact_h(1)); + align_nw(iter_south(iter, draw).full_h()) + .exact_w(track_width(index, track)) + .draw(to)?; } Ok(Some(XYWH(0, 0, 0, 0))) })))) @@ -483,18 +492,17 @@ pub fn view_track_inputs ( view_track_row_section(theme, button_2("i", "nput", false), button_2("I", "+", false), bg(theme.darker.term, align_w(thunk(move|to: &mut Tui|{ for (index, track, _x1, _x2) in tracks { - wh_exact(Some(track_width(index, track)), Some(height + 1), - align_nw(south( - bg(track.color.base.term, - w_full(align_w(east!( - either(track.sequencer.monitoring, fg(Green, "●mon "), "·mon "), - either(track.sequencer.recording, fg(Red, "●rec "), "·rec "), - either(track.sequencer.overdub, fg(Yellow, "●dub "), "·dub "), - )))), - iter_south(||track.sequencer.midi_ins.iter(), - |port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term, - w_full(align_w(format!("·i{index:02} {}", port.port_name())))))))) - .draw(to)?; + align_nw(south( + bg(track.color.base.term, + align_w(east!( + either(track.sequencer.monitoring, fg(Green, "●mon "), "·mon "), + either(track.sequencer.recording, fg(Red, "●rec "), "·rec "), + either(track.sequencer.overdub, fg(Yellow, "●dub "), "·dub "), + )).full_w()), + iter_south(||track.sequencer.midi_ins.iter(), + |port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term, + align_w(format!("·i{index:02} {}", port.port_name())).full_w())) + )).exact_wh(track_width(index, track), height + 1).draw(to)?; } Ok(Some(XYWH(0, 0, 0, 0))) })))) @@ -506,12 +514,12 @@ pub fn view_scenes_names ( editor: Option<&MidiEditor>, editing: bool, ) -> impl Draw { - w_exact(20, thunk(move |to: &mut Tui|{ + thunk(move |to: &mut Tui|{ for (index, scene, ..) in scenes { view_scene_name(select, editor, index, scene, editing).draw(to)?; } Ok(Some(XYWH(1, 1, 1, 1))) - })) + }).exact_w(20) } pub fn view_scene_name ( @@ -526,18 +534,18 @@ pub fn view_scene_name ( } else { H_SCENE as u16 }; - let a = w_full(align_w(east(format!("·s{index:02} "), - fg(g(255), bold(true, &scene.name))))); - let b = when(select.scene() == Some(index) && editing, - wh_full(align_nw(south( - editor.as_ref().map(|e|e.clip_status()), - editor.as_ref().map(|e|e.edit_status()))))); + let a = align_w(east(format!("·s{index:02} "), + fg(g(255), bold(true, &scene.name)))).full_w(); + let b = when(select.scene() == Some(index) && editing, align_nw(south( + editor.as_ref().map(|e|e.clip_status()), + editor.as_ref().map(|e|e.edit_status()))).full_wh()); let c = if select.scene() == Some(index) { scene.color.light.term } else { scene.color.base.term }; - wh_exact(Some(20), Some(h), bg(c, align_nw(south(a, b)))) + bg(c, align_nw(south(a, b))) + .exact_wh(20, h) } pub fn view_midi_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw { @@ -561,10 +569,11 @@ pub fn view_track_per <'a, T: Draw + 'a, U: TracksSizes<'a>> ( callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a ) -> impl Draw { iter_east(tracks, move|(index, track, x1, x2): (usize, &Track, usize, usize), _|{ - w_exact((x2 - x1) as u16, fg_bg( + fg_bg( track.color.lightest.term, track.color.base.term, - callback(index, track))) + callback(index, track) + ).exact_w((x2 - x1) as u16) }) } @@ -573,27 +582,34 @@ pub fn view_per_track () -> impl Draw {} pub fn view_per_track_top () -> impl Draw {} pub fn view_inputs (tracks: impl TracksSizes<'_>, midi_ins: &[MidiInput]) -> impl Draw { - 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_1 = align_w(button_3("i", "nput ", format!("{}", midi_ins.len()), false)).exact_wh(20, 1); + let title_2 = button_2("I", "+", false).exact_wh(4, 1); east(title_1, west(title_2, thunk(move|to: &mut Tui|{ for (_index, track, x1, _x2) in tracks { south( - x_push(x1 as u16, bg(track.color.dark.term, align_w(w_exact(track.width as u16, east!( + bg(track.color.dark.term, align_w(east!( either(track.sequencer.monitoring, fg(Green, "mon "), "mon "), either(track.sequencer.recording, fg(Red, "rec "), "rec "), either(track.sequencer.overdub, fg(Yellow, "dub "), "dub "), - ))))), + ).exact_w(track.width as u16))).push_x(x1 as u16), thunk(move |to: &mut Tui|{ for (index, port) in midi_ins.iter().enumerate() { - 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|{ - bg(track.color.darker.term, align_w(w_exact(track.width as u16, east!( - either(track.sequencer.monitoring, fg(Green, " ● "), " · "), - either(track.sequencer.recording, fg(Red, " ● "), " · "), - either(track.sequencer.overdub, fg(Yellow, " ● "), " · "), - )))).draw(to); - todo!() - }))))).draw(to); + east( + align_w(east( + " ● ", + bold(true, fg(Rgb(255,255,255), port.port_name())) + )).exact_w(20), + west( + ().exact_w(4), + thunk(move|to: &mut Tui|{ + bg(track.color.darker.term, align_w(east!( + either(track.sequencer.monitoring, fg(Green, " ● "), " · "), + either(track.sequencer.recording, fg(Red, " ● "), " · "), + either(track.sequencer.overdub, fg(Yellow, " ● "), " · "), + ).exact_w(track.width as u16))).draw(to); + todo!() + })) + ).push_x(index as u16 * 10).exact_h(1).draw(to); } todo!() }) @@ -611,52 +627,47 @@ pub fn view_outputs ( ) -> impl Draw { let list = south( - h_exact(1, w_full(align_w(button_3( + align_w(button_3( "o", "utput", format!("{}", midi_outs.len()), false - )))), - h_exact(height - 1, wh_full(align_nw(thunk(|to: &mut Tui|{ + )).full_w().exact_h(1), + align_nw(thunk(|to: &mut Tui|{ for (_index, port) in midi_outs.iter().enumerate() { - h_exact(1,w_full(east( + east( align_w(east(" ● ", fg(Rgb(255,255,255), bold(true, port.port_name())))), - w_full(align_e(format!("{}/{} ", + align_e(format!("{}/{} ", port.port().get_connections().len(), - port.connections.len())))))).draw(to)?; + port.connections.len()) + ).full_w().exact_h(1)).full_w().draw(to)?; for (index, conn) in port.connections.iter().enumerate() { - h_exact(1, w_full(align_w(format!(" c{index:02}{}", conn.info())))) - .draw(to)?; + align_w(format!(" c{index:02}{}", conn.info())).full_w().exact_h(1).draw(to)?; } } todo!(); - })))) + })).full_wh().exact_h(height - 1) ); - h_exact(height, view_track_row_section(theme, list, button_2("O", "+", false), - bg(theme.darker.term, align_w(w_full( - thunk(|to: &mut Tui|{ - for (index, track, _x1, _x2) in tracks { - w_exact(track_width(index, track), - thunk(|to: &mut Tui|{ - h_exact(1, align_w(east( - either(true, fg(Green, "play "), "play "), - either(false, fg(Yellow, "solo "), "solo "), - ))).draw(to)?; - for (_index, port) in midi_outs.iter().enumerate() { - h_exact(1, align_w(east( - either(true, fg(Green, " ● "), " · "), - either(false, fg(Yellow, " ● "), " · "), - ))).draw(to)?; - for (_index, _conn) in port.connections.iter().enumerate() { - h_exact(1, w_full("")).draw(to)?; - } - } - todo!() - }) - ).draw(to); - } - todo!() - }) - ))) - )) + view_track_row_section(theme, list, button_2("O", "+", false), + bg(theme.darker.term, align_w(thunk(|to: &mut Tui|{ + for (index, track, _x1, _x2) in tracks { + thunk(|to: &mut Tui|{ + align_w(east( + either(true, fg(Green, "play "), "play "), + either(false, fg(Yellow, "solo "), "solo "), + )).exact_h(1).draw(to)?; + for (_index, port) in midi_outs.iter().enumerate() { + align_w(east( + either(true, fg(Green, " ● "), " · "), + either(false, fg(Yellow, " ● "), " · "), + )).exact_h(1).draw(to)?; + for (_index, _conn) in port.connections.iter().enumerate() { + "".full_w().exact_h(1).draw(to)?; + } + } + todo!() + }).exact_w(track_width(index, track)).draw(to); + } + todo!() + }).full_w()))).exact_h(height) } pub fn view_track_devices ( @@ -668,24 +679,25 @@ pub fn view_track_devices ( view_track_row_section(theme, button_3("d", "evice", format!("{}", track.map(|t|t.devices.len()).unwrap_or(0)), false), button_2("D", "+", false), - iter_once(tracks, move|(_, track, _x1, _x2), index| wh_exact( - Some(track_width(index, track)), - Some(h + 1), - bg(track.color.dark.term, align_nw(iter_south(move||0..h, - |_, _index|wh_exact(Some(track.width as u16), Some(2), - fg_bg( - ItemTheme::G[32].lightest.term, - ItemTheme::G[32].dark.term, - align_nw(format!(" · {}", "--")) - ) - ))))))) + iter_once(tracks, move|(_, track, _x1, _x2), index|bg( + track.color.dark.term, + align_nw(iter_south(move||0..h, + |_, _index|fg_bg( + ItemTheme::G[32].lightest.term, + ItemTheme::G[32].dark.term, + align_nw(format!(" · {}", "--")) + ).exact_wh(track.width as u16, 2) + ))).exact_wh( + Some(track_width(index, track)), + Some(h + 1), + ))) } pub fn per_track <'a, T: Draw + 'a, U: TracksSizes<'a>> ( tracks: impl Fn() -> U + Send + Sync + 'a, callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a ) -> impl Draw + 'a { - per_track_top(tracks, move|index, track|h_full(align_y(callback(index, track)))) + per_track_top(tracks, move|index, track|align_y(callback(index, track).full_h())) } pub fn per_track_top <'a, T: Draw + 'a, U: TracksSizes<'a>> ( @@ -694,10 +706,12 @@ pub fn per_track_top <'a, T: Draw + 'a, U: TracksSizes<'a>> ( ) -> impl Draw + 'a { align_x(bg(Reset, iter_east(tracks, move|(index, track, x1, x2): (usize, &'a Track, usize, usize), _|{ - w_exact((x2 - x1) as u16, fg_bg( + fg_bg( track.color.lightest.term, track.color.base.term, - callback(index, track))) }))) + callback(index, track) + ).exact_w((x2 - x1) as u16) + }))) } pub fn field_h (theme: ItemTheme, head: impl Draw, body: impl Draw) -> impl Draw { @@ -710,19 +724,19 @@ pub fn view_sessions () -> impl Draw { let h = 6; let w = Some(30); let f = Rgb(224, 192, 128); - h_exact(h, w_min(w, thunk(move |to: &mut Tui|{ + thunk(move |to: &mut Tui|{ for (index, name) in ["session1", "session2", "session3"].iter().enumerate() { let b = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) }; let y = (2 * index) as u16; let h = 2; - y_push(y, h_exact(h, w_full(bg(b, align_w(fg(f, *name)))))).draw(to)?; + bg(b, align_w(fg(f, *name))).full_w().exact_h(h).push_y(y).draw(to)?; } Ok(Some(to.area().into())) - }))) + }).min_w(w).exact_h(h) } pub fn view_browse_title (state: &App) -> impl Draw { - w_full(align_w(field_v(ItemTheme::default(), + align_w(field_v(ItemTheme::default(), match state.dialog.browser_target().unwrap() { BrowseTarget::SaveProject => "Save project:", BrowseTarget::LoadProject => "Load project:", @@ -730,8 +744,8 @@ pub fn view_browse_title (state: &App) -> impl Draw { BrowseTarget::ExportSample(_) => "Export sample:", BrowseTarget::ImportClip(_) => "Import clip:", BrowseTarget::ExportClip(_) => "Export clip:", - }, h_exact(1, fg(g(96), x_repeat("🭻"))) - ))) + }, fg(g(96), x_repeat("🭻")).exact_h(1) + )).full_w() } pub fn view_device (state: &App) -> impl Draw { @@ -742,5 +756,6 @@ pub fn view_device (state: &App) -> impl Draw { let b = if i == selected { Rgb(64,128,32) } else { Rgb(0,0,0) }; let l = if i == selected { "[ " } else { " " }; let r = if i == selected { " ]" } else { " " }; - w_full(bg(b, east(l, west(r, "FIXME device name")))) })) + bg(b, east(l, west(r, "FIXME device name"))).full_w() + })) } diff --git a/src/device/browse.rs b/src/device/browse.rs index f8a196b8..5210a81a 100644 --- a/src/device/browse.rs +++ b/src/device/browse.rs @@ -241,7 +241,7 @@ impl<'a> PoolView<'a> { //let on_bg = |x|x;//below(Repeat(" "), bg(color.darkest.term, x)); //let border = |x|x;//Outer(Style::default().fg(color.dark.term).bg(color.darkest.term)).enclose(x); //let height = pool.clips.read().unwrap().len() as u16; - w_exact(20, h_full(origin_n(iter( + origin_n(iter( ||pool.clips().clone().into_iter(), move|clip: Arc>, i: usize|{ let MidiClip { ref name, color, length, .. } = *clip.read().unwrap(); @@ -252,13 +252,13 @@ impl<'a> PoolView<'a> { let f = color.lightest.term; let name = if false { format!(" {i:>3}") } else { format!(" {i:>3} {name}") }; let length = if false { String::default() } else { format!("{length} ") }; - h_exact(1, bg(b, below!( - w_full(origin_w(fg(f, bold(selected, name)))), - w_full(origin_e(fg(f, bold(selected, length)))), - w_full(origin_w(when(selected, bold(true, fg(g(255), "▶"))))), - w_full(origin_e(when(selected, bold(true, fg(g(255), "◀"))))), - ))) - })))) + bg(b, below!( + origin_w(fg(f, bold(selected, name))).full_w(), + origin_e(fg(f, bold(selected, length))).full_w(), + origin_w(when(selected, bold(true, fg(g(255), "▶")))).full_w(), + origin_e(when(selected, bold(true, fg(g(255), "◀")))).full_w(), + )).exact_h(1) + })).full_h().exact_w(20) } } @@ -315,7 +315,7 @@ impl Browse { impl Browse { fn tui (&self) -> impl Draw { - let item = |entry, _index|w_full(origin_w(entry)); + let item = |entry, _index|origin_w(entry).full_w(); let iterate = ||EntriesIterator { offset: 0, index: 0, diff --git a/src/device/editor.rs b/src/device/editor.rs index 80133a4d..31000a45 100644 --- a/src/device/editor.rs +++ b/src/device/editor.rs @@ -98,17 +98,14 @@ impl MidiEditor { let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { (clip.color, clip.name.clone(), clip.length, clip.looped) } else { (ItemTheme::G[64], String::new().into(), 0, false) }; - w_exact(20, south!( - w_full(origin_w(east( - button_2("f2", "name ", false), - w_full(origin_e(fg(Rgb(255, 255, 255), format!("{name} "))))))), - w_full(origin_w(east( - button_2("l", "ength ", false), - w_full(origin_e(fg(Rgb(255, 255, 255), format!("{length} "))))))), - w_full(origin_w(east( - button_2("r", "epeat ", false), - w_full(origin_e(fg(Rgb(255, 255, 255), format!("{looped} "))))))), - )) + south!( + origin_w(east(button_2("f2", "name ", false), + origin_e(fg(Rgb(255, 255, 255), format!("{name} "))).full_w())).full_w(), + origin_w(east(button_2("l", "ength ", false), + origin_e(fg(Rgb(255, 255, 255), format!("{length} "))).full_w())).full_w(), + origin_w(east(button_2("r", "epeat ", false), + origin_e(fg(Rgb(255, 255, 255), format!("{looped} "))).full_w())).full_w(), + ).exact_w(20) } pub fn edit_status (&self) -> impl Draw + '_ { let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { @@ -121,20 +118,17 @@ impl MidiEditor { let note_name = format!("{:4}", note_pitch_to_name(note_pos)); let note_pos = format!("{:>3}", note_pos); let note_len = format!("{:>4}", self.get_note_len()); - w_exact(20, south!( - w_full(origin_w(east( - button_2("t", "ime ", false), - w_full(origin_e(fg(Rgb(255, 255, 255), - format!("{length} /{time_zoom} +{time_pos} "))))))), - w_full(origin_w(east( - button_2("z", "lock ", false), - w_full(origin_e(fg(Rgb(255, 255, 255), - format!("{time_lock}"))))))), - w_full(origin_w(east( - button_2("x", "note ", false), - w_full(origin_e(fg(Rgb(255, 255, 255), - format!("{note_name} {note_pos} {note_len}"))))))), - )) + south!( + origin_w(east(button_2("t", "ime ", false), + origin_e(fg(Rgb(255, 255, 255), + format!("{length} /{time_zoom} +{time_pos} "))).full_w())).full_w(), + origin_w(east(button_2("z", "lock ", false), + origin_e(fg(Rgb(255, 255, 255), + format!("{time_lock}"))).full_w())).full_w(), + origin_w(east(button_2("x", "note ", false), + origin_e(fg(Rgb(255, 255, 255), + format!("{note_name} {note_pos} {note_len}"))).full_w())).full_w(), + ).exact_w(20) } } diff --git a/src/device/editor/piano.rs b/src/device/editor/piano.rs index 4102953f..e3c4320a 100644 --- a/src/device/editor/piano.rs +++ b/src/device/editor/piano.rs @@ -27,8 +27,14 @@ impl_has!(Sizer: |self: PianoHorizontal| self.size); impl View for PianoHorizontal { fn view (&self) -> impl Draw { south( - east(w_exact(5, format!("{}x{}", self.size.w(), self.size.h())), self.timeline()), - east(self.keys(), self.size.of(below(wh_full(self.notes()), wh_full(self.cursor())))), + east( + format!("{}x{}", self.size.w(), self.size.h()).exact_w(5), + self.timeline() + ), + east( + self.keys(), + self.size.of(below(self.notes().full_wh(), self.cursor().full_wh())) + ), ) } } @@ -203,7 +209,7 @@ impl PianoHorizontal { let key_style = Some(Style::default().fg(Rgb(192, 192, 192)).bg(Rgb(0, 0, 0))); let off_style = Some(Style::default().fg(g(255))); let on_style = Some(Style::default().fg(Rgb(255,0,0)).bg(color.base.term).bold()); - h_full(w_exact(self.keys_width, thunk(move|to: &mut Tui|{ + thunk(move|to: &mut Tui|{ let xywh = to.area().into(); let XYWH(x, y0, _w, _h) = xywh; for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) { @@ -218,11 +224,11 @@ impl PianoHorizontal { }; } Ok(Some(xywh)) - }))) + }).exact_w(self.keys_width).full_h() } fn timeline (&self) -> impl Draw + '_ { - w_full(h_exact(1, thunk(move|to: &mut Tui|{ + thunk(move|to: &mut Tui|{ let xywh = to.area().into(); let XYWH(x, y, w, _h) = xywh; let style = Some(Style::default().dim()); @@ -234,7 +240,7 @@ impl PianoHorizontal { } } Ok(Some(xywh)) - }))) + }).exact_h(1).full_w() } } diff --git a/src/device/meter.rs b/src/device/meter.rs index e7c493ac..fc28c19a 100644 --- a/src/device/meter.rs +++ b/src/device/meter.rs @@ -40,9 +40,9 @@ impl_draw!(|self: Log10Meter, to: Tui| { }); fn draw_meters (meters: &[f32]) -> impl Draw + use<'_> { - bg(Black, w_exact(2, iter_east_fixed(1, ||meters.iter(), |value, _index|{ - h_full(RmsMeter(*value)) - }))) + bg(Black, iter_east_fixed(1, ||meters.iter(), |value, _index|{ + RmsMeter(*value).full_h() + }).exact_w(2)) } pub fn to_log10 (samples: &[f32]) -> f32 { diff --git a/tengri b/tengri index 1f60b43f..09463649 160000 --- a/tengri +++ b/tengri @@ -1 +1 @@ -Subproject commit 1f60b43f616ff49ddd8187bcca8d31e9b6597cec +Subproject commit 09463649c673b0d883ca18746a36aa86c6bd114f