use crate::layout::{LayoutBox, Rect};
use crate::tdom::node::NodeArena;
use crate::tui::graph_api::SelectionMode;
use super::state::TextSel;
pub(super) fn selection_lines(sel: &TextSel, cols: u32) -> Vec<(u32, u32, u32)> {
let (ax, ay) = sel.anchor;
let (ex, ey) = sel.end;
match sel.mode {
SelectionMode::Block => {
let x1 = ax.min(ex);
let x2 = ax.max(ex).saturating_add(1);
let y1 = ay.min(ey);
let y2 = ay.max(ey).saturating_add(1);
(y1..y2).map(|y| (y, x1, x2)).collect()
}
SelectionMode::Flow => {
if ay == ey {
vec![(ay, ax.min(ex), ax.max(ex).saturating_add(1))]
} else if ay < ey {
let mut lines = vec![(ay, ax, cols)];
for y in ay.saturating_add(1)..ey {
lines.push((y, 0, cols));
}
lines.push((ey, 0, ex.saturating_add(1)));
lines
} else {
let mut lines = vec![(ey, ex, cols)];
for y in ey.saturating_add(1)..ay {
lines.push((y, 0, cols));
}
lines.push((ay, 0, ax.saturating_add(1)));
lines
}
}
}
}
pub(super) fn lines_bounds(lines: &[(u32, u32, u32)]) -> Option<Rect> {
let mut min_x = u32::MAX;
let mut min_y = u32::MAX;
let mut max_x = 0u32;
let mut max_y = 0u32;
for &(y, xs, xe) in lines {
min_y = min_y.min(y);
min_x = min_x.min(xs);
max_y = max_y.max(y);
max_x = max_x.max(xe);
}
if max_y < min_y {
return None;
}
Some(Rect::new(
min_x as usize,
min_y as usize,
(max_x - min_x) as usize,
(max_y - min_y + 1) as usize,
))
}
pub(super) fn highlight_lines(
arena: &NodeArena,
boxes: &[LayoutBox],
sel: &TextSel,
cols: u32,
) -> Vec<(u32, u32, u32)> {
let raw = selection_lines(sel, cols);
match sel.mode {
SelectionMode::Flow => {
let raw = crate::layout::clip_flow_lines_scoped(boxes, sel.anchor, sel.end, &raw);
crate::layout::selection_text_lines(arena, boxes, &raw)
}
SelectionMode::Block => raw,
}
}