use super::*;
#[derive(Clone, Copy, Default)]
struct LineCell {
up: bool,
down: bool,
left: bool,
right: bool,
}
fn line_cell_symbol(l: LineCell, thick: bool) -> &'static str {
if thick {
match (l.up, l.down, l.left, l.right) {
(true, true, true, true) => "╋",
(true, true, true, false) => "┫",
(true, true, false, true) => "┣",
(true, false, true, true) => "┻",
(false, true, true, true) => "┳",
(true, true, false, false)
| (true, false, false, false)
| (false, true, false, false) => "┃",
(false, false, true, true)
| (false, false, true, false)
| (false, false, false, true) => "━",
(false, true, false, true) => "┏",
(false, true, true, false) => "┓",
(true, false, false, true) => "┗",
(true, false, true, false) => "┛",
_ => "",
}
} else {
match (l.up, l.down, l.left, l.right) {
(true, true, true, true) => "┼",
(true, true, true, false) => "┤",
(true, true, false, true) => "├",
(true, false, true, true) => "┴",
(false, true, true, true) => "┬",
(true, true, false, false)
| (true, false, false, false)
| (false, true, false, false) => "│",
(false, false, true, true)
| (false, false, true, false)
| (false, false, false, true) => "─",
(false, true, false, true) => "┌",
(false, true, true, false) => "┐",
(true, false, false, true) => "└",
(true, false, true, false) => "┘",
_ => "",
}
}
}
fn add_box(cells: &mut std::collections::HashMap<(u16, u16), LineCell>, rect: Rect) {
if rect.width < 2 || rect.height < 2 {
return;
}
let right = rect.x + rect.width - 1;
let bottom = rect.y + rect.height - 1;
for x in rect.x..=right {
let top = cells.entry((x, rect.y)).or_default();
top.left |= x > rect.x;
top.right |= x < right;
let bot = cells.entry((x, bottom)).or_default();
bot.left |= x > rect.x;
bot.right |= x < right;
}
for y in rect.y..=bottom {
let lft = cells.entry((rect.x, y)).or_default();
lft.up |= y > rect.y;
lft.down |= y < bottom;
let rgt = cells.entry((right, y)).or_default();
rgt.up |= y > rect.y;
rgt.down |= y < bottom;
}
}
fn on_perimeter(x: u16, y: u16, r: Rect) -> bool {
if r.width < 2 || r.height < 2 {
return false;
}
let right = r.x + r.width - 1;
let bottom = r.y + r.height - 1;
let in_x = x >= r.x && x <= right;
let in_y = y >= r.y && y <= bottom;
(in_y && (x == r.x || x == right)) || (in_x && (y == r.y || y == bottom))
}
pub(super) fn render_pane_borders(
f: &mut RenderTarget,
rects: &[(PaneId, Rect)],
focus: PaneId,
t: &Theme,
) {
if rects.len() < 2 {
return;
}
let mut cells = std::collections::HashMap::new();
let mut focus_rect = None;
for (id, rect) in rects {
add_box(&mut cells, *rect);
if *id == focus {
focus_rect = Some(*rect);
}
}
let area = f.area();
let buf = f.buffer_mut();
for ((x, y), line) in cells {
if x >= area.right() || y >= area.bottom() {
continue;
}
let focused = focus_rect.is_some_and(|r| on_perimeter(x, y, r));
let sym = line_cell_symbol(line, focused);
if sym.is_empty() {
continue;
}
let color = if focused { t.border_focus } else { t.border };
let cell = &mut buf[(x, y)];
cell.set_symbol(sym);
cell.set_style(Style::new().fg(color));
}
}