diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/mod.rs | 2 | ||||
| -rw-r--r-- | src/eval/scope.rs | 1 | ||||
| -rw-r--r-- | src/eval/state.rs | 180 | ||||
| -rw-r--r-- | src/eval/value.rs | 6 |
4 files changed, 186 insertions, 3 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 65fc71c4..d21fbc7f 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -2,8 +2,10 @@ mod dict; mod scope; +mod state; mod value; pub use dict::*; pub use scope::*; +pub use state::*; pub use value::*; diff --git a/src/eval/scope.rs b/src/eval/scope.rs index 8e6576d1..d4b24880 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -6,6 +6,7 @@ use std::fmt::{self, Debug, Formatter}; use super::value::FuncValue; /// A map from identifiers to functions. +#[derive(Clone, PartialEq)] pub struct Scope { functions: HashMap<String, FuncValue>, } diff --git a/src/eval/state.rs b/src/eval/state.rs new file mode 100644 index 00000000..d6e0b195 --- /dev/null +++ b/src/eval/state.rs @@ -0,0 +1,180 @@ +//! State. + +use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight}; + +use super::Scope; +use crate::geom::{Insets, Linear, Sides, Size}; +use crate::layout::{Dir, GenAlign, LayoutAlign, LayoutSystem}; +use crate::length::Length; +use crate::paper::{Paper, PaperClass, PAPER_A4}; + +/// The active evaluation state. +#[derive(Debug, Clone, PartialEq)] +pub struct State { + /// The scope that contains function definitions. + pub scope: Scope, + /// The text state. + pub text: TextState, + /// The page state. + pub page: PageState, + /// The active layouting system. + pub sys: LayoutSystem, + /// The active alignments. + pub align: LayoutAlign, +} + +impl Default for State { + fn default() -> Self { + Self { + scope: crate::library::_std(), + text: TextState::default(), + page: PageState::default(), + sys: LayoutSystem::new(Dir::LTR, Dir::TTB), + align: LayoutAlign::new(GenAlign::Start, GenAlign::Start), + } + } +} + +/// Defines which fonts to use and how to space text. +#[derive(Debug, Clone, PartialEq)] +pub struct TextState { + /// A tree of font family names and generic class names. + pub fallback: FallbackTree, + /// The selected font variant. + pub variant: FontVariant, + /// Whether the strong toggle is active or inactive. This determines + /// whether the next `*` adds or removes font weight. + pub strong: bool, + /// Whether the emphasis toggle is active or inactive. This determines + /// whether the next `_` makes italic or non-italic. + pub emph: bool, + /// The font size. + pub font_size: FontSize, + /// The word spacing (relative to the the font size). + pub word_spacing: Linear, + /// The line spacing (relative to the the font size). + pub line_spacing: Linear, + /// The paragraphs spacing (relative to the the font size). + pub par_spacing: Linear, +} + +impl TextState { + /// The absolute font size. + pub fn font_size(&self) -> f64 { + self.font_size.eval() + } + + /// The absolute word spacing. + pub fn word_spacing(&self) -> f64 { + self.word_spacing.eval(self.font_size()) + } + + /// The absolute line spacing. + pub fn line_spacing(&self) -> f64 { + self.line_spacing.eval(self.font_size()) + } + + /// The absolute paragraph spacing. + pub fn paragraph_spacing(&self) -> f64 { + self.par_spacing.eval(self.font_size()) + } +} + +impl Default for TextState { + fn default() -> Self { + Self { + fallback: fallback! { + list: ["sans-serif"], + classes: { + "serif" => ["source serif pro", "noto serif"], + "sans-serif" => ["source sans pro", "noto sans"], + "monospace" => ["source code pro", "noto sans mono"], + "math" => ["latin modern math", "serif"], + }, + base: [ + "source sans pro", "noto sans", "segoe ui emoji", + "noto emoji", "latin modern math", + ], + }, + variant: FontVariant { + style: FontStyle::Normal, + weight: FontWeight::REGULAR, + stretch: FontStretch::Normal, + }, + strong: false, + emph: false, + font_size: FontSize::abs(Length::pt(11.0).as_raw()), + word_spacing: Linear::rel(0.25), + line_spacing: Linear::rel(0.2), + par_spacing: Linear::rel(0.5), + } + } +} + +/// The font size, defined by base and scale. +#[derive(Debug, Clone, PartialEq)] +pub struct FontSize { + /// The base font size, updated whenever the font size is set absolutely. + pub base: f64, + /// The scale to apply on the base font size, updated when the font size + /// is set relatively. + pub scale: Linear, +} + +impl FontSize { + /// Create a new font size. + pub fn new(base: f64, scale: Linear) -> Self { + Self { base, scale } + } + + /// Create a new font size with the given `base` and a scale of `1.0`. + pub fn abs(base: f64) -> Self { + Self::new(base, Linear::rel(1.0)) + } + + /// Compute the absolute font size. + pub fn eval(&self) -> f64 { + self.scale.eval(self.base) + } +} + +/// Defines the size and margins of a page. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct PageState { + /// The class of this page. + pub class: PaperClass, + /// The width and height of the page. + pub size: Size, + /// The amount of white space in the order [left, top, right, bottom]. If a + /// side is set to `None`, the default for the paper class is used. + pub margins: Sides<Option<Linear>>, +} + +impl PageState { + /// The default page style for the given paper. + pub fn new(paper: Paper) -> Self { + Self { + class: paper.class, + size: paper.size(), + margins: Sides::uniform(None), + } + } + + /// The absolute insets. + pub fn insets(&self) -> Insets { + let Size { width, height } = self.size; + let default = self.class.default_margins(); + Insets { + x0: -self.margins.left.unwrap_or(default.left).eval(width), + y0: -self.margins.top.unwrap_or(default.top).eval(height), + x1: -self.margins.right.unwrap_or(default.right).eval(width), + y1: -self.margins.bottom.unwrap_or(default.bottom).eval(height), + } + } +} + +impl Default for PageState { + fn default() -> Self { + Self::new(PAPER_A4) + } +} diff --git a/src/eval/value.rs b/src/eval/value.rs index f6c1fcd7..f88c0704 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -12,7 +12,7 @@ use crate::geom::Linear; use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign}; use crate::paper::Paper; use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree}; -use crate::{DynFuture, Feedback, Pass}; +use crate::{DynFuture, Feedback}; /// A computational value. #[derive(Clone, PartialEq)] @@ -149,13 +149,13 @@ impl Debug for Value { pub struct FuncValue(pub Rc<FuncType>); /// The signature of executable functions. -type FuncType = dyn Fn(Span, DictValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>; +type FuncType = dyn Fn(DictValue, &mut LayoutContext) -> DynFuture<Value>; impl FuncValue { /// Create a new function value from a rust function or closure. pub fn new<F: 'static>(f: F) -> Self where - F: Fn(Span, DictValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>, + F: Fn(DictValue, &mut LayoutContext) -> DynFuture<Value>, { Self(Rc::new(f)) } |
