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(),
":scene-add" => self.view_scene_add().boxed(),
":scenes" => self.view_scenes().boxed(),
":toolbar" => self.view_clock().boxed(),
":transport" => self.view_transport().boxed(),
":status" => self.view_status().boxed(),
":tracks" => self.view_tracks().boxed(),

View file

@ -29,23 +29,6 @@ impl Tek {
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<'_> {
self.update_clock();
let theme = ItemPalette::G[96];
@ -66,9 +49,9 @@ impl Tek {
Tui::bg(Black, row!(Bsp::a(
Fill::xy(Align::w(FieldH(theme, "Selected", self.selected.describe(&self.tracks, &self.scenes)))),
Fill::xy(Align::e(row!(
FieldH(theme, "SR", fmtd.sr.view.clone()),
FieldH(theme, "Buf", fmtd.buf.view.clone()),
FieldH(theme, "Lat", fmtd.lat.view.clone()),
FieldH(theme, "SR", fmtd.sr.view.clone()),
FieldH(theme, "Buf", fmtd.buf.view.clone()),
FieldH(theme, "Lat", fmtd.lat.view.clone()),
)))
)))
}

View file

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

View file

@ -1,5 +1,6 @@
use crate::*;
use crate::Color::*;
use ratatui::prelude::Position;
macro_rules! impl_content_layout_render {
($Output:ty: |$self:ident: $Struct:ty, $to:ident| layout = $layout:expr; render = $render:expr) => {
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);
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> {
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);
impl Content<TuiOut> for Repeat<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
to
}
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
fn render (&self, to: &mut TuiOut) {
let [x, y, w, h] = to.area().xywh();
let a = self.0.len();
for (_v, y) in (y..y+h).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;
cell.set_symbol(&self.0[u..u+1]);
}
@ -81,13 +79,11 @@ impl Content<TuiOut> for Repeat<'_> {
pub struct RepeatV<'a>(pub &'a str);
impl Content<TuiOut> for RepeatV<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
to
}
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
fn render (&self, to: &mut TuiOut) {
let [x, y, _w, h] = to.area().xywh();
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);
}
}
@ -96,19 +92,83 @@ impl Content<TuiOut> for RepeatV<'_> {
pub struct RepeatH<'a>(pub &'a str);
impl Content<TuiOut> for RepeatH<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
to
}
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
fn render (&self, to: &mut TuiOut) {
let [x, y, w, _h] = to.area().xywh();
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);
}
}
}
}
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,
/// but stacks, giving (N+1)*2 rows per N cells.
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> {
//fn content (&self) -> impl Render<TuiOut> {