1#![doc = include_str!("../readme.md")]
2
3mod cellselection;
4pub mod edit;
5mod noselection;
6mod rowselection;
7mod rowsetselection;
8mod table;
9pub mod textdata;
10mod util;
11
12use crate::textdata::Row;
13use ratatui_core::buffer::Buffer;
14use ratatui_core::layout::{Constraint, Rect};
15use ratatui_core::style::Style;
16
17#[derive(Debug)]
19pub struct TableContext {
20 pub focus: bool,
22
23 pub selected_cell: bool,
25 pub selected_row: bool,
27 pub selected_column: bool,
29
30 pub style: Style,
32 pub row_style: Option<Style>,
34 pub select_style: Option<Style>,
36
37 pub space_area: Rect,
40 pub row_area: Rect,
42
43 pub non_exhaustive: NonExhaustive,
45}
46
47pub trait TableData<'a> {
53 fn rows(&self) -> usize;
55
56 fn header(&self) -> Option<Row<'a>> {
59 None
60 }
61
62 fn footer(&self) -> Option<Row<'a>> {
65 None
66 }
67
68 #[allow(unused_variables)]
70 fn row_height(&self, row: usize) -> u16 {
71 1
72 }
73
74 #[allow(unused_variables)]
76 fn row_style(&self, row: usize) -> Option<Style> {
77 None
78 }
79
80 fn widths(&self) -> Vec<Constraint> {
82 Vec::default()
83 }
84
85 fn render_cell(
88 &self,
89 ctx: &TableContext,
90 column: usize,
91 row: usize,
92 area: Rect,
93 buf: &mut Buffer,
94 );
95}
96
97impl<'a> TableData<'a> for Box<dyn TableData<'a> + 'a> {
98 fn rows(&self) -> usize {
99 (**self).rows()
100 }
101
102 fn header(&self) -> Option<Row<'a>> {
103 (**self).header()
104 }
105
106 fn footer(&self) -> Option<Row<'a>> {
107 (**self).footer()
108 }
109
110 fn row_height(&self, row: usize) -> u16 {
111 (**self).row_height(row)
112 }
113
114 fn row_style(&self, row: usize) -> Option<Style> {
115 (**self).row_style(row)
116 }
117
118 fn widths(&self) -> Vec<Constraint> {
119 (**self).widths()
120 }
121
122 fn render_cell(
123 &self,
124 ctx: &TableContext,
125 column: usize,
126 row: usize,
127 area: Rect,
128 buf: &mut Buffer,
129 ) {
130 (**self).render_cell(ctx, column, row, area, buf)
131 }
132}
133
134pub trait TableDataIter<'a> {
138 fn cloned(&self) -> Option<Box<dyn TableDataIter<'a> + 'a>> {
142 None
143 }
144
145 fn rows(&self) -> Option<usize>;
153
154 fn header(&self) -> Option<Row<'a>> {
157 None
158 }
159
160 fn footer(&self) -> Option<Row<'a>> {
163 None
164 }
165
166 fn nth(&mut self, n: usize) -> bool;
169
170 fn row_height(&self) -> u16 {
172 1
173 }
174
175 fn row_style(&self) -> Option<Style> {
177 None
178 }
179
180 fn widths(&self) -> Vec<Constraint> {
182 Vec::default()
183 }
184
185 fn render_cell(&self, ctx: &TableContext, column: usize, area: Rect, buf: &mut Buffer);
188}
189
190pub trait TableSelection {
192 fn count(&self) -> usize;
194
195 fn clear(&mut self) {}
197
198 fn is_selected_row(&self, row: usize) -> bool;
200
201 fn is_selected_column(&self, column: usize) -> bool;
203
204 fn is_selected_cell(&self, column: usize, row: usize) -> bool;
206
207 fn lead_selection(&self) -> Option<(usize, usize)>;
209
210 #[allow(unused_variables)]
212 fn validate_rows(&mut self, rows: usize) {}
213
214 #[allow(unused_variables)]
216 fn validate_cols(&mut self, cols: usize) {}
217
218 #[allow(unused_variables)]
220 fn items_added(&mut self, pos: usize, n: usize) {}
221
222 #[allow(unused_variables)]
224 fn items_removed(&mut self, pos: usize, n: usize, rows: usize) {}
225}
226
227use crate::_private::NonExhaustive;
228
229pub use table::{Table, TableState, TableStyle, handle_doubleclick_events};
230
231pub mod selection {
233 pub use crate::cellselection::CellSelection;
234 pub mod cellselection {
235 pub use crate::cellselection::{handle_events, handle_mouse_events};
236 }
237 pub use crate::noselection::NoSelection;
238 pub mod noselection {
239 pub use crate::noselection::{handle_events, handle_mouse_events};
240 }
241 pub use crate::rowselection::RowSelection;
242 pub mod rowselection {
243 pub use crate::rowselection::{handle_events, handle_mouse_events};
244 }
245 pub use crate::rowsetselection::RowSetSelection;
246 pub mod rowsetselection {
247 pub use crate::rowsetselection::{handle_events, handle_mouse_events};
248 }
249}
250
251pub mod event {
253 pub use rat_event::*;
254
255 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
257 #[non_exhaustive]
258 pub enum TableOutcome {
259 Continue,
261 Unchanged,
263 Header(usize),
265 Footer(usize),
267 Changed,
269 Selected,
271 }
272
273 impl ConsumedEvent for TableOutcome {
274 fn is_consumed(&self) -> bool {
275 *self != TableOutcome::Continue
276 }
277 }
278
279 impl From<TableOutcome> for Outcome {
280 fn from(value: TableOutcome) -> Self {
281 match value {
282 TableOutcome::Continue => Outcome::Continue,
283 TableOutcome::Unchanged => Outcome::Unchanged,
284 TableOutcome::Header(_) => Outcome::Unchanged,
285 TableOutcome::Footer(_) => Outcome::Unchanged,
286 TableOutcome::Changed => Outcome::Changed,
287 TableOutcome::Selected => Outcome::Changed,
288 }
289 }
290 }
291
292 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
294 pub enum DoubleClickOutcome {
295 Continue,
297 Unchanged,
300 Changed,
305 ClickClick(usize, usize),
307 }
308
309 impl From<DoubleClickOutcome> for Outcome {
310 fn from(value: DoubleClickOutcome) -> Self {
311 match value {
312 DoubleClickOutcome::Continue => Outcome::Continue,
313 DoubleClickOutcome::Unchanged => Outcome::Unchanged,
314 DoubleClickOutcome::Changed => Outcome::Changed,
315 DoubleClickOutcome::ClickClick(_, _) => Outcome::Changed,
316 }
317 }
318 }
319
320 impl From<Outcome> for DoubleClickOutcome {
321 fn from(value: Outcome) -> Self {
322 match value {
323 Outcome::Continue => DoubleClickOutcome::Continue,
324 Outcome::Unchanged => DoubleClickOutcome::Unchanged,
325 Outcome::Changed => DoubleClickOutcome::Changed,
326 }
327 }
328 }
329
330 impl ConsumedEvent for DoubleClickOutcome {
331 fn is_consumed(&self) -> bool {
332 !matches!(self, DoubleClickOutcome::Continue)
333 }
334 }
335
336 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
338 pub enum EditOutcome {
339 Continue,
341 Unchanged,
344 Changed,
349 Cancel,
351 Commit,
353 CommitAndAppend,
355 CommitAndEdit,
357 Insert,
359 Remove,
361 Edit,
363 Append,
366 }
367
368 impl From<Outcome> for EditOutcome {
369 fn from(value: Outcome) -> Self {
370 match value {
371 Outcome::Continue => EditOutcome::Continue,
372 Outcome::Unchanged => EditOutcome::Unchanged,
373 Outcome::Changed => EditOutcome::Changed,
374 }
375 }
376 }
377
378 impl From<EditOutcome> for Outcome {
379 fn from(value: EditOutcome) -> Self {
380 match value {
381 EditOutcome::Continue => Outcome::Continue,
382 EditOutcome::Unchanged => Outcome::Unchanged,
383 EditOutcome::Changed => Outcome::Changed,
384 EditOutcome::Insert => Outcome::Unchanged,
385 EditOutcome::Remove => Outcome::Unchanged,
386 EditOutcome::Edit => Outcome::Unchanged,
387 EditOutcome::Append => Outcome::Unchanged,
388 EditOutcome::Cancel => Outcome::Unchanged,
389 EditOutcome::Commit => Outcome::Unchanged,
390 EditOutcome::CommitAndAppend => Outcome::Unchanged,
391 EditOutcome::CommitAndEdit => Outcome::Unchanged,
392 }
393 }
394 }
395
396 impl ConsumedEvent for EditOutcome {
397 fn is_consumed(&self) -> bool {
398 !matches!(self, EditOutcome::Continue)
399 }
400 }
401}
402
403mod _private {
404 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
405 pub struct NonExhaustive;
406}