use super::Buffer;
use crate::render::Color;
use rdom_style::layout::{BorderStyle, CornerStyle};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BorderSide {
Top,
Right,
Bottom,
Left,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BorderContribution {
pub style: BorderStyle,
pub fg: Color,
pub priority: u64,
pub corner_style: CornerStyle,
pub side: BorderSide,
}
impl BorderContribution {
pub fn pack_priority(depth: u16, dom_index: u32) -> u64 {
((depth as u64) << 32) | ((u32::MAX - dom_index) as u64)
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct BorderDirState {
pub winner: Option<BorderContribution>,
pub killed: bool,
}
impl BorderDirState {
pub fn merge(&mut self, new: BorderContribution) {
if new.style.is_none() {
return;
}
if new.style.is_hidden() {
self.killed = true;
return;
}
let new_key = (new.style.rank(), new.priority);
let win = match self.winner {
None => true,
Some(prev) => {
let prev_key = (prev.style.rank(), prev.priority);
new_key > prev_key
}
};
if win {
self.winner = Some(new);
}
}
pub fn is_visible(&self) -> bool {
!self.killed && self.winner.is_some()
}
}
pub type BorderCell = [BorderDirState; 4];
pub const DIR_N: usize = 0;
pub const DIR_E: usize = 1;
pub const DIR_S: usize = 2;
pub const DIR_W: usize = 3;
pub const QUAD_TL: u8 = 0b0001;
pub const QUAD_TR: u8 = 0b0010;
pub const QUAD_BL: u8 = 0b0100;
pub const QUAD_BR: u8 = 0b1000;
impl Buffer {
pub fn add_half_block_quads(&mut self, x: u16, y: u16, quads: u8) {
if let Some(i) = self.index_of(x, y) {
self.half_block_quads[i] |= quads;
}
}
pub fn half_block_quads_at(&self, x: u16, y: u16) -> u8 {
self.index_of(x, y)
.map(|i| self.half_block_quads[i])
.unwrap_or(0)
}
pub fn clear_half_block_quads(&mut self, x: u16, y: u16) {
if let Some(i) = self.index_of(x, y) {
self.half_block_quads[i] = 0;
}
}
pub fn clear_border_at(&mut self, x: u16, y: u16) {
if let Some(i) = self.index_of(x, y) {
self.border_dirs[i] = BorderCell::default();
self.half_block_quads[i] = 0;
}
}
pub fn add_border_dir(&mut self, x: u16, y: u16, dir: usize, contribution: BorderContribution) {
debug_assert!(dir < 4, "BorderCell index out of range");
if let Some(i) = self.index_of(x, y) {
self.border_dirs[i][dir].merge(contribution);
}
}
pub fn border_dir_at(&self, x: u16, y: u16, dir: usize) -> BorderDirState {
debug_assert!(dir < 4, "BorderCell index out of range");
self.index_of(x, y)
.map(|i| self.border_dirs[i][dir])
.unwrap_or_default()
}
pub fn set_border_dir(&mut self, x: u16, y: u16, dir: usize, state: BorderDirState) {
debug_assert!(dir < 4, "BorderCell index out of range");
if let Some(i) = self.index_of(x, y) {
self.border_dirs[i][dir] = state;
}
}
pub fn border_mask_at(&self, x: u16, y: u16) -> u8 {
let Some(i) = self.index_of(x, y) else {
return 0;
};
let cell = &self.border_dirs[i];
let mut mask = 0u8;
if cell[DIR_N].is_visible() {
mask |= 0b0001;
}
if cell[DIR_E].is_visible() {
mask |= 0b0010;
}
if cell[DIR_S].is_visible() {
mask |= 0b0100;
}
if cell[DIR_W].is_visible() {
mask |= 0b1000;
}
mask
}
}