tui_react/
list.rs

1use tui::{
2    buffer::Buffer,
3    layout::Rect,
4    text::{Line, Span, Text},
5    widgets::{Block, Paragraph, Widget},
6};
7
8#[derive(Default)]
9pub struct List {
10    /// The index at which the list last started. Used for scrolling
11    pub offset: usize,
12}
13
14impl List {
15    fn list_offset_for(&self, entry_in_view: Option<usize>, height: usize) -> usize {
16        match entry_in_view {
17            Some(pos) => match height as usize {
18                h if (self.offset + h).saturating_sub(1) < pos => pos - h + 1,
19                _ if self.offset > pos => pos,
20                _ => self.offset,
21            },
22            None => 0,
23        }
24    }
25}
26
27#[derive(Default)]
28pub struct ListProps<'b> {
29    pub block: Option<Block<'b>>,
30    pub entry_in_view: Option<usize>,
31}
32
33impl List {
34    pub fn render<'a, 't>(
35        &mut self,
36        props: ListProps<'a>,
37        items: impl IntoIterator<Item = Vec<Span<'t>>>,
38        area: Rect,
39        buf: &mut Buffer,
40    ) {
41        let ListProps {
42            block,
43            entry_in_view,
44        } = props;
45
46        let list_area = match block {
47            Some(b) => {
48                let inner_area = b.inner(area);
49                b.render(area, buf);
50                inner_area
51            }
52            None => area,
53        };
54        self.offset = self.list_offset_for(entry_in_view, list_area.height as usize);
55
56        if list_area.width < 1 || list_area.height < 1 {
57            return;
58        }
59
60        for (i, vec_of_spans) in items
61            .into_iter()
62            .skip(self.offset)
63            .enumerate()
64            .take(list_area.height as usize)
65        {
66            let (x, y) = (list_area.left(), list_area.top() + i as u16);
67            Paragraph::new(Text::from(Line::from(vec_of_spans))).render(
68                Rect {
69                    x,
70                    y,
71                    width: list_area.width,
72                    height: 1,
73                },
74                buf,
75            );
76        }
77    }
78}