feat(example): debounce, top right corner performance info and update on resize

This commit is contained in:
EdJoPaTo
2024-05-06 17:20:42 +02:00
parent 65fd1c04ed
commit a20134bdcd
+45 -1
View File
@@ -1,6 +1,10 @@
use std::time::{Duration, Instant};
use crossterm::event::{Event, KeyCode, MouseEventKind}; use crossterm::event::{Event, KeyCode, MouseEventKind};
use ratatui::backend::{Backend, CrosstermBackend}; use ratatui::backend::{Backend, CrosstermBackend};
use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style}; use ratatui::style::{Color, Modifier, Style};
use ratatui::text::Span;
use ratatui::widgets::{Block, Scrollbar, ScrollbarOrientation}; use ratatui::widgets::{Block, Scrollbar, ScrollbarOrientation};
use ratatui::{Frame, Terminal}; use ratatui::{Frame, Terminal};
use tui_tree_widget::{Tree, TreeItem, TreeState}; use tui_tree_widget::{Tree, TreeItem, TreeState};
@@ -133,8 +137,17 @@ fn main() -> std::io::Result<()> {
} }
fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> std::io::Result<()> { fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> std::io::Result<()> {
const DEBOUNCE: Duration = Duration::from_millis(20); // 50 FPS
let before = Instant::now();
terminal.draw(|frame| app.draw(frame))?; terminal.draw(|frame| app.draw(frame))?;
let mut last_render_took = before.elapsed();
let mut debounce: Option<Instant> = None;
loop { loop {
let timeout = debounce.map_or(DEBOUNCE, |start| DEBOUNCE.saturating_sub(start.elapsed()));
if crossterm::event::poll(timeout)? {
let update = match crossterm::event::read()? { let update = match crossterm::event::read()? {
Event::Key(key) => match key.code { Event::Key(key) => match key.code {
KeyCode::Char('q') => return Ok(()), KeyCode::Char('q') => return Ok(()),
@@ -155,10 +168,41 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> std::io::Res
MouseEventKind::ScrollUp => app.state.scroll_up(1), MouseEventKind::ScrollUp => app.state.scroll_up(1),
_ => false, _ => false,
}, },
Event::Resize(_, _) => true,
_ => false, _ => false,
}; };
if update { if update {
terminal.draw(|frame| app.draw(frame))?; debounce.get_or_insert_with(Instant::now);
}
}
if debounce.is_some_and(|debounce| debounce.elapsed() > DEBOUNCE) {
let before = Instant::now();
terminal.draw(|frame| {
app.draw(frame);
// Performance info in top right corner
{
let text = format!(
" {} {last_render_took:?} {:.1} FPS",
frame.count(),
1.0 / last_render_took.as_secs_f64()
);
#[allow(clippy::cast_possible_truncation)]
let area = Rect {
y: 0,
height: 1,
x: frame.size().width.saturating_sub(text.len() as u16),
width: text.len() as u16,
};
frame.render_widget(
Span::styled(text, Style::new().fg(Color::Black).bg(Color::Gray)),
area,
);
}
})?;
last_render_took = before.elapsed();
debounce = None;
} }
} }
} }