Implement app components
This commit is contained in:
parent
022574877d
commit
557d3f32fd
62
src/app.rs
62
src/app.rs
@ -1,27 +1,77 @@
|
|||||||
|
use crossterm::event::Event;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use ratatui::prelude::*;
|
use ratatui::prelude::*;
|
||||||
use std::io::Stdout;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::app_event::AppEvent;
|
||||||
|
use crate::component::Component;
|
||||||
|
use crate::components;
|
||||||
use crate::tui;
|
use crate::tui;
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub terminal: Terminal<CrosstermBackend<Stdout>>,
|
pub tui: tui::Tui,
|
||||||
pub tick_rate: Duration,
|
pub tick_rate: Duration,
|
||||||
|
pub components: Vec<Box<dyn Component>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn start(tick_rate: Duration) -> Result<Self> {
|
pub fn new(tick_rate: Duration) -> Result<Self> {
|
||||||
let terminal = tui::init()?;
|
let tui = tui::init()?;
|
||||||
|
|
||||||
|
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 {
|
||||||
terminal,
|
tui,
|
||||||
tick_rate,
|
tick_rate,
|
||||||
|
components: vec![
|
||||||
|
Box::new(hello_world),
|
||||||
|
Box::new(hello_world1),
|
||||||
|
Box::new(hello_world2),
|
||||||
|
Box::new(hello_world3),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<()> {
|
pub fn run(&mut self) -> Result<()> {
|
||||||
Ok(())
|
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(""))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn quit(&mut self) -> Result<()> {
|
pub fn quit(&mut self) -> Result<()> {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crossterm::event::{KeyEvent, MouseEvent};
|
use crossterm::event::{KeyEvent, MouseEvent};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum AppEvent {
|
pub enum AppEvent {
|
||||||
Key(KeyEvent),
|
Key(KeyEvent),
|
||||||
Mouse(MouseEvent),
|
Mouse(MouseEvent),
|
||||||
|
@ -39,5 +39,5 @@ pub trait Component {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, frame: &mut Frame, rect: Rect);
|
fn render(&mut self, frame: &mut Frame, rect: Rect) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
17
src/components/hello_world.rs
Normal file
17
src/components/hello_world.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use ratatui::prelude::*;
|
||||||
|
use ratatui::widgets::Paragraph;
|
||||||
|
|
||||||
|
use crate::component::Component;
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct HelloWorld {
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for HelloWorld {
|
||||||
|
fn render(&mut self, frame: &mut Frame, rect: Rect) -> eyre::Result<()> {
|
||||||
|
frame.render_widget(Paragraph::new(self.text.clone()), rect);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
1
src/components/mod.rs
Normal file
1
src/components/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod hello_world;
|
@ -2,12 +2,14 @@ mod action;
|
|||||||
mod app;
|
mod app;
|
||||||
mod app_event;
|
mod app_event;
|
||||||
mod component;
|
mod component;
|
||||||
|
mod components;
|
||||||
mod tui;
|
mod tui;
|
||||||
|
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let mut app = app::App::start(std::time::Duration::from_millis(10))?;
|
let mut app = app::App::new(std::time::Duration::from_millis(10))?;
|
||||||
|
app.run()?;
|
||||||
|
|
||||||
app.quit()
|
app.quit()
|
||||||
}
|
}
|
||||||
|
14
src/tui.rs
14
src/tui.rs
@ -1,7 +1,7 @@
|
|||||||
use std::io::{self, stdout, Stdout};
|
use crossterm::{event, event::Event, execute, terminal::*};
|
||||||
|
|
||||||
use crossterm::{execute, terminal::*};
|
|
||||||
use ratatui::prelude::*;
|
use ratatui::prelude::*;
|
||||||
|
use std::io;
|
||||||
|
use std::io::{stdout, Stdout};
|
||||||
|
|
||||||
pub type Tui = Terminal<CrosstermBackend<Stdout>>;
|
pub type Tui = Terminal<CrosstermBackend<Stdout>>;
|
||||||
|
|
||||||
@ -18,3 +18,11 @@ pub fn restore() -> io::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_event(tick: std::time::Duration) -> io::Result<Option<Event>> {
|
||||||
|
if event::poll(tick)? {
|
||||||
|
return Ok(Some(event::read()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user