use std::ops::{BitOr, BitOrAssign};
use crate::types::Color;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct TextDecorationLines {
pub underline: bool,
pub overline: bool,
pub line_through: bool,
}
impl TextDecorationLines {
pub const fn any(self) -> bool {
self.underline || self.overline || self.line_through
}
}
impl BitOr for TextDecorationLines {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self {
underline: self.underline || rhs.underline,
overline: self.overline || rhs.overline,
line_through: self.line_through || rhs.line_through,
}
}
}
impl BitOrAssign for TextDecorationLines {
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum TextDecorationStyle {
#[default]
Solid,
Wavy,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum TextDecorationSkipInk {
#[default]
Auto,
None,
All,
}
impl TextDecorationSkipInk {
pub(crate) fn parse(value: &str) -> Option<Self> {
match value.trim() {
"auto" => Some(Self::Auto),
"none" => Some(Self::None),
"all" => Some(Self::All),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct TextDecoration {
pub lines: TextDecorationLines,
pub style: TextDecorationStyle,
pub skip_ink: TextDecorationSkipInk,
pub thickness: Option<f32>,
pub underline_offset: Option<f32>,
pub color: Option<Color>,
}
impl TextDecoration {
pub const fn is_empty(self) -> bool {
!self.lines.any()
}
pub fn resolved_color(self, current_color: Color) -> Color {
self.color.unwrap_or(current_color)
}
pub fn with_resolved_color(mut self, current_color: Color) -> Self {
self.color = Some(self.resolved_color(current_color));
self
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct TextDecorations {
pub current: TextDecoration,
propagated: Vec<TextDecoration>,
}
impl TextDecorations {
pub fn for_descendant(
parent: &Self,
parent_color: Color,
include_propagated_origins: bool,
) -> Self {
let mut propagated = if include_propagated_origins {
parent.propagated.clone()
} else {
Vec::new()
};
if !parent.current.is_empty() {
propagated.push(parent.current.with_resolved_color(parent_color));
}
Self {
current: TextDecoration {
skip_ink: parent.current.skip_ink,
underline_offset: parent.current.underline_offset,
..Default::default()
},
propagated,
}
}
pub fn active(&self, current_color: Color) -> Vec<TextDecoration> {
let mut active = self.propagated.clone();
if !self.current.is_empty() {
active.push(self.current.with_resolved_color(current_color));
}
active
}
pub fn clear_propagated(&mut self) {
self.propagated.clear();
}
}