diff --git a/config/config_arranger.edn b/config/config_arranger.edn index c2ede8ca..8ac29f05 100644 --- a/config/config_arranger.edn +++ b/config/config_arranger.edn @@ -3,8 +3,7 @@ (info "A session grid.") (keys - (layer-if :focus-editor "./keys_editor.edn") - (layer-if :focus-dialog "./keys_dialog.edn") + (layer-if :is-editing "./keys_editor.edn") (layer-if :focus-message "./keys_message.edn") (layer-if :focus-device-add "./keys_device_add.edn") (layer-if :focus-browser "./keys_browser.edn") @@ -27,6 +26,6 @@ (bsp/s :view-tracks-devices (bsp/s :view-tracks-outputs (bsp/s :view-tracks-names - (fill/xy (either :focus-editor + (fill/xy (either :is-editing (bsp/e :view-scenes-names :view-editor) :view-scenes))))))))))) diff --git a/config/keys_arranger.edn b/config/keys_arranger.edn index a6411816..76e1e6b4 100644 --- a/config/keys_arranger.edn +++ b/config/keys_arranger.edn @@ -1,5 +1,7 @@ (@c color) (@q launch) +(@t select :select-track-header) +(@s select :select-scene-header) (@tab project edit) (@enter project edit) (@escape project home) @@ -13,5 +15,3 @@ (@down select :select-scene-next) (@left select :select-track-prev) (@right select :select-track-next) -(@t select :select-track) -(@s select :select-scene) diff --git a/config/keys_arranger_clip.edn b/config/keys_arranger_clip.edn deleted file mode 100644 index 8b137891..00000000 --- a/config/keys_arranger_clip.edn +++ /dev/null @@ -1 +0,0 @@ - diff --git a/config/keys_arranger_device.edn b/config/keys_arranger_device.edn deleted file mode 100644 index e69de29b..00000000 diff --git a/config/keys_arranger_input.rs b/config/keys_arranger_input.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/config/keys_arranger_output.rs b/config/keys_arranger_output.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/config/keys_arranger_scene.edn b/config/keys_arranger_scene.edn deleted file mode 100644 index e69de29b..00000000 diff --git a/config/keys_arranger_track.rs b/config/keys_arranger_track.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/config/keys_dialog.edn b/config/keys_dialog.edn deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 4e381025..e15634e1 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -1,72 +1,38 @@ use crate::*; use std::path::PathBuf; + type MaybeClip = Option>>; + macro_rules! ns { ($C:ty, $s:expr, $a:expr, $W:expr) => { <$C>::try_from_expr($s, $a).map($W) } } macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; } macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; } -handle!(TuiIn: |self: App, input|self.handle_tui_key_with_history(input)); -impl App { - fn handle_tui_key_with_history (&mut self, input: &TuiIn) -> Perhaps { - Ok(if let Some(command) = self.config.keys.command(self, input) { - // FIXME failed commands not persisted in undo history - let undo = command.clone().execute(self)?; - self.history.push((command, undo)); - Some(true) - } else { - None - }) + +handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.command(self, input) { + let undo = command.execute(self)?; + if let Some(undo) = undo { + self.history.push(undo); + } + Some(true) +} else { + None +})); + +#[tengri_proc::command(App)] impl AppCommand { + fn dialog (app: &mut App, dialog: Option) -> Perhaps { + app.toggle_dialog(dialog); + Ok(None) + } + fn cancel_dialog (app: &mut App) -> Perhaps { + app.toggle_dialog(None); + Ok(None) } -} -#[tengri_proc::command(App)] -impl AppCommand { fn toggle_editor (app: &mut App, value: bool) -> Perhaps { app.toggle_editor(Some(value)); Ok(None) } - fn editor (app: &mut App, command: MidiEditCommand) -> Perhaps { - Ok(if let Some(editor) = app.editor_mut() { - let undo = command.clone().delegate(editor, |command|AppCommand::Editor{command})?; - // update linked sampler after editor action - app.project.sampler_mut().map(|sampler|match command { - // autoselect: automatically select sample in sampler - MidiEditCommand::SetNotePos { pos } => { sampler.set_note_pos(pos); }, - _ => {} - }); - undo - } else { - None - }) - } - fn dialog (app: &mut App, command: DialogCommand) -> Perhaps { - Ok(command.delegate(&mut app.dialog, |command|Self::Dialog{command})?) - } - fn project (app: &mut App, command: ArrangementCommand) -> Perhaps { - Ok(command.delegate(&mut app.project, |command|Self::Project{command})?) - } - fn clock (app: &mut App, command: ClockCommand) -> Perhaps { - Ok(command.execute(app.clock_mut())?.map(|command|Self::Clock{command})) - } - fn sampler (app: &mut App, command: SamplerCommand) -> Perhaps { - Ok(app.project.sampler_mut() - .map(|s|command.delegate(s, |command|Self::Sampler{command})) - .transpose()? - .flatten()) - } - fn pool (app: &mut App, command: PoolCommand) -> Perhaps { - let undo = command.clone().delegate(&mut app.pool, |command|AppCommand::Pool{command})?; - // update linked editor after pool action - match command { - // autoselect: automatically load selected clip in editor - PoolCommand::Select { .. } | - // autocolor: update color in all places simultaneously - PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } => { - let clip = app.pool.clip().clone(); - app.editor_mut().map(|editor|editor.set_clip(clip.as_ref())) - }, - _ => None - }; - Ok(undo) - } + //fn color (app: &mut App, theme: ItemTheme) -> Perhaps { + //Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme})) + //} fn enqueue (app: &mut App, clip: Option>>) -> Perhaps { todo!() } @@ -76,6 +42,10 @@ impl AppCommand { fn zoom (app: &mut App, zoom: usize) -> Perhaps { todo!() } + //fn launch (app: &mut App) -> Perhaps { + //app.project.launch(); + //Ok(None) + //} fn select (app: &mut App, selection: Selection) -> Perhaps { *app.project.selection_mut() = selection; //todo! @@ -103,41 +73,88 @@ impl AppCommand { app.tracks_stop_all(); Ok(None) } - //fn color (app: &mut App, theme: ItemTheme) -> Perhaps { - //Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme})) - //} - //fn launch (app: &mut App) -> Perhaps { - //app.project.launch(); - //Ok(None) - //} + fn sampler (app: &mut App, command: SamplerCommand) -> Perhaps { + Ok(app.project.sampler_mut() + .map(|s|command.delegate(s, |command|Self::Sampler{command})) + .transpose()? + .flatten()) + } + fn project (app: &mut App, command: ArrangementCommand) -> Perhaps { + Ok(command.delegate(&mut app.project, |command|Self::Project{command})?) + } + fn clock (app: &mut App, command: ClockCommand) -> Perhaps { + Ok(command.execute(app.clock_mut())?.map(|command|Self::Clock{command})) + } + fn message (app: &mut App, command: MessageCommand) -> Perhaps { + Ok(command.delegate(app, |command|Self::Message{command})?) + } + fn editor (app: &mut App, command: MidiEditCommand) -> Perhaps { + Ok(if let Some(editor) = app.editor_mut() { + let undo = command.clone().delegate(editor, |command|AppCommand::Editor{command})?; + // update linked sampler after editor action + app.project.sampler_mut().map(|sampler|match command { + // autoselect: automatically select sample in sampler + MidiEditCommand::SetNotePos { pos } => { sampler.set_note_pos(pos); }, + _ => {} + }); + undo + } else { + None + }) + } + fn pool (app: &mut App, command: PoolCommand) -> Perhaps { + let undo = command.clone().delegate( + &mut app.pool, + |command|AppCommand::Pool{command} + )?; + // update linked editor after pool action + match command { + // autoselect: automatically load selected clip in editor + PoolCommand::Select { .. } | + // autocolor: update color in all places simultaneously + PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } => { + let clip = app.pool.clip().clone(); + app.editor_mut().map(|editor|editor.set_clip(clip.as_ref())) + }, + _ => None + }; + Ok(undo) + } } + impl<'state> Context<'state, ClockCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { Context::get(&self.clock(), iter) } } + impl<'state> Context<'state, MidiEditCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.editor().map(|e|Context::get(e, iter)).flatten() } } + impl<'state> Context<'state, PoolCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { Context::get(&self.pool, iter) } } + impl<'state> Context<'state, SamplerCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.project.sampler().map(|p|Context::get(p, iter)).flatten() } } + impl<'state> Context<'state, ArrangementCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { Context::get(&self.project, iter) } } -impl<'state> Context<'state, DialogCommand> for App { - fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { - Context::get(&self, iter) + +#[tengri_proc::command(App)] impl MessageCommand { + fn dismiss (app: &mut App) -> Perhaps { + app.dialog = None; + Ok(None) } } diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 9d833fab..5553da0e 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -18,7 +18,7 @@ pub struct App { /// Contains the currently edited musical arrangement pub project: Arrangement, /// Undo history - pub history: Vec<(AppCommand, Option)>, + pub history: Vec, // Dialog overlay pub dialog: Option, // Cache of formatted strings @@ -179,8 +179,8 @@ impl App { fn focus_editor (&self) -> bool { self.project.editor.is_some() } - fn focus_dialog (&self) -> bool { - self.dialog.is_some() + fn is_editing (&self) -> bool { + self.project.editor.is_some() } fn focus_message (&self) -> bool { matches!(self.dialog, Some(Dialog::Message(..))) @@ -192,20 +192,16 @@ impl App { self.browser().is_some() } fn focus_clip (&self) -> bool { - !self.focus_editor() && matches!(self.selection(), - Selection::TrackClip{..}) + !self.is_editing() && self.selection().is_clip() } fn focus_track (&self) -> bool { - !self.focus_editor() && matches!(self.selection(), - Selection::Track(..)) + !self.is_editing() && self.selection().is_track() } fn focus_scene (&self) -> bool { - !self.focus_editor() && matches!(self.selection(), - Selection::Scene(..)) + !self.is_editing() && self.selection().is_scene() } fn focus_mix (&self) -> bool { - !self.focus_editor() && matches!(self.selection(), - Selection::Mix) + !self.is_editing() && self.selection().is_mix() } fn focus_pool_import (&self) -> bool { matches!(self.pool.mode, Some(PoolMode::Import(..))) @@ -264,32 +260,29 @@ impl App { fn scene_count (&self) -> usize { self.scenes().len() } - fn scene_selected (&self) -> Option { + fn scene_selection (&self) -> Option { self.selection().scene() } fn track_count (&self) -> usize { self.tracks().len() } - fn track_selected (&self) -> Option { + fn track_selection (&self) -> Option { self.selection().track() } - fn select_scene (&self) -> Selection { - self.selection().select_scene(self.tracks().len()) - } fn select_scene_next (&self) -> Selection { - self.selection().select_scene_next(self.scenes().len()) + self.selection().scene_next(self.scenes().len()) } fn select_scene_prev (&self) -> Selection { - self.selection().select_scene_prev() + self.selection().scene_prev() } - fn select_track (&self) -> Selection { - self.selection().select_track(self.tracks().len()) + fn select_track_header (&self) -> Selection { + self.selection().track_header(self.tracks().len()) } fn select_track_next (&self) -> Selection { - self.selection().select_track_next(self.tracks().len()) + self.selection().track_next(self.tracks().len()) } fn select_track_prev (&self) -> Selection { - self.selection().select_track_prev() + self.selection().track_prev() } fn clip_selected (&self) -> Option>> { match self.selection() { @@ -454,11 +447,13 @@ impl Configuration { let cond = cond.unwrap(); println!("ok"); map.add_layer_if( - Box::new(move |state: &App|{ - Context::get(state, - &mut format!("{cond}").as_str().into()) - .unwrap_or_else(||panic!( - "missing input layer conditional {cond} from {exp:?}")) + Box::new(move |state|{ + let mut exp = exp.clone(); + let value = Context::get(state, &mut format!(":{cond}").as_str().into()).unwrap_or(false); + if value { + panic!("layer-if cond={cond:?} exp={exp:?} value={value:?}"); + } + value }), keys ); diff --git a/crates/app/src/view.rs b/crates/app/src/view.rs index a358f023..dc93ffce 100644 --- a/crates/app/src/view.rs +++ b/crates/app/src/view.rs @@ -7,11 +7,6 @@ impl App { pub fn view_nil (&self) -> impl Content + use<'_> { "nil" } - pub fn view_history (&self) -> impl Content { - Fixed::y(1, Fill::x(Align::w(FieldH(self.color, - format!("History ({})", self.history.len()), - self.history.last().map(|last|Fill::x(Align::w(format!("{:?}", last.0)))))))) - } pub fn view_status_h2 (&self) -> impl Content + use<'_> { self.update_clock(); let theme = self.color; @@ -29,33 +24,24 @@ impl App { ) ) ))); - add(&" "); { let cache = self.view_cache.read().unwrap(); - add(&Fixed::x(15, Align::w(Bsp::s( + add(&Fixed::x(16, Align::w(Bsp::s( FieldH(theme, "Beat", cache.beat.view.clone()), FieldH(theme, "Time", cache.time.view.clone()), )))); - add(&Fixed::x(13, Align::w(Bsp::s( + add(&Fixed::x(16, Align::w(Bsp::s( Fill::x(Align::w(FieldH(theme, "BPM", cache.bpm.view.clone()))), Fill::x(Align::w(FieldH(theme, "SR ", cache.sr.view.clone()))), )))); - add(&Fixed::x(12, Align::w(Bsp::s( + add(&Fixed::x(16, Align::w(Bsp::s( Fill::x(Align::w(FieldH(theme, "Buf", cache.buf.view.clone()))), Fill::x(Align::w(FieldH(theme, "Lat", cache.lat.view.clone()))), )))); - add(&Bsp::s( - Fill::x(Align::w(FieldH(theme, "Selected", Align::w(self.selection().describe( - self.tracks(), - self.scenes() - ))))), - Fill::x(Align::w(FieldH(theme, format!("History ({})", self.history.len()), - self.history.last().map(|last|Fill::x(Align::w(format!("{:?}", last.0))))))) - )); - //if let Some(last) = self.history.last() { - //add(&FieldV(theme, format!("History ({})", self.history.len()), - //Fill::x(Align::w(format!("{:?}", last.0))))); - //} + add(&FieldV(theme, "Selection", Fill::x(Align::w(self.selection().describe( + self.tracks(), + self.scenes() + ))))); } })) } diff --git a/crates/device/src/arranger/arranger_select.rs b/crates/device/src/arranger/arranger_select.rs index 665acb42..db9536ba 100644 --- a/crates/device/src/arranger/arranger_select.rs +++ b/crates/device/src/arranger/arranger_select.rs @@ -39,6 +39,18 @@ pub enum Selection { /// Focus identification methods impl Selection { + pub fn is_mix (&self) -> bool { + matches!(self, Self::Mix) + } + pub fn is_track (&self) -> bool { + matches!(self, Self::Track(_)) + } + pub fn is_scene (&self) -> bool { + matches!(self, Self::Scene(_)) + } + pub fn is_clip (&self) -> bool { + matches!(self, Self::TrackClip {..}) + } pub fn track (&self) -> Option { use Selection::*; match self { @@ -50,7 +62,7 @@ impl Selection { _ => None } } - pub fn select_track (&self, track_count: usize) -> Self { + pub fn track_header (&self, track_count: usize) -> Self { use Selection::*; match self { Mix => Track(0), @@ -60,7 +72,7 @@ impl Selection { _ => todo!(), } } - pub fn select_track_next (&self, len: usize) -> Self { + pub fn track_next (&self, len: usize) -> Self { use Selection::*; match self { Mix => Track(0), @@ -78,7 +90,7 @@ impl Selection { _ => todo!() } } - pub fn select_track_prev (&self) -> Self { + pub fn track_prev (&self) -> Self { use Selection::*; match self { Mix => Mix, @@ -97,16 +109,7 @@ impl Selection { _ => None } } - pub fn select_scene (&self, scene_count: usize) -> Self { - use Selection::*; - match self { - Mix | Track(_) => Scene(0), - Scene(s) => Scene((s + 1) % scene_count), - TrackClip { scene, .. } => Track(*scene), - _ => todo!(), - } - } - pub fn select_scene_next (&self, len: usize) -> Self { + pub fn scene_next (&self, len: usize) -> Self { use Selection::*; match self { Mix => Scene(0), @@ -124,7 +127,7 @@ impl Selection { _ => todo!() } } - pub fn select_scene_prev (&self) -> Self { + pub fn scene_prev (&self) -> Self { use Selection::*; match self { Mix | Scene(0) => Mix, @@ -139,9 +142,11 @@ impl Selection { use Selection::*; format!("{}", match self { Mix => "Everything".to_string(), - Scene(s) => scenes.get(*s).map(|scene|format!("S{s}: {}", &scene.name)) + Scene(s) => scenes.get(*s) + .map(|scene|format!("S{s}: {}", &scene.name)) .unwrap_or_else(||"S??".into()), - Track(t) => tracks.get(*t).map(|track|format!("T{t}: {}", &track.name)) + Track(t) => tracks.get(*t) + .map(|track|format!("T{t}: {}", &track.name)) .unwrap_or_else(||"T??".into()), TrackClip { track, scene } => match (tracks.get(*track), scenes.get(*scene)) { (Some(_), Some(s)) => match s.clip(*track) { @@ -154,3 +159,6 @@ impl Selection { }).into() } } + +impl Arrangement { +} diff --git a/crates/device/src/arranger/arranger_view.rs b/crates/device/src/arranger/arranger_view.rs index 5e7bd877..c9ebc98a 100644 --- a/crates/device/src/arranger/arranger_view.rs +++ b/crates/device/src/arranger/arranger_view.rs @@ -90,11 +90,8 @@ impl Arrangement { for (index, track, x1, x2) in self.tracks_with_sizes() { add(&Fixed::xy(self.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, - Tui::fg_bg( - ItemTheme::G[32].lightest.rgb, - ItemTheme::G[32].dark.rgb, - Align::nw(format!(" · {}", "--"))))))))); + |_, index|Fixed::xy(track.width as u16, 2, Tui::bg(ItemTheme::G[32].base.rgb, + Align::nw(format!(" · {}", "--"))))))))); } })) } diff --git a/crates/device/src/dialog.rs b/crates/device/src/dialog.rs index 430edafc..f9f7c309 100644 --- a/crates/device/src/dialog.rs +++ b/crates/device/src/dialog.rs @@ -1,6 +1,4 @@ use crate::*; -mod dialog_api; pub use self::dialog_api::*; -mod dialog_view; pub use self::dialog_view::*; /// Various possible dialog overlays #[derive(Clone, Debug)] @@ -18,3 +16,98 @@ pub enum Dialog { pub enum Message { FailedToAddDevice, } + +content!(TuiOut: |self: Message| match self { + Self::FailedToAddDevice => "Failed to add device." +}); + +content!(TuiOut: |self: Dialog| match self { + Self::Menu(_) => + self.view_dialog_menu().boxed(), + Self::Help(offset) => + self.view_dialog_help(*offset).boxed(), + Self::Browser(target, browser) => + self.view_dialog_browser(target, browser).boxed(), + Self::Options => + self.view_dialog_options().boxed(), + Self::Device(index) => + self.view_dialog_device(*index).boxed(), + Self::Message(message) => + self.view_dialog_message(message).boxed(), +}); + +impl Dialog { + pub fn view_dialog_menu (&self) -> impl Content { + let options = ||["Projects", "Settings", "Help", "Quit"].iter(); + let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a)); + Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option))) + } + pub fn view_dialog_help <'a> (&'a self, offset: usize) -> impl Content + use<'a> { + Bsp::s(Tui::bold(true, "Help"), "FIXME") + //Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, + //move||self.config.keys.layers.iter() + //.filter_map(|a|(a.0)(self).then_some(a.1)) + //.flat_map(|a|a) + //.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None }) + //.skip(offset) + //.take(20), + //|mut b,i|Fixed::x(60, Align::w(Bsp::e("(", Bsp::e( + //b.next().map(|t|Fixed::x(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))), + //Bsp::e(" ", Align::w(format!("{}", b.0.0.trim())))))))))) + } + pub fn view_dialog_device (&self, index: usize) -> impl Content + use<'_> { + let choices = ||device_kinds().iter(); + let choice = move|label, i| + Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) }, + Bsp::e(if i == index { "[ " } else { " " }, + Bsp::w(if i == index { " ]" } else { " " }, + label)))); + Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice)) + } + pub fn view_dialog_message <'a> (&'a self, message: &'a Message) -> impl Content + use<'a> { + Bsp::s(message, Bsp::s("", "[ OK ]")) + } + pub fn view_dialog_browser <'a> (&'a self, target: &BrowserTarget, browser: &'a Browser) -> impl Content + use<'a> { + Bsp::s( + Padding::xy(3, 1, Fill::x(Align::w(FieldV( + Default::default(), + match target { + BrowserTarget::SaveProject => "Save project:", + BrowserTarget::LoadProject => "Load project:", + BrowserTarget::ImportSample(_) => "Import sample:", + BrowserTarget::ExportSample(_) => "Export sample:", + BrowserTarget::ImportClip(_) => "Import clip:", + BrowserTarget::ExportClip(_) => "Export clip:", + }, + Shrink::x(3, Fixed::y(1, Tui::fg(Tui::g(96), RepeatH("🭻")))))))), + Outer(true, Style::default().fg(Tui::g(96))) + .enclose(Fill::xy(browser))) + } + pub fn view_dialog_load <'a> (&'a self, browser: &'a Browser) -> impl Content + use<'a> { + Bsp::s( + Fill::x(Align::w(Margin::xy(1, 1, Bsp::e( + Tui::bold(true, " Load project: "), + Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))), + Outer(true, Style::default().fg(Tui::g(96))) + .enclose(Fill::xy(browser))) + } + pub fn view_dialog_export <'a> (&'a self, browser: &'a Browser) -> impl Content + use<'a> { + Bsp::s( + Fill::x(Align::w(Margin::xy(1, 1, Bsp::e( + Tui::bold(true, " Export: "), + Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))), + Outer(true, Style::default().fg(Tui::g(96))) + .enclose(Fill::xy(browser))) + } + pub fn view_dialog_import <'a> (&'a self, browser: &'a Browser) -> impl Content + use<'a> { + Bsp::s( + Fill::x(Align::w(Margin::xy(1, 1, Bsp::e( + Tui::bold(true, " Import: "), + Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))), + Outer(true, Style::default().fg(Tui::g(96))) + .enclose(Fill::xy(browser))) + } + pub fn view_dialog_options <'a> (&'a self) -> impl Content + use<'a> { + "TODO" + } +} diff --git a/crates/device/src/dialog/dialog_api.rs b/crates/device/src/dialog/dialog_api.rs deleted file mode 100644 index 9c39a26a..00000000 --- a/crates/device/src/dialog/dialog_api.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::*; - -#[tengri_proc::command(Option)] -impl DialogCommand { - fn dismiss (dialog: &mut Option) -> Perhaps { - *dialog = None; - Ok(None) - } -} diff --git a/crates/device/src/dialog/dialog_view.rs b/crates/device/src/dialog/dialog_view.rs deleted file mode 100644 index dadeadbb..00000000 --- a/crates/device/src/dialog/dialog_view.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::*; - -content!(TuiOut: |self: Dialog| match self { - Self::Menu(_) => - self.view_dialog_menu().boxed(), - Self::Help(offset) => - self.view_dialog_help(*offset).boxed(), - Self::Browser(target, browser) => - self.view_dialog_browser(target, browser).boxed(), - Self::Options => - self.view_dialog_options().boxed(), - Self::Device(index) => - self.view_dialog_device(*index).boxed(), - Self::Message(message) => - self.view_dialog_message(message).boxed(), -}); - -content!(TuiOut: |self: Message| match self { - Self::FailedToAddDevice => "Failed to add device." -}); - -impl Dialog { - pub fn view_dialog_menu (&self) -> impl Content { - let options = ||["Projects", "Settings", "Help", "Quit"].iter(); - let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a)); - Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option))) - } - pub fn view_dialog_help <'a> (&'a self, offset: usize) -> impl Content + use<'a> { - Bsp::s(Tui::bold(true, "Help"), "FIXME") - //Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, - //move||self.config.keys.layers.iter() - //.filter_map(|a|(a.0)(self).then_some(a.1)) - //.flat_map(|a|a) - //.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None }) - //.skip(offset) - //.take(20), - //|mut b,i|Fixed::x(60, Align::w(Bsp::e("(", Bsp::e( - //b.next().map(|t|Fixed::x(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))), - //Bsp::e(" ", Align::w(format!("{}", b.0.0.trim())))))))))) - } - pub fn view_dialog_device (&self, index: usize) -> impl Content + use<'_> { - let choices = ||device_kinds().iter(); - let choice = move|label, i| - Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) }, - Bsp::e(if i == index { "[ " } else { " " }, - Bsp::w(if i == index { " ]" } else { " " }, - label)))); - Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice)) - } - pub fn view_dialog_message <'a> (&'a self, message: &'a Message) -> impl Content + use<'a> { - Bsp::s(message, Bsp::s("", "[ OK ]")) - } - pub fn view_dialog_browser <'a> (&'a self, target: &BrowserTarget, browser: &'a Browser) -> impl Content + use<'a> { - Bsp::s( - Padding::xy(3, 1, Fill::x(Align::w(FieldV( - Default::default(), - match target { - BrowserTarget::SaveProject => "Save project:", - BrowserTarget::LoadProject => "Load project:", - BrowserTarget::ImportSample(_) => "Import sample:", - BrowserTarget::ExportSample(_) => "Export sample:", - BrowserTarget::ImportClip(_) => "Import clip:", - BrowserTarget::ExportClip(_) => "Export clip:", - }, - Shrink::x(3, Fixed::y(1, Tui::fg(Tui::g(96), RepeatH("🭻")))))))), - Outer(true, Style::default().fg(Tui::g(96))) - .enclose(Fill::xy(browser))) - } - pub fn view_dialog_load <'a> (&'a self, browser: &'a Browser) -> impl Content + use<'a> { - Bsp::s( - Fill::x(Align::w(Margin::xy(1, 1, Bsp::e( - Tui::bold(true, " Load project: "), - Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))), - Outer(true, Style::default().fg(Tui::g(96))) - .enclose(Fill::xy(browser))) - } - pub fn view_dialog_export <'a> (&'a self, browser: &'a Browser) -> impl Content + use<'a> { - Bsp::s( - Fill::x(Align::w(Margin::xy(1, 1, Bsp::e( - Tui::bold(true, " Export: "), - Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))), - Outer(true, Style::default().fg(Tui::g(96))) - .enclose(Fill::xy(browser))) - } - pub fn view_dialog_import <'a> (&'a self, browser: &'a Browser) -> impl Content + use<'a> { - Bsp::s( - Fill::x(Align::w(Margin::xy(1, 1, Bsp::e( - Tui::bold(true, " Import: "), - Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))), - Outer(true, Style::default().fg(Tui::g(96))) - .enclose(Fill::xy(browser))) - } - pub fn view_dialog_options <'a> (&'a self) -> impl Content + use<'a> { - "TODO" - } -} diff --git a/deps/tengri b/deps/tengri index 3bc73932..921378b6 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 3bc739328eed0c8fa67b432c7354c7929ddb505f +Subproject commit 921378b6dbb38d4f301f688abd1cfef9bdc0f941