implement scrollbar components

This commit is contained in:
🪞👃🪞 2025-01-29 06:53:34 +01:00
parent 357efeea3e
commit 6755f972f3
4 changed files with 88 additions and 63 deletions

View file

@ -20,7 +20,6 @@ view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); {
":sampler" => ().boxed(),//self.view_sampler(self.is_editing(), &self.editor).boxed(), ":sampler" => ().boxed(),//self.view_sampler(self.is_editing(), &self.editor).boxed(),
":scene-add" => self.view_scene_add().boxed(), ":scene-add" => self.view_scene_add().boxed(),
":scenes" => self.view_scenes().boxed(), ":scenes" => self.view_scenes().boxed(),
":toolbar" => self.view_clock().boxed(),
":transport" => self.view_transport().boxed(), ":transport" => self.view_transport().boxed(),
":status" => self.view_status().boxed(), ":status" => self.view_status().boxed(),
":tracks" => self.view_tracks().boxed(), ":tracks" => self.view_tracks().boxed(),

View file

@ -29,23 +29,6 @@ impl Tek {
fmtd.bpm.update(None, rewrite!(buf, "---.---")); fmtd.bpm.update(None, rewrite!(buf, "---.---"));
} }
} }
pub(crate) fn view_clock (&self) -> impl Content<TuiOut> + use<'_> {
self.update_clock();
let theme = ItemPalette::G[96];
let fmtd = self.fmtd.read().unwrap();
Bsp::a(
Fill::xy(Align::w(self.view_play_pause())),
Fill::xy(Align::e(row!(
FieldH(theme, "Sel", self.selected.describe(&self.tracks, &self.scenes)),
FieldH(theme, "SR", fmtd.sr.view.clone()),
FieldH(theme, "Buf", fmtd.buf.view.clone()),
FieldH(theme, "Lat", fmtd.lat.view.clone()),
FieldH(theme, "BPM", fmtd.bpm.view.clone()),
FieldH(theme, "Beat", fmtd.beat.view.clone()),
FieldH(theme, "Time", fmtd.time.view.clone())
)))
)
}
pub(crate) fn view_status (&self) -> impl Content<TuiOut> + use<'_> { pub(crate) fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
self.update_clock(); self.update_clock();
let theme = ItemPalette::G[96]; let theme = ItemPalette::G[96];
@ -66,9 +49,9 @@ impl Tek {
Tui::bg(Black, row!(Bsp::a( Tui::bg(Black, row!(Bsp::a(
Fill::xy(Align::w(FieldH(theme, "Selected", self.selected.describe(&self.tracks, &self.scenes)))), Fill::xy(Align::w(FieldH(theme, "Selected", self.selected.describe(&self.tracks, &self.scenes)))),
Fill::xy(Align::e(row!( Fill::xy(Align::e(row!(
FieldH(theme, "SR", fmtd.sr.view.clone()), FieldH(theme, "SR", fmtd.sr.view.clone()),
FieldH(theme, "Buf", fmtd.buf.view.clone()), FieldH(theme, "Buf", fmtd.buf.view.clone()),
FieldH(theme, "Lat", fmtd.lat.view.clone()), FieldH(theme, "Lat", fmtd.lat.view.clone()),
))) )))
))) )))
} }

View file

