wip: structure PianoHorizontal render sanely

This commit is contained in:
🪞👃🪞 2024-12-16 18:10:26 +01:00
parent d401870b2d
commit e57415aac9
4 changed files with 81 additions and 70 deletions

View file

@ -184,10 +184,10 @@ pub struct PhraseSelector {
// TODO: Display phrases always in order of appearance // TODO: Display phrases always in order of appearance
render!(|self: PhraseSelector|Tui::fixed_xy(24, 1, row!([ render!(|self: PhraseSelector|Tui::fixed_xy(24, 1, row!([
Tui::fg(self.color.lighter.rgb, Tui::bold(true, &self.title)), Tui::fg(self.color.lighter.rgb, Tui::bold(true, &self.title)),
Tui::bg(self.color.base.rgb, Tui::fg(self.color.lighter.rgb, row!([ Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!([
format!("{:8}", &self.name[0..8.min(self.name.len())]), format!("{:8}", &self.name[0..8.min(self.name.len())]),
Tui::bg(self.color.dark.rgb, &self.time), Tui::bg(self.color.dark.rgb, &self.time),
]))), ])),
]))); ])));
impl PhraseSelector { impl PhraseSelector {
@ -311,19 +311,19 @@ render!(|self: SequencerStatusBar|Tui::fixed_y(2, lay!([
row!([" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,]), row!([" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,]),
row!([" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,]), row!([" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,]),
]); ]);
Tui::bg(TuiTheme::g(50), Tui::fg(TuiTheme::g(255), row!([ Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!([
single("SPACE", "play/pause"), single("SPACE", "play/pause"),
double(("", "cursor"), ("C-✣", "scroll"), ), double(("", "cursor"), ("C-✣", "scroll"), ),
double((",.", "note"), ("<>", "triplet"),), double((",.", "note"), ("<>", "triplet"),),
double(("[]", "phrase"), ("{}", "order"), ), double(("[]", "phrase"), ("{}", "order"), ),
double(("q", "enqueue"), ("e", "edit"), ), double(("q", "enqueue"), ("e", "edit"), ),
]))) ]))
}, },
Tui::fill_xy(Tui::at_se({ Tui::fill_xy(Tui::at_se({
Tui::bg(TuiTheme::g(25), row!([ Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), row!([
Tui::fg(TuiTheme::orange(), &self.cpu), &self.cpu,
Tui::fg(TuiTheme::orange(), &self.res), &self.res,
Tui::fg(TuiTheme::orange(), &self.size), &self.size,
])) ]))
})), })),
]))); ])));

View file

@ -102,21 +102,21 @@ render!(|self: TransportView|{
struct Field<'a>(&'a str, &'a str, &'a ItemPalette); struct Field<'a>(&'a str, &'a str, &'a ItemPalette);
render!(|self: Field<'a>|row!([ render!(|self: Field<'a>|row!([
Tui::bg(Color::Reset, Tui::bold(true, Tui::fg_bg(self.2.lightest.rgb, self.2.darkest.rgb, Tui::bold(true, self.0)),
Tui::fg(self.2.lighter.rgb, self.0))), Tui::fg_bg(self.2.lighter.rgb, self.2.darkest.rgb, ""),
Tui::fg(self.2.lighter.rgb, format!("{:>10}", self.1)), Tui::fg_bg(self.2.lighter.rgb, self.2.base.rgb, format!("{:>10}", self.1)),
])); ]));
Tui::bg(color.base.rgb, Tui::fill_x(row!([ Tui::bg(color.base.rgb, Tui::fill_x(row!([
//PlayPause(self.started), " ", //PlayPause(self.started), " ",
col!([ col!([
Field(" Beat|", self.beat.as_str(), &color), Field(" Beat", self.beat.as_str(), &color),
Field(" BPM|", self.bpm.as_str(), &color), Field(" BPM", self.bpm.as_str(), &color),
]), ]),
" ", " ",
col!([ col!([
Field(" Time|", format!("{:.1}s", self.current_second).as_str(), &color), Field(" Time", format!("{:.1}s", self.current_second).as_str(), &color),
Field(" Smpl|", format!("{:.1}k", self.current_sample).as_str(), &color), Field(" Smpl", format!("{:.1}k", self.current_sample).as_str(), &color),
]), ]),
]))) ])))
@ -128,12 +128,12 @@ render!(|self: PlayPause|Tui::bg(
Tui::fixed_x(5, col!(|add|if self.0 { Tui::fixed_x(5, col!(|add|if self.0 {
add(&Tui::fg(Color::Rgb(0, 255, 0), col!([ add(&Tui::fg(Color::Rgb(0, 255, 0), col!([
" 🭍🭑🬽 ", " 🭍🭑🬽 ",
" 🭞🭜🭘 " " 🭞🭜🭘 ",
]))) ])))
} else { } else {
add(&Tui::fg(Color::Rgb(255, 128, 0), col!([ add(&Tui::fg(Color::Rgb(255, 128, 0), col!([
" ▗▄▖ ", " ▗▄▖ ",
" ▝▀▘ " " ▝▀▘ ",
]))) ])))
})) }))
)); ));
@ -168,8 +168,8 @@ impl FocusWrap<TransportFocus> for TransportFocus {
fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W) fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Tui> + 'a -> impl Render<Tui> + 'a
{ {
let focused = focus == self; let focused = focus == self;
let corners = focused.then_some(CORNERS); let corners = focused.then_some(CORNERS);
//let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50))); //let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50)));
lay!([corners, /*highlight,*/ *content]) lay!([corners, /*highlight,*/ *content])
} }
@ -179,8 +179,8 @@ impl FocusWrap<TransportFocus> for Option<TransportFocus> {
fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W) fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Tui> + 'a -> impl Render<Tui> + 'a
{ {
let focused = Some(focus) == self; let focused = Some(focus) == self;
let corners = focused.then_some(CORNERS); let corners = focused.then_some(CORNERS);
//let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50))); //let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50)));
lay!([corners, /*highlight,*/ *content]) lay!([corners, /*highlight,*/ *content])
} }

