wip: restabilizing inversion of control shenanigans again
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
🪞👃🪞 2025-05-25 11:44:15 +03:00
parent 4a2e742e56
commit 287983c140
6 changed files with 99 additions and 111 deletions

View file

@ -42,12 +42,12 @@ maybe_has!(Scene: |self: App|
impl HasSceneScroll for App { fn scene_scroll (&self) -> usize { self.project.scene_scroll() } } impl HasSceneScroll for App { fn scene_scroll (&self) -> usize { self.project.scene_scroll() } }
has_clips!(|self: App|self.pool.clips); has_clips!(|self: App|self.pool.clips);
impl HasClipsSize for App { fn clips_size (&self) -> &Measure<TuiOut> { &self.project.inner_size } } impl HasClipsSize for App { fn clips_size (&self) -> &Measure<TuiOut> { &self.project.inner_size } }
from_dsl!(ClockCommand: |state: App, iter|Take::take(state.clock(), iter)); take!(ClockCommand |state: App, iter|Take::take(state.clock(), iter));
from_dsl!(MidiEditCommand: |state: App, iter|Ok(state.editor().map(|x|Take::take(x, iter)).transpose()?.flatten())); take!(MidiEditCommand |state: App, iter|Ok(state.editor().map(|x|Take::take(x, iter)).transpose()?.flatten()));
from_dsl!(PoolCommand: |state: App, iter|Take::take(&state.pool, iter)); take!(PoolCommand |state: App, iter|Take::take(&state.pool, iter));
from_dsl!(SamplerCommand: |state: App, iter|Ok(state.project.sampler().map(|x|Take::take(x, iter)).transpose()?.flatten())); take!(SamplerCommand |state: App, iter|Ok(state.project.sampler().map(|x|Take::take(x, iter)).transpose()?.flatten()));
from_dsl!(ArrangementCommand: |state: App, iter|Take::take(&state.project, iter)); take!(ArrangementCommand |state: App, iter|Take::take(&state.project, iter));
from_dsl!(DialogCommand: |state: App, iter|Take::take(&state.dialog, iter)); take!(DialogCommand |state: App, iter|Take::take(&state.dialog, iter));
//has_editor!(|self: App|{ //has_editor!(|self: App|{
//editor = self.editor; //editor = self.editor;
//editor_w = { //editor_w = {
@ -450,8 +450,7 @@ impl Configuration {
println!("ok"); println!("ok");
map.add_layer_if( map.add_layer_if(
Box::new(move |state: &App|Take::take_or_fail( Box::new(move |state: &App|Take::take_or_fail(
state, &mut exp.clone(), state, exp, ||"missing input layer conditional"
||"missing input layer conditional"
)), keys )), keys
); );
} else { } else {

View file

@ -24,88 +24,86 @@ impl<T: Content<TuiOut>> Content<TuiOut> for ErrorBoundary<TuiOut, T> {
impl App { impl App {
pub fn view (model: &Self) -> impl Content<TuiOut> + '_ { pub fn view (model: &Self) -> impl Content<TuiOut> + '_ {
ErrorBoundary::new( ErrorBoundary::new(Ok(Some(Tui::bg(Black, "give or take"))))
Ok(Some(Tui::bg(Black, "give or take"))) //ErrorBoundary::new(Take::take(model, &mut model.config.view.clone()))
//Default::default(), Take::take(model, &mut model.config.view.clone()) //ErrorBoundary::new(Give::give(model, &mut model.config.view.clone()))
//Default::default(), Give::give(model, &mut model.config.view.clone())
)
} }
} }
#[tengri_proc::view(TuiOut)] #[tengri_proc::view(TuiOut)]
impl App { impl App {
pub fn view_nil (model: &Self) -> impl Content<TuiOut> { //pub fn view_nil (model: &Self) -> impl Content<TuiOut> {
"nil" //"nil"
} //}
pub fn view_dialog (model: &Self) -> impl Content<TuiOut> + use<'_> { //pub fn view_dialog (model: &Self) -> impl Content<TuiOut> + use<'_> {
model.dialog.as_ref().map(|dialog|Bsp::b("", //model.dialog.as_ref().map(|dialog|Bsp::b("",
Fixed::xy(70, 23, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b( //Fixed::xy(70, 23, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b(
Repeat(" "), Outer(true, Style::default().fg(Tui::g(96))) //Repeat(" "), Outer(true, Style::default().fg(Tui::g(96)))
.enclose(dialog)))))) //.enclose(dialog))))))
} //}
pub fn view_meters_input (model: &Self) -> impl Content<TuiOut> + use<'_> { //pub fn view_meters_input (model: &Self) -> impl Content<TuiOut> + use<'_> {
model.project.sampler().map(|s| //model.project.sampler().map(|s|
s.view_meters_input()) //s.view_meters_input())
} //}
pub fn view_meters_output (model: &Self) -> impl Content<TuiOut> + use<'_> { //pub fn view_meters_output (model: &Self) -> impl Content<TuiOut> + use<'_> {
model.project.sampler().map(|s| //model.project.sampler().map(|s|
s.view_meters_output()) //s.view_meters_output())
} //}
pub fn view_history (model: &Self) -> impl Content<TuiOut> { //pub fn view_history (model: &Self) -> impl Content<TuiOut> {
Fixed::y(1, Fill::x(Align::w(FieldH(model.color, //Fixed::y(1, Fill::x(Align::w(FieldH(model.color,
format!("History ({})", model.history.len()), //format!("History ({})", model.history.len()),
model.history.last().map(|last|Fill::x(Align::w(format!("{:?}", last.0)))))))) //model.history.last().map(|last|Fill::x(Align::w(format!("{:?}", last.0))))))))
} //}
pub fn view_status_h2 (model: &Self) -> impl Content<TuiOut> { //pub fn view_status_h2 (model: &Self) -> impl Content<TuiOut> {
model.update_clock(); //model.update_clock();
let theme = model.color; //let theme = model.color;
let clock = model.clock(); //let clock = model.clock();
let playing = clock.is_rolling(); //let playing = clock.is_rolling();
let cache = clock.view_cache.clone(); //let cache = clock.view_cache.clone();
//let selection = model.selection().describe(model.tracks(), model.scenes()); ////let selection = model.selection().describe(model.tracks(), model.scenes());
let hist_len = model.history.len(); //let hist_len = model.history.len();
let hist_last = model.history.last(); //let hist_last = model.history.last();
Fixed::y(2, Stack::east(move|add: &mut dyn FnMut(&dyn Render<TuiOut>)|{ //Fixed::y(2, Stack::east(move|add: &mut dyn FnMut(&dyn Render<TuiOut>)|{
add(&Fixed::x(5, Tui::bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) }, //add(&Fixed::x(5, Tui::bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) },
Either::new(false, // TODO //Either::new(false, // TODO
Thunk::new(move||Fixed::x(9, Either::new(playing, //Thunk::new(move||Fixed::x(9, Either::new(playing,
Tui::fg(Rgb(0, 255, 0), " PLAYING "), //Tui::fg(Rgb(0, 255, 0), " PLAYING "),
Tui::fg(Rgb(255, 128, 0), " STOPPED "))) //Tui::fg(Rgb(255, 128, 0), " STOPPED ")))
), //),
Thunk::new(move||Fixed::x(5, Either::new(playing, //Thunk::new(move||Fixed::x(5, Either::new(playing,
Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)), //Tui::fg(Rgb(0, 255, 0), Bsp::s(" 🭍🭑🬽 ", " 🭞🭜🭘 ",)),
Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",)))) //Tui::fg(Rgb(255, 128, 0), Bsp::s(" ▗▄▖ ", " ▝▀▘ ",))))
) //)
) //)
))); //)));
add(&" "); //add(&" ");
{ //{
let cache = cache.read().unwrap(); //let cache = cache.read().unwrap();
add(&Fixed::x(15, Align::w(Bsp::s( //add(&Fixed::x(15, Align::w(Bsp::s(
FieldH(theme, "Beat", cache.beat.view.clone()), //FieldH(theme, "Beat", cache.beat.view.clone()),
FieldH(theme, "Time", cache.time.view.clone()), //FieldH(theme, "Time", cache.time.view.clone()),
)))); //))));
add(&Fixed::x(13, Align::w(Bsp::s( //add(&Fixed::x(13, Align::w(Bsp::s(
Fill::x(Align::w(FieldH(theme, "BPM", cache.bpm.view.clone()))), //Fill::x(Align::w(FieldH(theme, "BPM", cache.bpm.view.clone()))),
Fill::x(Align::w(FieldH(theme, "SR ", cache.sr.view.clone()))), //Fill::x(Align::w(FieldH(theme, "SR ", cache.sr.view.clone()))),
)))); //))));
add(&Fixed::x(12, Align::w(Bsp::s( //add(&Fixed::x(12, Align::w(Bsp::s(
Fill::x(Align::w(FieldH(theme, "Buf", cache.buf.view.clone()))), //Fill::x(Align::w(FieldH(theme, "Buf", cache.buf.view.clone()))),
Fill::x(Align::w(FieldH(theme, "Lat", cache.lat.view.clone()))), //Fill::x(Align::w(FieldH(theme, "Lat", cache.lat.view.clone()))),
)))); //))));
//add(&Bsp::s( ////add(&Bsp::s(
////Fill::x(Align::w(FieldH(theme, "Selected", Align::w(selection)))), //////Fill::x(Align::w(FieldH(theme, "Selected", Align::w(selection)))),
//Fill::x(Align::w(FieldH(theme, format!("History ({})", hist_len), ////Fill::x(Align::w(FieldH(theme, format!("History ({})", hist_len),
//hist_last.map(|last|Fill::x(Align::w(format!("{:?}", last.0))))))), ////hist_last.map(|last|Fill::x(Align::w(format!("{:?}", last.0))))))),
//"" ////""
//)); ////));
////if let Some(last) = model.history.last() { //////if let Some(last) = model.history.last() {
////add(&FieldV(theme, format!("History ({})", model.history.len()), //////add(&FieldV(theme, format!("History ({})", model.history.len()),
////Fill::x(Align::w(format!("{:?}", last.0))))); //////Fill::x(Align::w(format!("{:?}", last.0)))));
////} //////}
} //}
})) //}))
} //}
//pub fn view_status_v (&self) -> impl Content<TuiOut> + use<'_> { //pub fn view_status_v (&self) -> impl Content<TuiOut> + use<'_> {
//self.update_clock(); //self.update_clock();
//let cache = self.project.clock.view_cache.read().unwrap(); //let cache = self.project.clock.view_cache.read().unwrap();

View file

@ -58,17 +58,17 @@ maybe_has!(Track: |self: Arrangement|
maybe_has!(Scene: |self: Arrangement| maybe_has!(Scene: |self: Arrangement|
{ Has::<Selection>::get(self).track().map(|index|Has::<Vec<Scene>>::get(self).get(index)).flatten() }; { Has::<Selection>::get(self).track().map(|index|Has::<Vec<Scene>>::get(self).get(index)).flatten() };
{ Has::<Selection>::get(self).track().map(|index|Has::<Vec<Scene>>::get_mut(self).get_mut(index)).flatten() }); { Has::<Selection>::get(self).track().map(|index|Has::<Vec<Scene>>::get_mut(self).get_mut(index)).flatten() });
from_dsl!(MidiInputCommand: |state: Arrangement, iter|state.selected_midi_in().as_ref() take!(MidiInputCommand |state: Arrangement, iter|state.selected_midi_in().as_ref()
.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); .map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
from_dsl!(MidiOutputCommand: |state: Arrangement, iter|state.selected_midi_out().as_ref() take!(MidiOutputCommand |state: Arrangement, iter|state.selected_midi_out().as_ref()
.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); .map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
from_dsl!(DeviceCommand:|state: Arrangement, iter|state.selected_device().as_ref() take!(DeviceCommand|state: Arrangement, iter|state.selected_device().as_ref()
.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); .map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
from_dsl!(TrackCommand: |state: Arrangement, iter|state.selected_track().as_ref() take!(TrackCommand |state: Arrangement, iter|state.selected_track().as_ref()
.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); .map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
from_dsl!(SceneCommand: |state: Arrangement, iter|state.selected_scene().as_ref() take!(SceneCommand |state: Arrangement, iter|state.selected_scene().as_ref()
.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); .map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
from_dsl!(ClipCommand: |state: Arrangement, iter|state.selected_clip().as_ref() take!(ClipCommand |state: Arrangement, iter|state.selected_clip().as_ref()
.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten())); .map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
#[tengri_proc::expose] impl Arrangement { #[tengri_proc::expose] impl Arrangement {
fn selected_midi_in (&self) -> Option<MidiInput> { todo!() } fn selected_midi_in (&self) -> Option<MidiInput> { todo!() }

View file

@ -75,23 +75,12 @@ pub struct DeviceAudio<'a>(pub &'a mut Device);
audio!(|self: DeviceAudio<'a>, client, scope|{ audio!(|self: DeviceAudio<'a>, client, scope|{
use Device::*; use Device::*;
match self.0 { match self.0 {
#[cfg(feature = "sampler")] #[cfg(feature = "sampler")] Sampler(sampler) => sampler.process(client, scope),
Sampler(sampler) => sampler.process(client, scope), #[cfg(feature = "lv2")] Lv2(lv2) => lv2.process(client, scope),
#[cfg(feature = "vst2")] Vst2 => { todo!() }, // TODO
#[cfg(feature = "lv2")] #[cfg(feature = "vst3")] Vst3 => { todo!() }, // TODO
Lv2(lv2) => lv2.process(client, scope), #[cfg(feature = "clap")] Clap => { todo!() }, // TODO
#[cfg(feature = "sf2")] Sf2 => { todo!() }, // TODO
#[cfg(feature = "vst2")]
Vst2 => { todo!() }, // TODO
#[cfg(feature = "vst3")]
Vst3 => { todo!() }, // TODO
#[cfg(feature = "clap")]
Clap => { todo!() }, // TODO
#[cfg(feature = "sf2")]
Sf2 => { todo!() }, // TODO
} }
}); });

View file

@ -12,8 +12,10 @@ pub struct Pool {
/// Embedded file browser /// Embedded file browser
pub browser: Option<Browser>, pub browser: Option<Browser>,
} }
from_dsl!(BrowserCommand: |state: Pool, iter|Ok(state.browser take!(BrowserCommand |state: Pool, iter|Ok(state.browser.as_ref()
.as_ref().map(|p|Take::take(p, iter)).transpose()?.flatten())); .map(|p|Take::take(p, iter))
.transpose()?
.flatten()));
impl Default for Pool { impl Default for Pool {
fn default () -> Self { fn default () -> Self {
use PoolMode::*; use PoolMode::*;

2
deps/tengri vendored

@ -1 +1 @@
Subproject commit 5a2177cc77fd8827b565a2bf08c18d6bc25ea0dd Subproject commit 31e84bf5b3a44fb0b51f853f135109ea184ace84