aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShav Kinderlehrer <[email protected]>2024-03-06 11:45:18 -0500
committerShav Kinderlehrer <[email protected]>2024-03-06 11:45:18 -0500
commita5dbccee4f22de991e33449ae1d1835269c6075d (patch)
tree8a530c8efe28afb61768f0d44c7e71c7049829e2
parent557d3f32fd2ac7a21bd3da01e8e903db16a31e7e (diff)
downloadmolehole-a5dbccee4f22de991e33449ae1d1835269c6075d.tar.gz
Fix event handling
-rw-r--r--src/action.rs2
-rw-r--r--src/app.rs103
-rw-r--r--src/app_action.rs3
-rw-r--r--src/component.rs10
-rw-r--r--src/components/global_keys.rs46
-rw-r--r--src/components/hello_world.rs5
-rw-r--r--src/components/mod.rs1
-rw-r--r--src/main.rs2
8 files changed, 123 insertions, 49 deletions
diff --git a/src/action.rs b/src/action.rs
deleted file mode 100644
index 4272dea..0000000
--- a/src/action.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-pub enum Action {
-}
diff --git a/src/app.rs b/src/app.rs
index b894f1c..22a8c40 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,8 +1,8 @@
use crossterm::event::Event;
use eyre::Result;
-use ratatui::prelude::*;
use std::time::Duration;
+use crate::app_action::AppAction;
use crate::app_event::AppEvent;
use crate::component::Component;
use crate::components;
@@ -12,71 +12,92 @@ pub struct App {
pub tui: tui::Tui,
pub tick_rate: Duration,
pub components: Vec<Box<dyn Component>>,
+
+ should_quit: bool,
}
impl App {
pub fn new(tick_rate: Duration) -> Result<Self> {
let tui = tui::init()?;
+ let global_keys = components::global_keys::GlobalKeys::default();
let hello_world = components::hello_world::HelloWorld::default();
- let hello_world1 = components::hello_world::HelloWorld::default();
- let hello_world2 = components::hello_world::HelloWorld::default();
- let hello_world3 = components::hello_world::HelloWorld::default();
Ok(Self {
tui,
tick_rate,
- components: vec![
- Box::new(hello_world),
- Box::new(hello_world1),
- Box::new(hello_world2),
- Box::new(hello_world3),
- ],
+ components: vec![Box::new(hello_world), Box::new(global_keys)],
+ should_quit: false,
})
}
pub fn run(&mut self) -> Result<()> {
+ for component in self.components.iter_mut() {
+ component.init()?;
+ }
+
loop {
- let event: Option<AppEvent> = match tui::get_event(self.tick_rate)?
- {
- Some(event) => match event {
- Event::Key(key) => Some(AppEvent::Key(key)),
- Event::Mouse(mouse) => Some(AppEvent::Mouse(mouse)),
- Event::FocusGained => todo!(),
- Event::FocusLost => todo!(),
- Event::Paste(_) => todo!(),
- Event::Resize(_, _) => todo!(),
- },
- None => None,
- };
-
- if event.is_some() {
- for component in self.components.iter_mut() {
- let _ = component.handle_event(event.expect(""))?;
- }
+ if self.should_quit {
+ break Ok(());
}
- self.tui.draw(|frame| {
- let layout = Layout::default()
- .direction(Direction::Vertical)
- .constraints([
- Constraint::Percentage(25),
- Constraint::Percentage(25),
- Constraint::Percentage(25),
- Constraint::Percentage(25),
- ])
- .split(frame.size());
-
- for (i, component) in self.components.iter_mut().enumerate() {
- let _ = component.render(frame, layout[i]);
+ self.draw()?;
+ }
+ }
+
+ pub fn draw(&mut self) -> Result<()> {
+ let event: Option<AppEvent> = match tui::get_event(self.tick_rate)? {
+ Some(event) => match event {
+ Event::Key(key) => Some(AppEvent::Key(key)),
+ Event::Mouse(mouse) => Some(AppEvent::Mouse(mouse)),
+ Event::FocusGained => todo!(),
+ Event::FocusLost => todo!(),
+ Event::Paste(_) => todo!(),
+ Event::Resize(_, _) => todo!(),
+ },
+ None => None,
+ };
+
+ if let Some(event) = event {
+ let mut actions: Vec<AppAction> = vec![];
+ for component in self.components.iter_mut() {
+ match component.handle_event(event)? {
+ Some(action) => actions.push(action),
+ None => (),
}
- })?;
+ }
+
+ for action in actions {
+ self.handle_action(action)?;
+ }
}
+
+ if self.should_quit {
+ return Ok(());
+ }
+
+ self.tui.draw(|frame| {
+ for (_i, component) in self.components.iter_mut().enumerate() {
+ match component.render(frame, frame.size()) {
+ Ok(_) => (),
+ Err(_) => (),
+ }
+ }
+ })?;
+
+ Ok(())
}
pub fn quit(&mut self) -> Result<()> {
tui::restore()?;
+ self.should_quit = true;
Ok(())
}
+
+ fn handle_action(&mut self, action: AppAction) -> Result<()> {
+ match action {
+ AppAction::Quit => Ok(self.quit()?),
+ }
+ }
}
diff --git a/src/app_action.rs b/src/app_action.rs
new file mode 100644
index 0000000..104e4f9
--- /dev/null
+++ b/src/app_action.rs
@@ -0,0 +1,3 @@
+pub enum AppAction {
+ Quit
+}
diff --git a/src/component.rs b/src/component.rs
index d8ca48f..8ec7d26 100644
--- a/src/component.rs
+++ b/src/component.rs
@@ -2,7 +2,7 @@ use crossterm::event::{KeyEvent, MouseEvent};
use eyre::Result;
use ratatui::prelude::{Frame, Rect};
-use crate::action::Action;
+use crate::app_action::AppAction;
use crate::app_event::AppEvent;
pub trait Component {
@@ -11,7 +11,7 @@ pub trait Component {
}
#[allow(unused)]
- fn handle_event(&mut self, event: AppEvent) -> Result<Option<Action>> {
+ fn handle_event(&mut self, event: AppEvent) -> Result<Option<AppAction>> {
match event {
AppEvent::Key(key_event) => Ok(self.handle_key_event(key_event)?),
AppEvent::Mouse(mouse_event) => {
@@ -22,7 +22,7 @@ pub trait Component {
}
#[allow(unused)]
- fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> {
+ fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<AppAction>> {
Ok(None)
}
@@ -30,12 +30,12 @@ pub trait Component {
fn handle_mouse_event(
&mut self,
mouse: MouseEvent,
- ) -> Result<Option<Action>> {
+ ) -> Result<Option<AppAction>> {
Ok(None)
}
#[allow(unused)]
- fn update(&mut self, action: Action) -> Result<Option<Action>> {
+ fn update(&mut self, action: AppAction) -> Result<Option<AppAction>> {
Ok(None)
}
diff --git a/src/components/global_keys.rs b/src/components/global_keys.rs
new file mode 100644
index 0000000..e99e2e0
--- /dev/null
+++ b/src/components/global_keys.rs
@@ -0,0 +1,46 @@
+use crossterm::event::{KeyCode, KeyEvent, KeyEventKind};
+use ratatui::prelude::*;
+use ratatui::widgets::*;
+
+use crate::app_action::AppAction;
+use crate::component::Component;
+
+#[derive(Default, Clone, Copy)]
+pub struct GlobalKeys {
+ should_show: bool,
+}
+
+impl Component for GlobalKeys {
+ fn handle_key_event(
+ &mut self,
+ key: KeyEvent,
+ ) -> eyre::Result<Option<AppAction>> {
+ if key.kind == KeyEventKind::Press {
+ return match key.code {
+ KeyCode::Char('q') => Ok(Some(AppAction::Quit)),
+ KeyCode::Char('?') => {
+ self.should_show = !self.should_show;
+ Ok(None)
+ }
+ _ => Ok(None),
+ };
+ }
+
+ Ok(None)
+ }
+
+ fn render(&mut self, frame: &mut Frame, rect: Rect) -> eyre::Result<()> {
+ let horizontal_center = Layout::default()
+ .direction(Direction::Horizontal);
+
+ let block = Block::default()
+ .title("Keyboard shortcuts")
+ .borders(Borders::ALL);
+
+ if self.should_show {
+ frame.render_widget(block, rect);
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/components/hello_world.rs b/src/components/hello_world.rs
index 22c966c..afb9d47 100644
--- a/src/components/hello_world.rs
+++ b/src/components/hello_world.rs
@@ -9,6 +9,11 @@ pub struct HelloWorld {
}
impl Component for HelloWorld {
+ fn init(&mut self) -> eyre::Result<()> {
+ self.text = "Hello, world!".to_string();
+ Ok(())
+ }
+
fn render(&mut self, frame: &mut Frame, rect: Rect) -> eyre::Result<()> {
frame.render_widget(Paragraph::new(self.text.clone()), rect);
diff --git a/src/components/mod.rs b/src/components/mod.rs
index c6dbc18..78abbca 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -1 +1,2 @@
pub mod hello_world;
+pub mod global_keys;
diff --git a/src/main.rs b/src/main.rs
index 29c6439..16bee88 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
-mod action;
mod app;
+mod app_action;
mod app_event;
mod component;
mod components;