jwtop/
tui.rs

1use crate::app::{App, AppResult};
2use crate::event::EventHandler;
3use crate::ui;
4use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
5use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
6use std::io;
7use tui::backend::Backend;
8use tui::Terminal;
9
10/// Representation of a terminal user interface.
11///
12/// It is responsible for setting up the terminal,
13/// initializing the interface and handling the draw events.
14#[derive(Debug)]
15pub struct Tui<B: Backend> {
16    /// Interface to the Terminal.
17    terminal: Terminal<B>,
18    /// Terminal event handler.
19    pub events: EventHandler,
20}
21
22impl<B: Backend> Tui<B> {
23    /// Constructs a new instance of [`Tui`].
24    pub fn new(terminal: Terminal<B>, events: EventHandler) -> Self {
25        Self { terminal, events }
26    }
27
28    /// Initializes the terminal interface.
29    ///
30    /// It enables the raw mode and sets terminal properties.
31    pub fn init(&mut self) -> AppResult<()> {
32        terminal::enable_raw_mode()?;
33        crossterm::execute!(io::stderr(), EnterAlternateScreen, EnableMouseCapture)?;
34        self.terminal.hide_cursor()?;
35        self.terminal.clear()?;
36
37        let original_hook = std::panic::take_hook();
38        std::panic::set_hook(Box::new(move |panic| {
39            terminal::disable_raw_mode().unwrap();
40            crossterm::execute!(io::stderr(), LeaveAlternateScreen, DisableMouseCapture).unwrap();
41            original_hook(panic)
42        }));
43
44        Ok(())
45    }
46
47    /// [`Draw`] the terminal interface by [`rendering`] the widgets.
48    ///
49    /// [`Draw`]: tui::Terminal::draw
50    /// [`rendering`]: crate::ui:render
51    pub fn draw(&mut self, app: &mut App) -> AppResult<()> {
52        self.terminal.draw(|frame| ui::render(app, frame))?;
53        Ok(())
54    }
55
56    /// Exits the terminal interface.
57    ///
58    /// It disables the raw mode and reverts back the terminal properties.
59    pub fn exit(&mut self) -> AppResult<()> {
60        terminal::disable_raw_mode()?;
61        crossterm::execute!(io::stderr(), LeaveAlternateScreen, DisableMouseCapture)?;
62        self.terminal.show_cursor()?;
63        Ok(())
64    }
65}