use smallvec::smallvec;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{elem, Content, Packed, Show, Smart, StyleChain};
use crate::layout::{Abs, Corners, Length, Rel, Sides};
use crate::text::{BottomEdge, BottomEdgeMetric, TextElem, TopEdge, TopEdgeMetric};
use crate::visualize::{Color, FixedStroke, Paint, Stroke};
#[elem(Show)]
pub struct UnderlineElem {
#[resolve]
#[fold]
pub stroke: Smart<Stroke>,
#[resolve]
pub offset: Smart<Length>,
#[resolve]
pub extent: Length,
#[default(true)]
pub evade: bool,
#[default(false)]
pub background: bool,
#[required]
pub body: Content,
}
impl Show for Packed<UnderlineElem> {
#[typst_macros::time(name = "underline", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body.clone().styled(TextElem::set_deco(smallvec![Decoration {
line: DecoLine::Underline {
stroke: self.stroke(styles).unwrap_or_default(),
offset: self.offset(styles),
evade: self.evade(styles),
background: self.background(styles),
},
extent: self.extent(styles),
}])))
}
}
#[elem(Show)]
pub struct OverlineElem {
#[resolve]
#[fold]
pub stroke: Smart<Stroke>,
#[resolve]
pub offset: Smart<Length>,
#[resolve]
pub extent: Length,
#[default(true)]
pub evade: bool,
#[default(false)]
pub background: bool,
#[required]
pub body: Content,
}
impl Show for Packed<OverlineElem> {
#[typst_macros::time(name = "overline", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body.clone().styled(TextElem::set_deco(smallvec![Decoration {
line: DecoLine::Overline {
stroke: self.stroke(styles).unwrap_or_default(),
offset: self.offset(styles),
evade: self.evade(styles),
background: self.background(styles),
},
extent: self.extent(styles),
}])))
}
}
#[elem(title = "Strikethrough", Show)]
pub struct StrikeElem {
#[resolve]
#[fold]
pub stroke: Smart<Stroke>,
#[resolve]
pub offset: Smart<Length>,
#[resolve]
pub extent: Length,
#[default(false)]
pub background: bool,
#[required]
pub body: Content,
}
impl Show for Packed<StrikeElem> {
#[typst_macros::time(name = "strike", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body.clone().styled(TextElem::set_deco(smallvec![Decoration {
line: DecoLine::Strikethrough {
stroke: self.stroke(styles).unwrap_or_default(),
offset: self.offset(styles),
background: self.background(styles),
},
extent: self.extent(styles),
}])))
}
}
#[elem(Show)]
pub struct HighlightElem {
#[default(Some(Color::from_u8(0xFF, 0xFD, 0x11, 0xA1).into()))]
pub fill: Option<Paint>,
#[resolve]
#[fold]
pub stroke: Sides<Option<Option<Stroke>>>,
#[default(TopEdge::Metric(TopEdgeMetric::Ascender))]
pub top_edge: TopEdge,
#[default(BottomEdge::Metric(BottomEdgeMetric::Descender))]
pub bottom_edge: BottomEdge,
#[resolve]
pub extent: Length,
#[resolve]
#[fold]
pub radius: Corners<Option<Rel<Length>>>,
#[required]
pub body: Content,
}
impl Show for Packed<HighlightElem> {
#[typst_macros::time(name = "highlight", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body.clone().styled(TextElem::set_deco(smallvec![Decoration {
line: DecoLine::Highlight {
fill: self.fill(styles),
stroke: self
.stroke(styles)
.unwrap_or_default()
.map(|stroke| stroke.map(Stroke::unwrap_or_default)),
top_edge: self.top_edge(styles),
bottom_edge: self.bottom_edge(styles),
radius: self.radius(styles).unwrap_or_default(),
},
extent: self.extent(styles),
}])))
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Decoration {
pub line: DecoLine,
pub extent: Abs,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum DecoLine {
Underline {
stroke: Stroke<Abs>,
offset: Smart<Abs>,
evade: bool,
background: bool,
},
Strikethrough {
stroke: Stroke<Abs>,
offset: Smart<Abs>,
background: bool,
},
Overline {
stroke: Stroke<Abs>,
offset: Smart<Abs>,
evade: bool,
background: bool,
},
Highlight {
fill: Option<Paint>,
stroke: Sides<Option<FixedStroke>>,
top_edge: TopEdge,
bottom_edge: BottomEdge,
radius: Corners<Rel<Abs>>,
},
}