tui.rs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. use crate::app::{App, AppResult};
  2. use crate::event::EventHandler;
  3. use crate::ui;
  4. use crossterm::event::DisableMouseCapture;
  5. use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
  6. use std::io;
  7. use std::panic;
  8. use ratatui::backend::Backend;
  9. use ratatui::Terminal;
  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)]
  15. pub struct Tui<B: Backend> {
  16. /// Interface to the Terminal.
  17. terminal: Terminal<B>,
  18. /// Terminal event handler.
  19. pub events: EventHandler,
  20. }
  21. impl<B: Backend> Tui<B> {
  22. /// Constructs a new instance of [`Tui`].
  23. pub fn new(terminal: Terminal<B>, events: EventHandler) -> Self {
  24. Self { terminal, events }
  25. }
  26. /// Initializes the terminal interface.
  27. ///
  28. /// It enables the raw mode and sets terminal properties.
  29. pub fn init(&mut self) -> AppResult<()> {
  30. terminal::enable_raw_mode()?;
  31. crossterm::execute!(io::stderr(), EnterAlternateScreen, DisableMouseCapture)?;
  32. // Define a custom panic hook to reset the terminal properties.
  33. // This way, you won't have your terminal messed up if an unexpected error happens.
  34. let panic_hook = panic::take_hook();
  35. panic::set_hook(Box::new(move |panic| {
  36. Self::reset().expect("failed to reset the terminal");
  37. panic_hook(panic);
  38. }));
  39. self.terminal.hide_cursor()?;
  40. self.terminal.clear()?;
  41. Ok(())
  42. }
  43. /// [`Draw`] the terminal interface by [`rendering`] the widgets.
  44. ///
  45. /// [`Draw`]: ratatui::Terminal::draw
  46. /// [`rendering`]: crate::ui:render
  47. pub fn draw(&mut self, app: &mut App) -> AppResult<()> {
  48. self.terminal.draw(|frame| ui::render(app, frame))?;
  49. Ok(())
  50. }
  51. /// Resets the terminal interface.
  52. ///
  53. /// This function is also used for the panic hook to revert
  54. /// the terminal properties if unexpected errors occur.
  55. fn reset() -> AppResult<()> {
  56. terminal::disable_raw_mode()?;
  57. crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
  58. Ok(())
  59. }
  60. /// Exits the terminal interface.
  61. ///
  62. /// It disables the raw mode and reverts back the terminal properties.
  63. pub fn exit(&mut self) -> AppResult<()> {
  64. Self::reset()?;
  65. self.terminal.show_cursor()?;
  66. Ok(())
  67. }
  68. }