diff --git a/src/eval/template.rs b/src/eval/template.rs index 2df347aad..6c1223cb1 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -10,7 +10,7 @@ use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size}; use crate::layout::{Layout, PackedNode}; use crate::library::{ Decoration, DocumentNode, FlowChild, FlowNode, PadNode, PageNode, ParChild, ParNode, - Spacing, + PlacedNode, Spacing, }; use crate::style::Style; use crate::util::EcoString; @@ -331,15 +331,21 @@ impl Builder { } /// Push an inline node into the active paragraph. - fn inline(&mut self, node: impl Into) { + fn inline(&mut self, node: PackedNode) { self.flow.par.push(ParChild::Node(node.into())); } /// Push a block node into the active flow, finishing the active paragraph. - fn block(&mut self, node: impl Into) { - self.parbreak(); - self.flow.push(FlowChild::Node(node.into())); + fn block(&mut self, node: PackedNode) { self.parbreak(); + let in_flow = node.downcast::().is_none(); + self.flow.push(FlowChild::Node(node)); + if in_flow { + self.parbreak(); + } else { + // This prevents duplicate paragraph spacing around placed nodes. + self.flow.last = Last::None; + } } /// Push spacing into the active paragraph or flow depending on the `axis`. diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 33502fffa..3ac327228 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -19,7 +19,7 @@ use crate::font::FontStore; use crate::frame::Frame; use crate::geom::{Align, Linear, Spec}; use crate::image::ImageStore; -use crate::library::{AlignNode, DocumentNode, SizedNode}; +use crate::library::{AlignNode, DocumentNode, MoveNode, SizedNode}; use crate::Context; /// Layout a document node into a collection of frames. @@ -104,21 +104,27 @@ impl PackedNode { } /// Force a size for this node. - pub fn sized(self, width: Option, height: Option) -> PackedNode { - if width.is_some() || height.is_some() { - Layout::pack(SizedNode { - child: self, - sizing: Spec::new(width, height), - }) + pub fn sized(self, w: Option, h: Option) -> Self { + if w.is_some() || h.is_some() { + SizedNode { child: self, sizing: Spec::new(w, h) }.pack() } else { self } } /// Set alignments for this node. - pub fn aligned(self, x: Option, y: Option) -> PackedNode { + pub fn aligned(self, x: Option, y: Option) -> Self { if x.is_some() || y.is_some() { - Layout::pack(AlignNode { child: self, aligns: Spec::new(x, y) }) + AlignNode { child: self, aligns: Spec::new(x, y) }.pack() + } else { + self + } + } + + /// Move this node's contents without affecting layout. + pub fn moved(self, dx: Option, dy: Option) -> Self { + if dx.is_some() || dy.is_some() { + MoveNode { child: self, offset: Spec::new(dx, dy) }.pack() } else { self } diff --git a/src/library/align.rs b/src/library/align.rs index 591a40857..19c52f987 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -2,6 +2,20 @@ use super::prelude::*; /// `align`: Configure the alignment along the layouting axes. pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult { + let Spec { x, y } = parse_aligns(args)?; + let body = args.expect::