From 33e5f475260124e563693db608a56f5f3a8debe0 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 12 Jul 2024 16:05:16 +0300 Subject: [PATCH] add Exit trait to modals --- src/config.rs | 12 +++++++++-- src/control.rs | 6 +++++- src/core.rs | 8 ++++++++ src/model.rs | 9 ++++----- src/model/transport.rs | 20 ++++++++++--------- src/view/help.rs | 45 +++++++++++++++++++++++++++--------------- 6 files changed, 67 insertions(+), 33 deletions(-) diff --git a/src/config.rs b/src/config.rs index d54b033b..51eaa12a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -47,7 +47,7 @@ impl AppPaths { } } -pub struct SetupModal(pub Option>); +pub struct SetupModal(pub Option>, pub bool); render!(SetupModal |self, buf, area| { for cell in buf.content.iter_mut() { @@ -83,9 +83,17 @@ handle!(SetupModal |self, e| { .. })) = e { AppPaths::new(&self.0.as_ref().unwrap())?.create()?; - self.0 = None; + self.exit(); Ok(true) } else { Ok(false) } }); +impl Exit for SetupModal { + fn exited (&self) -> bool { + self.1 + } + fn exit (&mut self) { + self.1 = true + } +} diff --git a/src/control.rs b/src/control.rs index e1063c8c..cc4585cd 100644 --- a/src/control.rs +++ b/src/control.rs @@ -6,7 +6,9 @@ handle!{ App |self, e| { if let Some(ref mut modal) = self.modal { if modal.handle(e)? { - self.modal = None; + if modal.exited() { + self.modal = None; + } return Ok(true) }; } @@ -145,10 +147,12 @@ pub const KEYMAP: &'static [KeyBinding] = keymap!(App { fn focus_next (app: &mut App) -> Usually { app.section.next(); + app.transport.focused = app.section == AppSection::Transport; Ok(true) } fn focus_prev (app: &mut App) -> Usually { app.section.prev(); + app.transport.focused = app.section == AppSection::Transport; Ok(true) } diff --git a/src/core.rs b/src/core.rs index 8e7a8eba..78b5c3de 100644 --- a/src/core.rs +++ b/src/core.rs @@ -41,6 +41,14 @@ pub trait Component: Render + Handle + Sync { } } +pub trait Exit: Component { + fn exited (&self) -> bool; + fn exit (&mut self); + fn boxed (self) -> Box where Self: Sized + 'static { + Box::new(self) + } +} + /// Anything that implements `Render` + `Handle` can be used as a UI component. impl Component for T {} diff --git a/src/model.rs b/src/model.rs index ead0273a..6d756cb9 100644 --- a/src/model.rs +++ b/src/model.rs @@ -34,7 +34,7 @@ pub struct App { /// Display buffer for sequencer pub seq_buf: BufferedSequencerView, /// Optional modal dialog - pub modal: Option>, + pub modal: Option>, /// Currently focused section pub section: AppSection, /// Whether the current focus section has input priority @@ -57,8 +57,6 @@ pub struct App { xdg: Option>, /// Main audio outputs. audio_outs: Vec>>, - /// Tick enable? - metronome: bool, /// Number of frames requested by process callback chunk_size: usize, @@ -78,10 +76,8 @@ impl App { chunk_size: 0, entered: true, jack: Some(jack), - metronome: false, midi_in: None, midi_ins: vec![], - modal: first_run.then(||crate::config::SetupModal(Some(xdg.clone())).boxed()), note_cursor: 0, note_start: 2, scene_cursor: 1, @@ -92,6 +88,9 @@ impl App { time_cursor: 0, track_cursor: 1, tracks: vec![], + modal: first_run.then( + ||Exit::boxed(crate::config::SetupModal(Some(xdg.clone()), false)) + ), xdg: Some(xdg), }) } diff --git a/src/model/transport.rs b/src/model/transport.rs index fd16ad44..271f0a1b 100644 --- a/src/model/transport.rs +++ b/src/model/transport.rs @@ -1,27 +1,29 @@ use crate::core::*; pub struct TransportToolbar { - pub mode: bool, - pub focused: bool, - pub entered: bool, + pub metronome: bool, + pub mode: bool, + pub focused: bool, + pub entered: bool, /// Current sample rate, tempo, and PPQ. - pub timebase: Arc, + pub timebase: Arc, /// JACK transport handle. - transport: Option, + transport: Option, /// Quantization factor - pub quant: usize, + pub quant: usize, /// Current transport state - pub playing: Option, + pub playing: Option, /// Current position according to transport - playhead: usize, + playhead: usize, /// Global frame and usec at which playback started - pub started: Option<(usize, usize)>, + pub started: Option<(usize, usize)>, } impl TransportToolbar { pub fn new (transport: Option) -> Self { Self { transport, + metronome: false, mode: false, focused: false, entered: false, diff --git a/src/view/help.rs b/src/view/help.rs index 483b4c26..a3d0799e 100644 --- a/src/view/help.rs +++ b/src/view/help.rs @@ -3,18 +3,27 @@ use crate::{core::*, view::*}; pub struct HelpModal { cursor: usize, search: Option, + exited: bool, } impl HelpModal { pub fn new () -> Self { - Self { cursor: 0, search: None } + Self { cursor: 0, search: None, exited: false } + } +} +impl Exit for HelpModal { + fn exited (&self) -> bool { + self.exited + } + fn exit (&mut self) { + self.exited = true; } } render!(HelpModal |self, buf, area|{ for cell in buf.content.iter_mut() { - cell.bg = ratatui::style::Color::Rgb(44,44,44); - cell.fg = ratatui::style::Color::Rgb(88,88,88); + cell.bg = ratatui::style::Color::Rgb(30,30,30); + cell.fg = ratatui::style::Color::Rgb(100,100,100); cell.modifier = ratatui::style::Modifier::DIM; } let width = 64.min(area.width * 3 / 5); @@ -40,25 +49,28 @@ render!(HelpModal |self, buf, area|{ for i in 0..height-3 { let y = y + i; if let Some(command) = crate::control::KEYMAP_FOCUS.get(i as usize) { - format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().bold()))?; - command.2.blit(buf, x + 11, y, Some(Style::default().bold()))?; - command.3.blit(buf, x + 26, y, None)?; + format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().white().bold()))?; + command.2.blit(buf, x + 11, y, Some(Style::default().white().bold()))?; + command.3.blit(buf, x + 26, y, Some(Style::default().white().dim()))?; } else if let Some(command) = crate::control::KEYMAP.get((i as usize) - crate::control::KEYMAP_FOCUS.len()) { - format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().bold()))?; - command.2.blit(buf, x + 11, y, Some(Style::default().bold()))?; - command.3.blit(buf, x + 26, y, None)?; + format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().white().bold()))?; + command.2.blit(buf, x + 11, y, Some(Style::default().white().bold()))?; + command.3.blit(buf, x + 26, y, Some(Style::default().white().dim()))?; } else { break } } let hi_area = Rect { x: area.x + 1, width: area.width - 2, y: area.y + 3 + self.cursor as u16, height: 1 }; fill_bg(buf, hi_area, Nord::bg_hi(true, true)); - fill_fg(buf, hi_area, Color::Reset); + fill_fg(buf, hi_area, Color::White); Lozenge(Style::default()).draw(buf, area) }); handle!(HelpModal |self, e| { - Ok(handle_keymap(self, e, KEYMAP_HELP)? || match e { + if handle_keymap(self, e, KEYMAP_HELP)? { + return Ok(true) + } + Ok(match e { AppEvent::Input(Event::Key(KeyEvent { code: KeyCode::Char(c), modifiers: KeyModifiers::NONE, .. @@ -67,22 +79,23 @@ handle!(HelpModal |self, e| { self.search = Some(String::new()); } self.search.as_mut().unwrap().push(*c); - false + true }, - _ => false + _ => true }) }); pub const KEYMAP_HELP: &'static [KeyBinding] = keymap!(HelpModal { - [Esc, NONE, "help_close", "close help dialog", |_: &mut HelpModal|{ + [Esc, NONE, "help_close", "close help dialog", |modal: &mut HelpModal|{ + modal.exit(); Ok(true) }], [Up, NONE, "help_prev", "select previous command", |modal: &mut HelpModal|{ modal.cursor = modal.cursor.saturating_sub(1); - Ok(false) + Ok(true) }], [Down, NONE, "help_next", "select next command", |modal: &mut HelpModal|{ modal.cursor = modal.cursor + 1; - Ok(false) + Ok(true) }], });