mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-04-30 14:20:14 +02:00
wip: more flattening and view_arranger
This commit is contained in:
parent
e0f4ec9a15
commit
53f443f4bd
|
@ -1,5 +1,10 @@
|
|||
use crate::*;
|
||||
pub(crate) use std::fmt::Write;
|
||||
pub(crate) use ::tek_tui::ratatui::prelude::Position;
|
||||
/// Clear a pre-allocated buffer, then write into it.
|
||||
#[macro_export] macro_rules! rewrite {
|
||||
($buf:ident, $($rest:tt)*) => { |$buf,_,_|{$buf.clear();write!($buf, $($rest)*)} } }
|
||||
/// Define a type alias for iterators of sized items (columns).
|
||||
macro_rules! def_sizes_iter {
|
||||
($Type:ident => $($Item:ty),+) => {
|
||||
pub(crate) trait $Type<'a> =
|
||||
|
@ -9,13 +14,13 @@ def_sizes_iter!(TracksSizes => Track);
|
|||
def_sizes_iter!(InputsSizes => JackMidiIn);
|
||||
def_sizes_iter!(OutputsSizes => JackMidiOut);
|
||||
def_sizes_iter!(PortsSizes => Arc<str>, [PortConnect]);
|
||||
pub(crate) trait ScenesColors<'a> = Iterator<Item=SceneColor<'a>>;
|
||||
pub(crate) type SceneColor<'a> = (usize, &'a Scene, usize, usize, Option<ItemPalette>);
|
||||
pub(crate) trait ScenesColors<'a> = Iterator<Item=SceneWithColor<'a>>;
|
||||
pub(crate) type SceneWithColor<'a> = (usize, &'a Scene, usize, usize, Option<ItemPalette>);
|
||||
view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); {
|
||||
":editor" => (&self.editor).boxed(),
|
||||
":arranger" => self.view_arranger().boxed(),
|
||||
":editor" => self.editor.as_ref().map(|e|Bsp::e(e.clip_status(), e.edit_status())).boxed(),
|
||||
":inputs" => self.view_inputs().boxed(),
|
||||
":outputs" => self.view_outputs().boxed(),
|
||||
":pool" => self.view_pool().boxed(),
|
||||
":sample" => ().boxed(),//self.view_sample(self.is_editing()).boxed(),
|
||||
":sampler" => ().boxed(),//self.view_sampler(self.is_editing(), &self.editor).boxed(),
|
||||
":scene-add" => self.view_scene_add().boxed(),
|
||||
|
@ -23,6 +28,9 @@ view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); {
|
|||
":transport" => self.view_transport().boxed(),
|
||||
":status" => self.view_status().boxed(),
|
||||
":tracks" => self.view_tracks().boxed(),
|
||||
":pool" => self.pool.as_ref()
|
||||
.map(|pool|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), pool)))
|
||||
.boxed(),
|
||||
});
|
||||
provide_num!(u16: |self: Tek| {
|
||||
":h-ins" => self.h_inputs(),
|
||||
|
@ -34,21 +42,6 @@ provide_num!(u16: |self: Tek| {
|
|||
":y-outs" => (self.size.h() as u16).saturating_sub(self.h_outputs() + 1),
|
||||
":y-samples" => if self.is_editing() { 1 } else { 0 },
|
||||
});
|
||||
#[macro_export] macro_rules! rewrite {
|
||||
($buf:ident, $($rest:tt)*) => { |$buf,_,_|{$buf.clear();write!($buf, $($rest)*)} }
|
||||
}
|
||||
impl Tek {
|
||||
fn view_editor (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
self.editor.as_ref()
|
||||
.map(|e|Bsp::e(e.clip_status(), e.edit_status()))
|
||||
}
|
||||
fn view_pool (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
self.pool.as_ref()
|
||||
.map(|pool|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), pool)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn row <'a> (
|
||||
w: u16,
|
||||
h: u16,
|
||||
|
@ -65,7 +58,6 @@ pub(crate) fn row <'a> (
|
|||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn row_top <'a> (
|
||||
w: u16,
|
||||
h: u16,
|
||||
|
@ -82,7 +74,6 @@ pub(crate) fn row_top <'a> (
|
|||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn wrap (
|
||||
bg: Color,
|
||||
fg: Color,
|
||||
|
@ -92,7 +83,6 @@ pub(crate) fn wrap (
|
|||
Bsp::w(Tui::fg_bg(bg, Reset, "▌"),
|
||||
Tui::fg_bg(fg, bg, content)))
|
||||
}
|
||||
|
||||
pub(crate) fn button_2 <'a, K, L> (
|
||||
key: K,
|
||||
label: L,
|
||||
|
@ -108,7 +98,6 @@ pub(crate) fn button_2 <'a, K, L> (
|
|||
let label = When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label));
|
||||
Tui::bold(true, Bsp::e(key, label))
|
||||
}
|
||||
|
||||
pub(crate) fn button_3 <'a, K, L, V> (
|
||||
key: K,
|
||||
label: L,
|
||||
|
@ -136,7 +125,6 @@ pub(crate) fn button_3 <'a, K, L, V> (
|
|||
));
|
||||
Tui::bold(true, Bsp::e(key, label))
|
||||
}
|
||||
|
||||
fn heading <'a> (
|
||||
key: &'a str,
|
||||
label: &'a str,
|
||||
|
@ -147,7 +135,6 @@ fn heading <'a> (
|
|||
let count = format!("{count}");
|
||||
Fill::xy(Align::w(Bsp::s(Fill::x(Align::w(button_3(key, label, count, editing))), content)))
|
||||
}
|
||||
|
||||
#[cfg(test)] mod test {
|
||||
use super::*;
|
||||
#[test] fn test_view () {
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
(bsp/n (fixed/y 1 :transport) (bsp/s (fixed/y 1 :status) (fill/xy (bsp/a (fill/xy (align/e :pool)) :arranger))))
|
||||
(bsp/n (fixed/y 1 :transport)
|
||||
(bsp/s (fixed/y 1 :status)
|
||||
(fill/xy (bsp/a (fill/xy (align/e :pool)) :arranger))))
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
use crate::*;
|
||||
impl Tek {
|
||||
|
||||
/// Blit the currently visible section of the arranger to the output.
|
||||
///
|
||||
/// If the arranger is larger than the available display area,
|
||||
/// the scrollbars determine the portion that will be shown.
|
||||
pub fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
() // TODO
|
||||
}
|
||||
|
||||
/// Draw the full arranger to the arranger view buffer.
|
||||
///
|
||||
/// This should happen on changes to the arrangement view
|
||||
/// other than scrolling. Scrolling should just determine
|
||||
/// which part of the arranger buffer to blit to output.
|
||||
/// This should happen on changes to the arrangement contents,
|
||||
/// i.e. not on scroll. Scrolling just determines which
|
||||
/// part of the arranger buffer to blit in [view_arranger]
|
||||
pub fn redraw_arranger (&self) {
|
||||
let width = self.w_tracks();
|
||||
let height = self.h_scenes() + self.h_inputs() + self.h_outputs();
|
||||
|
@ -24,6 +16,34 @@ impl Tek {
|
|||
*self.arranger.write().unwrap() = output.buffer;
|
||||
}
|
||||
|
||||
/// Blit the currently visible section of the arranger view buffer to the output.
|
||||
///
|
||||
/// If the arranger is larger than the available display area,
|
||||
/// the scrollbars determine the portion that will be shown.
|
||||
///
|
||||
/// This function is called on every frame, but is relatively cheap
|
||||
/// as the rendering logic of [redraw_arranger] is only invoked on
|
||||
/// changes to the content.
|
||||
pub fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
ThunkRender::new(move|to: &mut TuiOut|{
|
||||
let [x0, y0, w, h] = to.area().xywh();
|
||||
let source = self.arranger.read().unwrap();
|
||||
for (source_x, target_x) in (x0..x0+w).enumerate() {
|
||||
for (source_y, target_y) in (y0..y0+h).enumerate() {
|
||||
let source_pos = Position::from((source_x as u16, source_y as u16));
|
||||
let target_pos = Position::from((target_x, target_y));
|
||||
if let Some(target) = to.buffer.cell_mut(target_pos) {
|
||||
if let Some(source) = source.cell(source_pos) {
|
||||
*target = source.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
()
|
||||
})
|
||||
}
|
||||
|
||||
/// Display the current scene scroll state.
|
||||
fn scene_scrollbar (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
let offset = self.scene_scroll;
|
||||
|
@ -89,11 +109,11 @@ impl Tek {
|
|||
Fixed::y(self.h_tracks_area(), row(self.w_tracks_area(), h, s,
|
||||
Map::new(
|
||||
move||self.scenes_with_colors(editing, h_area),
|
||||
move|(s, scene, y1, y2, prev): SceneColor, _|self.view_scene_name(
|
||||
move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_name(
|
||||
w_full, (1 + y2 - y1) as u16, y1 as u16, s, scene, prev)),
|
||||
self.per_track(move|t, track|Map::new(
|
||||
move||self.scenes_with_track_colors(editing, h_area, t),
|
||||
move|(s, scene, y1, y2, prev): SceneColor, _|self.view_scene_clip(
|
||||
move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_clip(
|
||||
w, (1 + y2 - y1) as u16, y1 as u16,
|
||||
scene, prev, s, t, editing, selected_track == Some(t), selected_scene))),
|
||||
() )))))
|
||||
|
|
|
@ -34,7 +34,7 @@ impl Tek {
|
|||
let theme = ItemPalette::G[96];
|
||||
let fmtd = self.fmtd.read().unwrap();
|
||||
Tui::bg(Black, row!(Bsp::a(
|
||||
Fill::xy(Align::w(self.view_play_pause())),
|
||||
Fill::xy(Align::w(button_play_pause(self.clock.is_rolling()))),
|
||||
Fill::xy(Align::e(row!(
|
||||
FieldH(theme, "BPM", fmtd.bpm.view.clone()),
|
||||
FieldH(theme, "Beat", fmtd.beat.view.clone()),
|
||||
|
@ -47,7 +47,9 @@ impl Tek {
|
|||
let theme = ItemPalette::G[96];
|
||||
let fmtd = self.fmtd.read().unwrap();
|
||||
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!(
|
||||
FieldH(theme, "SR", fmtd.sr.view.clone()),
|
||||
FieldH(theme, "Buf", fmtd.buf.view.clone()),
|
||||
|
@ -55,17 +57,17 @@ impl Tek {
|
|||
)))
|
||||
)))
|
||||
}
|
||||
fn view_play_pause (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
let playing = self.clock.is_rolling();
|
||||
let compact = true;//self.is_editing();
|
||||
Tui::bg(
|
||||
if playing{Rgb(0,128,0)}else{Rgb(128,64,0)},
|
||||
Either::new(compact,
|
||||
Thunk::new(move||Fixed::x(9, Either::new(playing,
|
||||
Tui::fg(Rgb(0, 255, 0), " PLAYING "),
|
||||
Tui::fg(Rgb(255, 128, 0), " STOPPED ")))),
|
||||
Thunk::new(move||Fixed::x(5, Either::new(playing,
|
||||
Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
||||
Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",)))))))
|
||||
}
|
||||
}
|
||||
|
||||
fn button_play_pause (playing: bool) -> impl Content<TuiOut> {
|
||||
let compact = true;//self.is_editing();
|
||||
Tui::bg(
|
||||
if playing{Rgb(0,128,0)}else{Rgb(128,64,0)},
|
||||
Either::new(compact,
|
||||
Thunk::new(move||Fixed::x(9, Either::new(playing,
|
||||
Tui::fg(Rgb(0, 255, 0), " PLAYING "),
|
||||
Tui::fg(Rgb(255, 128, 0), " STOPPED ")))),
|
||||
Thunk::new(move||Fixed::x(5, Either::new(playing,
|
||||
Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
|
||||
Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",)))))))
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ use crate::*;
|
|||
pub(crate) view: Arc<RwLock<U>>
|
||||
}
|
||||
impl<T: PartialEq, U> ViewMemo<T, U> {
|
||||
fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } }
|
||||
fn new (value: T, view: U) -> Self {
|
||||
Self { value, view: Arc::new(view.into()) }
|
||||
}
|
||||
pub(crate) fn update <R> (&mut self, newval: T, render: impl Fn(&mut U, &T, &T)->R) -> Option<R> {
|
||||
if newval != self.value {
|
||||
let result = render(&mut*self.view.write().unwrap(), &newval, &self.value);
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
use crate::*;
|
||||
impl Tek {
|
||||
fn view_meter <'a> (&'a self, label: &'a str, value: f32) -> impl Content<TuiOut> + 'a {
|
||||
col!(
|
||||
FieldH(ItemPalette::G[128], label, format!("{:>+9.3}", value)),
|
||||
Fixed::xy(if value >= 0.0 { 13 }
|
||||
else if value >= -1.0 { 12 }
|
||||
else if value >= -2.0 { 11 }
|
||||
else if value >= -3.0 { 10 }
|
||||
else if value >= -4.0 { 9 }
|
||||
else if value >= -6.0 { 8 }
|
||||
else if value >= -9.0 { 7 }
|
||||
else if value >= -12.0 { 6 }
|
||||
else if value >= -15.0 { 5 }
|
||||
else if value >= -20.0 { 4 }
|
||||
else if value >= -25.0 { 3 }
|
||||
else if value >= -30.0 { 2 }
|
||||
else if value >= -40.0 { 1 }
|
||||
else { 0 }, 1, Tui::bg(if value >= 0.0 { Red }
|
||||
else if value >= -3.0 { Yellow }
|
||||
else { Green }, ())))
|
||||
}
|
||||
fn view_meters (&self, values: &[f32;2]) -> impl Content<TuiOut> + use<'_> {
|
||||
Bsp::s(
|
||||
format!("L/{:>+9.3}", values[0]),
|
||||
format!("R/{:>+9.3}", values[1]),
|
||||
)
|
||||
}
|
||||
}
|
||||
fn view_meter <'a> (label: &'a str, value: f32) -> impl Content<TuiOut> + 'a {
|
||||
col!(
|
||||
FieldH(ItemPalette::G[128], label, format!("{:>+9.3}", value)),
|
||||
Fixed::xy(if value >= 0.0 { 13 }
|
||||
else if value >= -1.0 { 12 }
|
||||
else if value >= -2.0 { 11 }
|
||||
else if value >= -3.0 { 10 }
|
||||
else if value >= -4.0 { 9 }
|
||||
else if value >= -6.0 { 8 }
|
||||
else if value >= -9.0 { 7 }
|
||||
else if value >= -12.0 { 6 }
|
||||
else if value >= -15.0 { 5 }
|
||||
else if value >= -20.0 { 4 }
|
||||
else if value >= -25.0 { 3 }
|
||||
else if value >= -30.0 { 2 }
|
||||
else if value >= -40.0 { 1 }
|
||||
else { 0 }, 1, Tui::bg(if value >= 0.0 { Red }
|
||||
else if value >= -3.0 { Yellow }
|
||||
else { Green }, ())))
|
||||
}
|
||||
fn view_meters (values: &[f32;2]) -> impl Content<TuiOut> + use<'_> {
|
||||
Bsp::s(
|
||||
format!("L/{:>+9.3}", values[0]),
|
||||
format!("R/{:>+9.3}", values[1]),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue