use ratatui::buffer::Buffer;
use ratatui::layout::Rect as RRect;
use ratatui::style::Color as RatatuiColor;
use super::{ratatui_color, set_cell};
use crate::theme::Theme;
pub fn draw_focus_ring(buf: &mut Buffer, rect: RRect, theme: &Theme) {
let fg = ratatui_color(theme.accent_fg);
let (x, y, w, h) = (rect.x, rect.y, rect.width, rect.height);
if w == 0 || h == 0 {
return;
}
let bg_at = |buf: &Buffer, cx: u16, cy: u16| -> RatatuiColor {
let area = buf.area;
if cx >= area.x && cy >= area.y && cx < area.x + area.width && cy < area.y + area.height {
buf[(cx, cy)].bg
} else {
RatatuiColor::Reset
}
};
for col in 0..w {
let ch = if col == 0 {
'╭'
} else if col == w - 1 {
'╮'
} else {
'─'
};
set_cell(buf, x + col, y, ch, fg, bg_at(buf, x + col, y));
}
if h > 1 {
for col in 0..w {
let ch = if col == 0 {
'╰'
} else if col == w - 1 {
'╯'
} else {
'─'
};
set_cell(
buf,
x + col,
y + h - 1,
ch,
fg,
bg_at(buf, x + col, y + h - 1),
);
}
}
for row in (y + 1)..(y + h.saturating_sub(1)) {
set_cell(buf, x, row, '│', fg, bg_at(buf, x, row));
set_cell(buf, x + w - 1, row, '│', fg, bg_at(buf, x + w - 1, row));
}
}
#[cfg(test)]
mod tests {
use super::*;
use ratatui::buffer::Cell;
fn filled_buffer(w: u16, h: u16, bg: RatatuiColor) -> Buffer {
let mut buf = Buffer::empty(RRect::new(0, 0, w, h));
for y in 0..h {
for x in 0..w {
let mut cell = Cell::default();
cell.set_char('x').set_bg(bg);
buf[(x, y)] = cell;
}
}
buf
}
#[test]
fn draws_corners_and_edges() {
let theme = Theme::default();
let mut buf = filled_buffer(10, 5, RatatuiColor::Black);
draw_focus_ring(&mut buf, RRect::new(1, 1, 5, 3), &theme);
assert_eq!(buf[(1, 1)].symbol(), "╭");
assert_eq!(buf[(5, 1)].symbol(), "╮");
assert_eq!(buf[(1, 3)].symbol(), "╰");
assert_eq!(buf[(5, 3)].symbol(), "╯");
assert_eq!(buf[(2, 1)].symbol(), "─");
assert_eq!(buf[(1, 2)].symbol(), "│");
}
#[test]
fn preserves_existing_background() {
let theme = Theme::default();
let bg = RatatuiColor::Rgb(10, 20, 30);
let mut buf = filled_buffer(10, 5, bg);
draw_focus_ring(&mut buf, RRect::new(1, 1, 5, 3), &theme);
assert_eq!(buf[(1, 1)].bg, bg, "ring cells must keep the existing bg");
assert_eq!(buf[(3, 2)].symbol(), "x");
assert_eq!(buf[(3, 2)].bg, bg);
}
#[test]
fn zero_size_rect_is_a_noop() {
let theme = Theme::default();
let mut buf = filled_buffer(10, 5, RatatuiColor::Black);
draw_focus_ring(&mut buf, RRect::new(1, 1, 0, 3), &theme);
for y in 0..5u16 {
for x in 0..10u16 {
assert_eq!(buf[(x, y)].symbol(), "x");
}
}
}
}