diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-07 17:07:44 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-07 17:07:44 +0200 |
| commit | 537545e7f8351d7677c396456e46568f5a5e2a7a (patch) | |
| tree | f4c7614293246db06c7fa7496458da01b15c3b84 /src/library | |
| parent | ca1256c924f3672feb76dbc2bc2e309eb4fc4cf5 (diff) | |
Evaluation and node-based layouting 🚀
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/align.rs | 28 | ||||
| -rw-r--r-- | src/library/boxed.rs | 52 | ||||
| -rw-r--r-- | src/library/color.rs | 2 | ||||
| -rw-r--r-- | src/library/font.rs | 41 | ||||
| -rw-r--r-- | src/library/mod.rs | 2 | ||||
| -rw-r--r-- | src/library/page.rs | 43 | ||||
| -rw-r--r-- | src/library/spacing.rs | 29 |
7 files changed, 111 insertions, 86 deletions
diff --git a/src/library/align.rs b/src/library/align.rs index f3280065..acd3a85c 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -14,7 +14,9 @@ use crate::prelude::*; /// - `vertical`: Any of `top`, `bottom` or `center`. /// /// There may not be two alignment specifications for the same axis. -pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value { +pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value { + let snapshot = ctx.state.clone(); + let body = args.find::<SynTree>(); let first = args.get::<_, Spanned<SpecAlign>>(ctx, 0); let second = args.get::<_, Spanned<SpecAlign>>(ctx, 1); @@ -29,21 +31,25 @@ pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value { .chain(hor.into_iter().map(|align| (Some(SpecAxis::Horizontal), align))) .chain(ver.into_iter().map(|align| (Some(SpecAxis::Vertical), align))); - let aligns = dedup_aligns(ctx, iter); + let prev_main = ctx.state.aligns.main; + ctx.state.aligns = dedup_aligns(ctx, iter); + + if prev_main != ctx.state.aligns.main { + ctx.end_par_group(); + ctx.start_par_group(); + } + + if let Some(body) = body { + body.eval(ctx); + ctx.state = snapshot; + } - Value::Commands(match body { - Some(tree) => vec![ - SetAlignment(aligns), - LayoutSyntaxTree(tree), - SetAlignment(ctx.state.aligns), - ], - None => vec![SetAlignment(aligns)], - }) + Value::None } /// Deduplicate alignments and deduce to which axes they apply. fn dedup_aligns( - ctx: &mut LayoutContext, + ctx: &mut EvalContext, iter: impl Iterator<Item = (Option<SpecAxis>, Spanned<SpecAlign>)>, ) -> Gen2<GenAlign> { let mut aligns = ctx.state.aligns; diff --git a/src/library/boxed.rs b/src/library/boxed.rs index b88f5b7c..6edb3b17 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -1,4 +1,5 @@ use crate::geom::Linear; +use crate::layout::nodes::{Fixed, Stack}; use crate::prelude::*; /// `box`: Layouts its contents into a box. @@ -6,34 +7,37 @@ use crate::prelude::*; /// # Keyword arguments /// - `width`: The width of the box (length or relative to parent's width). /// - `height`: The height of the box (length or relative to parent's height). -pub async fn boxed(mut args: Args, ctx: &mut LayoutContext) -> Value { +pub fn boxed(mut args: Args, ctx: &mut EvalContext) -> Value { let body = args.find::<SynTree>().unwrap_or_default(); let width = args.get::<_, Linear>(ctx, "width"); let height = args.get::<_, Linear>(ctx, "height"); args.done(ctx); + let dirs = ctx.state.dirs; let aligns = ctx.state.aligns; - let constraints = &mut ctx.constraints; - constraints.base = constraints.spaces[0].size; - constraints.spaces.truncate(1); - constraints.repeat = false; - - if let Some(width) = width { - let abs = width.eval(constraints.base.width); - constraints.base.width = abs; - constraints.spaces[0].size.width = abs; - constraints.spaces[0].expansion.horizontal = true; - } - - if let Some(height) = height { - let abs = height.eval(constraints.base.height); - constraints.base.height = abs; - constraints.spaces[0].size.height = abs; - constraints.spaces[0].expansion.vertical = true; - } - - let layouted = layout_tree(&body, ctx).await; - let layout = layouted.into_iter().next().unwrap(); - - Value::Commands(vec![Add(layout, aligns)]) + + let snapshot = ctx.state.clone(); + + ctx.start_group(()); + ctx.start_par_group(); + + body.eval(ctx); + + ctx.end_par_group(); + let ((), children) = ctx.end_group(); + + ctx.push(Fixed { + width, + height, + child: LayoutNode::dynamic(Stack { + dirs, + children, + aligns, + expand: Spec2::new(width.is_some(), height.is_some()), + }), + }); + + ctx.state = snapshot; + + Value::None } diff --git a/src/library/color.rs b/src/library/color.rs index 261352ba..17c33806 100644 --- a/src/library/color.rs +++ b/src/library/color.rs @@ -2,7 +2,7 @@ use crate::color::RgbaColor; use crate::prelude::*; /// `rgb`: Create an RGB(A) color. -pub async fn rgb(mut args: Args, ctx: &mut LayoutContext) -> Value { +pub fn rgb(mut args: Args, ctx: &mut EvalContext) -> Value { let r = args.need::<_, Spanned<i64>>(ctx, 0, "red value"); let g = args.need::<_, Spanned<i64>>(ctx, 1, "green value"); let b = args.need::<_, Spanned<i64>>(ctx, 2, "blue value"); diff --git a/src/library/font.rs b/src/library/font.rs index 21fb2d13..be6823c3 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use fontdock::{FontStretch, FontStyle, FontWeight}; use crate::eval::StringLike; @@ -49,37 +51,38 @@ use crate::prelude::*; /// ```typst /// [font: "My Serif", serif] /// ``` -pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value { - let mut text = ctx.state.text.clone(); - let mut needs_flattening = false; +pub fn font(mut args: Args, ctx: &mut EvalContext) -> Value { + let snapshot = ctx.state.clone(); let body = args.find::<SynTree>(); if let Some(linear) = args.find::<Linear>() { if linear.rel == 0.0 { - text.font_size.base = linear.abs; - text.font_size.scale = Linear::rel(1.0); + ctx.state.text.font_size.base = linear.abs; + ctx.state.text.font_size.scale = Linear::rel(1.0); } else { - text.font_size.scale = linear; + ctx.state.text.font_size.scale = linear; } } + let mut needs_flattening = false; let list: Vec<_> = args.find_all::<StringLike>().map(|s| s.to_lowercase()).collect(); + if !list.is_empty() { - text.fallback.list = list; + Rc::make_mut(&mut ctx.state.text.fallback).list = list; needs_flattening = true; } if let Some(style) = args.get::<_, FontStyle>(ctx, "style") { - text.variant.style = style; + ctx.state.text.variant.style = style; } if let Some(weight) = args.get::<_, FontWeight>(ctx, "weight") { - text.variant.weight = weight; + ctx.state.text.variant.weight = weight; } if let Some(stretch) = args.get::<_, FontStretch>(ctx, "stretch") { - text.variant.stretch = stretch; + ctx.state.text.variant.stretch = stretch; } for (class, dict) in args.find_all_str::<Spanned<ValueDict>>() { @@ -88,22 +91,20 @@ pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value { .map(|s| s.to_lowercase()) .collect(); - text.fallback.update_class_list(class, fallback); + Rc::make_mut(&mut ctx.state.text.fallback).update_class_list(class, fallback); needs_flattening = true; } args.done(ctx); if needs_flattening { - text.fallback.flatten(); + Rc::make_mut(&mut ctx.state.text.fallback).flatten(); + } + + if let Some(body) = body { + body.eval(ctx); + ctx.state = snapshot; } - Value::Commands(match body { - Some(tree) => vec![ - SetTextState(text), - LayoutSyntaxTree(tree), - SetTextState(ctx.state.text.clone()), - ], - None => vec![SetTextState(text)], - }) + Value::None } diff --git a/src/library/mod.rs b/src/library/mod.rs index 191a3920..af23d050 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -21,7 +21,7 @@ macro_rules! std { /// Create a scope with all standard library functions. pub fn _std() -> Scope { let mut std = Scope::new(); - $(std.set($name, ValueFunc::new(|args, ctx| Box::pin($func(args, ctx))));)* + $(std.set($name, ValueFunc::new($func));)* std } }; diff --git a/src/library/page.rs b/src/library/page.rs index fd33039c..448932a5 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -19,54 +19,61 @@ use crate::prelude::*; /// - `top`: The top margin (length or relative to height). /// - `bottom`: The bottom margin (length or relative to height). /// - `flip`: Flips custom or paper-defined width and height (boolean). -pub async fn page(mut args: Args, ctx: &mut LayoutContext) -> Value { - let mut page = ctx.state.page.clone(); +pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value { + let snapshot = ctx.state.clone(); if let Some(paper) = args.find::<Paper>() { - page.class = paper.class; - page.size = paper.size(); + ctx.state.page.class = paper.class; + ctx.state.page.size = paper.size(); } if let Some(Absolute(width)) = args.get::<_, Absolute>(ctx, "width") { - page.class = PaperClass::Custom; - page.size.width = width; + ctx.state.page.class = PaperClass::Custom; + ctx.state.page.size.width = width; } if let Some(Absolute(height)) = args.get::<_, Absolute>(ctx, "height") { - page.class = PaperClass::Custom; - page.size.height = height; + ctx.state.page.class = PaperClass::Custom; + ctx.state.page.size.height = height; } if let Some(margins) = args.get::<_, Linear>(ctx, "margins") { - page.margins = Sides::uniform(Some(margins)); + ctx.state.page.margins = Sides::uniform(Some(margins)); } if let Some(left) = args.get::<_, Linear>(ctx, "left") { - page.margins.left = Some(left); + ctx.state.page.margins.left = Some(left); } if let Some(top) = args.get::<_, Linear>(ctx, "top") { - page.margins.top = Some(top); + ctx.state.page.margins.top = Some(top); } if let Some(right) = args.get::<_, Linear>(ctx, "right") { - page.margins.right = Some(right); + ctx.state.page.margins.right = Some(right); } if let Some(bottom) = args.get::<_, Linear>(ctx, "bottom") { - page.margins.bottom = Some(bottom); + ctx.state.page.margins.bottom = Some(bottom); } if args.get::<_, bool>(ctx, "flip").unwrap_or(false) { - mem::swap(&mut page.size.width, &mut page.size.height); + let size = &mut ctx.state.page.size; + mem::swap(&mut size.width, &mut size.height); } args.done(ctx); - Value::Commands(vec![SetPageState(page)]) + + ctx.end_page_group(); + ctx.start_page_group(false); + + Value::None } -/// `pagebreak`: Ends the current page. -pub async fn pagebreak(args: Args, ctx: &mut LayoutContext) -> Value { +/// `pagebreak`: Starts a new page. +pub fn pagebreak(mut args: Args, ctx: &mut EvalContext) -> Value { args.done(ctx); - Value::Commands(vec![BreakPage]) + ctx.end_page_group(); + ctx.start_page_group(true); + Value::None } diff --git a/src/library/spacing.rs b/src/library/spacing.rs index e254d5e4..6d00bd1c 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -1,12 +1,12 @@ use crate::geom::Linear; -use crate::layout::SpacingKind; +use crate::layout::nodes::{Softness, Spacing}; use crate::prelude::*; /// `h`: Add horizontal spacing. /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn h(args: Args, ctx: &mut LayoutContext) -> Value { +pub fn h(args: Args, ctx: &mut EvalContext) -> Value { spacing(args, ctx, SpecAxis::Horizontal) } @@ -14,19 +14,26 @@ pub async fn h(args: Args, ctx: &mut LayoutContext) -> Value { /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn v(args: Args, ctx: &mut LayoutContext) -> Value { +pub fn v(args: Args, ctx: &mut EvalContext) -> Value { spacing(args, ctx, SpecAxis::Vertical) } -fn spacing(mut args: Args, ctx: &mut LayoutContext, axis: SpecAxis) -> Value { +/// Apply spacing along a specific axis. +fn spacing(mut args: Args, ctx: &mut EvalContext, axis: SpecAxis) -> Value { let spacing = args.need::<_, Linear>(ctx, 0, "spacing"); args.done(ctx); - Value::Commands(if let Some(spacing) = spacing { - let spacing = spacing.eval(ctx.state.text.font_size()); - let axis = axis.switch(ctx.state.dirs); - vec![AddSpacing(spacing, SpacingKind::Hard, axis)] - } else { - vec![] - }) + if let Some(linear) = spacing { + let amount = linear.eval(ctx.state.text.font_size()); + let spacing = Spacing { amount, softness: Softness::Hard }; + if ctx.state.dirs.main.axis() == axis { + ctx.end_par_group(); + ctx.push(spacing); + ctx.start_par_group(); + } else { + ctx.push(spacing); + } + } + + Value::None } |
