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