wip: simplify and document

This commit is contained in:
i do not exist 2026-07-05 18:46:33 +03:00
parent 701a651fbd
commit b9e7b9732e
12 changed files with 116 additions and 72 deletions

View file

@ -35,7 +35,7 @@ pub mod size; pub use self::size::*;
/// Must not be dropped for the duration of the process /// Must not be dropped for the duration of the process
pub jack: Jack<'static>, pub jack: Jack<'static>,
/// Display size /// Display size
pub size: Size, pub size: Sizer,
/// Performance counter /// Performance counter
pub perf: PerfModel, pub perf: PerfModel,
/// Available view modes and input bindings /// Available view modes and input bindings

View file

@ -1,19 +1,16 @@
use crate::*; use crate::*;
tui_view!(|self: App| {
""
});
/// The [Draw] implementation for [App] handles the loaded view, /// The [Draw] implementation for [App] handles the loaded view,
/// which is defined in terms of [dizzle] DSL. /// which is defined in terms of [dizzle] DSL.
/// ///
/// If there is an error, the error is displayed. FIXME: overlay it /// If there is an error, the error is displayed. FIXME: overlay it
/// Then, every top-level form of the DSL description is rendered. /// Then, every top-level form of the DSL description is rendered.
impl Draw<Tui> for App { impl View<Tui> for App {
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> { fn view (&self) -> impl Draw<Tui> {
thunk(|to: &mut Tui|{
let xywh = to.area().into(); let xywh = to.area().into();
if let Some(e) = self.error.read().unwrap().as_ref() { if let Some(e) = self.error.read().unwrap().as_ref() {
to.show(xywh, e.as_ref())?; to.show(Layout::XYWH(xywh, e.as_ref()))?;
} }
for (index, dsl) in self.mode.view.iter().enumerate() { for (index, dsl) in self.mode.view.iter().enumerate() {
if let Err(e) = self.interpret(to, dsl) { if let Err(e) = self.interpret(to, dsl) {
@ -22,6 +19,7 @@ impl Draw<Tui> for App {
} }
} }
Ok(xywh) Ok(xywh)
})
} }
} }
@ -127,7 +125,7 @@ pub fn draw_dialog (
if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) }, if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) },
if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) }, if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) },
h_exact(2, origin_n(w_full(item))) h_exact(2, origin_n(w_full(item)))
)).draw(to); )).draw(to)?;
} }
Ok(to.area().into()) Ok(to.area().into())
}))) })))
@ -364,7 +362,7 @@ pub fn view_scenes_clips <'a, S: ScenesSizes<'a>> (
tracks: impl TracksSizes<'a>, tracks: impl TracksSizes<'a>,
select: &Selection, select: &Selection,
editor: Option<&MidiEditor>, editor: Option<&MidiEditor>,
size: &Size, size: &Sizer,
editing: bool, editing: bool,
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
let status = wh_full(origin_se(fg(Green, format!("{}x{}", size.w(), size.h())))); let status = wh_full(origin_se(fg(Green, format!("{}x{}", size.w(), size.h()))));
@ -465,7 +463,7 @@ pub fn view_track_names (
}, south(w_full(origin_nw(east( }, south(w_full(origin_nw(east(
format!("·t{index:02} "), format!("·t{index:02} "),
fg(Rgb(255, 255, 255), bold(true, &track.name)) fg(Rgb(255, 255, 255), bold(true, &track.name))
))), ""))) ).draw(to); ))), ""))) ).draw(to)?;
} }
Ok(XYWH(0, 0, 0, 0)) Ok(XYWH(0, 0, 0, 0))
})))) }))))
@ -490,7 +488,7 @@ pub fn view_track_outputs (
h_exact(1, bg(track.color.dark.term, w_full(origin_w( h_exact(1, bg(track.color.dark.term, w_full(origin_w(
format!("·o{index:02} {}", port.port_name())))))); format!("·o{index:02} {}", port.port_name()))))));
w_exact(track_width(index, track), w_exact(track_width(index, track),
origin_nw(h_full(iter_south(iter, draw)))).draw(to); origin_nw(h_full(iter_south(iter, draw)))).draw(to)?;
} }
Ok(XYWH(0, 0, 0, 0)) Ok(XYWH(0, 0, 0, 0))
})))) }))))
@ -513,7 +511,7 @@ pub fn view_track_inputs (
iter_south(||track.sequencer.midi_ins.iter(), iter_south(||track.sequencer.midi_ins.iter(),
|port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term, |port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term,
w_full(origin_w(format!("·i{index:02} {}", port.port_name())))))))) w_full(origin_w(format!("·i{index:02} {}", port.port_name()))))))))
.draw(to); .draw(to)?;
} }
Ok(XYWH(0, 0, 0, 0)) Ok(XYWH(0, 0, 0, 0))
})))) }))))
@ -527,7 +525,7 @@ pub fn view_scenes_names (
) -> impl Draw<Tui> { ) -> impl Draw<Tui> {
w_exact(20, thunk(move |to: &mut Tui|{ w_exact(20, thunk(move |to: &mut Tui|{
for (index, scene, ..) in scenes { for (index, scene, ..) in scenes {
view_scene_name(select, editor, index, scene, editing).draw(to); view_scene_name(select, editor, index, scene, editing).draw(to)?;
} }
Ok(XYWH(1, 1, 1, 1)) Ok(XYWH(1, 1, 1, 1))
})) }))
@ -639,10 +637,10 @@ pub fn view_outputs (
origin_w(east("", fg(Rgb(255,255,255), bold(true, port.port_name())))), origin_w(east("", fg(Rgb(255,255,255), bold(true, port.port_name())))),
w_full(origin_e(format!("{}/{} ", w_full(origin_e(format!("{}/{} ",
port.port().get_connections().len(), port.port().get_connections().len(),
port.connections.len())))))).draw(to); port.connections.len())))))).draw(to)?;
for (index, conn) in port.connections.iter().enumerate() { for (index, conn) in port.connections.iter().enumerate() {
h_exact(1, w_full(origin_w(format!(" c{index:02}{}", conn.info())))) h_exact(1, w_full(origin_w(format!(" c{index:02}{}", conn.info()))))
.draw(to); .draw(to)?;
} }
} }
todo!(); todo!();
@ -658,14 +656,14 @@ pub fn view_outputs (
h_exact(1, origin_w(east( h_exact(1, origin_w(east(
either(true, fg(Green, "play "), "play "), either(true, fg(Green, "play "), "play "),
either(false, fg(Yellow, "solo "), "solo "), either(false, fg(Yellow, "solo "), "solo "),
))).draw(to); ))).draw(to)?;
for (_index, port) in midi_outs.iter().enumerate() { for (_index, port) in midi_outs.iter().enumerate() {
h_exact(1, origin_w(east( h_exact(1, origin_w(east(
either(true, fg(Green, ""), " · "), either(true, fg(Green, ""), " · "),
either(false, fg(Yellow, ""), " · "), either(false, fg(Yellow, ""), " · "),
))).draw(to); ))).draw(to)?;
for (_index, _conn) in port.connections.iter().enumerate() { for (_index, _conn) in port.connections.iter().enumerate() {
h_exact(1, w_full("")).draw(to); h_exact(1, w_full("")).draw(to)?;
} }
} }
todo!() todo!()
@ -734,7 +732,7 @@ pub fn view_sessions () -> impl Draw<Tui> {
let b = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) }; let b = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) };
let y = (2 * index) as u16; let y = (2 * index) as u16;
let h = 2; let h = 2;
y_push(y, &h_exact(h, w_full(bg(b, origin_w(fg(f, name)))))).draw(to); y_push(y, h_exact(h, w_full(bg(b, origin_w(fg(f, *name)))))).draw(to)?;
} }
Ok(to.area().into()) Ok(to.area().into())
}))) })))

