diff --git a/src/eval/template.rs b/src/eval/template.rs index e9cbbfcf0..d447161a2 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -337,13 +337,24 @@ impl Builder { /// Push a block node into the active flow, finishing the active paragraph. fn block(&mut self, node: PackedNode) { + let mut is_placed = false; + if let Some(placed) = node.downcast::() { + is_placed = true; + + // This prevents paragraph spacing after the placed node if it + // is completely out-of-flow. + if placed.out_of_flow() { + self.flow.last = Last::None; + } + } + 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.parbreak(); + + // This prevents paragraph spacing between the placed node and + // the paragraph below it. + if is_placed { self.flow.last = Last::None; } } diff --git a/src/frame.rs b/src/frame.rs index 4eea0578f..e02fdf46a 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -57,13 +57,13 @@ impl Frame { /// Resize the frame to a new size, distributing new space according to the /// given alignments. - pub fn resize(&mut self, new: Size, aligns: Spec) { - if self.size != new { + pub fn resize(&mut self, target: Size, aligns: Spec) { + if self.size != target { let offset = Point::new( - aligns.x.resolve(new.x - self.size.x), - aligns.y.resolve(new.y - self.size.y), + aligns.x.resolve(target.x - self.size.x), + aligns.y.resolve(target.y - self.size.y), ); - self.size = new; + self.size = target; self.baseline += offset.y; self.translate(offset); } diff --git a/src/geom/align.rs b/src/geom/align.rs index f068b821b..be2eac96a 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -18,6 +18,12 @@ pub enum Align { } impl Align { + /// Top-left alignment. + pub const LEFT_TOP: Spec = Spec { x: Align::Left, y: Align::Top }; + + /// Center-horizon alignment. + pub const CENTER_HORIZON: Spec = Spec { x: Align::Center, y: Align::Horizon }; + /// The axis this alignment belongs to. pub const fn axis(self) -> SpecAxis { match self { diff --git a/src/geom/spec.rs b/src/geom/spec.rs index 640d6231e..16d63959b 100644 --- a/src/geom/spec.rs +++ b/src/geom/spec.rs @@ -281,6 +281,14 @@ impl BitOr for Spec { } } +impl BitOr for Spec { + type Output = Self; + + fn bitor(self, rhs: bool) -> Self::Output { + Self { x: self.x | rhs, y: self.y | rhs } + } +} + impl BitAnd for Spec { type Output = Self; @@ -289,6 +297,14 @@ impl BitAnd for Spec { } } +impl BitAnd for Spec { + type Output = Self; + + fn bitand(self, rhs: bool) -> Self::Output { + Self { x: self.x & rhs, y: self.y & rhs } + } +} + impl BitOrAssign for Spec { fn bitor_assign(&mut self, rhs: Self) { self.x |= rhs.x; diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 405e4e83c..9c57152aa 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -136,10 +136,7 @@ impl PackedNode { /// Transform this node's contents without affecting layout. pub fn moved(self, offset: Point) -> Self { - self.transformed( - Transform::translation(offset.x, offset.y), - Spec::new(Align::Left, Align::Top), - ) + self.transformed(Transform::translation(offset.x, offset.y), Align::LEFT_TOP) } /// Transform this node's contents without affecting layout. diff --git a/src/library/align.rs b/src/library/align.rs index 7ad5a2d4b..a2881ccea 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -2,6 +2,18 @@ use super::prelude::*; /// `align`: Configure the alignment along the layouting axes. pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult { + castable! { + Spec>, + Expected: "1d or 2d alignment", + @align: Align => { + let mut aligns = Spec::default(); + aligns.set(align.axis(), Some(*align)); + aligns + }, + @aligns: Spec => aligns.map(Some), + + } + let aligns = args.expect::>("alignment")?; let body = args.expect::