generated from GarandPLG/rust-flake-template
Add resize handling and non-blocking input loop
Use `recv_timeout` to prevent UI blocking, forward terminal resize events, adjust keybinding width calculation, and replace percentage layout with fill/length for the main menu.
This commit is contained in:
+17
-5
@@ -12,11 +12,13 @@ use ratatui::{
|
|||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
io::Result,
|
io::Result,
|
||||||
sync::mpsc::{self, Receiver},
|
sync::mpsc::{self, Receiver, RecvTimeoutError},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Input(KeyEvent),
|
Input(KeyEvent),
|
||||||
|
Resize(u16, u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
@@ -80,12 +82,16 @@ impl App {
|
|||||||
while !self.exit {
|
while !self.exit {
|
||||||
terminal.draw(|frame: &mut Frame<'_>| self.draw(frame))?;
|
terminal.draw(|frame: &mut Frame<'_>| self.draw(frame))?;
|
||||||
|
|
||||||
let event: Event = match rx.recv() {
|
let event = match rx.recv_timeout(Duration::from_millis(100)) {
|
||||||
Ok(ev) => ev,
|
Ok(ev) => ev,
|
||||||
|
Err(RecvTimeoutError::Timeout) => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
};
|
};
|
||||||
match event {
|
match event {
|
||||||
Event::Input(key_event) => self.handle_key_event(key_event)?,
|
Event::Input(key_event) => self.handle_key_event(key_event)?,
|
||||||
|
Event::Resize(_, _) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +123,19 @@ impl App {
|
|||||||
pub fn handle_input_events(tx: mpsc::Sender<Event>) {
|
pub fn handle_input_events(tx: mpsc::Sender<Event>) {
|
||||||
loop {
|
loop {
|
||||||
match event::read() {
|
match event::read() {
|
||||||
Ok(ev) => {
|
Ok(ev) => match ev {
|
||||||
if let event::Event::Key(key_event) = ev {
|
event::Event::Key(key_event) => {
|
||||||
if tx.send(Event::Input(key_event)).is_err() {
|
if tx.send(Event::Input(key_event)).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
event::Event::Resize(cols, rows) => {
|
||||||
|
if tx.send(Event::Resize(cols, rows)).is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ impl Widget for KeybindingsWidget {
|
|||||||
|
|
||||||
block.render(area, buf);
|
block.render(area, buf);
|
||||||
|
|
||||||
let base: u16 = if count == 0 { 0 } else { 10 };
|
let base: u16 = if count == 0 { 0 } else { 100u16 / count };
|
||||||
|
|
||||||
let constraints: Vec<Constraint> = vec![Constraint::Percentage(base); count as usize];
|
let constraints: Vec<Constraint> = vec![Constraint::Percentage(base); count as usize];
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ fn view_options() -> Vec<(usize, String)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_menu_widget(app: &App, area: Rect, buf: &mut Buffer) {
|
pub fn main_menu_widget(app: &App, area: Rect, buf: &mut Buffer) {
|
||||||
let vertical_layout: Layout =
|
let vertical_layout: Layout = Layout::vertical([Constraint::Fill(1), Constraint::Length(4)]);
|
||||||
Layout::vertical([Constraint::Percentage(92), Constraint::Percentage(8)]);
|
|
||||||
|
|
||||||
let [main_menu_area, keybindings_area] = vertical_layout.areas(area);
|
let [main_menu_area, keybindings_area] = vertical_layout.areas(area);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user