View file

@ -1,6 +1,6 @@
use crate::*; use crate::*;
impl_has!(Size: |self: App|self.size); impl_has!(Sizer: |self: App|self.size);
/// Define a type alias for iterators of sized items (columns). /// Define a type alias for iterators of sized items (columns).
macro_rules! def_sizes_iter { macro_rules! def_sizes_iter {

View file

@ -16,9 +16,9 @@ use crate::*;
/// TODO rename to "render_cache" or smth /// TODO rename to "render_cache" or smth
pub arranger: Arc<RwLock<Buffer>>, pub arranger: Arc<RwLock<Buffer>>,
/// Display size /// Display size
pub size: Size, pub size: Sizer,
/// Display size of clips area /// Display size of clips area
pub size_inner: Size, pub size_inner: Sizer,
/// Source of time /// Source of time
#[cfg(feature = "clock")] pub clock: Clock, #[cfg(feature = "clock")] pub clock: Clock,
/// Allows one MIDI clip to be edited /// Allows one MIDI clip to be edited
@ -47,7 +47,7 @@ use crate::*;
impl HasJack<'static> for Arrangement { fn jack (&self) -> &Jack<'static> { &self.jack } } impl HasJack<'static> for Arrangement { fn jack (&self) -> &Jack<'static> { &self.jack } }
impl_has!(Jack<'static>: |self: Arrangement| self.jack); impl_has!(Jack<'static>: |self: Arrangement| self.jack);
impl_has!(Size: |self: Arrangement| self.size); impl_has!(Sizer: |self: Arrangement| self.size);
impl_has!(Vec<MidiInput>: |self: Arrangement| self.midi_ins); impl_has!(Vec<MidiInput>: |self: Arrangement| self.midi_ins);
impl_has!(Vec<MidiOutput>: |self: Arrangement| self.midi_outs); impl_has!(Vec<MidiOutput>: |self: Arrangement| self.midi_outs);
impl_has!(Clock: |self: Arrangement| self.clock); impl_has!(Clock: |self: Arrangement| self.clock);

