diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-10-17 17:35:15 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-10-23 20:24:35 +0200 |
| commit | b42ecbd6a67d6af42f06c52c290d88e176cee0ea (patch) | |
| tree | 578e983db4ebfc259fdd109f79c92a7f22b7dd8b /src/layout/deco.rs | |
| parent | 5becb32ba463d6b0ace914ab06bb237483a94fbc (diff) | |
Simplify decorations
Diffstat (limited to 'src/layout/deco.rs')
| -rw-r--r-- | src/layout/deco.rs | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/layout/deco.rs b/src/layout/deco.rs new file mode 100644 index 00000000..669bf404 --- /dev/null +++ b/src/layout/deco.rs @@ -0,0 +1,92 @@ +use super::*; +use crate::util::EcoString; + +/// A decoration for a frame. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum Decoration { + /// A link to an external resource. + Link(EcoString), + /// An underline/strikethrough/overline decoration. + Line(LineDecoration), +} + +impl Decoration { + /// Apply a decoration to a child's frame. + pub fn apply(&self, ctx: &LayoutContext, frame: &mut Frame) { + match self { + Decoration::Link(href) => { + let link = Element::Link(href.to_string(), frame.size); + frame.push(Point::zero(), link); + } + Decoration::Line(line) => { + line.apply(ctx, frame); + } + } + } +} + +/// Defines a line that is positioned over, under or on top of text. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct LineDecoration { + /// The kind of line. + pub kind: LineKind, + /// Stroke color of the line, defaults to the text color if `None`. + pub stroke: Option<Paint>, + /// Thickness of the line's strokes (dependent on scaled font size), read + /// from the font tables if `None`. + pub thickness: Option<Linear>, + /// Position of the line relative to the baseline (dependent on scaled font + /// size), read from the font tables if `None`. + pub offset: Option<Linear>, + /// Amount that the line will be longer or shorter than its associated text + /// (dependent on scaled font size). + pub extent: Linear, +} + +/// The kind of line decoration. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum LineKind { + /// A line under text. + Underline, + /// A line through text. + Strikethrough, + /// A line over text. + Overline, +} + +impl LineDecoration { + /// Apply a line decoration to a all text elements in a frame. + pub fn apply(&self, ctx: &LayoutContext, frame: &mut Frame) { + for i in 0 .. frame.children.len() { + let (pos, child) = &frame.children[i]; + if let FrameChild::Element(Element::Text(text)) = child { + let face = ctx.fonts.get(text.face_id); + let metrics = match self.kind { + LineKind::Underline => face.underline, + LineKind::Strikethrough => face.strikethrough, + LineKind::Overline => face.overline, + }; + + let stroke = self.stroke.unwrap_or(text.fill); + + let thickness = self + .thickness + .map(|s| s.resolve(text.size)) + .unwrap_or(metrics.strength.to_length(text.size)); + + let offset = self + .offset + .map(|s| s.resolve(text.size)) + .unwrap_or(-metrics.position.to_length(text.size)); + + let extent = self.extent.resolve(text.size); + + let subpos = Point::new(pos.x - extent, pos.y + offset); + let vector = Point::new(text.width + 2.0 * extent, Length::zero()); + let line = Geometry::Line(vector, thickness); + + frame.push(subpos, Element::Geometry(line, stroke)); + } + } + } +} |
