use crate::visual::Color;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontWeight {
Normal,
Bold,
}
impl FontWeight {
pub fn as_str(&self) -> &'static str {
match self {
FontWeight::Normal => "normal",
FontWeight::Bold => "bold",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontStyle {
Normal,
Italic,
}
impl FontStyle {
pub fn as_str(&self) -> &'static str {
match self {
FontStyle::Normal => "normal",
FontStyle::Italic => "italic",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TextAlign {
Left,
Center,
Right,
Justify,
}
impl TextAlign {
pub fn as_str(&self) -> &'static str {
match self {
TextAlign::Left => "left",
TextAlign::Center => "center",
TextAlign::Right => "right",
TextAlign::Justify => "justify",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum PageBreak {
#[default]
Auto,
Always,
Avoid,
Left,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Display {
Block,
Inline,
InlineBlock,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum WhiteSpace {
#[default]
Normal,
Pre,
NoWrap,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum ListStyleType {
#[default]
Disc,
Circle,
Square,
Decimal,
DecimalLeadingZero,
LowerRoman,
UpperRoman,
LowerAlpha,
UpperAlpha,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum BorderStyle {
#[default]
None,
Solid,
Dashed,
Dotted,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BoxSides {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}
impl BoxSides {
pub const ZERO: Self = Self {
top: 0.0,
right: 0.0,
bottom: 0.0,
left: 0.0,
};
pub fn all(v: f32) -> Self {
Self {
top: v,
right: v,
bottom: v,
left: v,
}
}
pub fn vertical(v: f32) -> Self {
Self {
top: v,
right: 0.0,
bottom: v,
left: 0.0,
}
}
pub fn horizontal(v: f32) -> Self {
Self {
top: 0.0,
right: v,
bottom: 0.0,
left: v,
}
}
pub fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
Self {
top,
right,
bottom,
left,
}
}
pub fn horizontal_sum(&self) -> f32 {
self.left + self.right
}
pub fn vertical_sum(&self) -> f32 {
self.top + self.bottom
}
}
impl Default for BoxSides {
fn default() -> Self {
Self::ZERO
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BorderSide {
pub width: f32,
pub style: BorderStyle,
pub color: Color,
}
impl BorderSide {
pub const NONE: Self = Self {
width: 0.0,
style: BorderStyle::None,
color: Color::new(0, 0, 0),
};
pub fn new(width: f32, style: BorderStyle, color: Color) -> Self {
Self {
width,
style,
color,
}
}
pub fn is_visible(&self) -> bool {
self.style != BorderStyle::None && self.width > 0.0
}
}
impl Default for BorderSide {
fn default() -> Self {
Self::NONE
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BoxBorders {
pub top: BorderSide,
pub right: BorderSide,
pub bottom: BorderSide,
pub left: BorderSide,
pub radius: f32, }
impl BoxBorders {
pub const NONE: Self = Self {
top: BorderSide::NONE,
right: BorderSide::NONE,
bottom: BorderSide::NONE,
left: BorderSide::NONE,
radius: 0.0,
};
pub fn uniform(width: f32, style: BorderStyle, color: Color) -> Self {
Self {
top: BorderSide::new(width, style, color),
right: BorderSide::new(width, style, color),
bottom: BorderSide::new(width, style, color),
left: BorderSide::new(width, style, color),
radius: 0.0,
}
}
pub fn is_any_visible(&self) -> bool {
self.top.is_visible()
|| self.right.is_visible()
|| self.bottom.is_visible()
|| self.left.is_visible()
}
pub fn max_width(&self) -> f32 {
self.top
.width
.max(self.right.width)
.max(self.bottom.width)
.max(self.left.width)
}
}
impl Default for BoxBorders {
fn default() -> Self {
Self::NONE
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ObjectFit {
Contain,
Cover,
Fill,
None,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TextDecoration {
None,
Underline,
LineThrough,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CssLength {
Pt(f32),
Px(f32),
Em(f32),
Rem(f32),
Percent(f32),
}
impl CssLength {
pub fn resolve(&self, font_size: f32, root_font_size: f32) -> f32 {
match self {
CssLength::Pt(v) => *v,
CssLength::Px(v) => v * 0.75,
CssLength::Em(v) => v * font_size,
CssLength::Rem(v) => v * root_font_size,
CssLength::Percent(v) => v / 100.0 * font_size,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineHeight {
Length(CssLength),
Number(f32),
}
impl LineHeight {
pub fn resolve(&self, font_size: f32, root_font_size: f32) -> f32 {
match self {
LineHeight::Length(l) => l.resolve(font_size, root_font_size),
LineHeight::Number(n) => n * font_size,
}
}
}
#[derive(Debug, Clone)]
pub struct Style {
pub font_family: Vec<String>,
pub font_size_pt: f32,
pub font_weight: FontWeight,
pub font_style: FontStyle,
pub color: Color,
pub line_height_pt: f32,
pub letter_spacing: f32,
pub text_indent_em: f32,
pub text_align: TextAlign,
pub display: Display,
pub white_space: WhiteSpace,
pub list_style_type: ListStyleType,
pub margin: BoxSides,
pub padding: BoxSides,
pub border: BoxBorders,
pub width: Option<f32>,
pub height: Option<f32>,
pub object_fit: ObjectFit,
pub background_color: Option<Color>,
pub page_break_before: PageBreak,
pub page_break_after: PageBreak,
pub table_border_color: Color,
pub table_border_width_pt: f32,
pub table_cell_padding_h_pt: f32,
pub table_cell_padding_v_pt: f32,
pub table_header_bg: Option<Color>,
pub table_alt_row_bg: Option<Color>,
pub link_url: Option<String>,
pub text_decoration: TextDecoration,
pub list_indent_pt: Option<f32>,
pub baseline_shift: f32,
}
impl Style {
pub fn inherit_from(parent: &Style) -> Self {
Self {
font_family: parent.font_family.clone(),
font_size_pt: parent.font_size_pt,
font_weight: parent.font_weight,
font_style: parent.font_style,
color: parent.color,
line_height_pt: parent.line_height_pt,
letter_spacing: parent.letter_spacing,
text_indent_em: parent.text_indent_em,
text_align: parent.text_align,
white_space: parent.white_space,
list_style_type: parent.list_style_type,
display: Display::Inline,
margin: BoxSides::ZERO,
padding: BoxSides::ZERO,
border: BoxBorders::NONE,
width: None,
height: None,
object_fit: ObjectFit::None,
background_color: None,
page_break_before: parent.page_break_before,
page_break_after: parent.page_break_after,
table_border_color: parent.table_border_color,
table_border_width_pt: parent.table_border_width_pt,
table_cell_padding_h_pt: parent.table_cell_padding_h_pt,
table_cell_padding_v_pt: parent.table_cell_padding_v_pt,
table_header_bg: parent.table_header_bg,
table_alt_row_bg: parent.table_alt_row_bg,
link_url: parent.link_url.clone(),
text_decoration: parent.text_decoration,
list_indent_pt: None,
baseline_shift: parent.baseline_shift,
}
}
}
impl Default for Style {
fn default() -> Self {
Self {
font_family: vec!["serif".to_string()],
font_size_pt: 10.5,
font_weight: FontWeight::Normal,
font_style: FontStyle::Normal,
color: Color::new(0, 0, 0),
line_height_pt: 15.75,
letter_spacing: 0.0,
text_indent_em: 0.0,
text_align: TextAlign::Left,
white_space: WhiteSpace::Normal,
list_style_type: ListStyleType::Disc, display: Display::Block,
margin: BoxSides::new(0.0, 0.0, 12.0, 0.0),
padding: BoxSides::ZERO,
border: BoxBorders::NONE,
width: None,
height: None,
object_fit: ObjectFit::Contain,
background_color: None,
page_break_before: PageBreak::Auto,
page_break_after: PageBreak::Auto,
table_border_color: Color::new(180, 180, 180),
table_border_width_pt: 0.5,
table_cell_padding_h_pt: 4.0,
table_cell_padding_v_pt: 2.0,
table_header_bg: None,
table_alt_row_bg: None,
link_url: None,
text_decoration: TextDecoration::None,
list_indent_pt: None,
baseline_shift: 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct PageConfig {
pub margin_top: Option<f32>,
pub margin_bottom: Option<f32>,
pub margin_left: Option<f32>,
pub margin_right: Option<f32>,
pub width: Option<f32>,
pub height: Option<f32>,
pub height_unlimited: Option<bool>,
pub header: Option<String>,
pub footer: Option<String>,
pub header_font_size: Option<f32>,
pub footer_font_size: Option<f32>,
}
impl Default for PageConfig {
fn default() -> Self {
Self {
margin_top: None,
margin_bottom: None,
margin_left: None,
margin_right: None,
width: None,
height: None,
height_unlimited: None,
header: None,
footer: Some("- {page} -".to_string()),
header_font_size: None,
footer_font_size: None,
}
}
}