use crate::*; /// A three-column layout. pub(crate) struct Tryptich { pub top: bool, pub h: u16, pub left: (u16, A), pub middle: (u16, B), pub right: (u16, C), } impl Tryptich<(), (), ()> { pub fn center (h: u16) -> Self { Self { h, top: false, left: (0, ()), middle: (0, ()), right: (0, ()) } } pub fn top (h: u16) -> Self { Self { h, top: true, left: (0, ()), middle: (0, ()), right: (0, ()) } } } impl Tryptich { pub fn left (self, w: u16, content: D) -> Tryptich { Tryptich { left: (w, content), ..self } } pub fn middle (self, w: u16, content: D) -> Tryptich { Tryptich { middle: (w, content), ..self } } pub fn right (self, w: u16, content: D) -> Tryptich { Tryptich { right: (w, content), ..self } } } impl Content for Tryptich where A: Content, B: Content, C: Content { fn content (&self) -> impl Render { let Self { top, h, left: (w_a, ref a), middle: (w_b, ref b), right: (w_c, ref c) } = *self; Fixed::y(h, if top { Bsp::a( Fill::x(Align::n(Fixed::x(w_b, Align::x(Tui::bg(Reset, b))))), Bsp::a( Fill::x(Align::nw(Fixed::x(w_a, Tui::bg(Reset, a)))), Fill::x(Align::ne(Fixed::x(w_c, Tui::bg(Reset, c)))), ), ) } else { Bsp::a( Fill::xy(Align::c(Fixed::x(w_b, Align::x(Tui::bg(Reset, b))))), Bsp::a( Fill::xy(Align::w(Fixed::x(w_a, Tui::bg(Reset, a)))), Fill::xy(Align::e(Fixed::x(w_c, Tui::bg(Reset, c)))), ), ) }) } } pub(crate) fn wrap ( bg: Color, fg: Color, content: impl Content ) -> impl Content { Bsp::e(Tui::fg_bg(bg, Reset, "▐"), Bsp::w(Tui::fg_bg(bg, Reset, "▌"), Tui::fg_bg(fg, bg, content))) } pub(crate) fn button_2 <'a, K, L> ( key: K, label: L, editing: bool, ) -> impl Content + 'a where K: Content + 'a, L: Content + 'a, { let key = Tui::fg_bg(Tui::g(0), Tui::orange(), Bsp::e( Tui::fg_bg(Tui::orange(), Reset, "▐"), Bsp::e(key, Tui::fg(Tui::g(96), "▐")) )); let label = When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label)); Tui::bold(true, Bsp::e(key, label)) } pub(crate) fn button_3 <'a, K, L, V> ( key: K, label: L, value: V, editing: bool, ) -> impl Content + 'a where K: Content + 'a, L: Content + 'a, V: Content + 'a, { let key = Tui::fg_bg(Tui::g(0), Tui::orange(), Bsp::e(Tui::fg_bg(Tui::orange(), Reset, "▐"), Bsp::e(key, Tui::fg(if editing { Tui::g(128) } else { Tui::g(96) }, "▐")))); let label = Bsp::e( When::new(!editing, Bsp::e( Tui::fg_bg(Tui::g(255), Tui::g(96), label), Tui::fg_bg(Tui::g(128), Tui::g(96), "▐"), )), Bsp::e( Tui::fg_bg(Tui::g(224), Tui::g(128), value), Tui::fg_bg(Tui::g(128), Reset, "▌"), )); Tui::bold(true, Bsp::e(key, label)) } pub(crate) fn heading <'a> ( key: &'a str, label: &'a str, count: usize, content: impl Content + Send + Sync + 'a, editing: bool, ) -> impl Content + 'a { let count = format!("{count}"); Fill::xy(Align::w(Bsp::s(Fill::x(Align::w(button_3(key, label, count, editing))), content))) } pub(crate) fn io_ports <'a, T: PortsSizes<'a>> ( fg: Color, bg: Color, iter: impl Fn()->T + Send + Sync + 'a ) -> impl Content + 'a { Map::new(iter, move|(index, name, connections, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s( Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(Bsp::e(" 󰣲 ", name))))), Map::new(||connections.iter(), move|connect, index|map_south(index as u16, 1, Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, &connect.info))))))))) } pub(crate) fn io_conns <'a, T: PortsSizes<'a>> ( fg: Color, bg: Color, iter: impl Fn()->T + Send + Sync + 'a ) -> impl Content + 'a { Map::new(iter, move|(index, name, connections, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s( Fill::x(Tui::bold(true, wrap(bg, fg, Fill::x(Align::w("▞▞▞▞ ▞▞▞▞"))))), Map::new(||connections.iter(), move|connect, index|map_south(index as u16, 1, Fill::x(Align::w(Tui::bold(false, wrap(bg, fg, Fill::x("")))))))))) } pub(crate) fn per_track_top <'a, T: Content + 'a, U: TracksSizes<'a>> ( width: u16, tracks: impl Fn() -> U + Send + Sync + 'a, callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a ) -> impl Content + 'a { Align::x(Tui::bg(Reset, Map::new(tracks, move|(index, track, x1, x2), _|{ let width = (x2 - x1) as u16; map_east(x1 as u16, width, Fixed::x(width, Tui::fg_bg( track.color.lightest.rgb, track.color.base.rgb, callback(index, track) ))) }))) } pub(crate) fn per_track <'a, T: Content + 'a, U: TracksSizes<'a>> ( width: u16, tracks: impl Fn() -> U + Send + Sync + 'a, callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a ) -> impl Content + 'a { per_track_top( width, tracks, move|index, track|Fill::y(Align::y(callback(index, track))) ) } #[cfg(test)] mod test { use super::*; #[test] fn test_view () { let _ = button_2("", "", true); let _ = button_2("", "", false); let _ = button_3("", "", "", true); let _ = button_3("", "", "", false); let _ = heading("", "", 0, "", true); let _ = heading("", "", 0, "", false); let _ = wrap(Reset, Reset, ""); } }