View file

@ -37,10 +37,6 @@ pub trait ClipsView: TracksView + ScenesView {
} }
} }
impl HasClipsSize for Arrangement {
fn clips_size (&self) -> &Size { &self.size_inner }
}
def_command!(ClipCommand: |clip: MidiClip| { def_command!(ClipCommand: |clip: MidiClip| {
SetColor { color: Option<ItemTheme> } => { SetColor { color: Option<ItemTheme> } => {
//(SetColor [t: usize, s: usize, c: ItemTheme] //(SetColor [t: usize, s: usize, c: ItemTheme]
@ -86,8 +82,14 @@ impl Arrangement {
} }
} }
pub trait HasClipsSize { fn clips_size (&self) -> &Size; } pub trait HasClipsSize {
fn clips_size (&self) -> &Sizer;
}
impl HasClipsSize for App { impl HasClipsSize for App {
fn clips_size (&self) -> &Size { &self.project.size_inner } fn clips_size (&self) -> &Sizer { &self.project.size_inner }
}
impl HasClipsSize for Arrangement {
fn clips_size (&self) -> &Sizer { &self.size_inner }
} }

View file

@ -21,7 +21,7 @@ def_command!(FileBrowserCommand: |sampler: Sampler|{
pub filter: String, pub filter: String,
pub index: usize, pub index: usize,
pub scroll: usize, pub scroll: usize,
pub size: Size, pub size: Sizer,
} }
pub(crate) struct EntriesIterator<'a, S: Screen> { pub(crate) struct EntriesIterator<'a, S: Screen> {

View file

@ -1,7 +1,12 @@
use crate::*; use crate::*;
use ::std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::*}}; use ::std::sync::{Arc, RwLock, atomic::AtomicUsize};
use ::atomic_float::AtomicF64; use ::atomic_float::AtomicF64;
use ::tengri::{draw::*, term::*};
mod memo; pub use self::memo::*;
mod moment; pub use self::moment::*;
mod ticker; pub use self::ticker::*;
mod timebase; pub use self::timebase::*;
mod clock_view; pub use self::clock_view::*;
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {} impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
pub trait HasClock: AsRef<Clock> + AsMut<Clock> { pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
@ -396,8 +401,3 @@ impl_time_unit!(Ppq);
impl_time_unit!(Pulse); impl_time_unit!(Pulse);
impl_time_unit!(Bpm); impl_time_unit!(Bpm);
impl_time_unit!(LaunchSync); impl_time_unit!(LaunchSync);
mod moment; pub use self::moment::*;
mod ticker; pub use self::ticker::*;
mod timebase; pub use self::timebase::*;
mod clock_view; pub use self::clock_view::*;

53
src/device/clock/memo.rs Normal file
View file

@ -0,0 +1,53 @@
use crate::*;
#[macro_export] macro_rules! rewrite {
($buf:ident, $($rest:tt)*) => {
|$buf,_,_|{
$buf.clear();
write!($buf, $($rest)*)
}
};
}
pub struct Memo<T, U> {
value: T,
view: U,
}
impl<T, U> Memo<T, U> {
pub fn new (value: T, view: U) -> Self {
Self { value, view }
}
}
impl<T: PartialEq + Debug, U: Debug> Debug for Memo<T, U> {
fn fmt (&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
todo!()
}
}
impl<T: PartialEq, U> Memo<T, U> {
pub 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, &newval, &self.value);
self.value = newval;
return Some(result);
}
None
}
}
pub trait Gettable<T> {
/// Returns current value
fn get (&self) -> T;
}
pub trait Mutable<T>: Gettable<T> {
/// Sets new value, returns old
fn set (&mut self, value: T) -> T;
}
pub trait InteriorMutable<T>: Gettable<T> {
/// Sets new value, returns old
fn set (&self, value: T) -> T;
}

View file