View file

@ -231,34 +231,43 @@ impl std::fmt::Debug for PhraseEditorModel {
pub struct PhraseEditStatus<'a>(pub &'a PhraseEditorModel); pub struct PhraseEditStatus<'a>(pub &'a PhraseEditorModel);
render!(|self:PhraseEditStatus<'a>|row!(|add|{ render!(|self:PhraseEditStatus<'a>|row!(|add|{
let (color, name, length) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) { let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) {
(phrase.color, phrase.name.clone(), phrase.length) (phrase.color, phrase.name.clone(), phrase.length, phrase.loop_on)
} else { } else {
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0) (ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false)
}; };
let bg = color.base.rgb; let bg = color.base.rgb;
let fg = color.lightest.rgb; let fg = color.lightest.rgb;
add(&Tui::fill_x(Tui::bg(bg, row!(|add|{ let field = move|x, y|row!([
Tui::fg_bg(color.lightest.rgb, Color::Reset, Tui::bold(true, x)),
Tui::fg_bg(color.lighter.rgb, Color::Reset, Tui::bold(true, "")),
&y
]);
add(&Tui::fill_x(Tui::fg_bg(fg, bg, row!(|add|{
add(&Tui::fixed_xy(26, 3, col!(![ add(&Tui::fixed_xy(26, 3, col!(![
row!(![" Edit ", Tui::bold(true, format!("{name}"))]), field(" Edit", format!("{name}")),
row!(![" Length ", Tui::bold(true, format!("{length}"))]), field(" Length", format!("{length}")),
row!(![" Loop ", Tui::bold(true, format!("on"))])])))?; field(" Loop", format!("{looped}")),
])))?;
add(&Tui::fixed_xy(25, 3, col!(![ add(&Tui::fixed_xy(25, 3, col!(![
row!(!["Time ", Tui::bold(true, format!("{}", self.0.time_point()))]), field(" Time", format!("{}",
row!(!["View ", Tui::bold(true, format!("{}-{} ({}*{})", self.0.time_point())),
field(" View", format!("{}-{} ({}*{})",
self.0.time_start(), self.0.time_start(),
self.0.time_end(), self.0.time_end(),
self.0.time_axis(), self.0.time_axis(),
self.0.time_zoom()))])])))?; self.0.time_zoom()))
])))?;
add(&Tui::fixed_xy(25, 3, col!(![ add(&Tui::fixed_xy(25, 3, col!(![
row!(!["Note ", Tui::bold(true, format!("{:4} ({:3}) {:4}", field(" Note", format!("{:4} ({:3}) {:4}",
to_note_name(self.0.note_point()), to_note_name(self.0.note_point()),
self.0.note_point(), self.0.note_point(),
self.0.note_len()))]), self.0.note_len())),
row!(!["View ", Tui::bold(true, format!("{}-{} ({})", field(" View", format!("{}-{} ({})",
to_note_name(self.0.note_lo()), to_note_name(self.0.note_lo()),
to_note_name(self.0.note_hi()), to_note_name(self.0.note_hi()),
self.0.note_axis()))])])))?; self.0.note_axis()))
])))?;
add(&Tui::fixed_xy(16, 3, col!(![ add(&Tui::fixed_xy(16, 3, col!(![
row!(!["TimeLock ", Tui::bold(true, format!("{}", self.0.time_lock()))])])))?; row!(!["TimeLock ", Tui::bold(true, format!("{}", self.0.time_lock()))])])))?;
Ok(()) Ok(())

View file

@ -6,7 +6,7 @@ pub struct PianoHorizontal {
phrase: Option<Arc<RwLock<Phrase>>>, phrase: Option<Arc<RwLock<Phrase>>>,
/// Buffer where the whole phrase is rerendered on change /// Buffer where the whole phrase is rerendered on change
buffer: BigBuffer, buffer: BigBuffer,
/// Width and height of notes area at last render /// Size of actual notes area
size: Measure<Tui>, size: Measure<Tui>,
/// The display window /// The display window
range: MidiRangeModel, range: MidiRangeModel,
@ -39,7 +39,7 @@ impl PianoHorizontal {
render!(|self: PianoHorizontal|{ render!(|self: PianoHorizontal|{
let bg = TuiTheme::g(32); let bg = TuiTheme::g(32);
let fg = self.color; let color = self.color;
let note_lo = self.range.note_lo(); let note_lo = self.range.note_lo();
let note_hi = self.range.note_hi(); let note_hi = self.range.note_hi();
let time_lock = self.range.time_lock(); let time_lock = self.range.time_lock();
@ -48,45 +48,47 @@ render!(|self: PianoHorizontal|{
let time_point = self.point.time_point(); let time_point = self.point.time_point();
let note_point = self.point.note_point(); let note_point = self.point.note_point();
let note_len = self.point.note_len(); let note_len = self.point.note_len();
lay!([ let timeline = move||PianoHorizontalTimeline {
&self.size, color,
Tui::fill_xy(Tui::bg(bg, Tui::split_s(false, 1, time_start,
Tui::fill_x(Tui::push_x(5, Tui::bg(fg.darkest.rgb, Tui::fg(fg.lightest.rgb, time_zoom,
PianoHorizontalTimeline { };
time_start, let notes = move||PianoHorizontalNotes {
time_zoom, source: &self.buffer,
} time_start,
)))), note_hi,
Tui::split_e(true, 5, Tui::debug(lay!([ };
PianoHorizontalNotes { let cursor = move||PianoHorizontalCursor {
source: &self.buffer, time_zoom,
time_start, time_point,
note_hi, time_start,
}, note_point: note_point,
PianoHorizontalCursor { note_len: note_len,
time_zoom, note_hi: note_hi,
time_point, note_lo: note_lo,
time_start, };
note_point: note_point, let keys = move||PianoHorizontalKeys {
note_len: note_len, color: self.color,
note_hi: note_hi, note_lo,
note_lo: note_lo, note_hi,
}, note_point: Some(note_point),
])), PianoHorizontalKeys { };
color: self.color, Tui::fill_xy(Tui::bg(bg, Tui::split_s(false, 1,
note_lo, Tui::fill_x(Tui::push_x(5, timeline())),
note_hi, Tui::split_e(true, 5, Tui::debug(lay!([&self.size, notes(), cursor()])), keys()),
note_point: Some(note_point), )))
}),
)))
])
}); });
pub struct PianoHorizontalTimeline { pub struct PianoHorizontalTimeline {
color: ItemPalette,
time_start: usize, time_start: usize,
time_zoom: usize, time_zoom: usize,
} }
render!(|self: PianoHorizontalTimeline|format!("{}*{}", self.time_start, self.time_zoom).as_str()); render!(|self: PianoHorizontalTimeline|Tui::fg_bg(
self.color.lightest.rgb,
self.color.darkest.rgb,
format!("{}*{}", self.time_start, self.time_zoom).as_str()
));
pub struct PianoHorizontalKeys { pub struct PianoHorizontalKeys {
color: ItemPalette, color: ItemPalette,