summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-07-29 12:21:55 +0200
committerLaurenz <laurmaedje@gmail.com>2021-07-29 12:28:54 +0200
commit7d15dc634b3be1b6e284bb6b2450e3736d3e6e8d (patch)
treef1dc308528515ccfc90e047fe3cb75bd171b3f8c /src
parent853361338bd756c23992041511b1836a2cd0647f (diff)
Move font family and refactor alignment
Diffstat (limited to 'src')
-rw-r--r--src/exec/state.rs25
-rw-r--r--src/font.rs20
-rw-r--r--src/geom/align.rs62
-rw-r--r--src/library/elements.rs4
-rw-r--r--src/library/layout.rs89
-rw-r--r--src/library/mod.rs49
-rw-r--r--src/library/text.rs32
-rw-r--r--src/library/utility.rs2
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),