@ -19,17 +19,19 @@ impl Tek {
y += height; y += height;
data})} data})}
fn scene_scrollbar (&self) -> impl Content<TuiOut> + use<'_> { fn scene_scrollbar (&self) -> impl Content<TuiOut> + use<'_> {
Bsp::s(Tui::fg_bg(Rgb(255,255,255), Rgb(0,0,0),""), Fill::y(Fixed::x(1, ScrollbarV {
Bsp::n(Tui::fg_bg(Rgb(255,255,255), Rgb(0,0,0),""), Bsp::a( offset: self.scene_scroll,
Fill::y(Align::nw(Fixed::xy(1, 1, Tui::fg(Rgb(255,255,255), "")))), length: 0,
Fill::y(Fixed::x(1, Tui::fg(Rgb(0,0,0), RepeatV("")))), total: self.tracks.len()
))) } }))
}
fn track_scrollbar (&self) -> impl Content<TuiOut> + use<'_> { fn track_scrollbar (&self) -> impl Content<TuiOut> + use<'_> {
Bsp::e(Tui::fg_bg(Rgb(255,255,255), Rgb(0,0,0), "🞀"), Fill::x(Fixed::y(1, ScrollbarH {
Bsp::w(Tui::fg_bg(Rgb(255,255,255), Rgb(0,0,0), "🞂"), Bsp::a( offset: self.track_scroll,
Fill::x(Align::nw(Fixed::xy(1, 1, Tui::fg(Rgb(255,255,255), "")))), length: 0,// self.view_track_count(),
Fill::x(Fixed::y(1, Tui::fg(Rgb(0,0,0), RepeatH("")))), total: self.tracks.len()
))) } }))
}
pub fn view_scenes (&self) -> impl Content<TuiOut> + use<'_> { pub fn view_scenes (&self) -> impl Content<TuiOut> + use<'_> {
let w_full = self.w(); let w_full = self.w();
let w = self.w_tracks_area(); let w = self.w_tracks_area();

View file

@ -1,5 +1,6 @@
use crate::*; use crate::*;
use crate::Color::*; use crate::Color::*;
use ratatui::prelude::Position;
macro_rules! impl_content_layout_render { macro_rules! impl_content_layout_render {
($Output:ty: |$self:ident: $Struct:ty, $to:ident| layout = $layout:expr; render = $render:expr) => { ($Output:ty: |$self:ident: $Struct:ty, $to:ident| layout = $layout:expr; render = $render:expr) => {
impl Content<$Output> for $Struct { impl Content<$Output> for $Struct {
@ -34,7 +35,6 @@ impl<T: Content<TuiOut>> Content<TuiOut> for std::sync::Arc<T> {
} }
} }
pub struct FieldH<T, U>(pub ItemPalette, pub T, pub U); pub struct FieldH<T, U>(pub ItemPalette, pub T, pub U);
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> { impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> {
fn content (&self) -> impl Render<TuiOut> { fn content (&self) -> impl Render<TuiOut> {
@ -62,15 +62,13 @@ impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldV<T, U> {
pub struct Repeat<'a>(pub &'a str); pub struct Repeat<'a>(pub &'a str);
impl Content<TuiOut> for Repeat<'_> { impl Content<TuiOut> for Repeat<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] { fn layout (&self, to: [u16;4]) -> [u16;4] { to }
to
}
fn render (&self, to: &mut TuiOut) { fn render (&self, to: &mut TuiOut) {
let [x, y, w, h] = to.area().xywh(); let [x, y, w, h] = to.area().xywh();
let a = self.0.len(); let a = self.0.len();
for (_v, y) in (y..y+h).enumerate() { for (_v, y) in (y..y+h).enumerate() {
for (u, x) in (x..x+w).enumerate() { for (u, x) in (x..x+w).enumerate() {
if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
let u = u % a; let u = u % a;
cell.set_symbol(&self.0[u..u+1]); cell.set_symbol(&self.0[u..u+1]);
} }
@ -81,13 +79,11 @@ impl Content<TuiOut> for Repeat<'_> {
pub struct RepeatV<'a>(pub &'a str); pub struct RepeatV<'a>(pub &'a str);
impl Content<TuiOut> for RepeatV<'_> { impl Content<TuiOut> for RepeatV<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] { fn layout (&self, to: [u16;4]) -> [u16;4] { to }
to
}
fn render (&self, to: &mut TuiOut) { fn render (&self, to: &mut TuiOut) {
let [x, y, _w, h] = to.area().xywh(); let [x, y, _w, h] = to.area().xywh();
for y in y..y+h { for y in y..y+h {
if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
cell.set_symbol(&self.0); cell.set_symbol(&self.0);
} }
} }
@ -96,19 +92,83 @@ impl Content<TuiOut> for RepeatV<'_> {
pub struct RepeatH<'a>(pub &'a str); pub struct RepeatH<'a>(pub &'a str);
impl Content<TuiOut> for RepeatH<'_> { impl Content<TuiOut> for RepeatH<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] { fn layout (&self, to: [u16;4]) -> [u16;4] { to }
to
}
fn render (&self, to: &mut TuiOut) { fn render (&self, to: &mut TuiOut) {
let [x, y, w, _h] = to.area().xywh(); let [x, y, w, _h] = to.area().xywh();
for x in x..x+w { for x in x..x+w {
if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
cell.set_symbol(&self.0); cell.set_symbol(&self.0);
} }
} }
} }
} }
pub struct ScrollbarV {
pub offset: usize,
pub length: usize,
pub total: usize,
}
impl ScrollbarV {
const ICON_DEC: &[char] = &['▲'];
const ICON_INC: &[char] = &['▼'];
}
impl Content<TuiOut> for ScrollbarV {
fn render (&self, to: &mut TuiOut) {
let [x, y1, _w, h] = to.area().xywh();
let y2 = y1 + h;
for (i, y) in (y1..=y2).enumerate() {
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
if (i as usize) < (Self::ICON_DEC.len()) {
cell.set_fg(Rgb(255, 255, 255));
cell.set_bg(Rgb(0, 0, 0));
cell.set_char(Self::ICON_DEC[i as usize]);
} else if (i as usize) > (h as usize - Self::ICON_INC.len()) {
cell.set_fg(Rgb(255, 255, 255));
cell.set_bg(Rgb(0, 0, 0));
cell.set_char(Self::ICON_INC[h as usize - i]);
} else {
cell.set_fg(Rgb(0, 0, 0));
cell.set_bg(Reset);
cell.set_char('╎'); // ━
}
}
}
}
}
pub struct ScrollbarH {
pub offset: usize,
pub length: usize,
pub total: usize,
}
impl ScrollbarH {
const ICON_DEC: &[char] = &[' ', '🞀', ' '];
const ICON_INC: &[char] = &[' ', '🞂', ' '];
}
impl Content<TuiOut> for ScrollbarH {
fn render (&self, to: &mut TuiOut) {
let [x1, y, w, _h] = to.area().xywh();
let x2 = x1 + w;
for (i, x) in (x1..=x2).enumerate() {
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
if i < (Self::ICON_DEC.len()) {
cell.set_fg(Rgb(255, 255, 255));
cell.set_bg(Rgb(0, 0, 0));
cell.set_char(Self::ICON_DEC[x as usize]);
} else if i > (w as usize - Self::ICON_INC.len()) {
cell.set_fg(Rgb(255, 255, 255));
cell.set_bg(Rgb(0, 0, 0));
cell.set_char(Self::ICON_INC[w as usize - i]);
} else {
cell.set_fg(Rgb(0, 0, 0));
cell.set_bg(Reset);
cell.set_char('╌'); // ━
}
}
}
}
}
/// A cell that takes up 3 rows on its own, /// A cell that takes up 3 rows on its own,
/// but stacks, giving (N+1)*2 rows per N cells. /// but stacks, giving (N+1)*2 rows per N cells.
pub struct Phat<T> { pub struct Phat<T> {
@ -445,25 +505,6 @@ border! {
} }
} }
//pub trait TuiStyle: Render<TuiOut> + Sized {
//fn fg (self, color: Color) -> impl Render<TuiOut> {
//Layers::new(move |add|{ add(&Foreground(color))?; add(&self) })
//}
//fn bg (self, color: Color) -> impl Render<TuiOut> {
//Layers::new(move |add|{ add(&Background(color))?; add(&self) })
//}
//fn bold (self, on: bool) -> impl Render<TuiOut> {
//Layers::new(move |add|{ add(&Bold(on))?; add(&self) })
//}
//fn border <S: BorderStyle> (self, style: S) -> impl Render<TuiOut> {
//Bordered(style, self)
//}
//}
//impl<R: Content<TuiOut>> TuiStyle for R {}
//impl<S: BorderStyle> Content<TuiOut> for Border<S> {
//}
//impl<S: BorderStyle, R: Content<TuiOut>> Content<TuiOut> for Bordered<S, R> { //impl<S: BorderStyle, R: Content<TuiOut>> Content<TuiOut> for Bordered<S, R> {
//fn content (&self) -> impl Render<TuiOut> { //fn content (&self) -> impl Render<TuiOut> {