1use ratatui::layout::Rect;
4
5use super::DataTableState;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub(crate) struct DrawnTable {
10 pub(crate) area: Rect,
12 pub(crate) header: u16,
13 pub(crate) start_row: usize,
15 pub(crate) rows: usize,
16 pub(crate) columns: DrawnColumns,
17}
18
19pub type DrawnColumns = Vec<(u16, u16, String)>;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct CellHit {
26 pub row: Option<usize>,
27 pub column: Option<String>,
28}
29
30impl DataTableState {
31 pub fn forget_drawn(&mut self) {
34 self.drawn = None;
35 }
36
37 pub fn drawn_cell(&self, x: u16, y: u16) -> Option<CellHit> {
40 let drawn = self.drawn.as_ref()?;
41 if !drawn.area.contains(ratatui::layout::Position { x, y }) {
42 return None;
43 }
44 let below_header = usize::from(y - drawn.area.y).checked_sub(usize::from(drawn.header));
45 let row = match below_header {
46 Some(row) if row >= drawn.rows => return None,
47 row => row,
48 };
49 let column = drawn
50 .columns
51 .iter()
52 .find(|(from, to, _)| (*from..*to).contains(&x))
53 .map(|(_, _, name)| name.clone());
54 Some(CellHit { row, column })
55 }
56
57 pub fn drawn_edge(&self, x: u16, y: u16) -> Option<String> {
60 let drawn = self.drawn.as_ref()?;
61 let header = drawn.area.y..drawn.area.y + drawn.header;
62 if !header.contains(&y) || !drawn.area.contains(ratatui::layout::Position { x, y }) {
63 return None;
64 }
65 if let Some(name) = Self::right_edge(drawn, x) {
66 return Some(name);
67 }
68 if drawn
69 .columns
70 .iter()
71 .any(|(from, to, _)| (*from..*to).contains(&x))
72 {
73 return None;
74 }
75 drawn
76 .columns
77 .iter()
78 .find(|(_, to, _)| *to == x)
79 .map(|(_, _, name)| name.clone())
80 }
81
82 fn right_edge(drawn: &DrawnTable, x: u16) -> Option<String> {
85 let (_, to, name) = drawn.columns.iter().max_by_key(|(_, to, _)| *to)?;
86 (*to >= drawn.area.right() && x + 1 == *to).then(|| name.clone())
87 }
88
89 pub fn drawn_header(&self) -> Option<(Rect, DrawnColumns)> {
92 let drawn = self.drawn.as_ref()?;
93 Some((
94 Rect {
95 height: drawn.header.min(drawn.area.height),
96 ..drawn.area
97 },
98 drawn.columns.clone(),
99 ))
100 }
101
102 pub fn point_at(&mut self, hit: &CellHit) -> bool {
106 let mut landed = true;
107 if let Some(row) = hit.row {
108 if let Some(drawn) = self.drawn.as_ref()
109 && drawn.start_row == self.view.start_row
110 && row < drawn.rows
111 {
112 self.table_state.select(Some(row));
113 } else {
114 landed = false;
115 }
116 }
117 if let Some(name) = &hit.column {
118 self.set_current_column(name);
119 landed &= self.current_column() == Some(name.as_str());
120 }
121 landed
122 }
123}