use super::*;
impl<R> UiState<R> {
pub fn is_selected(&self, row: VisRowPos, col: VisColumnPos) -> bool {
if let CursorState::Select(selections) = &self.cc_cursor {
selections
.iter()
.any(|sel| self.vis_sel_contains(*sel, row, col))
} else {
false
}
}
pub fn is_selected_cci(&self, row: VisRowPos, col: VisColumnPos) -> bool {
self.cci_selection.is_some_and(|(pivot, current)| {
self.vis_sel_contains(
VisSelection::from_points(self.p.vis_cols.len(), pivot, current),
row,
col,
)
})
}
pub fn vis_sel_contains(&self, sel: VisSelection, row: VisRowPos, col: VisColumnPos) -> bool {
sel.contains(self.p.vis_cols.len(), row, col)
}
pub fn cci_sel_update(&mut self, current: VisLinearIdx) {
if let Some((_, pivot)) = &mut self.cci_selection {
*pivot = current;
} else {
self.cci_selection = Some((current, current));
}
}
pub fn cci_sel_update_row(&mut self, row: VisRowPos) {
for col in [0, self.p.vis_cols.len() - 1] {
self.cci_sel_update(row.linear_index(self.p.vis_cols.len(), VisColumnPos(col)));
}
}
pub fn has_cci_selection(&self) -> bool {
self.cci_selection.is_some()
}
pub fn cci_take_selection(&mut self, modifier: SelectionModifier) -> Option<Vec<VisSelection>> {
let ncol = self.p.vis_cols.len();
let cci_sel = self
.cci_selection
.take()
.map(|(_0, _1)| VisSelection::from_points(ncol, _0, _1))?;
if modifier == SelectionModifier::None {
return Some(vec![cci_sel]);
}
let mut sel = self.cursor_as_selection().unwrap_or_default().to_owned();
let idx_contains = sel.iter().position(|x| x.contains_rect(ncol, cci_sel));
if sel.is_empty() {
sel.push(cci_sel);
return Some(sel);
}
if modifier == SelectionModifier::Toggle {
if let Some(idx) = idx_contains {
sel.remove(idx);
} else {
sel.push(cci_sel);
}
}
if modifier == SelectionModifier::Extend {
let last = sel.last_mut().unwrap();
if cci_sel.is_point() && last.is_point() {
*last = last.union(ncol, cci_sel);
} else if idx_contains.is_none() {
sel.push(cci_sel);
};
}
Some(sel)
}
pub(super) fn collect_selection(&self) -> BTreeSet<(VisRowPos, VisColumnPos)> {
let mut set = BTreeSet::new();
if let CursorState::Select(selections) = &self.cc_cursor {
for sel in selections.iter() {
let (top, left) = sel.0.row_col(self.p.vis_cols.len());
let (bottom, right) = sel.1.row_col(self.p.vis_cols.len());
for r in top.0..=bottom.0 {
for c in left.0..=right.0 {
set.insert((VisRowPos(r), VisColumnPos(c)));
}
}
}
}
set
}
pub(super) fn collect_selected_rows(&self) -> BTreeSet<VisRowPos> {
let mut rows = BTreeSet::new();
if let CursorState::Select(selections) = &self.cc_cursor {
for sel in selections.iter() {
let (top, _) = sel.0.row_col(self.p.vis_cols.len());
let (bottom, _) = sel.1.row_col(self.p.vis_cols.len());
for r in top.0..=bottom.0 {
rows.insert(VisRowPos(r));
}
}
}
rows
}
pub(super) fn moved_position(&self, pos: VisLinearIdx, dir: MoveDirection) -> VisLinearIdx {
let (VisRowPos(r), VisColumnPos(c)) = pos.row_col(self.p.vis_cols.len());
let (rmax, cmax) = (
self.cc_rows.len().saturating_sub(1),
self.p.vis_cols.len().saturating_sub(1),
);
let (nr, nc) = match dir {
MoveDirection::Up => match (r, c) {
(0, c) => (0, c),
(r, c) => (r - 1, c),
},
MoveDirection::Down => match (r, c) {
(r, c) if r == rmax => (r, c),
(r, c) => (r + 1, c),
},
MoveDirection::Left => match (r, c) {
(0, 0) => (0, 0),
(r, 0) => (r - 1, cmax),
(r, c) => (r, c - 1),
},
MoveDirection::Right => match (r, c) {
(r, c) if r == rmax && c == cmax => (r, c),
(r, c) if c == cmax => (r + 1, 0),
(r, c) => (r, c + 1),
},
};
VisLinearIdx(nr * self.p.vis_cols.len() + nc)
}
pub(super) fn get_highlight_changes<'a>(
&'a self,
table: &'a DataTable<R>,
sel: &[VisSelection],
) -> (Vec<&'a R>, Vec<&'a R>) {
let mut ohs: BTreeSet<&VisSelection> = BTreeSet::default();
let nhs: BTreeSet<&VisSelection> = sel.iter().collect();
if let CursorState::Select(s) = &self.cc_cursor {
ohs = s.iter().collect();
}
fn flatten_ranges(ranges: &[(usize, usize)]) -> HashSet<usize> {
ranges
.iter()
.flat_map(|&(start, end)| start..=end)
.collect()
}
fn deselected_rows(old_rows: &HashSet<usize>, new_rows: &HashSet<usize>) -> Vec<usize> {
let missing: Vec<usize> = old_rows.difference(&new_rows).copied().collect();
missing
}
let nhs_range = self.make_row_range(&nhs);
let ohs_range = self.make_row_range(&ohs);
let nhs_rows = flatten_ranges(&nhs_range);
let ohs_rows = flatten_ranges(&ohs_range);
let deselected_rows = deselected_rows(&ohs_rows, &nhs_rows);
let highlighted: Vec<&R> = nhs_rows
.into_iter()
.sorted()
.map(|r| {
let row_id = self.cc_rows[r];
&table.rows[row_id.0]
})
.collect();
let unhighlighted: Vec<&R> = deselected_rows
.into_iter()
.sorted()
.map(|r| {
let row_id = self.cc_rows[r];
&table.rows[row_id.0]
})
.collect();
(highlighted, unhighlighted)
}
fn make_row_range<'a>(&'a self, nhs: &BTreeSet<&VisSelection>) -> Vec<(usize, usize)> {
nhs.iter()
.map(|sel| {
let (start_ic_r, _ic_c) = sel.0.row_col(self.p.vis_cols.len());
let (end_ic_r, _ic_c) = sel.1.row_col(self.p.vis_cols.len());
(start_ic_r.0, end_ic_r.0)
})
.collect::<Vec<(usize, usize)>>()
}
}