use crossterm::style::Color;
use crate::{
graphics::FontStyle,
layout::{BorderStyle, LayoutBox, Rect},
};
use super::{BackgroundFill, PaintCanvas, background_at};
pub(crate) fn paint_borders(
lb: &LayoutBox,
r: Rect,
canvas: &mut PaintCanvas<'_>,
fg: Option<Color>,
bg: Option<BackgroundFill<'_>>,
clip: Rect,
) {
let sides = &lb.paint_style.box_edges.border;
if !sides.any_visible() {
return;
}
if r.width == 0 || r.height == 0 {
return;
}
let cols = canvas.columns as usize;
let cell_start = canvas.cell_index(r.x, r.y);
let max_cells = canvas.layout.len();
let in_clip = |x: usize, y: usize| -> bool {
x >= clip.x
&& y >= clip.y
&& x < clip.x.saturating_add(clip.width)
&& y < clip.y.saturating_add(clip.height)
};
let top_t = sides.top.thickness().clamp(0, r.height).min(1);
let bottom_t = sides.bottom.thickness().clamp(0, r.height).min(1);
let left_t = sides.left.thickness().clamp(0, r.width).min(1);
let right_t = sides.right.thickness().clamp(0, r.width).min(1);
let top_color = sides.top.color.or(fg);
let bottom_color = sides.bottom.color.or(fg);
let left_color = sides.left.color.or(fg);
let right_color = sides.right.color.or(fg);
let style = FontStyle::empty();
let right_col_start = r.width.saturating_sub(right_t);
if sides.top.style == BorderStyle::Solid && top_t > 0 {
for row_offset in 0..top_t {
let row_start = cell_start + row_offset * cols;
for col in left_t..right_col_start {
let idx = row_start + col;
if idx < max_cells && canvas.in_region(idx) && in_clip(r.x + col, r.y + row_offset)
{
let cell = &mut canvas.layout[idx];
cell.word.clear();
cell.word.push('─');
cell.fcolor = top_color;
cell.bcolor = background_at(bg, idx % cols, idx / cols);
cell.style = style;
}
}
}
}
if sides.bottom.style == BorderStyle::Solid && bottom_t > 0 {
let bottom_row = cell_start + (r.height - bottom_t) * cols;
let bottom_y = r.y + r.height - bottom_t;
for row_offset in 0..bottom_t {
let row_start = bottom_row + row_offset * cols;
for col in left_t..right_col_start {
let idx = row_start + col;
if idx < max_cells
&& canvas.in_region(idx)
&& in_clip(r.x + col, bottom_y + row_offset)
{
let cell = &mut canvas.layout[idx];
cell.word.clear();
cell.word.push('─');
cell.fcolor = bottom_color;
cell.bcolor = background_at(bg, idx % cols, idx / cols);
cell.style = style;
}
}
}
}
if sides.left.style == BorderStyle::Solid && left_t > 0 {
for row_offset in top_t..r.height.saturating_sub(bottom_t) {
let row_start = cell_start + row_offset * cols;
for col_offset in 0..left_t {
let idx = row_start + col_offset;
if idx < max_cells
&& canvas.in_region(idx)
&& in_clip(r.x + col_offset, r.y + row_offset)
{
let cell = &mut canvas.layout[idx];
cell.word.clear();
cell.word.push('│');
cell.fcolor = left_color;
cell.bcolor = background_at(bg, idx % cols, idx / cols);
cell.style = style;
}
}
}
}
if sides.right.style == BorderStyle::Solid && right_t > 0 {
for row_offset in top_t..r.height.saturating_sub(bottom_t) {
let row_start = cell_start + row_offset * cols;
for col_offset in 0..right_t {
let idx = row_start + right_col_start + col_offset;
if idx < max_cells
&& canvas.in_region(idx)
&& in_clip(r.x + right_col_start + col_offset, r.y + row_offset)
{
let cell = &mut canvas.layout[idx];
cell.word.clear();
cell.word.push('│');
cell.fcolor = right_color;
cell.bcolor = background_at(bg, idx % cols, idx / cols);
cell.style = style;
}
}
}
}
let corner_chars = if lb.paint_style.border_radius.is_rounded() {
['╭', '╮', '╰', '╯']
} else {
['┌', '┐', '└', '┘']
};
let corner_positions: [(usize, usize); 4] = [
(0, 0),
(right_col_start, 0),
(0, r.height - bottom_t),
(right_col_start, r.height - bottom_t),
];
let corner_colors = [
top_color.or(left_color),
top_color.or(right_color),
bottom_color.or(left_color),
bottom_color.or(right_color),
];
let top_visible = sides.top.style == BorderStyle::Solid && top_t > 0;
let bottom_visible = sides.bottom.style == BorderStyle::Solid && bottom_t > 0;
let left_visible = sides.left.style == BorderStyle::Solid && left_t > 0;
let right_visible = sides.right.style == BorderStyle::Solid && right_t > 0;
let corner_visible = [
top_visible && left_visible,
top_visible && right_visible,
bottom_visible && left_visible,
bottom_visible && right_visible,
];
for i in 0..4 {
if !corner_visible[i] {
continue;
}
let ch = corner_chars[i];
let (cx, cy) = corner_positions[i];
let color = corner_colors[i];
let idx = cell_start + cy * cols + cx;
if idx < max_cells && canvas.in_region(idx) && in_clip(r.x + cx, r.y + cy) {
let cell = &mut canvas.layout[idx];
cell.word.clear();
cell.word.push(ch);
cell.fcolor = color;
cell.bcolor = background_at(bg, idx % cols, idx / cols);
cell.style = style;
}
}
}