mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
wip: the new new arranger
This commit is contained in:
parent
0b365e05c8
commit
0ee3059cf8
5 changed files with 142 additions and 73 deletions
|
|
@ -15,6 +15,9 @@ pub struct ArrangerCli {
|
||||||
/// Number of tracks
|
/// Number of tracks
|
||||||
#[arg(short = 'x', long, default_value_t = 16)]
|
#[arg(short = 'x', long, default_value_t = 16)]
|
||||||
tracks: usize,
|
tracks: usize,
|
||||||
|
/// Width of tracks
|
||||||
|
#[arg(short = 'w', long, default_value_t = 6)]
|
||||||
|
track_width: usize,
|
||||||
/// Number of scenes
|
/// Number of scenes
|
||||||
#[arg(short, long, default_value_t = 8)]
|
#[arg(short, long, default_value_t = 8)]
|
||||||
scenes: usize,
|
scenes: usize,
|
||||||
|
|
@ -51,7 +54,7 @@ fn add_tracks (jack: &JackConnection, app: &mut Arranger, cli: &ArrangerCli) ->
|
||||||
let track = app.track_add(None, Some(
|
let track = app.track_add(None, Some(
|
||||||
track_color_1.mix(track_color_2, i as f32 / n as f32).into()
|
track_color_1.mix(track_color_2, i as f32 / n as f32).into()
|
||||||
))?;
|
))?;
|
||||||
track.width = 4;
|
track.width = cli.track_width;
|
||||||
let name = track.name.read().unwrap();
|
let name = track.name.read().unwrap();
|
||||||
track.player.midi_ins.push(
|
track.player.midi_ins.push(
|
||||||
jack.register_port(&format!("{}I", &name), MidiIn::default())?
|
jack.register_port(&format!("{}I", &name), MidiIn::default())?
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@ pub fn map_south<O: Output>(
|
||||||
item_height: O::Unit,
|
item_height: O::Unit,
|
||||||
item: impl Content<O>
|
item: impl Content<O>
|
||||||
) -> impl Content<O> {
|
) -> impl Content<O> {
|
||||||
Push::y(item_offset,
|
Push::y(item_offset, Align::n(Fixed::y(item_height, Fill::x(item))))
|
||||||
Align::n(Fixed::y(item_height,
|
|
||||||
Fill::x(item))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_east<O: Output>(
|
pub fn map_east<O: Output>(
|
||||||
|
|
@ -15,9 +13,7 @@ pub fn map_east<O: Output>(
|
||||||
item_width: O::Unit,
|
item_width: O::Unit,
|
||||||
item: impl Content<O>
|
item: impl Content<O>
|
||||||
) -> impl Content<O> {
|
) -> impl Content<O> {
|
||||||
Push::x(item_offset,
|
Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item))))
|
||||||
Align::w(Fixed::y(item_width,
|
|
||||||
Fill::y(item))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Map<'a, A, B, I, F, G>(pub PhantomData<&'a()>, pub F, pub G) where
|
pub struct Map<'a, A, B, I, F, G>(pub PhantomData<&'a()>, pub F, pub G) where
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ from_jack!(|jack| Arranger {
|
||||||
note_buf: vec![],
|
note_buf: vec![],
|
||||||
perf: PerfModel::default(),
|
perf: PerfModel::default(),
|
||||||
jack: jack.clone(),
|
jack: jack.clone(),
|
||||||
compact: false,
|
compact: true,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//render!(TuiOut: (self: Arranger) => {
|
//render!(TuiOut: (self: Arranger) => {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,31 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
pub(crate) const HEADER_H: u16 = 0; // 5
|
||||||
|
pub(crate) const SCENES_W_OFFSET: u16 = 0;
|
||||||
render!(TuiOut: (self: Arranger) => {
|
render!(TuiOut: (self: Arranger) => {
|
||||||
let scenes = &self.scenes;
|
let scenes = &self.scenes;
|
||||||
|
let scenes_w = 16.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
let scene_heights = Arranger::scene_heights(scenes, 1);
|
let scene_heights = Arranger::scene_heights(scenes, 1);
|
||||||
let border_style_1 = Style::default().fg(Color::Rgb(48,48,48));
|
let border_style_1 = Style::default().fg(Color::Rgb(48,48,48));
|
||||||
let border_style_2 = Style::default().fg(Color::Rgb(72,72,72));
|
let border_style_2 = Style::default().fg(Color::Rgb(72,72,72));
|
||||||
|
let frame = Bsp::s(self.track_column_headers(),
|
||||||
|
Bsp::n(self.track_column_inputs(),
|
||||||
|
Bsp::s(self.track_column_outputs(),
|
||||||
|
Bsp::b(self.track_column_separators(), ""))));
|
||||||
|
let arranger = Bsp::n(
|
||||||
|
Fixed::y(20, Outer(border_style_2).enclose(&self.editor)),
|
||||||
|
Outer(border_style_1).enclose(Bsp::w(frame,
|
||||||
|
Bsp::s(Fixed::y(1, Tui::bold(true, Tui::fg(TuiTheme::g(128), "Track"))),
|
||||||
|
Bsp::s(Fixed::y(1, Tui::bold(true, Tui::fg(TuiTheme::g(128), "Playing"))),
|
||||||
|
Bsp::s(Fixed::y(1, Tui::bold(true, Tui::fg(TuiTheme::g(128), "Next"))),
|
||||||
|
Bsp::s(Fixed::y(1, Tui::bold(true, Tui::fg(TuiTheme::g(128), "Out 1: NI"))),
|
||||||
|
Bsp::n(Fixed::y(1, Tui::bold(true, Tui::fg(TuiTheme::g(128), "In 1: Korg"))),
|
||||||
|
Fixed::x(scenes_w, self.scene_row_headers())))))))));
|
||||||
self.size.of(
|
self.size.of(
|
||||||
Bsp::s(self.toolbar_view(),
|
Bsp::s(self.toolbar_view(),
|
||||||
Bsp::n(self.status_view(),
|
Bsp::n(self.status_view(),
|
||||||
Bsp::w(self.pool_view(),
|
Bsp::w(self.pool_view(),
|
||||||
Bsp::n(self.editor_status_view(),
|
Bsp::n(self.editor_status_view(),
|
||||||
Bsp::n(
|
arranger)))))
|
||||||
Fixed::y(20, Outer(border_style_2).enclose(&self.editor)),
|
|
||||||
Outer(border_style_1).enclose(
|
|
||||||
Bsp::s(self.track_column_headers(),
|
|
||||||
Bsp::s(self.track_column_inputs(),
|
|
||||||
Bsp::s(self.track_column_outputs(), ()))))))))))
|
|
||||||
//Outer(border_style).enclose(Tui::bg(Color::Rgb(0,32,0), self.track_column_headers())))))))) [>Align::nw(Fill::xy(Bsp::s(
|
//Outer(border_style).enclose(Tui::bg(Color::Rgb(0,32,0), self.track_column_headers())))))))) [>Align::nw(Fill::xy(Bsp::s(
|
||||||
//Align::w(Fill::x(
|
//Align::w(Fill::x(
|
||||||
//Bsp::s(Align::w(Fixed::y(3, self.track_column_headers())),
|
//Bsp::s(Align::w(Fixed::y(3, self.track_column_headers())),
|
||||||
|
|
@ -54,47 +65,79 @@ impl<'a> ArrangerVClips<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn row <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
fn row <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
||||||
Bsp::e(Tui::fg(color.light.rgb, "▎"), Tui::fg(color.lightest.rgb, field))
|
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Fixed::y(1, field))
|
||||||
}
|
}
|
||||||
impl Arranger {
|
impl Arranger {
|
||||||
|
pub const LEFT_SEP: char = '▎';
|
||||||
pub const TRACK_MIN_WIDTH: usize = 4;
|
pub const TRACK_MIN_WIDTH: usize = 4;
|
||||||
|
pub fn tracks_with_widths (&self)
|
||||||
|
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
||||||
|
{
|
||||||
|
Self::tracks_with_widths_static(self.tracks.as_slice())
|
||||||
|
}
|
||||||
|
fn tracks_with_widths_static (tracks: &[ArrangerTrack])
|
||||||
|
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
||||||
|
{
|
||||||
|
let mut x = 0;
|
||||||
|
tracks.iter().enumerate().map(move |(index, track)|{
|
||||||
|
let data = (index, track, x, x + track.width);
|
||||||
|
x += track.width;
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn track_column_separators <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
||||||
|
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
||||||
|
let fg = Color::Rgb(64,64,64);
|
||||||
|
Map::new(move||self.tracks_with_widths(), move|(_n, _track, x1, x2), _i|{
|
||||||
|
Push::x(scenes_w, map_east(x1 as u16, (x2 - x1) as u16,
|
||||||
|
Fixed::x((x2 - x1) as u16, Tui::fg(fg, RepeatV(&"·")))))
|
||||||
|
})
|
||||||
|
}
|
||||||
fn track_column_headers (&self) -> impl Content<TuiOut> + use<'_> {
|
fn track_column_headers (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
||||||
Fixed::y(3, Push::x(scenes_w, Map::new(
|
Fixed::y(3, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
||Arranger::tracks_with_widths(self.tracks.as_slice()),
|
let color = track.color();
|
||||||
|(_, track, x1, x2), i| {
|
Push::x(scenes_w, Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16,
|
||||||
let color = track.color();
|
Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
||||||
map_east(x1 as u16, (x2 - x1) as u16, Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
Bsp::s(row(color, Tui::bold(true, format!("{}", track.name.read().unwrap()))),
|
||||||
Bsp::s(format!("{}", track.name.read().unwrap()),
|
|
||||||
Bsp::s(
|
Bsp::s(
|
||||||
Self::cell_elapsed(track, self.clock().timebase()),
|
row(color, Self::cell_elapsed(track, self.clock().timebase())),
|
||||||
Self::cell_until_next(track, &self.clock().playhead)))))})))
|
row(color, Self::cell_until_next(track, &self.clock().playhead))
|
||||||
|
))))))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
fn track_column_inputs (&self) -> impl Content<TuiOut> + use<'_> {
|
fn track_column_inputs (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
||||||
Fixed::y(1, Push::x(scenes_w, Map::new(
|
Fixed::y(1, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
||Arranger::tracks_with_widths(self.tracks.as_slice()),
|
let w = (x2 - x1) as u16;
|
||||||
|(_, track, x1, x2), i| {
|
let color = track.color();
|
||||||
let color = track.color();
|
let cell = Self::cell_input(track).ok();
|
||||||
let input = Self::cell_input(track);
|
Push::x(scenes_w, map_east(x1 as u16, w, Fixed::x(w, Fixed::y(1, row(color, cell)))))
|
||||||
map_east(x1 as u16, (x2 - x1) as u16, Tui::bg(color.base.rgb,
|
}))
|
||||||
row(color, Self::cell_input(track).ok()))) })))
|
|
||||||
}
|
}
|
||||||
fn track_column_outputs (&self) -> impl Content<TuiOut> + use<'_> {
|
fn track_column_outputs (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
||||||
Fixed::y(1, Push::x(scenes_w, Map::new(
|
Fixed::y(1, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
||Arranger::tracks_with_widths(self.tracks.as_slice()),
|
let w = (x2 - x1) as u16;
|
||||||
|(_, track, x1, x2), i| {
|
let color = track.color();
|
||||||
let (w, h) = (Arranger::TRACK_MIN_WIDTH.max(x2 - x1), HEADER_H);
|
let cell = Self::cell_output(track).ok();
|
||||||
let color = track.color();
|
Push::x(scenes_w, map_east(x1 as u16, w, Fixed::x(w, Fixed::y(1, row(color, cell)))))
|
||||||
map_east(x1 as u16, (x2 - x1) as u16, Tui::bg(color.base.rgb,
|
}))
|
||||||
row(color, Self::cell_output(track).ok()))) })))
|
|
||||||
}
|
}
|
||||||
/// name and width of track
|
/// name and width of track
|
||||||
fn cell_name (track: &ArrangerTrack, _w: usize) -> impl Content<TuiOut> {
|
fn cell_name (track: &ArrangerTrack, _w: usize) -> impl Content<TuiOut> {
|
||||||
let name = track.name().read().unwrap().clone();
|
let name = track.name().read().unwrap().clone();
|
||||||
Tui::bold(true, Tui::fg(track.color.lightest.rgb, name))
|
Tui::bold(true, Tui::fg(track.color.lightest.rgb, name))
|
||||||
}
|
}
|
||||||
|
fn cell_input (track: &ArrangerTrack) -> Usually<impl Content<TuiOut>> {
|
||||||
|
Ok(format!("⦗R⦘⦗M⦘"))/*, track.player.midi_ins().first().map(|port|port.short_name())
|
||||||
|
.transpose()?.unwrap_or("?".into())))*/
|
||||||
|
}
|
||||||
|
/// output port
|
||||||
|
fn cell_output (track: &ArrangerTrack) -> Usually<impl Content<TuiOut>> {
|
||||||
|
Ok(format!("⦗M⦘⦗S⦘"))/*, track.player.midi_outs().first().map(|port|port.short_name())
|
||||||
|
.transpose()?.unwrap_or("?".into())))*/
|
||||||
|
}
|
||||||
/// beats elapsed
|
/// beats elapsed
|
||||||
fn cell_elapsed (track: &ArrangerTrack, timebase: &Arc<Timebase>) -> impl Content<TuiOut> {
|
fn cell_elapsed (track: &ArrangerTrack, timebase: &Arc<Timebase>) -> impl Content<TuiOut> {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
|
|
@ -120,14 +163,32 @@ impl Arranger {
|
||||||
}
|
}
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
fn cell_input (track: &ArrangerTrack) -> Usually<impl Content<TuiOut>> {
|
|
||||||
Ok(format!(">{}", track.player.midi_ins().first().map(|port|port.short_name())
|
pub fn scenes_with_heights (&self) -> impl Iterator<Item = (usize, &ArrangerScene, usize, usize)> {
|
||||||
.transpose()?.unwrap_or("?".into())))
|
let mut y = 0;
|
||||||
|
self.scenes.iter().enumerate().map(move|(index, scene)|{
|
||||||
|
let data = (index, scene, y, y + 1);
|
||||||
|
y += 1;
|
||||||
|
data
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/// output port
|
fn scene_row_headers (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
fn cell_output (track: &ArrangerTrack) -> Usually<impl Content<TuiOut>> {
|
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
||||||
Ok(format!("<{}", track.player.midi_outs().first().map(|port|port.short_name())
|
Fill::y(Map::new(||self.scenes_with_heights(), move|(_, scene, y1, y2), i| {
|
||||||
.transpose()?.unwrap_or("?".into())))
|
let h = (y2 - y1) as u16;
|
||||||
|
let color = scene.color();
|
||||||
|
let cell = row(color, scene.name.read().unwrap().clone());
|
||||||
|
map_south(y1 as u16, 1, cell)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn scene_rows (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
||||||
|
Map::new(||self.scenes_with_heights(), move|(_, scene, y1, y2), i| {
|
||||||
|
let h = (y2 - y1) as u16;
|
||||||
|
let color = scene.color();
|
||||||
|
let cell = Fixed::y(h, Fixed::x(scenes_w, row(color, scene.name.read().unwrap().clone())));
|
||||||
|
map_south(y1 as u16, 1, cell)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn scene_heights (scenes: &[ArrangerScene], factor: usize) -> Vec<(usize, usize)> {
|
pub fn scene_heights (scenes: &[ArrangerScene], factor: usize) -> Vec<(usize, usize)> {
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
|
|
@ -155,7 +216,7 @@ impl Arranger {
|
||||||
let name = Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
let name = Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
||||||
Expand::x(1, Tui::bold(true, scene.name.read().unwrap().clone()))
|
Expand::x(1, Tui::bold(true, scene.name.read().unwrap().clone()))
|
||||||
);
|
);
|
||||||
let clips = Map::new(||Arranger::tracks_with_widths(tracks), move|(index, track, x1, x2), _|
|
let clips = Map::new(||Arranger::tracks_with_widths_static(tracks), move|(index, track, x1, x2), _|
|
||||||
Push::x((x2 - x1) as u16, Self::cell_clip(scene, index, track, (x2 - x1) as u16, height))
|
Push::x((x2 - x1) as u16, Self::cell_clip(scene, index, track, (x2 - x1) as u16, height))
|
||||||
);
|
);
|
||||||
Fixed::y(height, Bsp::e(icon, Bsp::e(name, clips)))
|
Fixed::y(height, Bsp::e(icon, Bsp::e(name, clips)))
|
||||||
|
|
@ -204,14 +265,6 @@ impl Arranger {
|
||||||
Fixed::x(pool_w, Align::e(Fill::y(PoolView(self.compact, &self.pool))))
|
Fixed::x(pool_w, Align::e(Fill::y(PoolView(self.compact, &self.pool))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn track_col_sep <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
|
||||||
let fg = TuiTheme::separator_fg(false);
|
|
||||||
let x = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16;
|
|
||||||
Map::new(
|
|
||||||
move||Self::tracks_with_widths(self.tracks.as_slice()),
|
|
||||||
move|(_n, _track, x1, _x2), _i|Push::x(x + x1 as u16, Fill::y(Tui::fg(fg, "▎")))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pub fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
pub fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
||||||
let mut widths = vec![];
|
let mut widths = vec![];
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
|
|
@ -223,16 +276,6 @@ impl Arranger {
|
||||||
widths.push((0, total));
|
widths.push((0, total));
|
||||||
widths
|
widths
|
||||||
}
|
}
|
||||||
pub fn tracks_with_widths (tracks: &[ArrangerTrack])
|
|
||||||
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
|
||||||
{
|
|
||||||
let mut x = 0;
|
|
||||||
tracks.iter().enumerate().map(move |(index, track)|{
|
|
||||||
let data = (index, track, x, x + track.width);
|
|
||||||
x += track.width;
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scene_row_sep <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
fn scene_row_sep <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
||||||
let fg = Color::Rgb(255,255,255);
|
let fg = Color::Rgb(255,255,255);
|
||||||
|
|
@ -250,16 +293,6 @@ impl Arranger {
|
||||||
//}
|
//}
|
||||||
//})
|
//})
|
||||||
}
|
}
|
||||||
pub fn scenes_with_heights (&self)
|
|
||||||
-> impl Iterator<Item = (usize, &ArrangerScene, usize, usize)>
|
|
||||||
{
|
|
||||||
let mut y = 0;
|
|
||||||
self.scenes.iter().enumerate().map(move|(index, scene)|{
|
|
||||||
let data = (index, scene, y, y + 1);
|
|
||||||
y += 1;
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cursor (&self) -> impl Content<TuiOut> + '_ {
|
fn cursor (&self) -> impl Content<TuiOut> + '_ {
|
||||||
let color = self.color;
|
let color = self.color;
|
||||||
|
|
|
||||||
|
|
@ -17,3 +17,40 @@ impl Content<TuiOut> for String {
|
||||||
to.blit(self, to.area.x(), to.area.y(), None)
|
to.blit(self, to.area.x(), to.area.y(), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Repeat<'a>(pub &'a str);
|
||||||
|
|
||||||
|
impl Content<TuiOut> for Repeat<'_> {
|
||||||
|
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))) {
|
||||||
|
let u = u % a;
|
||||||
|
cell.set_symbol(&self.0[u..u+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RepeatV<'a>(pub &'a str);
|
||||||
|
|
||||||
|
impl Content<TuiOut> for RepeatV<'_> {
|
||||||
|
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 y in y..y+h {
|
||||||
|
if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) {
|
||||||
|
cell.set_symbol(&self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue