From 3b1c31c78d917a6695b9c75c92a7145019ec4e35 Mon Sep 17 00:00:00 2001 From: i do not exist Date: Thu, 2 Jul 2026 07:29:31 +0300 Subject: [PATCH] fix: runs, somehow --- src/app.rs | 207 +++++++++--------------------------------------- src/app/draw.rs | 139 ++++++++++++++++++++++++++++++++ src/app/view.rs | 24 ++++++ src/tek.rs | 26 ++---- tengri | 2 +- 5 files changed, 209 insertions(+), 189 deletions(-) create mode 100644 src/app/draw.rs diff --git a/src/app.rs b/src/app.rs index e362debd..ae9bcf87 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ pub mod bind; pub use self::bind::*; pub mod cli; pub use self::cli::*; pub mod config; pub use self::config::*; pub mod view; pub use self::view::*; +pub mod draw; pub use self::draw::*; pub mod mode; pub use self::mode::*; /// Total application state. @@ -278,42 +279,6 @@ impl HasJack<'static> for App { fn jack (&self) -> &Jack<'static> { &self.jack } } -//impl_handle!(TuiIn: |self: App, input|{ - //let commands = tek_collect_commands(self, input)?; - //let history = tek_execute_commands(self, commands)?; - //self.history.extend(history.into_iter()); - //Ok(None) -//}); - -//fn tek_collect_commands (app: &App, input: &TuiIn) -> Usually> { - //let mut commands = vec![]; - //for id in app.mode.keys.iter() { - //if let Some(event_map) = app.config.binds.clone().read().unwrap().get(id.as_ref()) - //&& let Some(bindings) = event_map.query(input.event()) { - //for binding in bindings { - //for command in binding.commands.iter() { - //if let Some(command) = app.namespace(command)? as Option { - //commands.push(command) - //} - //} - //} - //} - //} - //Ok(commands) -//} - -//fn tek_execute_commands ( - //app: &mut App, commands: Vec -//) -> Usually)>> { - //let mut history = vec![]; - //for command in commands.into_iter() { - //let result = command.act(app); - //match result { Err(err) => { history.push((command, None)); return Err(err) } - //Ok(undo) => { history.push((command, undo)); } }; - //} - //Ok(history) -//} - def_command!(AppCommand: |app: App| { Nop => Ok(None), Cancel => todo!(), // TODO delegate: @@ -430,140 +395,6 @@ impl<'a> Namespace<'a, AppCommand> for App { }); } -impl Interpret> for App { - fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Usually> { - tek_expr(self, to, lang) - } - fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Usually> { - tek_word(self, to, lang) - } -} - -fn tek_expr (state: &App, to: &mut Tui, lang: &impl Expression) -> Usually> { - if let Some(area) = eval_view(state, to, lang)? { - Ok(area) - } else if let Some(area) = eval_view_tui(state, to, lang)? { - Ok(area) - } else { - Err(format!("App::interpret_expr: unexpected: {lang:?}").into()) - } -} - -fn tek_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usually> { - let mut frags = dsl.src()?.unwrap().split("/"); - match frags.next() { - - Some(":logo") => view_logo().draw(to), - - Some(":status") => h_exact(1, "TODO: Status Bar").draw(to), - - Some(":meters") => match frags.next() { - Some("input") => bg(Rgb(30, 30, 30), h_full(origin_s("Input Meters"))).draw(to), - Some("output") => bg(Rgb(30, 30, 30), h_full(origin_s("Output Meters"))).draw(to), - _ => panic!() - }, - - Some(":tracks") => match frags.next() { - None => "TODO tracks".draw(to), - Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), w_full(origin_w("Track Names")))), - Some("inputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Inputs"))).draw(to), - Some("devices") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Devices"))).draw(to), - Some("outputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Outputs"))).draw(to), - _ => panic!() - }, - - Some(":scenes") => match frags.next() { - None => "TODO scenes".draw(to), - Some(":scenes/names") => "TODO Scene Names".draw(to), - _ => panic!() - }, - - Some(":editor") => "TODO Editor".draw(to), - - Some(":dialog") => match frags.next() { - Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog { - let items = items.clone(); - let selected = selected; - Some(wh_full(thunk(move|to: &mut Tui|{ - for (index, MenuItem(item, _)) in items.0.iter().enumerate() { - y_push((2 * index) as u16,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) }, - h_exact(2, origin_n(w_full(item))) - )).draw(to); - } - Ok(to.area().into()) - }))) - } else { - None - }.draw(to), - _ => unimplemented!("App::interpret_word: {dsl:?} ({frags:?})"), - }, - - Some(":templates") => { - let modes = state.config.modes.clone(); - let height = (modes.read().unwrap().len() * 2) as u16; - h_exact(height, w_min(Some(30), thunk(move |to: &mut Tui|{ - for (index, (id, profile)) in modes.read().unwrap().iter().enumerate() { - let b = 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(""); - let info = profile.info.get(0).map(|x|x.as_ref()).unwrap_or(""); - let fg1 = Rgb(224, 192, 128); - let fg2 = Rgb(224, 128, 32); - let field_name = w_full(origin_w(fg(fg1, name))); - let field_id = w_full(origin_e(fg(fg2, id))); - let field_info = w_full(origin_w(info)); - y_push((2 * index) as u16, - h_exact(2, w_full(bg(b, south( - above(field_name, field_id), - field_info - ))))).draw(to); - } - Ok(to.area().into()) - }))) - }.draw(to), - - Some(":sessions") => view_sessions().draw(to), - - Some(":browse/title") => w_full(origin_w(field_v(ItemTheme::default(), - match state.dialog.browser_target().unwrap() { - BrowseTarget::SaveProject => "Save project:", - BrowseTarget::LoadProject => "Load project:", - BrowseTarget::ImportSample(_) => "Import sample:", - BrowseTarget::ExportSample(_) => "Export sample:", - BrowseTarget::ImportClip(_) => "Import clip:", - BrowseTarget::ExportClip(_) => "Export clip:", - }, h_exact(1, fg(g(96), x_repeat("🭻"))) - ))).draw(to), - - Some(":device") => { - let selected = state.dialog.device_kind().unwrap(); - south(bold(true, "Add device"), iter_south( - move||device_kinds().iter(), - move|_label: &&'static str, i|{ - let b = if i == selected { Rgb(64,128,32) } else { Rgb(0,0,0) }; - let l = if i == selected { "[ " } else { " " }; - let r = if i == selected { " ]" } else { " " }; - w_full(bg(b, east(l, west(r, "FIXME device name")))) })).draw(to) - }, - - Some(":debug") => h_exact(1, format!("[{:?}]", to.area())).draw(to), - - Some(_) => { - let views = state.config.views.read().unwrap(); - if let Some(dsl) = views.get(dsl.src()?.unwrap()) { - let dsl = dsl.clone(); - std::mem::drop(views); - state.interpret(to, &dsl) - } else { - unimplemented!("{dsl:?}"); - } - }, - - _ => unreachable!() - } -} - impl HasTrackScroll for App { fn track_scroll (&self) -> usize { self.project.track_scroll() @@ -587,3 +418,39 @@ impl ScenesView for App { (self.size.h() as u16).saturating_sub(20) } } + +//impl_handle!(TuiIn: |self: App, input|{ + //let commands = tek_collect_commands(self, input)?; + //let history = tek_execute_commands(self, commands)?; + //self.history.extend(history.into_iter()); + //Ok(None) +//}); + +//fn tek_collect_commands (app: &App, input: &TuiIn) -> Usually> { + //let mut commands = vec![]; + //for id in app.mode.keys.iter() { + //if let Some(event_map) = app.config.binds.clone().read().unwrap().get(id.as_ref()) + //&& let Some(bindings) = event_map.query(input.event()) { + //for binding in bindings { + //for command in binding.commands.iter() { + //if let Some(command) = app.namespace(command)? as Option { + //commands.push(command) + //} + //} + //} + //} + //} + //Ok(commands) +//} + +//fn tek_execute_commands ( + //app: &mut App, commands: Vec +//) -> Usually)>> { + //let mut history = vec![]; + //for command in commands.into_iter() { + //let result = command.act(app); + //match result { Err(err) => { history.push((command, None)); return Err(err) } + //Ok(undo) => { history.push((command, undo)); } }; + //} + //Ok(history) +//} diff --git a/src/app/draw.rs b/src/app/draw.rs new file mode 100644 index 00000000..dbe9d2b5 --- /dev/null +++ b/src/app/draw.rs @@ -0,0 +1,139 @@ +use crate::*; + +impl Interpret> for App { + fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) + -> Usually> + { + tek_draw_expr(self, to, lang) + } + fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) + -> Usually> + { + tek_draw_word(self, to, lang) + } +} + +fn tek_draw_expr (state: &App, to: &mut Tui, lang: &impl Expression) + -> Usually> +{ + if let Some(area) = eval_view(state, to, lang)? { + Ok(area) + } else if let Some(area) = eval_view_tui(state, to, lang)? { + Ok(area) + } else { + Err(format!("App::interpret_expr: unexpected: {lang:?}").into()) + } +} + +fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression) + -> Usually> +{ + let mut frags = dsl.src()?.unwrap().split("/"); + match frags.next() { + Some(":logo") => view_logo().draw(to), + Some(":meters") => draw_meter_section(to, frags), + Some(":tracks") => draw_tracks(to, frags, state), + Some(":scenes") => draw_scenes(to, frags), + Some(":dialog") => draw_dialog(to, frags, state, dsl), + Some(":templates") => draw_templates(to, frags, state), + Some(":sessions") => view_sessions().draw(to), + Some(":browse/title") => view_browse_title(state).draw(to), + Some(":device") => view_device(state).draw(to), + Some(":status") => h_exact(1, "TODO: Status Bar").draw(to), + Some(":editor") => "TODO Editor".draw(to), + Some(":debug") => h_exact(1, format!("[{:?}]", to.area())).draw(to), + Some(_) => { + let views = state.config.views.read().unwrap(); + if let Some(dsl) = views.get(dsl.src()?.unwrap()) { + let dsl = dsl.clone(); + std::mem::drop(views); + state.interpret(to, &dsl) + } else { + unimplemented!("{dsl:?}"); + } + }, + _ => unreachable!() + } +} + +pub fn draw_meter_section (to: &mut Tui, mut frags: std::str::Split<&str>) + -> Usually> +{ + match frags.next() { + Some("input") => bg(Rgb(30, 30, 30), h_full(origin_s("Input Meters"))).draw(to), + Some("output") => bg(Rgb(30, 30, 30), h_full(origin_s("Output Meters"))).draw(to), + _ => panic!() + } +} + +pub fn draw_tracks (to: &mut Tui, mut frags: std::str::Split<&str>, state: &App) + -> Usually> +{ + match frags.next() { + None => "TODO tracks".draw(to), + Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), w_full(origin_w("Track Names")))), + Some("inputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Inputs"))).draw(to), + Some("devices") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Devices"))).draw(to), + Some("outputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Outputs"))).draw(to), + _ => panic!() + } +} + +pub fn draw_scenes (to: &mut Tui, mut frags: std::str::Split<&str>) + -> Usually> +{ + match frags.next() { + None => "TODO Scenes".draw(to), + Some(":scenes/names") => "TODO Scene Names".draw(to), + _ => panic!() + } +} + +pub fn draw_dialog ( + to: &mut Tui, mut frags: std::str::Split<&str>, state: &App, dsl: &impl Expression +) -> Usually> { + match frags.next() { + Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog { + let items = items.clone(); + let selected = selected; + Some(wh_full(thunk(move|to: &mut Tui|{ + for (index, MenuItem(item, _)) in items.0.iter().enumerate() { + y_push((2 * index) as u16,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) }, + h_exact(2, origin_n(w_full(item))) + )).draw(to); + } + Ok(to.area().into()) + }))) + } else { + None + }.draw(to), + _ => unimplemented!("App::interpret_word: {dsl:?} ({frags:?})"), + } +} + +pub fn draw_templates (to: &mut Tui, frags: std::str::Split<&str>, state: &App) + -> Usually> +{ + let modes = state.config.modes.clone(); + let height = (modes.read().unwrap().len() * 2) as u16; + h_exact(height, w_min(Some(30), thunk(move |to: &mut Tui|{ + for (index, (id, profile)) in modes.read().unwrap().iter().enumerate() { + let b = 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(""); + let info = profile.info.get(0).map(|x|x.as_ref()).unwrap_or(""); + let fg1 = Rgb(224, 192, 128); + let fg2 = Rgb(224, 128, 32); + let field_name = w_full(origin_w(fg(fg1, name))); + let field_id = w_full(origin_e(fg(fg2, id))); + let field_info = w_full(origin_w(info)); + y_push((2 * index) as u16, + h_exact(2, w_full(bg(b, south( + above(field_name, field_id), + field_info + ))))).draw(to); + } + Ok(to.area().into()) + }))).draw(to) +} diff --git a/src/app/view.rs b/src/app/view.rs index ca56d703..6b2690bb 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -584,3 +584,27 @@ pub fn view_sessions () -> impl Draw { Ok(to.area().into()) }))) } + +pub fn view_browse_title (state: &App) -> impl Draw { + w_full(origin_w(field_v(ItemTheme::default(), + match state.dialog.browser_target().unwrap() { + BrowseTarget::SaveProject => "Save project:", + BrowseTarget::LoadProject => "Load project:", + BrowseTarget::ImportSample(_) => "Import sample:", + BrowseTarget::ExportSample(_) => "Export sample:", + BrowseTarget::ImportClip(_) => "Import clip:", + BrowseTarget::ExportClip(_) => "Export clip:", + }, h_exact(1, fg(g(96), x_repeat("🭻"))) + ))) +} + +pub fn view_device (state: &App) -> impl Draw { + let selected = state.dialog.device_kind().unwrap(); + south(bold(true, "Add device"), iter_south( + move||device_kinds().iter(), + move|_label: &&'static str, i|{ + let b = if i == selected { Rgb(64,128,32) } else { Rgb(0,0,0) }; + let l = if i == selected { "[ " } else { " " }; + let r = if i == selected { " ]" } else { " " }; + w_full(bg(b, east(l, west(r, "FIXME device name")))) })) +} diff --git a/src/tek.rs b/src/tek.rs index 43eed2e1..53336e9c 100644 --- a/src/tek.rs +++ b/src/tek.rs @@ -87,25 +87,15 @@ pub(crate) use tengri::{ /// Command-line entrypoint. #[cfg(feature = "cli")] pub fn main () -> Usually<()> { + tui_setup_panic(); Config::watch(|config|{ - Exit::run(|exit|{ - let state = Jack::new_run("tek", move|jack|{ - let clock = Clock::new(&jack, Some(51.))?; - let project = Arrangement::new(&jack, None, clock, vec![], vec![], vec![], vec![]); - let app = App::new(&jack, project, config, ":menu"); - Ok(app) - })?; - let (keyboard, terminal) = tui_io( - exit.as_ref(), - &state, - Duration::from_millis(100), - Duration::from_millis(10), - std::io::stdout(), - )?; - Ok(()) - }) - })?; - Ok(()) + tui_run_main(Jack::new_run("tek", move|jack|{ + let clock = Clock::new(&jack, Some(51.))?; + let project = Arrangement::new(&jack, None, clock, vec![], vec![], vec![], vec![]); + let app = App::new(&jack, project, config, ":menu"); + Ok(app) + })?) + }).map(|_|()) } tui_keys!(|self: App, input| { diff --git a/tengri b/tengri index 2ab871d1..90ebae0f 160000 --- a/tengri +++ b/tengri @@ -1 +1 @@ -Subproject commit 2ab871d10b26b40d129d62f68ecbd9e960aa4c86 +Subproject commit 90ebae0f26fc4524659704df274d0aec815dba2e