tek/tui/src/tui_engine.rs

59 lines
2.1 KiB
Rust

use crate::*;
pub struct Tui {
pub exited: Arc<AtomicBool>,
pub backend: CrosstermBackend<Stdout>,
pub buffer: Buffer,
pub area: [u16;4],
}
impl Tui {
/// Construct a new TUI engine and wrap it for shared ownership.
pub fn new () -> Usually<Arc<RwLock<Self>>> {
let backend = CrosstermBackend::new(stdout());
let Size { width, height } = backend.size()?;
Ok(Arc::new(RwLock::new(Self {
exited: Arc::new(AtomicBool::new(false)),
buffer: Buffer::empty(Rect { x: 0, y: 0, width, height }),
area: [0, 0, width, height],
backend,
})))
}
/// True if done
pub fn exited (&self) -> bool {
self.exited.fetch_and(true, Relaxed)
}
/// Prepare before run
pub fn setup (&mut self) -> Usually<()> {
let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler();
std::panic::set_hook(Box::new(move |info: &std::panic::PanicHookInfo|{
stdout().execute(LeaveAlternateScreen).unwrap();
CrosstermBackend::new(stdout()).show_cursor().unwrap();
disable_raw_mode().unwrap();
better_panic_handler(info);
}));
stdout().execute(EnterAlternateScreen)?;
self.backend.hide_cursor()?;
enable_raw_mode().map_err(Into::into)
}
/// Update the display buffer.
pub fn flip (&mut self, mut buffer: Buffer, size: ratatui::prelude::Rect) -> Buffer {
if self.buffer.area != size {
self.backend.clear_region(ClearType::All).unwrap();
self.buffer.resize(size);
self.buffer.reset();
}
let updates = self.buffer.diff(&buffer);
self.backend.draw(updates.into_iter()).expect("failed to render");
self.backend.flush().expect("failed to flush output buffer");
std::mem::swap(&mut self.buffer, &mut buffer);
buffer.reset();
buffer
}
/// Clean up after run
pub fn teardown (&mut self) -> Usually<()> {
stdout().execute(LeaveAlternateScreen)?;
self.backend.show_cursor()?;
disable_raw_mode().map_err(Into::into)
}
}