use crate::core::color::Color;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Modifier(pub u16);
impl Modifier {
pub const NONE: Self = Self(0);
pub const BOLD: Self = Self(1 << 0);
pub const DIM: Self = Self(1 << 1);
pub const ITALIC: Self = Self(1 << 2);
pub const UNDERLINED: Self = Self(1 << 3);
pub const REVERSED: Self = Self(1 << 4);
pub const CROSSED_OUT: Self = Self(1 << 5);
pub const fn empty() -> Self {
Self::NONE
}
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub const fn remove(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
}
impl std::ops::BitOr for Modifier {
type Output = Modifier;
fn bitor(self, rhs: Self) -> Self::Output {
self.union(rhs)
}
}
impl std::ops::BitOrAssign for Modifier {
fn bitor_assign(&mut self, rhs: Self) {
*self = self.union(rhs);
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Style {
pub fg: Option<Color>,
pub bg: Option<Color>,
pub bold: bool,
pub italic: bool,
pub underlined: bool,
pub dim: bool,
pub add_modifier: Modifier,
pub sub_modifier: Modifier,
}
impl Style {
pub const fn new() -> Self {
Self {
fg: None,
bg: None,
bold: false,
italic: false,
underlined: false,
dim: false,
add_modifier: Modifier::NONE,
sub_modifier: Modifier::NONE,
}
}
pub const fn fg(mut self, fg: Color) -> Self {
self.fg = Some(fg);
self
}
pub const fn bg(mut self, bg: Color) -> Self {
self.bg = Some(bg);
self
}
pub const fn bold(mut self) -> Self {
self.bold = true;
self.add_modifier = self.add_modifier.union(Modifier::BOLD);
self
}
pub const fn italic(mut self) -> Self {
self.italic = true;
self.add_modifier = self.add_modifier.union(Modifier::ITALIC);
self
}
pub const fn underlined(mut self) -> Self {
self.underlined = true;
self.add_modifier = self.add_modifier.union(Modifier::UNDERLINED);
self
}
pub const fn dim(mut self) -> Self {
self.dim = true;
self.add_modifier = self.add_modifier.union(Modifier::DIM);
self
}
pub const fn reversed(mut self) -> Self {
self.add_modifier = self.add_modifier.union(Modifier::REVERSED);
self
}
pub const fn crossed_out(mut self) -> Self {
self.add_modifier = self.add_modifier.union(Modifier::CROSSED_OUT);
self
}
pub const fn add_modifier(mut self, modifier: Modifier) -> Self {
self.add_modifier = self.add_modifier.union(modifier);
self
}
pub const fn remove_modifier(mut self, modifier: Modifier) -> Self {
self.sub_modifier = self.sub_modifier.union(modifier);
self.add_modifier = self.add_modifier.remove(modifier);
self
}
pub fn merge(&self, other: &Style) -> Style {
Style {
fg: other.fg.or(self.fg),
bg: other.bg.or(self.bg),
bold: self.bold || other.bold,
italic: self.italic || other.italic,
underlined: self.underlined || other.underlined,
dim: self.dim || other.dim,
add_modifier: self
.add_modifier
.union(other.add_modifier)
.remove(other.sub_modifier),
sub_modifier: self.sub_modifier.union(other.sub_modifier),
}
}
pub fn fg_or_default(&self) -> Color {
self.fg.unwrap_or(Color::WHITE)
}
}
impl Default for Style {
fn default() -> Self {
Self::new()
}
}
impl From<Color> for Style {
fn from(c: Color) -> Self {
Style::new().fg(c)
}
}