mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
flatten arranger and piano modules
This commit is contained in:
parent
7a4fa1692b
commit
1723826cc2
19 changed files with 120 additions and 130 deletions
|
|
@ -3,8 +3,6 @@ include!("./lib.rs");
|
||||||
/// Application entrypoint.
|
/// Application entrypoint.
|
||||||
pub fn main () -> Usually<()> {
|
pub fn main () -> Usually<()> {
|
||||||
let name = "tek_transport";
|
let name = "tek_transport";
|
||||||
let engine = Tui::new()?;
|
Tui::new()?.run(&JackConnection::new(name)?
|
||||||
let state = JackConnection::new(name)?
|
.activate_with(|jack|TransportTui::new(jack))?)
|
||||||
.activate_with(|jack|TransportTui::try_from(jack))?;
|
|
||||||
engine.run(&state)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@ mod arranger_track; pub(crate) use self::arranger_track::*;
|
||||||
mod arranger_mode; pub(crate) use self::arranger_mode::*;
|
mod arranger_mode; pub(crate) use self::arranger_mode::*;
|
||||||
mod arranger_v; #[allow(unused)] pub(crate) use self::arranger_v::*;
|
mod arranger_v; #[allow(unused)] pub(crate) use self::arranger_v::*;
|
||||||
mod arranger_h;
|
mod arranger_h;
|
||||||
|
mod arranger_v_clips; pub(crate) use self::arranger_v_clips::*;
|
||||||
|
mod arranger_v_cursor; pub(crate) use self::arranger_v_cursor::*;
|
||||||
|
mod arranger_v_head; pub(crate) use self::arranger_v_head::*;
|
||||||
|
mod arranger_v_io; pub(crate) use self::arranger_v_io::*;
|
||||||
|
mod arranger_v_sep; pub(crate) use self::arranger_v_sep::*;
|
||||||
|
|
||||||
/// Root view for standalone `tek_arranger`
|
/// Root view for standalone `tek_arranger`
|
||||||
pub struct ArrangerTui {
|
pub struct ArrangerTui {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
mod v_clips; pub(crate) use self::v_clips::*;
|
|
||||||
mod v_cursor; pub(crate) use self::v_cursor::*;
|
|
||||||
mod v_head; pub(crate) use self::v_head::*;
|
|
||||||
mod v_io; pub(crate) use self::v_io::*;
|
|
||||||
mod v_sep; pub(crate) use self::v_sep::*;
|
|
||||||
// egyptian snakes den
|
// egyptian snakes den
|
||||||
const HEADER_H: u16 = 5;
|
pub(crate) const HEADER_H: u16 = 5;
|
||||||
const SCENES_W_OFFSET: u16 = 3;
|
pub(crate) const SCENES_W_OFFSET: u16 = 3;
|
||||||
impl ArrangerTui {
|
impl ArrangerTui {
|
||||||
pub fn render_mode_v (state: &ArrangerTui, factor: usize) -> impl Content<Tui> + use<'_> {
|
pub fn render_mode_v (state: &ArrangerTui, factor: usize) -> impl Content<Tui> + use<'_> {
|
||||||
lay!(
|
lay!(
|
||||||
|
|
|
||||||
|
|
@ -7,28 +7,28 @@ use KeyCode::{Enter, Left, Right, Char};
|
||||||
pub struct TransportTui {
|
pub struct TransportTui {
|
||||||
pub jack: Arc<RwLock<JackConnection>>,
|
pub jack: Arc<RwLock<JackConnection>>,
|
||||||
pub clock: Clock,
|
pub clock: Clock,
|
||||||
pub size: Measure<Tui>,
|
|
||||||
pub cursor: (usize, usize),
|
|
||||||
pub color: ItemPalette,
|
|
||||||
}
|
}
|
||||||
from_jack!(|jack|TransportTui Self {
|
|
||||||
jack: jack.clone(),
|
|
||||||
clock: Clock::from(jack),
|
|
||||||
size: Measure::new(),
|
|
||||||
cursor: (0, 0),
|
|
||||||
color: ItemPalette::random(),
|
|
||||||
});
|
|
||||||
has_clock!(|self: TransportTui|&self.clock);
|
has_clock!(|self: TransportTui|&self.clock);
|
||||||
audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope));
|
audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope));
|
||||||
handle!(<Tui>|self: TransportTui, from|TransportCommand::execute_with_state(self, from));
|
handle!(<Tui>|self: TransportTui, from|TransportCommand::execute_with_state(self, from));
|
||||||
render!(Tui: (self: TransportTui) => TransportView(&self.clock));
|
render!(Tui: (self: TransportTui) => TransportView(&self.clock));
|
||||||
|
impl TransportTui {
|
||||||
|
pub fn new (jack: &Arc<RwLock<JackConnection>>) -> Usually<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
jack: jack.clone(),
|
||||||
|
clock: Clock::from(jack),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TransportView<'a>(pub &'a Clock);
|
pub struct TransportView<'a>(pub &'a Clock);
|
||||||
render!(Tui: (self: TransportView<'a>) => row!(
|
render!(Tui: (self: TransportView<'a>) => Outer(
|
||||||
|
Style::default().fg(TuiTheme::g(255)).bg(TuiTheme::g(0))
|
||||||
|
).enclose(row!(
|
||||||
BeatStats::new(self.0), " ",
|
BeatStats::new(self.0), " ",
|
||||||
PlayPause(self.0.is_rolling()), " ",
|
PlayPause(self.0.is_rolling()), " ",
|
||||||
OutputStats::new(self.0),
|
OutputStats::new(self.0),
|
||||||
));
|
)));
|
||||||
|
|
||||||
pub struct PlayPause(pub bool);
|
pub struct PlayPause(pub bool);
|
||||||
render!(Tui: (self: PlayPause) => Tui::bg(
|
render!(Tui: (self: PlayPause) => Tui::bg(
|
||||||
|
|
@ -36,15 +36,6 @@ render!(Tui: (self: PlayPause) => Tui::bg(
|
||||||
Fixed::x(5, Tui::either(self.0,
|
Fixed::x(5, Tui::either(self.0,
|
||||||
Tui::fg(Color::Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
Tui::fg(Color::Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
||||||
Tui::fg(Color::Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",))))));
|
Tui::fg(Color::Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",))))));
|
||||||
impl std::fmt::Debug for TransportTui {
|
|
||||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
|
||||||
f.debug_struct("TransportTui")
|
|
||||||
.field("jack", &self.jack)
|
|
||||||
.field("size", &self.size)
|
|
||||||
.field("cursor", &self.cursor)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BeatStats { bpm: String, beat: String, time: String, }
|
pub struct BeatStats { bpm: String, beat: String, time: String, }
|
||||||
impl BeatStats {
|
impl BeatStats {
|
||||||
|
|
@ -60,7 +51,9 @@ impl BeatStats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render!(Tui: (self: BeatStats) => col!(
|
render!(Tui: (self: BeatStats) => col!(
|
||||||
Bsp::e(&self.bpm, " BPM"), Bsp::e("Beat ", &self.beat), Bsp::e("Time ", &self.time),
|
Bsp::e(Tui::fg(TuiTheme::g(255), &self.bpm), " BPM"),
|
||||||
|
Bsp::e("Beat ", Tui::fg(TuiTheme::g(255), &self.beat)),
|
||||||
|
Bsp::e("Time ", Tui::fg(TuiTheme::g(255), &self.time)),
|
||||||
));
|
));
|
||||||
|
|
||||||
pub struct OutputStats { sample_rate: String, buffer_size: String, latency: String, }
|
pub struct OutputStats { sample_rate: String, buffer_size: String, latency: String, }
|
||||||
|
|
@ -76,14 +69,16 @@ impl OutputStats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render!(Tui: (self: OutputStats) => col!(
|
render!(Tui: (self: OutputStats) => col!(
|
||||||
Bsp::e(format!("{}", self.sample_rate), " sample rate"),
|
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{}", self.sample_rate)), " sample rate"),
|
||||||
Bsp::e(format!("{}", self.buffer_size), " sample buffer"),
|
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{}", self.buffer_size)), " sample buffer"),
|
||||||
Bsp::e(format!("{:.3}ms", self.latency), " latency"),
|
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{:.3}ms", self.latency)), " latency"),
|
||||||
));
|
));
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum TransportCommand {
|
pub enum TransportCommand {
|
||||||
Clock(ClockCommand),
|
Clock(ClockCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
command!(|self:TransportCommand,state:TransportTui|match self {
|
command!(|self:TransportCommand,state:TransportTui|match self {
|
||||||
//Self::Focus(cmd) => cmd.execute(state)?.map(Self::Focus),
|
//Self::Focus(cmd) => cmd.execute(state)?.map(Self::Focus),
|
||||||
Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock),
|
Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock),
|
||||||
|
|
|
||||||
|
|
@ -111,21 +111,13 @@ render!(Tui: (self: Groovebox) => {
|
||||||
&self.size,
|
&self.size,
|
||||||
Bsp::s(
|
Bsp::s(
|
||||||
Fill::x(Fixed::y(3, Align::x(TransportView(&self.player.clock)))),
|
Fill::x(Fixed::y(3, Align::x(TransportView(&self.player.clock)))),
|
||||||
Bsp::s(
|
|
||||||
Fill::x(Fixed::y(1, Align::x(Bsp::e(
|
|
||||||
PhraseSelector::play_phrase(&self.player),
|
|
||||||
PhraseSelector::next_phrase(&self.player),
|
|
||||||
)))),
|
|
||||||
Bsp::n(
|
Bsp::n(
|
||||||
Fixed::y(9, col!(
|
Fixed::y(9, Bsp::s(
|
||||||
Bsp::e(
|
|
||||||
self.sampler.mapped[note_pt].as_ref().map(|sample|format!(
|
self.sampler.mapped[note_pt].as_ref().map(|sample|format!(
|
||||||
"Sample {}-{}",
|
"Sample {}-{}",
|
||||||
sample.read().unwrap().start,
|
sample.read().unwrap().start,
|
||||||
sample.read().unwrap().end,
|
sample.read().unwrap().end,
|
||||||
)),
|
)),
|
||||||
MidiEditStatus(&self.editor),
|
|
||||||
),
|
|
||||||
Bsp::a(
|
Bsp::a(
|
||||||
Outer(Style::default().fg(TuiTheme::g(128))),
|
Outer(Style::default().fg(TuiTheme::g(128))),
|
||||||
Fill::x(Fixed::y(8, if let Some((_, sample)) = &self.sampler.recording {
|
Fill::x(Fixed::y(8, if let Some((_, sample)) = &self.sampler.recording {
|
||||||
|
|
@ -144,13 +136,21 @@ render!(Tui: (self: Groovebox) => {
|
||||||
Meters(self.sampler.input_meter.as_ref()),
|
Meters(self.sampler.input_meter.as_ref()),
|
||||||
GrooveboxSamples(self)
|
GrooveboxSamples(self)
|
||||||
))))),
|
))))),
|
||||||
|
Bsp::s(
|
||||||
|
Fill::x(Align::c(Bsp::e(
|
||||||
|
PhraseSelector::play_phrase(&self.player),
|
||||||
|
PhraseSelector::next_phrase(&self.player),
|
||||||
|
))),
|
||||||
|
Bsp::n(
|
||||||
|
MidiEditStatus(&self.editor),
|
||||||
Fill::xy(Align::c("kyp"))
|
Fill::xy(Align::c("kyp"))
|
||||||
|
),
|
||||||
|
),
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
)});
|
)});
|
||||||
|
|
||||||
// TODO move this to sampler
|
// TODO move this to sampler
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ pub mod jack; pub use self::jack::*;
|
||||||
pub mod meter; pub use self::meter::*;
|
pub mod meter; pub use self::meter::*;
|
||||||
pub mod midi; pub use self::midi::*;
|
pub mod midi; pub use self::midi::*;
|
||||||
pub mod mixer; pub use self::mixer::*;
|
pub mod mixer; pub use self::mixer::*;
|
||||||
pub mod piano_h; pub use self::piano_h::*;
|
pub mod piano; pub use self::piano::*;
|
||||||
pub mod plugin; pub use self::plugin::*;
|
pub mod plugin; pub use self::plugin::*;
|
||||||
pub mod pool; pub use self::pool::*;
|
pub mod pool; pub use self::pool::*;
|
||||||
pub mod sampler; pub use self::sampler::*;
|
pub mod sampler; pub use self::sampler::*;
|
||||||
|
|
|
||||||
46
src/piano.rs
Normal file
46
src/piano.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod piano_h; pub(crate) use self::piano_h::*;
|
||||||
|
mod piano_h_cursor; pub(crate) use self::piano_h_cursor::*;
|
||||||
|
mod piano_h_keys; pub(crate) use self::piano_h_keys::*;
|
||||||
|
mod piano_h_notes; pub(crate) use self::piano_h_notes::*;
|
||||||
|
mod piano_h_time; pub(crate) use self::piano_h_time::*;
|
||||||
|
|
||||||
|
/// A phrase, rendered as a horizontal piano roll.
|
||||||
|
pub struct PianoHorizontal {
|
||||||
|
phrase: Option<Arc<RwLock<MidiClip>>>,
|
||||||
|
/// Buffer where the whole phrase is rerendered on change
|
||||||
|
buffer: BigBuffer,
|
||||||
|
/// Size of actual notes area
|
||||||
|
size: Measure<Tui>,
|
||||||
|
/// The display window
|
||||||
|
range: MidiRangeModel,
|
||||||
|
/// The note cursor
|
||||||
|
point: MidiPointModel,
|
||||||
|
/// The highlight color palette
|
||||||
|
color: ItemPalette,
|
||||||
|
/// Width of the keyboard
|
||||||
|
keys_width: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PianoHorizontal {
|
||||||
|
pub fn new (phrase: Option<&Arc<RwLock<MidiClip>>>) -> Self {
|
||||||
|
let size = Measure::new();
|
||||||
|
let mut range = MidiRangeModel::from((24, true));
|
||||||
|
range.time_axis = size.x.clone();
|
||||||
|
range.note_axis = size.y.clone();
|
||||||
|
let color = phrase.as_ref()
|
||||||
|
.map(|p|p.read().unwrap().color)
|
||||||
|
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
|
||||||
|
Self {
|
||||||
|
buffer: Default::default(),
|
||||||
|
point: MidiPointModel::default(),
|
||||||
|
phrase: phrase.cloned(),
|
||||||
|
size,
|
||||||
|
range,
|
||||||
|
color,
|
||||||
|
keys_width: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,53 +1,10 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
mod piano_h_cursor; use self::piano_h_cursor::*;
|
|
||||||
mod piano_h_keys; pub(crate) use self::piano_h_keys::*;
|
|
||||||
mod piano_h_notes; use self::piano_h_notes::*;
|
|
||||||
mod piano_h_time; use self::piano_h_time::*;
|
|
||||||
|
|
||||||
pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator<Item=(usize, u16, usize)> {
|
pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator<Item=(usize, u16, usize)> {
|
||||||
(note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n))
|
(note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A phrase, rendered as a horizontal piano roll.
|
|
||||||
pub struct PianoHorizontal {
|
|
||||||
phrase: Option<Arc<RwLock<MidiClip>>>,
|
|
||||||
/// Buffer where the whole phrase is rerendered on change
|
|
||||||
buffer: BigBuffer,
|
|
||||||
/// Size of actual notes area
|
|
||||||
size: Measure<Tui>,
|
|
||||||
/// The display window
|
|
||||||
range: MidiRangeModel,
|
|
||||||
/// The note cursor
|
|
||||||
point: MidiPointModel,
|
|
||||||
/// The highlight color palette
|
|
||||||
color: ItemPalette,
|
|
||||||
/// Width of the keyboard
|
|
||||||
keys_width: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PianoHorizontal {
|
|
||||||
pub fn new (phrase: Option<&Arc<RwLock<MidiClip>>>) -> Self {
|
|
||||||
let size = Measure::new();
|
|
||||||
let mut range = MidiRangeModel::from((24, true));
|
|
||||||
range.time_axis = size.x.clone();
|
|
||||||
range.note_axis = size.y.clone();
|
|
||||||
let color = phrase.as_ref()
|
|
||||||
.map(|p|p.read().unwrap().color)
|
|
||||||
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
|
|
||||||
Self {
|
|
||||||
buffer: Default::default(),
|
|
||||||
point: MidiPointModel::default(),
|
|
||||||
phrase: phrase.cloned(),
|
|
||||||
size,
|
|
||||||
range,
|
|
||||||
color,
|
|
||||||
keys_width: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render!(Tui: (self: PianoHorizontal) => {
|
render!(Tui: (self: PianoHorizontal) => {
|
||||||
let (color, name, length, looped) = if let Some(phrase) = self.phrase().as_ref().map(|p|p.read().unwrap()) {
|
let (color, name, length, looped) = if let Some(phrase) = self.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use super::note_y_iter;
|
use super::*;
|
||||||
|
|
||||||
pub struct PianoHorizontalCursor<'a>(pub(crate) &'a PianoHorizontal);
|
pub struct PianoHorizontalCursor<'a>(pub(crate) &'a PianoHorizontal);
|
||||||
render!(Tui: |self: PianoHorizontalCursor<'a>, render|{
|
render!(Tui: |self: PianoHorizontalCursor<'a>, render|{
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use super::note_y_iter;
|
use super::*;
|
||||||
|
|
||||||
pub struct PianoHorizontalKeys<'a>(pub(crate) &'a PianoHorizontal);
|
pub struct PianoHorizontalKeys<'a>(pub(crate) &'a PianoHorizontal);
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use super::note_y_iter;
|
use super::*;
|
||||||
|
|
||||||
pub struct PianoHorizontalNotes<'a>(pub(crate) &'a PianoHorizontal);
|
pub struct PianoHorizontalNotes<'a>(pub(crate) &'a PianoHorizontal);
|
||||||
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
pub struct PianoHorizontalTimeline<'a>(pub(crate) &'a PianoHorizontal);
|
pub struct PianoHorizontalTimeline<'a>(pub(crate) &'a PianoHorizontal);
|
||||||
render!(Tui: |self: PianoHorizontalTimeline<'a>, render|{
|
render!(Tui: |self: PianoHorizontalTimeline<'a>, render|{
|
||||||
|
|
@ -12,9 +13,3 @@ render!(Tui: |self: PianoHorizontalTimeline<'a>, render|{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Tui::fg_bg(
|
|
||||||
//self.0.color.lightest.rgb,
|
|
||||||
//self.0.color.darkest.rgb,
|
|
||||||
//format!("{}*{}", self.0.time_start(), self.0.time_zoom()).as_str()
|
|
||||||
//));
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
||||||
|
|
@ -211,7 +211,7 @@ render!(Tui: (self: PoolView<'a>) => {
|
||||||
let color = self.0.phrase().read().unwrap().color;
|
let color = self.0.phrase().read().unwrap().color;
|
||||||
Outer(
|
Outer(
|
||||||
Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)
|
Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)
|
||||||
).enclose(Tui::bg(Color::Black, Tui::map(||self.0.phrases().iter(), |clip, i|{
|
).enclose(Tui::map(||self.0.phrases().iter(), |clip, i|{
|
||||||
let MidiClip { ref name, color, length, .. } = *clip.read().unwrap();
|
let MidiClip { ref name, color, length, .. } = *clip.read().unwrap();
|
||||||
let item_height = 1;
|
let item_height = 1;
|
||||||
let item_offset = i as u16 * item_height;
|
let item_offset = i as u16 * item_height;
|
||||||
|
|
@ -223,7 +223,7 @@ render!(Tui: (self: PoolView<'a>) => {
|
||||||
Align::w(Tui::when(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "▶")))),
|
Align::w(Tui::when(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "▶")))),
|
||||||
Align::e(Tui::when(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "◀")))),
|
Align::e(Tui::when(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "◀")))),
|
||||||
)))
|
)))
|
||||||
})))
|
}))
|
||||||
/*//format!(" {i} {name} {length} ")[>
|
/*//format!(" {i} {name} {length} ")[>
|
||||||
//Push::y(i as u16 * 2, Fixed::y(2, Tui::bg(color.base.rgb, Fill::x(
|
//Push::y(i as u16 * 2, Fixed::y(2, Tui::bg(color.base.rgb, Fill::x(
|
||||||
//format!(" {i} {name} {length} ")))))[>,
|
//format!(" {i} {name} {length} ")))))[>,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue