Fix event handling
This commit is contained in:
parent
557d3f32fd
commit
a5dbccee4f
@ -1,2 +0,0 @@
|
|||||||
pub enum Action {
|
|
||||||
}
|
|
103
src/app.rs
103
src/app.rs
@ -1,8 +1,8 @@
|
|||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use ratatui::prelude::*;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::app_action::AppAction;
|
||||||
use crate::app_event::AppEvent;
|
use crate::app_event::AppEvent;
|
||||||
use crate::component::Component;
|
use crate::component::Component;
|
||||||
use crate::components;
|
use crate::components;
|
||||||
@ -12,71 +12,92 @@ pub struct App {
|
|||||||
pub tui: tui::Tui,
|
pub tui: tui::Tui,
|
||||||
pub tick_rate: Duration,
|
pub tick_rate: Duration,
|
||||||
pub components: Vec<Box<dyn Component>>,
|
pub components: Vec<Box<dyn Component>>,
|
||||||
|
|
||||||
|
should_quit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(tick_rate: Duration) -> Result<Self> {
|
pub fn new(tick_rate: Duration) -> Result<Self> {
|
||||||
let tui = tui::init()?;
|
let tui = tui::init()?;
|
||||||
|
|
||||||
|
let global_keys = components::global_keys::GlobalKeys::default();
|
||||||
let hello_world = components::hello_world::HelloWorld::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 {
|
Ok(Self {
|
||||||
tui,
|
tui,
|
||||||
tick_rate,
|
tick_rate,
|
||||||
components: vec![
|
components: vec![Box::new(hello_world), Box::new(global_keys)],
|
||||||
Box::new(hello_world),
|
should_quit: false,
|
||||||
Box::new(hello_world1),
|
|
||||||
Box::new(hello_world2),
|
|
||||||
Box::new(hello_world3),
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<()> {
|
pub fn run(&mut self) -> Result<()> {
|
||||||
loop {
|
for component in self.components.iter_mut() {
|
||||||
let event: Option<AppEvent> = match tui::get_event(self.tick_rate)?
|
component.init()?;
|
||||||
{
|
}
|
||||||
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() {
|
loop {
|
||||||
for component in self.components.iter_mut() {
|
if self.should_quit {
|
||||||
let _ = component.handle_event(event.expect(""))?;
|
break Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tui.draw(|frame| {
|
for action in actions {
|
||||||
let layout = Layout::default()
|
self.handle_action(action)?;
|
||||||
.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]);
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<()> {
|
pub fn quit(&mut self) -> Result<()> {
|
||||||
tui::restore()?;
|
tui::restore()?;
|
||||||
|
self.should_quit = true;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_action(&mut self, action: AppAction) -> Result<()> {
|
||||||
|
match action {
|
||||||
|
AppAction::Quit => Ok(self.quit()?),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
3
src/app_action.rs
Normal file
3
src/app_action.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub enum AppAction {
|
||||||
|
Quit
|
||||||
|
}
|
@ -2,7 +2,7 @@ use crossterm::event::{KeyEvent, MouseEvent};
|
|||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use ratatui::prelude::{Frame, Rect};
|
use ratatui::prelude::{Frame, Rect};
|
||||||
|
|
||||||
use crate::action::Action;
|
use crate::app_action::AppAction;
|
||||||
use crate::app_event::AppEvent;
|
use crate::app_event::AppEvent;
|
||||||
|
|
||||||
pub trait Component {
|
pub trait Component {
|
||||||
@ -11,7 +11,7 @@ pub trait Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn handle_event(&mut self, event: AppEvent) -> Result<Option<Action>> {
|
fn handle_event(&mut self, event: AppEvent) -> Result<Option<AppAction>> {
|
||||||
match event {
|
match event {
|
||||||
AppEvent::Key(key_event) => Ok(self.handle_key_event(key_event)?),
|
AppEvent::Key(key_event) => Ok(self.handle_key_event(key_event)?),
|
||||||
AppEvent::Mouse(mouse_event) => {
|
AppEvent::Mouse(mouse_event) => {
|
||||||
@ -22,7 +22,7 @@ pub trait Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[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)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,12 +30,12 @@ pub trait Component {
|
|||||||
fn handle_mouse_event(
|
fn handle_mouse_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
mouse: MouseEvent,
|
mouse: MouseEvent,
|
||||||
) -> Result<Option<Action>> {
|
) -> Result<Option<AppAction>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
fn update(&mut self, action: AppAction) -> Result<Option<AppAction>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
46
src/components/global_keys.rs
Normal file
46
src/components/global_keys.rs
Normal file
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,11 @@ pub struct HelloWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Component for 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<()> {
|
fn render(&mut self, frame: &mut Frame, rect: Rect) -> eyre::Result<()> {
|
||||||
frame.render_widget(Paragraph::new(self.text.clone()), rect);
|
frame.render_widget(Paragraph::new(self.text.clone()), rect);
|
||||||
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
pub mod hello_world;
|
pub mod hello_world;
|
||||||
|
pub mod global_keys;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
mod action;
|
|
||||||
mod app;
|
mod app;
|
||||||
|
mod app_action;
|
||||||
mod app_event;
|
mod app_event;
|
||||||
mod component;
|
mod component;
|
||||||
mod components;
|
mod components;
|
||||||
|
Loading…
Reference in New Issue
Block a user