mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-13 07:06:41 +01:00
177 lines
5.9 KiB
Rust
177 lines
5.9 KiB
Rust
use crate::*;
|
|
|
|
/// A three-column layout.
|
|
pub(crate) struct Tryptich<A, B, C> {
|
|
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<A, B, C> Tryptich<A, B, C> {
|
|
pub fn left <D> (self, w: u16, content: D) -> Tryptich<D, B, C> {
|
|
Tryptich { left: (w, content), ..self }
|
|
}
|
|
pub fn middle <D> (self, w: u16, content: D) -> Tryptich<A, D, C> {
|
|
Tryptich { middle: (w, content), ..self }
|
|
}
|
|
pub fn right <D> (self, w: u16, content: D) -> Tryptich<A, B, D> {
|
|
Tryptich { right: (w, content), ..self }
|
|
}
|
|
}
|
|
|
|
impl<A, B, C> Content<TuiOut> for Tryptich<A, B, C>
|
|
where A: Content<TuiOut>, B: Content<TuiOut>, C: Content<TuiOut> {
|
|
fn content (&self) -> impl Render<TuiOut> {
|
|
let Self { top, h, left: (w_a, ref a), middle: (w_b, ref b), right: (w_c, ref c) } = *self;
|
|
if top {
|
|
Fixed::y(h, 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 {
|
|
Fixed::y(h, 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<TuiOut>
|
|
) -> impl Content<TuiOut> {
|
|
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<TuiOut> + 'a where
|
|
K: Content<TuiOut> + 'a,
|
|
L: Content<TuiOut> + '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<TuiOut> + 'a where
|
|
K: Content<TuiOut> + 'a,
|
|
L: Content<TuiOut> + 'a,
|
|
V: Content<TuiOut> + '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<TuiOut> + Send + Sync + 'a,
|
|
editing: bool,
|
|
) -> impl Content<TuiOut> + '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<TuiOut> + '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<TuiOut> + '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<TuiOut> + '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<TuiOut> + '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<TuiOut> + '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<TuiOut> + '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, "");
|
|
}
|
|
}
|