Skip to main content

ansiq_widgets/
table.rs

1use ansiq_core::{
2    BlockFrame, Constraint, Element, ElementKind, Flex, HighlightSpacing, Layout, Length, Row,
3    SelectHandler, Style, TableAlignment, TableProps, TableState, Text,
4};
5
6pub struct Table<Message = ()> {
7    block: Option<BlockFrame>,
8    header: Option<Row>,
9    footer: Option<Row>,
10    rows: Vec<Row>,
11    widths: Vec<Constraint>,
12    column_spacing: u16,
13    flex: Flex,
14    alignments: Vec<TableAlignment>,
15    state: TableState,
16    highlight_symbol: Option<Text>,
17    row_highlight_style: Style,
18    column_highlight_style: Style,
19    cell_highlight_style: Style,
20    highlight_spacing: HighlightSpacing,
21    on_select: Option<SelectHandler<Message>>,
22    layout: Layout,
23    style: Style,
24    focusable: bool,
25}
26
27impl<Message> Default for Table<Message> {
28    fn default() -> Self {
29        Self {
30            block: None,
31            header: None,
32            footer: None,
33            rows: Vec::new(),
34            widths: Vec::new(),
35            column_spacing: 1,
36            flex: Flex::Start,
37            alignments: Vec::new(),
38            state: TableState::default(),
39            highlight_symbol: None,
40            row_highlight_style: Style::default(),
41            column_highlight_style: Style::default(),
42            cell_highlight_style: Style::default(),
43            highlight_spacing: HighlightSpacing::WhenSelected,
44            on_select: None,
45            layout: Layout {
46                width: Length::Fill,
47                height: Length::Auto,
48            },
49            style: Style::default(),
50            focusable: false,
51        }
52    }
53}
54
55impl Table<()> {
56    pub fn new<R, T, C>(rows: R, widths: C) -> Self
57    where
58        R: IntoIterator<Item = T>,
59        T: Into<Row>,
60        C: IntoIterator,
61        C::Item: Into<Constraint>,
62    {
63        Self::default().rows(rows).widths(widths)
64    }
65}
66
67impl<Message> Table<Message> {
68    pub fn rows<I, T>(mut self, rows: I) -> Self
69    where
70        I: IntoIterator<Item = T>,
71        T: Into<Row>,
72    {
73        self.rows = rows.into_iter().map(Into::into).collect();
74        self
75    }
76
77    pub fn row<T>(mut self, row: T) -> Self
78    where
79        T: Into<Row>,
80    {
81        self.rows.push(row.into());
82        self
83    }
84
85    pub fn header<T>(mut self, row: T) -> Self
86    where
87        T: Into<Row>,
88    {
89        self.header = Some(row.into());
90        self
91    }
92
93    pub fn headers<T>(self, row: T) -> Self
94    where
95        T: Into<Row>,
96    {
97        self.header(row)
98    }
99
100    pub fn footer<T>(mut self, row: T) -> Self
101    where
102        T: Into<Row>,
103    {
104        self.footer = Some(row.into());
105        self
106    }
107
108    pub fn widths<I>(mut self, widths: I) -> Self
109    where
110        I: IntoIterator,
111        I::Item: Into<Constraint>,
112    {
113        self.widths = widths.into_iter().map(Into::into).collect();
114        self
115    }
116
117    pub fn column_spacing(mut self, spacing: u16) -> Self {
118        self.column_spacing = spacing;
119        self
120    }
121
122    pub fn flex(mut self, flex: Flex) -> Self {
123        self.flex = flex;
124        self
125    }
126
127    pub fn block(mut self, block: crate::Block<Message>) -> Self {
128        self.block = Some(block.into_frame());
129        self
130    }
131
132    pub fn selected(mut self, selected: Option<usize>) -> Self {
133        self.state.select(selected);
134        self
135    }
136
137    pub fn offset(mut self, offset: usize) -> Self {
138        *self.state.offset_mut() = offset;
139        self
140    }
141
142    pub fn state(mut self, state: TableState) -> Self {
143        self.state = state;
144        self
145    }
146
147    pub fn highlight_symbol<T>(mut self, symbol: T) -> Self
148    where
149        T: Into<Text>,
150    {
151        self.highlight_symbol = Some(symbol.into());
152        self
153    }
154
155    pub fn highlight_style<S: Into<Style>>(self, style: S) -> Self {
156        self.row_highlight_style(style)
157    }
158
159    pub fn row_highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
160        self.row_highlight_style = style.into();
161        self
162    }
163
164    pub fn column_highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
165        self.column_highlight_style = style.into();
166        self
167    }
168
169    pub fn cell_highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
170        self.cell_highlight_style = style.into();
171        self
172    }
173
174    pub fn highlight_spacing(mut self, spacing: HighlightSpacing) -> Self {
175        self.highlight_spacing = spacing;
176        self
177    }
178
179    pub fn alignment(mut self, alignment: TableAlignment) -> Self {
180        self.alignments.push(alignment);
181        self
182    }
183
184    pub fn alignments<I>(mut self, alignments: I) -> Self
185    where
186        I: IntoIterator<Item = TableAlignment>,
187    {
188        self.alignments.extend(alignments);
189        self
190    }
191
192    pub fn on_select<NextMessage, F>(self, handler: F) -> Table<NextMessage>
193    where
194        F: FnMut(usize) -> Option<NextMessage> + 'static,
195    {
196        Table {
197            block: self.block,
198            header: self.header,
199            footer: self.footer,
200            rows: self.rows,
201            widths: self.widths,
202            column_spacing: self.column_spacing,
203            flex: self.flex,
204            alignments: self.alignments,
205            state: self.state,
206            highlight_symbol: self.highlight_symbol,
207            row_highlight_style: self.row_highlight_style,
208            column_highlight_style: self.column_highlight_style,
209            cell_highlight_style: self.cell_highlight_style,
210            highlight_spacing: self.highlight_spacing,
211            on_select: Some(std::boxed::Box::new(handler)),
212            layout: self.layout,
213            style: self.style,
214            focusable: true,
215        }
216    }
217
218    pub fn layout(mut self, layout: Layout) -> Self {
219        self.layout = layout;
220        self
221    }
222
223    pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
224        self.style = style.into();
225        self
226    }
227
228    pub fn build(self) -> Element<Message> {
229        Element::new(ElementKind::Table(TableProps {
230            block: self.block,
231            header: self.header,
232            footer: self.footer,
233            rows: self.rows,
234            widths: self.widths,
235            column_spacing: self.column_spacing,
236            flex: self.flex,
237            alignments: self.alignments,
238            state: self.state,
239            highlight_symbol: self.highlight_symbol,
240            row_highlight_style: self.row_highlight_style,
241            column_highlight_style: self.column_highlight_style,
242            cell_highlight_style: self.cell_highlight_style,
243            highlight_spacing: self.highlight_spacing,
244            on_select: self.on_select,
245        }))
246        .with_layout(self.layout)
247        .with_style(self.style)
248        .with_focusable(self.focusable)
249    }
250}
251
252impl<Item> FromIterator<Item> for Table<()>
253where
254    Item: Into<Row>,
255{
256    fn from_iter<Iter: IntoIterator<Item = Item>>(iter: Iter) -> Self {
257        Self::default().rows(iter)
258    }
259}