use def_command

This commit is contained in:
🪞👃🪞 2025-08-23 23:20:15 +03:00
parent 5ccbb9719f
commit cfd19062fd
37 changed files with 1578 additions and 1594 deletions

View file

@ -10,6 +10,8 @@ mod app_view; pub use self::app_view::*;
/// Total state
#[derive(Default, Debug)]
pub struct App {
/// Base color.
pub color: ItemTheme,
/// Must not be dropped for the duration of the process
pub jack: Jack<'static>,
/// Display size
@ -20,26 +22,24 @@ pub struct App {
pub config: Config,
/// Currently selected mode
pub mode: Arc<Mode<Arc<str>>>,
/// Contains the currently edited musical arrangement
pub project: Arrangement,
/// Contains all recently created clips.
pub pool: Pool,
/// Undo history
pub history: Vec<(AppCommand, Option<AppCommand>)>,
/// Dialog overlay
pub dialog: Dialog,
/// Base color.
pub color: ItemTheme,
/// Contains all recently created clips.
pub pool: Pool,
/// Contains the currently edited musical arrangement
pub project: Arrangement,
}
/// Various possible dialog modes.
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, PartialEq)]
pub enum Dialog {
#[default] None,
Help(usize),
Menu(usize),
Menu(usize, usize),
Device(usize),
Message(Arc<str>),
Browser(BrowserTarget, Arc<Browser>),
Browse(BrowseTarget, Arc<Browse>),
Options,
}
has!(Jack<'static>: |self: App|self.jack);
@ -61,68 +61,9 @@ maybe_has!(Scene: |self: App| { MaybeHas::<Scene>::get(&self.project) };
impl HasClipsSize for App { fn clips_size (&self) -> &Measure<TuiOut> { &self.project.inner_size } }
impl HasTrackScroll for App { fn track_scroll (&self) -> usize { self.project.track_scroll() } }
impl HasSceneScroll for App { fn scene_scroll (&self) -> usize { self.project.scene_scroll() } }
pub fn view_nil (_: &App) -> Box<dyn Render<TuiOut>> {
Box::new(Fill::xy("·"))
}
content!(TuiOut:|self: App|Fill::xy(Stack::above(|add|{
for dsl in self.mode.view.iter() { add(&Fill::xy(self.view(dsl.as_ref()))); }
})));
impl App {
fn view <D: Dsl> (&self, index: D) -> Box<dyn Render<TuiOut>> {
match index.src() {
Ok(Some(src)) => render_dsl(self, src),
Ok(None) => Box::new(Tui::fg(Color::Rgb(192, 192, 192), "empty view")),
Err(e) => Box::new(format!("{e}")),
}
}
pub fn update_clock (&self) {
ViewCache::update_clock(&self.project.clock.view_cache, self.clock(), self.size.w() > 80)
}
}
fn render_dsl <'t> (
state: &'t impl DslNs<'t, Box<dyn Render<TuiOut>>>,
src: &str
) -> Box<dyn Render<TuiOut>> {
let err: Option<Box<dyn Error>> = match state.from(&src) {
Ok(Some(value)) => return value, Ok(None) => None, Err(e) => Some(e),
};
let (fg_1, bg_1) = (Color::Rgb(240, 160, 100), Color::Rgb(48, 0, 0));
let (fg_2, bg_2) = (Color::Rgb(250, 200, 180), Color::Rgb(48, 0, 0));
let (fg_3, bg_3) = (Color::Rgb(250, 200, 120), Color::Rgb(0, 0, 0));
let bg = Color::Rgb(24, 0, 0);
Box::new(col! {
Tui::fg(bg, Fixed::y(1, Fill::x(RepeatH("")))),
Tui::bg(bg, col! {
Fill::x(Bsp::e(
Tui::bold(true, Tui::fg_bg(fg_1, bg_1, " Render error: ")),
Tui::fg_bg(fg_2, bg_2, err.map(|e|format!(" {e} "))),
)),
Fill::x(Align::x(Tui::fg_bg(fg_3, bg_3, format!(" {src} ")))),
}),
Tui::fg(bg, Fixed::y(1, Fill::x(RepeatH("")))),
})
}
handle!(TuiIn:|self: App, input|{
for id in self.mode.keys.iter() {
if let Some(event_map) = self.config.binds.read().unwrap().get(id.as_ref()) {
if let Some(bindings) = event_map.query(input.event()) {
for binding in bindings {
for command in binding.commands.iter() {
let command: Option<AppCommand> = self.from(command)?;
if let Some(command) = command {
panic!("{command:?}");
}
}
panic!("{binding:?}");
}
}
}
}
Ok(None)
});
impl Dialog {
pub fn menu_selected (&self) -> Option<usize> {
if let Self::Menu(selected) = self { Some(*selected) } else { None }
if let Self::Menu(selected, _) = self { Some(*selected) } else { None }
}
pub fn device_kind (&self) -> Option<usize> {
if let Self::Device(index) = self { Some(*index) } else { None }
@ -136,10 +77,10 @@ impl Dialog {
pub fn message (&self) -> Option<&str> {
todo!()
}
pub fn browser (&self) -> Option<&Arc<Browser>> {
pub fn browser (&self) -> Option<&Arc<Browse>> {
todo!()
}
pub fn browser_target (&self) -> Option<&BrowserTarget> {
pub fn browser_target (&self) -> Option<&BrowseTarget> {
todo!()
}
}
@ -189,8 +130,8 @@ impl App {
}
}
}
pub fn browser (&self) -> Option<&Browser> {
if let Dialog::Browser(_, ref b) = self.dialog { Some(b) } else { None }
pub fn browser (&self) -> Option<&Browse> {
if let Dialog::Browse(_, ref b) = self.dialog { Some(b) } else { None }
}
pub fn device_pick (&mut self, index: usize) {
self.dialog = Dialog::Device(index);