use ratatui::layout::Rect;
use super::DataTableState;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct DrawnTable {
pub(crate) area: Rect,
pub(crate) header: u16,
pub(crate) start_row: usize,
pub(crate) rows: usize,
pub(crate) columns: DrawnColumns,
}
pub type DrawnColumns = Vec<(u16, u16, String)>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CellHit {
pub row: Option<usize>,
pub column: Option<String>,
}
impl DataTableState {
pub fn forget_drawn(&mut self) {
self.drawn = None;
}
pub fn drawn_cell(&self, x: u16, y: u16) -> Option<CellHit> {
let drawn = self.drawn.as_ref()?;
if !drawn.area.contains(ratatui::layout::Position { x, y }) {
return None;
}
let below_header = usize::from(y - drawn.area.y).checked_sub(usize::from(drawn.header));
let row = match below_header {
Some(row) if row >= drawn.rows => return None,
row => row,
};
let column = drawn
.columns
.iter()
.find(|(from, to, _)| (*from..*to).contains(&x))
.map(|(_, _, name)| name.clone());
Some(CellHit { row, column })
}
pub fn drawn_edge(&self, x: u16, y: u16) -> Option<String> {
let drawn = self.drawn.as_ref()?;
let header = drawn.area.y..drawn.area.y + drawn.header;
if !header.contains(&y) || !drawn.area.contains(ratatui::layout::Position { x, y }) {
return None;
}
if let Some(name) = Self::right_edge(drawn, x) {
return Some(name);
}
if drawn
.columns
.iter()
.any(|(from, to, _)| (*from..*to).contains(&x))
{
return None;
}
drawn
.columns
.iter()
.find(|(_, to, _)| *to == x)
.map(|(_, _, name)| name.clone())
}
fn right_edge(drawn: &DrawnTable, x: u16) -> Option<String> {
let (_, to, name) = drawn.columns.iter().max_by_key(|(_, to, _)| *to)?;
(*to >= drawn.area.right() && x + 1 == *to).then(|| name.clone())
}
pub fn drawn_header(&self) -> Option<(Rect, DrawnColumns)> {
let drawn = self.drawn.as_ref()?;
Some((
Rect {
height: drawn.header.min(drawn.area.height),
..drawn.area
},
drawn.columns.clone(),
))
}
pub fn point_at(&mut self, hit: &CellHit) -> bool {
let mut landed = true;
if let Some(row) = hit.row {
if let Some(drawn) = self.drawn.as_ref()
&& drawn.start_row == self.view.start_row
&& row < drawn.rows
{
self.table_state.select(Some(row));
} else {
landed = false;
}
}
if let Some(name) = &hit.column {
self.set_current_column(name);
landed &= self.current_column() == Some(name.as_str());
}
landed
}
}