1use color_eyre::Result;
18use lipsum::lipsum;
19use ratatui::DefaultTerminal;
20use ratatui::crossterm::event::{self, Event, KeyCode, KeyEvent};
21use ratatui::prelude::{Constraint, Frame, Layout, Rect, Style, Stylize, Text};
22use ratatui::widgets::{Paragraph, Wrap};
23use tui_popup::{Popup, PopupState};
24
25fn main() -> Result<()> {
26 color_eyre::install()?;
27 ratatui::run(run)
28}
29
30fn run(terminal: &mut DefaultTerminal) -> Result<()> {
31 let mut state = PopupState::default();
32 let mut exit = false;
33 while !exit {
34 terminal.draw(|frame| draw(frame, &mut state))?;
35 handle_events(&mut state, &mut exit)?;
36 }
37 Ok(())
38}
39
40fn draw(frame: &mut Frame, state: &mut PopupState) {
41 let vertical = Layout::vertical([Constraint::Min(0), Constraint::Length(1)]);
42 let [background_area, status_area] = vertical.areas(frame.area());
43
44 render_background(frame, background_area);
45 render_popup(frame, background_area, state);
46 render_status_bar(frame, status_area, state);
47}
48
49fn render_background(frame: &mut Frame, area: Rect) {
50 let lorem_ipsum = lipsum(area.area() as usize / 5);
51 let background = Paragraph::new(lorem_ipsum)
52 .wrap(Wrap { trim: false })
53 .dark_gray();
54 frame.render_widget(background, area);
55}
56
57fn render_popup(frame: &mut Frame, area: Rect, state: &mut PopupState) {
58 let body = Text::from_iter([
59 "q: exit",
60 "r: reset",
61 "j: move down",
62 "k: move up",
63 "h: move left",
64 "l: move right",
65 ]);
66 let popup = Popup::new(body)
67 .title("Popup")
68 .style(Style::new().white().on_blue());
69 frame.render_stateful_widget(popup, area, state);
70}
71
72fn render_status_bar(frame: &mut Frame, area: Rect, state: &PopupState) {
76 let popup_area = state.area().unwrap_or_default();
77 let text = format!("Popup area: {popup_area:?}");
78 let paragraph = Paragraph::new(text).style(Style::new().white().on_black());
79 frame.render_widget(paragraph, area);
80}
81
82fn handle_events(popup: &mut PopupState, exit: &mut bool) -> Result<()> {
83 let event = event::read()?;
84 if let Some(key) = event.as_key_press_event() {
85 handle_key_event(key, popup, exit);
86 } else if let Event::Mouse(event) = event {
87 popup.handle_mouse_event(event);
88 }
89 Ok(())
90}
91
92fn handle_key_event(event: KeyEvent, popup: &mut PopupState, exit: &mut bool) {
93 match event.code {
94 KeyCode::Char('q') | KeyCode::Esc => *exit = true,
95 KeyCode::Char('r') => *popup = PopupState::default(),
96 KeyCode::Char('j') | KeyCode::Down => popup.move_down(1),
97 KeyCode::Char('k') | KeyCode::Up => popup.move_up(1),
98 KeyCode::Char('h') | KeyCode::Left => popup.move_left(1),
99 KeyCode::Char('l') | KeyCode::Right => popup.move_right(1),
100 _ => {}
101 }
102}