Skip to main content

gm_lib/tui/app/widgets/
select.rs

1use std::fmt::Display;
2
3use ratatui::{
4    layout::{Constraint, Layout},
5    style::Style,
6    text::Line,
7    widgets::{List, ListItem, Widget},
8};
9
10use crate::utils::cursor::Cursor;
11
12use super::scroll_bar::CustomScrollBar;
13
14pub struct Select<'a, T: Display> {
15    pub focus: bool,
16    pub list: &'a Vec<T>,
17    pub cursor: &'a Cursor,
18    pub focus_style: Style,
19}
20
21impl<T: Display> Widget for Select<'_, T> {
22    fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
23    where
24        Self: Sized,
25    {
26        let capacity = area.height as usize;
27        let page_number = self.cursor.current / capacity;
28        let idx = self.cursor.current % capacity;
29
30        let render_item = |(i, member)| {
31            let content = Line::from(format!("{member}"));
32            let style = if idx == i && self.focus {
33                self.focus_style
34            } else {
35                Style::default()
36            };
37            ListItem::new(content).style(style)
38        };
39
40        if capacity < self.list.len() {
41            let display_items = self
42                .list
43                .chunks(capacity)
44                .nth(page_number)
45                .unwrap()
46                .iter()
47                .enumerate()
48                .map(render_item)
49                .collect::<Vec<ListItem>>();
50
51            let horizontal_layout = Layout::horizontal([Constraint::Min(3), Constraint::Length(1)]);
52            let [list_area, scroll_area] = horizontal_layout.areas(area);
53            List::new(display_items).render(list_area, buf);
54            CustomScrollBar {
55                cursor: self.cursor.current,
56                total: self.list.len(),
57            }
58            .render(scroll_area, buf);
59        } else {
60            let display_items = self
61                .list
62                .iter()
63                .enumerate()
64                .map(render_item)
65                .collect::<Vec<ListItem>>();
66            List::new(display_items).render(area, buf);
67        }
68    }
69}