@ -19,12 +19,12 @@ pub struct MidiEditor {
/// View mode and state of editor /// View mode and state of editor
pub mode: PianoHorizontal, pub mode: PianoHorizontal,
/// Size of editor on screen /// Size of editor on screen
pub size: Size, pub size: Sizer,
} }
impl_default!(MidiEditor: Self { impl_default!(MidiEditor: Self {
mode: PianoHorizontal::new(None), mode: PianoHorizontal::new(None),
size: Size( size: Sizer(
Arc::new(0usize.into()), Arc::new(0usize.into()),
Arc::new(0usize.into()), Arc::new(0usize.into()),
), ),
@ -255,13 +255,7 @@ pub trait MidiViewer: MidiRange + MidiPoint + Debug + Send + Sync {
} }
} }
impl_has!(Size: |self: MidiEditor| self.size); impl_has!(Sizer: |self: MidiEditor| self.size);
impl Draw<Tui> for MidiEditor {
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
self.mode.tui().draw(to)
}
}
impl std::fmt::Debug for MidiEditor { impl std::fmt::Debug for MidiEditor {
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
@ -303,7 +297,7 @@ impl View<Tui> for MidiEditor {
fn view (&self) -> impl Draw<Tui> { fn view (&self) -> impl Draw<Tui> {
self.autoscroll(); self.autoscroll();
/*self.autozoom();*/ /*self.autozoom();*/
self.size.of(&self.mode) self.size.of(self.mode.view())
} }
} }

View file

@ -11,7 +11,7 @@ pub struct PianoHorizontal {
/// Buffer where the whole clip is rerendered on change /// Buffer where the whole clip is rerendered on change
pub buffer: Arc<RwLock<BigBuffer>>, pub buffer: Arc<RwLock<BigBuffer>>,
/// Size of actual notes area /// Size of actual notes area
pub size: Size, pub size: Sizer,
/// The display window /// The display window
pub range: MidiSelection, pub range: MidiSelection,
/// The note cursor /// The note cursor
@ -22,17 +22,21 @@ pub struct PianoHorizontal {
pub keys_width: u16, pub keys_width: u16,
} }
impl_has!(Size: |self: PianoHorizontal| self.size); impl_has!(Sizer: |self: PianoHorizontal| self.size);
impl Draw<Tui> for PianoHorizontal {
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> { impl View<Tui> for PianoHorizontal {
self.tui().draw(to) fn view (&self) -> impl Draw<Tui> {
south(
east(w_exact(5, format!("{}x{}", self.size.w(), self.size.h())), self.timeline()),
east(self.keys(), self.size.of(below(wh_full(self.notes()), wh_full(self.cursor())))),
)
} }
} }
impl PianoHorizontal { impl PianoHorizontal {
pub fn new (clip: Option<&Arc<RwLock<MidiClip>>>) -> Self { pub fn new (clip: Option<&Arc<RwLock<MidiClip>>>) -> Self {
let size = Size::default(); let size = Sizer::default();
let mut range = MidiSelection::from((12, true)); let mut range = MidiSelection::from((12, true));
range.time_axis = size.0.clone(); range.time_axis = size.0.clone();
range.note_axis = size.1.clone(); range.note_axis = size.1.clone();
@ -49,13 +53,6 @@ impl PianoHorizontal {
piano piano
} }
pub fn tui (&self) -> impl Draw<Tui> {
south(
east(w_exact(5, format!("{}x{}", self.size.w(), self.size.h())), self.timeline()),
east(self.keys(), self.size.of(below(wh_full(self.notes()), wh_full(self.cursor())))),
)
}
/// Draw the piano roll background. /// Draw the piano roll background.
/// ///
/// This mode uses full blocks on note on and half blocks on legato: █▄ █▄ █▄ /// This mode uses full blocks on note on and half blocks on legato: █▄ █▄ █▄

View file

@ -44,7 +44,7 @@ mod sample_kit; pub use self::sample_kit::*;
/// Currently active modal, if any. /// Currently active modal, if any.
pub mode: Option<SamplerMode>, pub mode: Option<SamplerMode>,
/// Size of rendered sampler. /// Size of rendered sampler.
pub size: Size, pub size: Sizer,
/// Lowest note displayed. /// Lowest note displayed.
pub note_lo: AtomicUsize, pub note_lo: AtomicUsize,
/// Currently selected note. /// Currently selected note.

2
tengri

@ -1 +1 @@
Subproject commit 90ebae0f26fc4524659704df274d0aec815dba2e Subproject commit 0b9e9c06962e5cd55b639d9c0a7cef6f11405d81