diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-07-29 12:21:55 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-07-29 12:28:54 +0200 |
| commit | 7d15dc634b3be1b6e284bb6b2450e3736d3e6e8d (patch) | |
| tree | f1dc308528515ccfc90e047fe3cb75bd171b3f8c | |
| parent | 853361338bd756c23992041511b1836a2cd0647f (diff) | |
Move font family and refactor alignment
| -rw-r--r-- | src/exec/state.rs | 25 | ||||
| -rw-r--r-- | src/font.rs | 20 | ||||
| -rw-r--r-- | src/geom/align.rs | 62 | ||||
| -rw-r--r-- | src/library/elements.rs | 4 | ||||
| -rw-r--r-- | src/library/layout.rs | 89 | ||||
| -rw-r--r-- | src/library/mod.rs | 49 | ||||
| -rw-r--r-- | src/library/text.rs | 32 | ||||
| -rw-r--r-- | src/library/utility.rs | 2 |
8 files changed, 133 insertions, 150 deletions
diff --git a/src/exec/state.rs b/src/exec/state.rs index 0145f60f..51bbe395 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 93c21441..911bd2f1 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 f6e5bb2a..d83c00b0 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>) -> 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<SpecAxis> { + 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>) -> 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 33e8069c..afd7444e 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::<Length>(ctx, "radius").map(|r| 2.0 * Linear::from(r)); - let width = radius.or_else(|| args.named(ctx, "width")); + let diameter = args.named::<Length>(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 ef909bc3..eea4afb5 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::<AlignValue>(); - let second = args.eat::<AlignValue>(); - let mut horizontal = args.named::<AlignValue>(ctx, "horizontal"); - let mut vertical = args.named::<AlignValue>(ctx, "vertical"); + let first = args.eat::<Align>(); + let second = args.eat::<Align>(); + let mut horizontal = args.named(ctx, "horizontal"); + let mut vertical = args.named(ctx, "vertical"); let body = args.expect::<Template>(ctx, "body").unwrap_or_default(); for value in first.into_iter().chain(second) { @@ -124,85 +124,18 @@ pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { Value::template(move |ctx| { if let Some(horizontal) = horizontal { - ctx.state.aligns.cross = horizontal.to_align(ctx.state.dir); + ctx.state.aligns.cross = horizontal; } if let Some(vertical) = vertical { - let new = vertical.to_align(Dir::TTB); - if ctx.state.aligns.main != new { - ctx.state.aligns.main = new; - ctx.parbreak(); - } + ctx.state.aligns.main = vertical; + ctx.parbreak(); } body.exec(ctx); }) } -/// An alignment specifier passed to `align`. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub(super) enum AlignValue { - Start, - Center, - End, - Left, - Right, - Top, - Bottom, -} - -impl AlignValue { - fn axis(self) -> Option<SpecAxis> { - 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), - } - } - - fn to_align(self, dir: Dir) -> Align { - let side = |is_at_positive_start| { - if dir.is_positive() == is_at_positive_start { - Align::Start - } else { - Align::End - } - }; - - match self { - Self::Start => Align::Start, - Self::Center => Align::Center, - Self::End => Align::End, - Self::Left => side(true), - Self::Right => side(false), - Self::Top => side(true), - Self::Bottom => side(false), - } - } -} - -impl Display for AlignValue { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::Start => "start", - Self::Center => "center", - Self::End => "end", - Self::Left => "left", - Self::Right => "right", - Self::Top => "top", - Self::Bottom => "bottom", - }) - } -} - -dynamic! { - AlignValue: "alignment", -} - /// `box`: Place content in a rectangular box. pub fn boxed(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let width = args.named(ctx, "width"); @@ -247,7 +180,7 @@ pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `stack`: Stack children along an axis. pub fn stack(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let dir = args.named::<Dir>(ctx, "dir").unwrap_or(Dir::TTB); + let dir = args.named(ctx, "dir").unwrap_or(Dir::TTB); let children: Vec<_> = args.all().collect(); Value::template(move |ctx| { @@ -272,10 +205,10 @@ pub fn grid(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let columns = args.named::<Tracks>(ctx, "columns").unwrap_or_default(); let rows = args.named::<Tracks>(ctx, "rows").unwrap_or_default(); - let gutter_columns = args.named::<Tracks>(ctx, "gutter-columns"); - let gutter_rows = args.named::<Tracks>(ctx, "gutter-rows"); + let gutter_columns = args.named(ctx, "gutter-columns"); + let gutter_rows = args.named(ctx, "gutter-rows"); let gutter = args - .named::<Linear>(ctx, "gutter") + .named(ctx, "gutter") .map(|v| vec![TrackSizing::Linear(v)]) .unwrap_or_default(); diff --git a/src/library/mod.rs b/src/library/mod.rs index 213106d6..ff2fb3e8 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -13,13 +13,13 @@ pub use layout::*; pub use text::*; pub use utility::*; -use std::fmt::{self, Display, Formatter}; +use std::convert::TryFrom; use std::rc::Rc; use crate::color::{Color, RgbaColor}; use crate::eval::{EvalContext, FuncArgs, Scope, Template, Type, Value}; -use crate::exec::{Exec, FontFamily}; -use crate::font::{FontStyle, FontWeight, VerticalFontMetric}; +use crate::exec::Exec; +use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; use crate::geom::*; use crate::syntax::Spanned; use crate::util::EcoString; @@ -71,17 +71,17 @@ pub fn new() -> Scope { std.def_const("forest", RgbaColor::new(0x43, 0xA1, 0x27, 0xFF)); // Arbitrary constants. - std.def_const("start", AlignValue::Start); - std.def_const("center", AlignValue::Center); - std.def_const("end", AlignValue::End); - std.def_const("left", AlignValue::Left); - std.def_const("right", AlignValue::Right); - std.def_const("top", AlignValue::Top); - std.def_const("bottom", AlignValue::Bottom); std.def_const("ltr", Dir::LTR); std.def_const("rtl", Dir::RTL); std.def_const("ttb", Dir::TTB); std.def_const("btt", Dir::BTT); + std.def_const("start", Align::Start); + std.def_const("center", Align::Center); + std.def_const("end", Align::End); + std.def_const("left", Align::Left); + std.def_const("right", Align::Right); + std.def_const("top", Align::Top); + std.def_const("bottom", Align::Bottom); std.def_const("serif", FontFamily::Serif); std.def_const("sans-serif", FontFamily::SansSerif); std.def_const("monospace", FontFamily::Monospace); @@ -102,3 +102,32 @@ pub fn new() -> Scope { dynamic! { Dir: "direction", } + +dynamic! { + Align: "alignment", +} + +dynamic! { + FontFamily: "font family", + Value::Str(string) => Self::Named(string.to_lowercase()), +} + +dynamic! { + FontStyle: "font style", +} + +dynamic! { + FontWeight: "font weight", + Value::Int(number) => { + u16::try_from(number).map_or(Self::BLACK, Self::from_number) + }, +} + +dynamic! { + FontStretch: "font stretch", + Value::Relative(relative) => Self::from_ratio(relative.get() as f32), +} + +dynamic! { + VerticalFontMetric: "vertical font metric", +} diff --git a/src/library/text.rs b/src/library/text.rs index 5e3ce204..b56cbcd3 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -1,7 +1,4 @@ -use std::convert::TryFrom; - use crate::exec::{LineState, TextState}; -use crate::font::{FontStretch, FontStyle, FontWeight}; use crate::layout::Paint; use super::*; @@ -15,7 +12,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { Some(FontDef(families)) }; - let size = args.eat().or_else(|| args.named::<Linear>(ctx, "size")); + let size = args.eat::<Linear>().or_else(|| args.named(ctx, "size")); let style = args.named(ctx, "style"); let weight = args.named(ctx, "weight"); let stretch = args.named(ctx, "stretch"); @@ -104,31 +101,6 @@ castable! { ), } -dynamic! { - FontFamily: "font family", - Value::Str(string) => Self::Named(string.to_lowercase()), -} - -dynamic! { - FontStyle: "font style", -} - -dynamic! { - FontWeight: "font weight", - Value::Int(number) => { - u16::try_from(number).map_or(Self::BLACK, Self::from_number) - }, -} - -dynamic! { - FontStretch: "font stretch", - Value::Relative(relative) => Self::from_ratio(relative.get() as f32), -} - -dynamic! { - VerticalFontMetric: "vertical font metric", -} - /// `par`: Configure paragraphs. pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let par_spacing = args.named(ctx, "spacing"); @@ -209,7 +181,7 @@ fn line_impl( substate: fn(&mut TextState) -> &mut Option<Rc<LineState>>, ) -> Value { let stroke = args.eat().or_else(|| args.named(ctx, "stroke")); - let thickness = args.eat().or_else(|| args.named::<Linear>(ctx, "thickness")); + let thickness = args.eat::<Linear>().or_else(|| args.named(ctx, "thickness")); let offset = args.named(ctx, "offset"); let extent = args.named(ctx, "extent").unwrap_or_default(); let body = args.expect::<Template>(ctx, "body").unwrap_or_default(); diff --git a/src/library/utility.rs b/src/library/utility.rs index ce45aae7..4001d14f 100644 --- a/src/library/utility.rs +++ b/src/library/utility.rs @@ -24,7 +24,7 @@ pub fn repr(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `len`: The length of a string, an array or a dictionary. pub fn len(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - match args.expect::<Spanned<Value>>(ctx, "collection") { + match args.expect(ctx, "collection") { Some(Spanned { v: Value::Str(v), .. }) => Value::Int(v.len() as i64), Some(Spanned { v: Value::Array(v), .. }) => Value::Int(v.len() as i64), Some(Spanned { v: Value::Dict(v), .. }) => Value::Int(v.len() as i64), |
