diff --git a/src/exec/state.rs b/src/exec/state.rs index 0145f60f7..51bbe395c 100644 --- a/src/exec/state.rs +++ b/src/exec/state.rs @@ -1,8 +1,9 @@ -use std::fmt::{self, Display, Formatter}; use std::rc::Rc; use crate::color::{Color, RgbaColor}; -use crate::font::{FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric}; +use crate::font::{ + FontFamily, FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric, +}; use crate::geom::*; use crate::layout::Paint; use crate::paper::{PaperClass, PAPER_A4}; @@ -236,26 +237,6 @@ impl Default for FamilyList { } } -/// A generic or named font family. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum FontFamily { - Serif, - SansSerif, - Monospace, - Named(String), -} - -impl Display for FontFamily { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::Serif => "serif", - Self::SansSerif => "sans-serif", - Self::Monospace => "monospace", - Self::Named(s) => s, - }) - } -} - /// Describes a line that is positioned over, under or on top of text. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct LineState { diff --git a/src/font.rs b/src/font.rs index 93c21441b..911bd2f1b 100644 --- a/src/font.rs +++ b/src/font.rs @@ -334,6 +334,26 @@ impl FaceId { } } +/// A generic or named font family. +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum FontFamily { + Serif, + SansSerif, + Monospace, + Named(String), +} + +impl Display for FontFamily { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.pad(match self { + Self::Serif => "serif", + Self::SansSerif => "sans-serif", + Self::Monospace => "monospace", + Self::Named(s) => s, + }) + } +} + /// Properties of a single font face. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct FaceInfo { diff --git a/src/geom/align.rs b/src/geom/align.rs index f6e5bb2af..d83c00b0e 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -1,6 +1,6 @@ use super::*; -/// Where to align something along a directed axis. +/// Where to align something along an axis. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Align { /// Align at the start of the axis. @@ -9,15 +9,27 @@ pub enum Align { Center, /// Align at the end of the axis. End, + /// Align at the left side of the axis. + Left, + /// Align at the right side of the axis. + Right, + /// Align at the top side of the axis. + Top, + /// Align at the bottom side of the axis. + Bottom, } impl Align { - /// Returns the position of this alignment in the given range. - pub fn resolve(self, dir: Dir, range: Range) -> Length { - match if dir.is_positive() { self } else { self.inv() } { - Self::Start => range.start, - Self::Center => (range.start + range.end) / 2.0, - Self::End => range.end, + /// The axis this alignment belongs to if it is specific. + pub fn axis(self) -> Option { + match self { + Self::Start => None, + Self::Center => None, + Self::End => None, + Self::Left => Some(SpecAxis::Horizontal), + Self::Right => Some(SpecAxis::Horizontal), + Self::Top => Some(SpecAxis::Vertical), + Self::Bottom => Some(SpecAxis::Vertical), } } @@ -27,6 +39,38 @@ impl Align { Self::Start => Self::End, Self::Center => Self::Center, Self::End => Self::Start, + Self::Left => Self::Right, + Self::Right => Self::Left, + Self::Top => Self::Bottom, + Self::Bottom => Self::Top, + } + } + + /// Returns the position of this alignment in the given range. + pub fn resolve(self, dir: Dir, range: Range) -> Length { + #[cfg(debug_assertions)] + if let Some(axis) = self.axis() { + debug_assert_eq!(axis, dir.axis()) + } + + match self { + Self::Start => { + if dir.is_positive() { + range.start + } else { + range.end + } + } + Self::Center => (range.start + range.end) / 2.0, + Self::End => { + if dir.is_positive() { + range.end + } else { + range.start + } + } + Self::Left | Self::Top => range.start, + Self::Right | Self::Bottom => range.end, } } } @@ -43,6 +87,10 @@ impl Display for Align { Self::Start => "start", Self::Center => "center", Self::End => "end", + Self::Left => "left", + Self::Right => "right", + Self::Top => "top", + Self::Bottom => "bottom", }) } } diff --git a/src/library/elements.rs b/src/library/elements.rs index 33e8069c7..afd7444e1 100644 --- a/src/library/elements.rs +++ b/src/library/elements.rs @@ -86,8 +86,8 @@ pub fn ellipse(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `circle`: A circle with optional content. pub fn circle(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let radius = args.named::(ctx, "radius").map(|r| 2.0 * Linear::from(r)); - let width = radius.or_else(|| args.named(ctx, "width")); + let diameter = args.named::(ctx, "radius").map(|r| 2.0 * Linear::from(r)); + let width = diameter.or_else(|| args.named(ctx, "width")); let height = width.is_none().then(|| args.named(ctx, "height")).flatten(); let fill = args.named(ctx, "fill"); let body = args.eat().unwrap_or_default(); diff --git a/src/library/layout.rs b/src/library/layout.rs index ef909bc33..eea4afb57 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -104,10 +104,10 @@ fn spacing_impl(ctx: &mut EvalContext, args: &mut FuncArgs, axis: GenAxis) -> Va /// `align`: Configure the alignment along the layouting axes. pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let first = args.eat::(); - let second = args.eat::(); - let mut horizontal = args.named::(ctx, "horizontal"); - let mut vertical = args.named::(ctx, "vertical"); + let first = args.eat::(); + let second = args.eat::(); + let mut horizontal = args.named(ctx, "horizontal"); + let mut vertical = args.named(ctx, "vertical"); let body = args.expect::