1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use super::*;

pub struct SizedTable {
    table: Table<'static>,
    height: usize,
    width: usize,
}

impl SizedTable {
    pub fn new(content: Vec<Vec<Text<'static>>>) -> Self {
        let height = content
            .iter()
            .map(|row| row.iter().map(Text::height).max().unwrap_or_default())
            .sum::<usize>();

        let widths = content
            .iter()
            .map(|row| row.iter().map(Text::width).collect())
            .reduce(|widths: Vec<usize>, row| {
                row.iter()
                    .zip(widths.iter())
                    .map(|(r, w)| r.max(w))
                    .cloned()
                    .collect()
            })
            .unwrap_or_default();

        let width = widths
            .iter()
            .cloned()
            .reduce(|width, w| width + w + 1) // +1 because of space between entries
            .unwrap_or_default();

        let rows = content.into_iter().map(Row::new);
        let table = Table::default()
            .widths(widths.iter().map(|w| {
                (*w).try_into()
                    .ok()
                    .map_or(Constraint::Min(0), Constraint::Length)
            }))
            .rows(rows);
        Self {
            table,
            height,
            width,
        }
    }
}

impl SizedWidget for SizedTable {
    fn height(&self) -> Option<u16> {
        self.height.try_into().ok()
    }
    fn width(&self) -> Option<u16> {
        self.width.try_into().ok()
    }
}

impl Draw for SizedTable {
    fn draw(&mut self, area: Rect, f: &mut Frame<'_>) {
        f.render_widget(&self.table, area);
    }
}