well, 55 errors until up to date

and then we fix
This commit is contained in:
okay stopped screaming 2026-03-21 20:33:51 +02:00
parent 0577309b19
commit 7ff1d989a9
5 changed files with 333 additions and 344 deletions

View file

@ -64,18 +64,18 @@ use std::fmt::Write;
}
}
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
impl <T: AsRef<Selection>+AsMut<Selection>> HasSelection for T {}
impl <T: AsRef<Sequencer>+AsMut<Sequencer>> HasSequencer for T {}
impl <T: AsRef<Vec<Scene>>+AsMut<Vec<Scene>>> HasScenes for T {}
impl <T: AsRef<Vec<Track>>+AsMut<Vec<Track>>> HasTracks for T {}
impl <T: AsRefOpt<MidiEditor>+AsMutOpt<MidiEditor>> HasEditor for T {}
impl <T: AsRefOpt<Scene>+AsMutOpt<Scene>+Send+Sync> HasScene for T {}
impl <T: AsRefOpt<Track>+AsMutOpt<Track>+Send+Sync> HasTrack for T {}
impl <T: NotePoint+TimePoint> MidiPoint for T {}
impl <T: ScenesView+HasMidiIns+HasMidiOuts+HasTrackScroll+Measured<TuiOut>> TracksView for T {}
impl <T: TimeRange+NoteRange> MidiRange for T {}
impl <T: TracksView+ScenesView+Send+Sync> ClipsView for T {}
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
impl <T: AsRef<Selection>+AsMut<Selection>> HasSelection for T {}
impl <T: AsRef<Sequencer>+AsMut<Sequencer>> HasSequencer for T {}
impl <T: AsRef<Vec<Scene>>+AsMut<Vec<Scene>>> HasScenes for T {}
impl <T: AsRef<Vec<Track>>+AsMut<Vec<Track>>> HasTracks for T {}
impl <T: AsRefOpt<MidiEditor>+AsMutOpt<MidiEditor>> HasEditor for T {}
impl <T: AsRefOpt<Scene>+AsMutOpt<Scene>+Send+Sync> HasScene for T {}
impl <T: AsRefOpt<Track>+AsMutOpt<Track>+Send+Sync> HasTrack for T {}
impl <T: NotePoint+TimePoint> MidiPoint for T {}
impl <T: ScenesView+HasMidiIns+HasMidiOuts+HasTrackScroll+Measured<Tui>> TracksView for T {}
impl <T: TimeRange+NoteRange> MidiRange for T {}
impl <T: TracksView+ScenesView+Send+Sync> ClipsView for T {}
mod app {
use crate::*;
@ -84,24 +84,24 @@ mod app {
impl_has!(Vec<MidiOutput>: |self: App|self.project.midi_outs);
impl_has!(Dialog: |self: App|self.dialog);
impl_has!(Jack<'static>: |self: App|self.jack);
impl_has!(Measure<TuiOut>: |self: App|self.size);
impl_has!(Measure<Tui>: |self: App|self.size);
impl_has!(Pool: |self: App|self.pool);
impl_has!(Selection: |self: App|self.project.selection);
impl_as_ref!(Vec<Scene>: |self: App|self.project.as_ref());
impl_as_mut!(Vec<Scene>: |self: App|self.project.as_mut());
impl_as_ref_opt!(MidiEditor: |self: App|self.project.as_ref_opt());
impl_as_mut_opt!(MidiEditor: |self: App|self.project.as_mut_opt());
has_clips!( |self: App|self.pool.clips);
impl_has_clips!( |self: App|self.pool.clips);
impl_audio!(App: tek_jack_process, tek_jack_event);
handle!(TuiIn: |self: App, input|{
impl_handle!(TuiIn: |self: App, input|{
let commands = collect_commands(self, input)?;
let history = execute_commands(self, commands)?;
self.history.extend(history.into_iter());
Ok(None)
});
impl Draw<TuiOut> for App {
fn draw (&self, to: &mut TuiOut) {
impl Draw<Tui> for App {
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
if let Some(e) = self.error.read().unwrap().as_ref() {
to.show(to.area(), e);
}
@ -125,16 +125,16 @@ mod app {
});
}
impl Understand<TuiOut, ()> for App {
fn understand_expr <'a> (&'a self, to: &mut TuiOut, lang: &'a impl Expression) -> Usually<()> {
impl Understand<Tui, ()> for App {
fn understand_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Usually<()> {
app_understand_expr(self, to, lang)
}
fn understand_word <'a> (&'a self, to: &mut TuiOut, lang: &'a impl Expression) -> Usually<()> {
fn understand_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Usually<()> {
app_understand_word(self, to, lang)
}
}
fn app_understand_expr (state: &App, to: &mut TuiOut, lang: &impl Expression) -> Usually<()> {
fn app_understand_expr (state: &App, to: &mut Tui, lang: &impl Expression) -> Usually<()> {
if evaluate_output_expression(state, to, lang)?
|| evaluate_output_expression_tui(state, to, lang)? {
Ok(())
@ -143,22 +143,22 @@ mod app {
}
}
fn app_understand_word (state: &App, to: &mut TuiOut, dsl: &impl Expression) -> Usually<()> {
fn app_understand_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usually<()> {
let mut frags = dsl.src()?.unwrap().split("/");
match frags.next() {
Some(":logo") => to.place(&view_logo()),
Some(":status") => to.place(&Fixed::Y(1, "TODO: Status Bar")),
Some(":status") => to.place(&h_exact(1, "TODO: Status Bar")),
Some(":meters") => match frags.next() {
Some("input") => to.place(&Tui::bg(Rgb(30, 30, 30), Fill::Y(Align::s("Input Meters")))),
Some("output") => to.place(&Tui::bg(Rgb(30, 30, 30), Fill::Y(Align::s("Output Meters")))),
Some("input") => to.place(&Tui::bg(Rgb(30, 30, 30), h_full(origin_s("Input Meters")))),
Some("output") => to.place(&Tui::bg(Rgb(30, 30, 30), h_full(origin_s("Output Meters")))),
_ => panic!()
},
Some(":tracks") => match frags.next() {
None => to.place(&"TODO tracks"),
Some("names") => to.place(&state.project.view_track_names(state.color.clone())),//Tui::bg(Rgb(40, 40, 40), Fill::X(Align::w("Track Names")))),
Some("inputs") => to.place(&Tui::bg(Rgb(40, 40, 40), Fill::X(Align::w("Track Inputs")))),
Some("devices") => to.place(&Tui::bg(Rgb(40, 40, 40), Fill::X(Align::w("Track Devices")))),
Some("outputs") => to.place(&Tui::bg(Rgb(40, 40, 40), Fill::X(Align::w("Track Outputs")))),
Some("names") => to.place(&state.project.view_track_names(state.color.clone())),//Tui::bg(Rgb(40, 40, 40), w_full(origin_w("Track Names")))),
Some("inputs") => to.place(&Tui::bg(Rgb(40, 40, 40), w_full(origin_w("Track Inputs")))),
Some("devices") => to.place(&Tui::bg(Rgb(40, 40, 40), w_full(origin_w("Track Devices")))),
Some("outputs") => to.place(&Tui::bg(Rgb(40, 40, 40), w_full(origin_w("Track Outputs")))),
_ => panic!()
},
Some(":scenes") => match frags.next() {
@ -171,13 +171,13 @@ mod app {
Some("menu") => to.place(&if let Dialog::Menu(selected, items) = &state.dialog {
let items = items.clone();
let selected = selected;
Some(Fill::XY(Thunk::new(move|to: &mut TuiOut|{
Some(wh_full(Thunk::new(move|to: &mut Tui|{
for (index, MenuItem(item, _)) in items.0.iter().enumerate() {
to.place(&Push::Y((2 * index) as u16,
to.place(&y_push((2 * index) as u16,
Tui::fg_bg(
if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) },
if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) },
Fixed::Y(2, Align::n(Fill::X(item)))
h_exact(2, origin_n(w_full(item)))
)));
}
})))
@ -189,31 +189,31 @@ mod app {
Some(":templates") => to.place(&{
let modes = state.config.modes.clone();
let height = (modes.read().unwrap().len() * 2) as u16;
Fixed::Y(height, Min::X(30, Thunk::new(move |to: &mut TuiOut|{
h_exact(height, w_min(30, Thunk::new(move |to: &mut Tui|{
for (index, (id, profile)) in modes.read().unwrap().iter().enumerate() {
let bg = if index == 0 { Rgb(70,70,70) } else { Rgb(50,50,50) };
let name = profile.name.get(0).map(|x|x.as_ref()).unwrap_or("<no name>");
let info = profile.info.get(0).map(|x|x.as_ref()).unwrap_or("<no info>");
let fg1 = Rgb(224, 192, 128);
let fg2 = Rgb(224, 128, 32);
let field_name = Fill::X(Align::w(Tui::fg(fg1, name)));
let field_id = Fill::X(Align::e(Tui::fg(fg2, id)));
let field_info = Fill::X(Align::w(info));
to.place(&Push::Y((2 * index) as u16,
Fixed::Y(2, Fill::X(Tui::bg(bg, Bsp::s(
Bsp::a(field_name, field_id), field_info))))));
let field_name = w_full(origin_w(Tui::fg(fg1, name)));
let field_id = w_full(origin_e(Tui::fg(fg2, id)));
let field_info = w_full(origin_w(info));
to.place(&y_push((2 * index) as u16,
h_exact(2, w_full(Tui::bg(bg, south(
above(field_name, field_id), field_info))))));
}
})))
}),
Some(":sessions") => to.place(&Fixed::Y(6, Min::X(30, Thunk::new(|to: &mut TuiOut|{
Some(":sessions") => to.place(&h_exact(6, w_min(30, Thunk::new(|to: &mut Tui|{
let fg = Rgb(224, 192, 128);
for (index, name) in ["session1", "session2", "session3"].iter().enumerate() {
let bg = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) };
to.place(&Push::Y((2 * index) as u16,
&Fixed::Y(2, Fill::X(Tui::bg(bg, Align::w(Tui::fg(fg, name)))))));
to.place(&y_push((2 * index) as u16,
&h_exact(2, w_full(Tui::bg(bg, origin_w(Tui::fg(fg, name)))))));
}
})))),
Some(":browse/title") => to.place(&Fill::X(Align::w(FieldV(ItemColor::default(),
Some(":browse/title") => to.place(&w_full(origin_w(field_v(ItemColor::default(),
match state.dialog.browser_target().unwrap() {
BrowseTarget::SaveProject => "Save project:",
BrowseTarget::LoadProject => "Load project:",
@ -221,18 +221,18 @@ mod app {
BrowseTarget::ExportSample(_) => "Export sample:",
BrowseTarget::ImportClip(_) => "Import clip:",
BrowseTarget::ExportClip(_) => "Export clip:",
}, Shrink::X(3, Fixed::Y(1, Tui::fg(Tui::g(96), Repeat::X("🭻")))))))),
}, w_shrink(3, h_exact(1, Tui::fg(Tui::g(96), x_repeat("🭻")))))))),
Some(":device") => {
let selected = state.dialog.device_kind().unwrap();
to.place(&Bsp::s(Tui::bold(true, "Add device"), Map::south(1,
to.place(&south(Tui::bold(true, "Add device"), iter_south(1,
move||device_kinds().iter(),
move|_label: &&'static str, i|{
let bg = if i == selected { Rgb(64,128,32) } else { Rgb(0,0,0) };
let lb = if i == selected { "[ " } else { " " };
let rb = if i == selected { " ]" } else { " " };
Fill::X(Tui::bg(bg, Bsp::e(lb, Bsp::w(rb, "FIXME device name")))) })))
w_full(Tui::bg(bg, east(lb, west(rb, "FIXME device name")))) })))
},
Some(":debug") => to.place(&Fixed::Y(1, format!("[{:?}]", to.area()))),
Some(":debug") => to.place(&h_exact(1, format!("[{:?}]", to.area()))),
Some(_) => {
let views = state.config.views.read().unwrap();
if let Some(dsl) = views.get(dsl.src()?.unwrap()) {
@ -375,7 +375,7 @@ mod app {
mod arrange {
use crate::*;
impl_has!(Jack<'static>: |self: Arrangement| self.jack);
impl_has!(Measure<TuiOut>: |self: Arrangement| self.size);
impl_has!(Measure<Tui>: |self: Arrangement| self.size);
impl_has!(Vec<Track>: |self: Arrangement| self.tracks);
impl_has!(Vec<Scene>: |self: Arrangement| self.scenes);
impl_has!(Vec<MidiInput>: |self: Arrangement| self.midi_ins);
@ -479,79 +479,79 @@ mod arrange {
}
Ok((index, &mut self.tracks_mut()[index]))
}
#[cfg(feature = "track")] pub fn view_inputs (&self, _theme: ItemTheme) -> impl Content<TuiOut> + '_ {
Bsp::s(
Fixed::Y(1, self.view_inputs_header()),
Thunk::new(|to: &mut TuiOut|{
#[cfg(feature = "track")] pub fn view_inputs (&self, _theme: ItemTheme) -> impl Draw<Tui> + '_ {
south(
h_exact(1, self.view_inputs_header()),
Thunk::new(|to: &mut Tui|{
for (index, port) in self.midi_ins().iter().enumerate() {
to.place(&Push::X(index as u16 * 10, Fixed::Y(1, self.view_inputs_row(port))))
to.place(&x_push(index as u16 * 10, h_exact(1, self.view_inputs_row(port))))
}
})
)
}
#[cfg(feature = "track")] fn view_inputs_header (&self) -> impl Content<TuiOut> + '_ {
Bsp::e(Fixed::X(20, Align::w(button_3("i", "nput ", format!("{}", self.midi_ins.len()), false))),
Bsp::w(Fixed::X(4, button_2("I", "+", false)), Thunk::new(move|to: &mut TuiOut|for (_index, track, x1, _x2) in self.tracks_with_sizes() {
#[cfg(feature = "track")] fn view_inputs_header (&self) -> impl Draw<Tui> + '_ {
east(w_exact(20, origin_w(button_3("i", "nput ", format!("{}", self.midi_ins.len()), false))),
west(w_exact(4, button_2("I", "+", false)), Thunk::new(move|to: &mut Tui|for (_index, track, x1, _x2) in self.tracks_with_sizes() {
#[cfg(feature = "track")]
to.place(&Push::X(x1 as u16, Tui::bg(track.color.dark.rgb, Align::w(Fixed::X(track.width as u16, row!(
Either::new(track.sequencer.monitoring, Tui::fg(Green, "mon "), "mon "),
Either::new(track.sequencer.recording, Tui::fg(Red, "rec "), "rec "),
Either::new(track.sequencer.overdub, Tui::fg(Yellow, "dub "), "dub "),
to.place(&x_push(x1 as u16, Tui::bg(track.color.dark.rgb, origin_w(w_exact(track.width as u16, east!(
either(track.sequencer.monitoring, Tui::fg(Green, "mon "), "mon "),
either(track.sequencer.recording, Tui::fg(Red, "rec "), "rec "),
either(track.sequencer.overdub, Tui::fg(Yellow, "dub "), "dub "),
))))))
})))
}
#[cfg(feature = "track")] fn view_inputs_row (&self, port: &MidiInput) -> impl Content<TuiOut> {
Bsp::e(Fixed::X(20, Align::w(Bsp::e("", Tui::bold(true, Tui::fg(Rgb(255,255,255), port.port_name()))))),
Bsp::w(Fixed::X(4, ()), Thunk::new(move|to: &mut TuiOut|for (_index, track, _x1, _x2) in self.tracks_with_sizes() {
#[cfg(feature = "track")] fn view_inputs_row (&self, port: &MidiInput) -> impl Draw<Tui> {
east(w_exact(20, origin_w(east("", Tui::bold(true, Tui::fg(Rgb(255,255,255), port.port_name()))))),
west(w_exact(4, ()), Thunk::new(move|to: &mut Tui|for (_index, track, _x1, _x2) in self.tracks_with_sizes() {
#[cfg(feature = "track")]
to.place(&Tui::bg(track.color.darker.rgb, Align::w(Fixed::X(track.width as u16, row!(
Either::new(track.sequencer.monitoring, Tui::fg(Green, ""), " · "),
Either::new(track.sequencer.recording, Tui::fg(Red, ""), " · "),
Either::new(track.sequencer.overdub, Tui::fg(Yellow, ""), " · "),
to.place(&Tui::bg(track.color.darker.rgb, origin_w(w_exact(track.width as u16, east!(
either(track.sequencer.monitoring, Tui::fg(Green, ""), " · "),
either(track.sequencer.recording, Tui::fg(Red, ""), " · "),
either(track.sequencer.overdub, Tui::fg(Yellow, ""), " · "),
)))))
})))
}
#[cfg(feature = "track")] pub fn view_outputs (&self, theme: ItemTheme) -> impl Content<TuiOut> {
#[cfg(feature = "track")] pub fn view_outputs (&self, theme: ItemTheme) -> impl Draw<Tui> {
let mut h = 1;
for output in self.midi_outs().iter() {
h += 1 + output.connections.len();
}
let h = h as u16;
let list = Bsp::s(
Fixed::Y(1, Fill::X(Align::w(button_3("o", "utput", format!("{}", self.midi_outs.len()), false)))),
Fixed::Y(h - 1, Fill::XY(Align::nw(Thunk::new(|to: &mut TuiOut|{
let list = south(
h_exact(1, w_full(origin_w(button_3("o", "utput", format!("{}", self.midi_outs.len()), false)))),
h_exact(h - 1, wh_full(origin_nw(Thunk::new(|to: &mut Tui|{
for (_index, port) in self.midi_outs().iter().enumerate() {
to.place(&Fixed::Y(1,Fill::X(Bsp::e(
Align::w(Bsp::e("", Tui::fg(Rgb(255,255,255),Tui::bold(true, port.port_name())))),
Fill::X(Align::e(format!("{}/{} ",
to.place(&h_exact(1,w_full(east(
origin_w(east("", Tui::fg(Rgb(255,255,255),Tui::bold(true, port.port_name())))),
w_full(origin_e(format!("{}/{} ",
port.port().get_connections().len(),
port.connections.len())))))));
for (index, conn) in port.connections.iter().enumerate() {
to.place(&Fixed::Y(1, Fill::X(Align::w(format!(" c{index:02}{}", conn.info())))));
to.place(&h_exact(1, w_full(origin_w(format!(" c{index:02}{}", conn.info())))));
}
}
})))));
Fixed::Y(h, view_track_row_section(theme, list, button_2("O", "+", false),
Tui::bg(theme.darker.rgb, Align::w(Fill::X(
Thunk::new(|to: &mut TuiOut|{
h_exact(h, view_track_row_section(theme, list, button_2("O", "+", false),
Tui::bg(theme.darker.rgb, origin_w(w_full(
Thunk::new(|to: &mut Tui|{
for (index, track, _x1, _x2) in self.tracks_with_sizes() {
to.place(&Fixed::X(track_width(index, track),
Thunk::new(|to: &mut TuiOut|{
to.place(&Fixed::Y(1, Align::w(Bsp::e(
Either::new(true, Tui::fg(Green, "play "), "play "),
Either::new(false, Tui::fg(Yellow, "solo "), "solo "),
to.place(&w_exact(track_width(index, track),
Thunk::new(|to: &mut Tui|{
to.place(&h_exact(1, origin_w(east(
either(true, Tui::fg(Green, "play "), "play "),
either(false, Tui::fg(Yellow, "solo "), "solo "),
))));
for (_index, port) in self.midi_outs().iter().enumerate() {
to.place(&Fixed::Y(1, Align::w(Bsp::e(
Either::new(true, Tui::fg(Green, ""), " · "),
Either::new(false, Tui::fg(Yellow, ""), " · "),
to.place(&h_exact(1, origin_w(east(
either(true, Tui::fg(Green, ""), " · "),
either(false, Tui::fg(Yellow, ""), " · "),
))));
for (_index, _conn) in port.connections.iter().enumerate() {
to.place(&Fixed::Y(1, Fill::X("")));
to.place(&h_exact(1, w_full("")));
}
}})))}}))))))
}
#[cfg(feature = "track")] pub fn view_track_devices (&self, theme: ItemTheme) -> impl Content<TuiOut> {
#[cfg(feature = "track")] pub fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<Tui> {
let mut h = 2u16;
for track in self.tracks().iter() {
h = h.max(track.devices.len() as u16 * 2);
@ -559,14 +559,14 @@ mod arrange {
view_track_row_section(theme,
button_3("d", "evice", format!("{}", self.track().map(|t|t.devices.len()).unwrap_or(0)), false),
button_2("D", "+", false),
Thunk::new(move|to: &mut TuiOut|for (index, track, _x1, _x2) in self.tracks_with_sizes() {
to.place(&Fixed::XY(track_width(index, track), h + 1,
Tui::bg(track.color.dark.rgb, Align::nw(Map::south(2, move||0..h,
|_, _index|Fixed::XY(track.width as u16, 2,
Thunk::new(move|to: &mut Tui|for (index, track, _x1, _x2) in self.tracks_with_sizes() {
to.place(&wh_exact(track_width(index, track), h + 1,
Tui::bg(track.color.dark.rgb, origin_nw(iter_south(2, move||0..h,
|_, _index|wh_exact(track.width as u16, 2,
Tui::fg_bg(
ItemTheme::G[32].lightest.rgb,
ItemTheme::G[32].dark.rgb,
Align::nw(format!(" · {}", "--")))))))));
origin_nw(format!(" · {}", "--")))))))));
}))
}
/// Put a clip in a slot
@ -616,7 +616,7 @@ mod arrange {
}
}
impl HasClipsSize for Arrangement {
fn clips_size (&self) -> &Measure<TuiOut> { &self.size_inner }
fn clips_size (&self) -> &Measure<Tui> { &self.size_inner }
}
}
@ -657,14 +657,14 @@ mod browse {
fn _todo_stub_usize (&self) -> usize { todo!() }
fn _todo_stub_arc_str (&self) -> Arc<str> { todo!() }
}
impl HasContent<TuiOut> for Browse {
fn content (&self) -> impl Content<TuiOut> {
Map::south(1, ||EntriesIterator {
impl Browse {
fn tui (&self) -> impl Draw<Tui> {
iter_south(1, ||EntriesIterator {
offset: 0,
index: 0,
length: self.dirs.len() + self.files.len(),
browser: self,
}, |entry, _index|Fill::X(Align::w(entry)))
}, |entry, _index|w_full(origin_w(entry)))
}
}
impl<'a> Iterator for EntriesIterator<'a> {
@ -1117,7 +1117,7 @@ impl InteriorMutable<usize> for AtomicUsize { fn set (&self, value: usize) -> us
impl PartialEq for MenuItem { fn eq (&self, other: &Self) -> bool { self.0 == other.0 } }
impl AsRef<Arc<[MenuItem]>> for MenuItems { fn as_ref (&self) -> &Arc<[MenuItem]> { &self.0 } }
impl HasClipsSize for App { fn clips_size (&self) -> &Measure<TuiOut> { &self.project.size_inner } }
impl HasClipsSize for App { fn clips_size (&self) -> &Measure<Tui> { &self.project.size_inner } }
impl HasJack<'static> for MidiInput { fn jack (&self) -> &Jack<'static> { &self.jack } }
impl HasJack<'static> for MidiOutput { fn jack (&self) -> &Jack<'static> { &self.jack } }
impl HasJack<'static> for AudioInput { fn jack (&self) -> &Jack<'static> { &self.jack } }
@ -1795,11 +1795,8 @@ mod audio {
mod meter {
use crate::*;
impl Layout<TuiOut> for RmsMeter {}
impl Layout<TuiOut> for Log10Meter {}
impl Draw<TuiOut> for RmsMeter {
fn draw (&self, to: &mut TuiOut) {
impl Draw<Tui> for RmsMeter {
fn draw(self, to: &mut Tui) -> Usually<XYWH<u16>> {
let XYWH(x, y, w, h) = to.area();
let signal = f32::max(0.0, f32::min(100.0, self.0.abs()));
let v = (signal * h as f32).ceil() as u16;
@ -1813,8 +1810,8 @@ mod audio {
}
}
impl Draw<TuiOut> for Log10Meter {
fn draw (&self, to: &mut TuiOut) {
impl Draw<Tui> for Log10Meter {
fn draw(self, to: &mut Tui) -> Usually<XYWH<u16>> {
let XYWH(x, y, w, h) = to.area();
let signal = 100.0 - f32::max(0.0, f32::min(100.0, self.0.abs()));
let v = (signal * h as f32 / 100.0).ceil() as u16;
@ -1828,9 +1825,9 @@ mod audio {
}
}
fn draw_meters (meters: &[f32]) -> impl Content<TuiOut> + use<'_> {
Tui::bg(Black, Fixed::X(2, Map::east(1, ||meters.iter(), |value, _index|{
Fill::Y(RmsMeter(*value))
fn draw_meters (meters: &[f32]) -> impl Draw<Tui> + use<'_> {
Tui::bg(Black, w_exact(2, iter_east(1, ||meters.iter(), |value, _index|{
h_full(RmsMeter(*value))
})))
}
}
@ -1879,14 +1876,14 @@ mod audio {
fn _todo_usize_stub_ (&self) -> usize { todo!() }
fn _todo_arc_str_stub_ (&self) -> Arc<str> { todo!() }
fn _todo_item_theme_stub (&self) -> ItemTheme { todo!() }
pub fn per <'a, T: Content<TuiOut> + 'a, U: TracksSizes<'a>> (
pub fn per <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> (
tracks: impl Fn() -> U + Send + Sync + 'a,
callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
Map::new(tracks,
) -> impl Draw<Tui> + 'a {
iter(tracks,
move|(index, track, x1, x2): (usize, &'a Track, usize, usize), _|{
let width = (x2 - x1) as u16;
map_east(x1 as u16, width, Fixed::X(width, Tui::fg_bg(
iter_east(x1 as u16, width, w_exact(width, Tui::fg_bg(
track.color.lightest.rgb,
track.color.base.rgb,
callback(index, track))))})
@ -1932,21 +1929,21 @@ mod audio {
}
}
pub fn per_track <'a, T: Content<TuiOut> + 'a, U: TracksSizes<'a>> (
pub fn per_track <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> (
tracks: impl Fn() -> U + Send + Sync + 'a,
callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
per_track_top(tracks, move|index, track|Fill::Y(Align::y(callback(index, track))))
) -> impl Draw<Tui> + 'a {
per_track_top(tracks, move|index, track|h_full(origin_y(callback(index, track))))
}
pub fn per_track_top <'a, T: Content<TuiOut> + 'a, U: TracksSizes<'a>> (
pub fn per_track_top <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> (
tracks: impl Fn() -> U + Send + Sync + 'a,
callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
Align::x(Tui::bg(Reset, Map::new(tracks,
) -> impl Draw<Tui> + 'a {
origin_x(Tui::bg(Reset, iter(tracks,
move|(index, track, x1, x2): (usize, &'a Track, usize, usize), _|{
let width = (x2 - x1) as u16;
map_east(x1 as u16, width, Fixed::X(width, Tui::fg_bg(
iter_east(x1 as u16, width, w_exact(width, Tui::fg_bg(
track.color.lightest.rgb,
track.color.base.rgb,
callback(index, track))))})))
@ -2007,8 +2004,8 @@ mod audio {
impl_has!(Clock: |self: Sequencer| self.clock);
impl_has!(Vec<MidiInput>: |self: Sequencer| self.midi_ins);
impl_has!(Vec<MidiOutput>: |self: Sequencer| self.midi_outs);
impl_has!(Measure<TuiOut>: |self: MidiEditor| self.size);
impl_has!(Measure<TuiOut>: |self: PianoHorizontal| self.size);
impl_has!(Measure<Tui>: |self: MidiEditor| self.size);
impl_has!(Measure<Tui>: |self: PianoHorizontal| self.size);
impl_default!(Sequencer: Self {
clock: Clock::default(),
play_clip: None,
@ -2224,11 +2221,15 @@ mod audio {
}
}
}
impl Draw<TuiOut> for MidiEditor {
fn draw (&self, to: &mut TuiOut) { self.content().draw(to) }
impl Draw<Tui> for MidiEditor {
fn draw(self, to: &mut Tui) -> Usually<XYWH<u16>> {
self.tui().draw(to)
}
}
impl Draw<TuiOut> for PianoHorizontal {
fn draw (&self, to: &mut TuiOut) { self.content().draw(to) }
impl Draw<Tui> for PianoHorizontal {
fn draw(self, to: &mut Tui) -> Usually<XYWH<u16>> {
self.tui().draw(to)
}
}
}
@ -2320,23 +2321,23 @@ mod audio {
self.get_time_pos().overflowing_sub(1)
.0.min(self.clip_length().saturating_sub(1))
}
pub fn clip_status (&self) -> impl Content<TuiOut> + '_ {
pub fn clip_status (&self) -> impl Draw<Tui> + '_ {
let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
(clip.color, clip.name.clone(), clip.length, clip.looped)
} else { (ItemTheme::G[64], String::new().into(), 0, false) };
Fixed::X(20, col!(
Fill::X(Align::w(Bsp::e(
w_exact(20, south!(
w_full(origin_w(east(
button_2("f2", "name ", false),
Fill::X(Align::e(Tui::fg(Rgb(255, 255, 255), format!("{name} "))))))),
Fill::X(Align::w(Bsp::e(
w_full(origin_e(Tui::fg(Rgb(255, 255, 255), format!("{name} "))))))),
w_full(origin_w(east(
button_2("l", "ength ", false),
Fill::X(Align::e(Tui::fg(Rgb(255, 255, 255), format!("{length} "))))))),
Fill::X(Align::w(Bsp::e(
w_full(origin_e(Tui::fg(Rgb(255, 255, 255), format!("{length} "))))))),
w_full(origin_w(east(
button_2("r", "epeat ", false),
Fill::X(Align::e(Tui::fg(Rgb(255, 255, 255), format!("{looped} "))))))),
w_full(origin_e(Tui::fg(Rgb(255, 255, 255), format!("{looped} "))))))),
))
}
pub fn edit_status (&self) -> impl Content<TuiOut> + '_ {
pub fn edit_status (&self) -> impl Draw<Tui> + '_ {
let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
(clip.color, clip.length)
} else { (ItemTheme::G[64], 0) };
@ -2347,18 +2348,18 @@ mod audio {
let note_name = format!("{:4}", note_pitch_to_name(note_pos));
let note_pos = format!("{:>3}", note_pos);
let note_len = format!("{:>4}", self.get_note_len());
Fixed::X(20, col!(
Fill::X(Align::w(Bsp::e(
w_exact(20, south!(
w_full(origin_w(east(
button_2("t", "ime ", false),
Fill::X(Align::e(Tui::fg(Rgb(255, 255, 255),
w_full(origin_e(Tui::fg(Rgb(255, 255, 255),
format!("{length} /{time_zoom} +{time_pos} "))))))),
Fill::X(Align::w(Bsp::e(
w_full(origin_w(east(
button_2("z", "lock ", false),
Fill::X(Align::e(Tui::fg(Rgb(255, 255, 255),
w_full(origin_e(Tui::fg(Rgb(255, 255, 255),
format!("{time_lock}"))))))),
Fill::X(Align::w(Bsp::e(
w_full(origin_w(east(
button_2("x", "note ", false),
Fill::X(Align::e(Tui::fg(Rgb(255, 255, 255),
w_full(origin_e(Tui::fg(Rgb(255, 255, 255),
format!("{note_name} {note_pos} {note_len}"))))))),
))
}
@ -2394,12 +2395,8 @@ mod audio {
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
}
impl Layout<TuiOut> for MidiEditor {
fn layout (&self, to: XYWH<u16>) -> XYWH<u16> { self.content().layout(to) }
}
impl HasContent<TuiOut> for MidiEditor {
fn content (&self) -> impl Content<TuiOut> { self.autoscroll(); /*self.autozoom();*/ self.size.of(&self.mode) }
impl MidiEditor {
fn tui (&self) -> impl Draw<Tui> { self.autoscroll(); /*self.autozoom();*/ self.size.of(&self.mode) }
}
@ -2423,14 +2420,11 @@ mod audio {
}
}
impl Layout<TuiOut> for PianoHorizontal {
fn layout (&self, to: XYWH<u16>) -> XYWH<u16> { self.content().layout(to) }
}
impl HasContent<TuiOut> for PianoHorizontal {
fn content (&self) -> impl Content<TuiOut> {
Bsp::s(
Bsp::e(Fixed::X(5, format!("{}x{}", self.size.w(), self.size.h())), self.timeline()),
Bsp::e(self.keys(), self.size.of(Bsp::b(Fill::XY(self.notes()), Fill::XY(self.cursor())))),
impl PianoHorizontal {
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())))),
)
}
}
@ -2507,12 +2501,12 @@ mod audio {
}
}
fn notes (&self) -> impl Content<TuiOut> {
fn notes (&self) -> impl Draw<Tui> {
let time_start = self.get_time_start();
let note_lo = self.get_note_lo();
let note_hi = self.get_note_hi();
let buffer = self.buffer.clone();
Thunk::new(move|to: &mut TuiOut|{
Thunk::new(move|to: &mut Tui|{
let source = buffer.read().unwrap();
let XYWH(x0, y0, w, _h) = to.area();
//if h as usize != note_axis {
@ -2538,7 +2532,7 @@ mod audio {
}
})
}
fn cursor (&self) -> impl Content<TuiOut> {
fn cursor (&self) -> impl Draw<Tui> {
let note_hi = self.get_note_hi();
let note_lo = self.get_note_lo();
let note_pos = self.get_note_pos();
@ -2547,7 +2541,7 @@ mod audio {
let time_start = self.get_time_start();
let time_zoom = self.get_time_zoom();
let style = Some(Style::default().fg(self.color.lightest.rgb));
Thunk::new(move|to: &mut TuiOut|{
Thunk::new(move|to: &mut Tui|{
let XYWH(x0, y0, w, _) = to.area();
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
if note == note_pos {
@ -2569,7 +2563,7 @@ mod audio {
}
})
}
fn keys (&self) -> impl Content<TuiOut> {
fn keys (&self) -> impl Draw<Tui> {
let state = self;
let color = state.color;
let note_lo = state.get_note_lo();
@ -2578,7 +2572,7 @@ mod audio {
let key_style = Some(Style::default().fg(Rgb(192, 192, 192)).bg(Rgb(0, 0, 0)));
let off_style = Some(Style::default().fg(Tui::g(255)));
let on_style = Some(Style::default().fg(Rgb(255,0,0)).bg(color.base.rgb).bold());
Fill::Y(Fixed::X(self.keys_width, Thunk::new(move|to: &mut TuiOut|{
h_full(w_exact(self.keys_width, Thunk::new(move|to: &mut Tui|{
let XYWH(x, y0, _w, _h) = to.area();
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
to.blit(&to_key(note), x, screen_y, key_style);
@ -2593,8 +2587,8 @@ mod audio {
}
})))
}
fn timeline (&self) -> impl Content<TuiOut> + '_ {
Fill::X(Fixed::Y(1, Thunk::new(move|to: &mut TuiOut|{
fn timeline (&self) -> impl Draw<Tui> + '_ {
w_full(h_exact(1, Thunk::new(move|to: &mut Tui|{
let XYWH(x, y, w, _h) = to.area();
let style = Some(Style::default().dim());
let length = self.clip.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
@ -2635,7 +2629,7 @@ mod audio {
fn clip_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> { &mut self.clip }
/// Determine the required space to render the clip.
fn buffer_size (&self, clip: &MidiClip) -> (usize, usize) { (clip.length / self.range.time_zoom().get(), 128) }
fn redraw (&self) {
fn redraw(self) {
*self.buffer.write().unwrap() = if let Some(clip) = self.clip.as_ref() {
let clip = clip.read().unwrap();
let buf_size = self.buffer_size(&clip);
@ -2671,9 +2665,9 @@ mod audio {
self.colors[if self.on[pitch] { 2 } else { match pitch { 0 | 2 | 4 | 5 | 6 | 8 | 10 => 0, _ => 1 } }]
}
}
impl HasContent<TuiOut> for OctaveVertical {
fn content (&self) -> impl Content<TuiOut> {
row!(
impl OctaveVertical {
fn tui (&self) -> impl Draw<Tui> {
east!(
Tui::fg_bg(self.color(0), self.color(1), ""),
Tui::fg_bg(self.color(2), self.color(3), ""),
Tui::fg_bg(self.color(4), self.color(5), ""),
@ -3107,8 +3101,8 @@ mod audio {
Ok(())
}
}
impl Draw<TuiOut> for SampleAdd {
fn draw (&self, _to: &mut TuiOut) {
impl Draw<Tui> for SampleAdd {
fn draw (self, _to: &mut Tui) -> Usually<XYWH<u16>> {
todo!()
}
}
@ -3129,9 +3123,9 @@ mod audio {
}
}
fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Content<TuiOut> + use<'_> {
fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> {
let min_db = -64.0;
Thunk::new(move|to: &mut TuiOut|{
Thunk::new(move|to: &mut Tui|{
let XYWH(x, y, width, height) = to.area();
let area = Rect { x, y, width, height };
if let Some(sample) = &sample {
@ -3216,7 +3210,7 @@ mod audio {
}
fn draw_sample (
to: &mut TuiOut, x: u16, y: u16, note: Option<&u7>, sample: &Sample, focus: bool
to: &mut Tui, x: u16, y: u16, note: Option<&u7>, sample: &Sample, focus: bool
) -> Usually<usize> {
let style = if focus { Style::default().green() } else { Style::default() };
if focus {
@ -3340,8 +3334,8 @@ mod audio {
}
}
impl Draw<TuiOut> for Lv2 {
fn draw (&self, to: &mut TuiOut) {
impl Draw<Tui> for Lv2 {
fn draw(self, to: &mut Tui) {
let area = to.area();
let XYWH(x, y, _, height) = area;
let mut width = 20u16;
@ -3373,7 +3367,7 @@ mod audio {
}
fn draw_header (state: &Lv2, to: &mut TuiOut, x: u16, y: u16, w: u16) {
fn draw_header (state: &Lv2, to: &mut Tui, x: u16, y: u16, w: u16) {
let style = Style::default().gray();
let label1 = format!(" {}", state.name);
to.blit(&label1, x + 1, y, Some(style.white().bold()));
@ -3387,8 +3381,8 @@ mod audio {
mod pool {
use crate::*;
has_clips!(|self: Pool|self.clips);
has_clip!(|self: Pool|self.clips().get(self.clip_index()).map(|c|c.clone()));
impl_has_clips!(|self: Pool|self.clips);
impl_from!(Pool: |clip:&Arc<RwLock<MidiClip>>|{
let model = Self::default();
model.clips.write().unwrap().push(clip.clone());
@ -3523,14 +3517,14 @@ mod pool {
fn _color_random (&self) -> ItemColor { ItemColor::random() }
}
impl<'a> HasContent<TuiOut> for PoolView<'a> {
fn content (&self) -> impl Content<TuiOut> {
impl<'a> PoolView<'a> {
fn tui (&self) -> impl Draw<Tui> {
let Self(pool) = self;
//let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||Tui::g(32).into());
//let on_bg = |x|x;//Bsp::b(Repeat(" "), Tui::bg(color.darkest.rgb, x));
//let on_bg = |x|x;//below(Repeat(" "), Tui::bg(color.darkest.rgb, x));
//let border = |x|x;//Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)).enclose(x);
//let height = pool.clips.read().unwrap().len() as u16;
Fixed::X(20, Fill::Y(Align::n(Map::new(
w_exact(20, h_full(origin_n(iter(
||pool.clips().clone().into_iter(),
move|clip: Arc<RwLock<MidiClip>>, i: usize|{
let item_height = 1;
@ -3541,26 +3535,26 @@ mod pool {
let fg = color.lightest.rgb;
let name = if false { format!(" {i:>3}") } else { format!(" {i:>3} {name}") };
let length = if false { String::default() } else { format!("{length} ") };
Fixed::Y(1, map_south(item_offset, item_height, Tui::bg(bg, lay!(
Fill::X(Align::w(Tui::fg(fg, Tui::bold(selected, name)))),
Fill::X(Align::e(Tui::fg(fg, Tui::bold(selected, length)))),
Fill::X(Align::w(When::new(selected, Tui::bold(true, Tui::fg(Tui::g(255), ""))))),
Fill::X(Align::e(When::new(selected, Tui::bold(true, Tui::fg(Tui::g(255), ""))))),
h_exact(1, iter_south(item_offset, item_height, Tui::bg(bg, below!(
w_full(origin_w(Tui::fg(fg, Tui::bold(selected, name)))),
w_full(origin_e(Tui::fg(fg, Tui::bold(selected, length)))),
w_full(origin_w(When::new(selected, Tui::bold(true, Tui::fg(Tui::g(255), ""))))),
w_full(origin_e(When::new(selected, Tui::bold(true, Tui::fg(Tui::g(255), ""))))),
))))
}))))
}
}
impl HasContent<TuiOut> for ClipLength {
fn content (&self) -> impl Content<TuiOut> {
impl ClipLength {
fn tui (&self) -> impl Draw<Tui> {
use ClipLengthFocus::*;
let bars = ||self.bars_string();
let beats = ||self.beats_string();
let ticks = ||self.ticks_string();
match self.focus {
None => row!(" ", bars(), ".", beats(), ".", ticks()),
Some(Bar) => row!("[", bars(), "]", beats(), ".", ticks()),
Some(Beat) => row!(" ", bars(), "[", beats(), "]", ticks()),
Some(Tick) => row!(" ", bars(), ".", beats(), "[", ticks()),
None => east!(" ", bars(), ".", beats(), ".", ticks()),
Some(Bar) => east!("[", bars(), "]", beats(), ".", ticks()),
Some(Beat) => east!(" ", bars(), "[", beats(), "]", ticks()),
Some(Tick) => east!(" ", bars(), ".", beats(), "[", ticks()),
}
}
}
@ -3848,14 +3842,6 @@ mod config {
Ok(map)
}
}
// Each mode contains a view, so here we should be drawing it.
// I'm not sure what's going on with this code, though.
impl<D: Language + Ord> Draw<TuiOut> for Mode<D> {
fn draw (&self, _to: &mut TuiOut) {
//self.content().draw(to)
}
}
}
mod dialog {