From cd089b6194c57b2e8dff70efaa7cbd53035f7327 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 9 Dec 2022 10:21:11 +0100 Subject: Align set rule --- library/src/layout/align.rs | 64 +++++++++------------------------------------ library/src/layout/flow.rs | 14 ++-------- library/src/layout/mod.rs | 4 ++- library/src/layout/par.rs | 6 ++--- library/src/layout/place.rs | 8 +++--- library/src/layout/stack.rs | 22 +++++----------- library/src/lib.rs | 2 +- library/src/math/mod.rs | 8 +++--- library/src/shared/ext.rs | 2 +- 9 files changed, 36 insertions(+), 94 deletions(-) (limited to 'library/src') diff --git a/library/src/layout/align.rs b/library/src/layout/align.rs index ae60b4c6..506ef684 100644 --- a/library/src/layout/align.rs +++ b/library/src/layout/align.rs @@ -1,62 +1,22 @@ -use super::{HorizontalAlign, ParNode}; use crate::prelude::*; -/// Align content along the layouting axes. +/// Just an empty shell to scope styles. #[derive(Debug, Hash)] -pub struct AlignNode { - /// How to align the content horizontally and vertically. - pub aligns: Axes>, - /// The content to be aligned. - pub body: Content, -} +pub enum AlignNode {} -#[node(Layout)] +#[node] impl AlignNode { - fn construct(_: &Vm, args: &mut Args) -> SourceResult { - let aligns: Axes> = args.find()?.unwrap_or_default(); - let body: Content = args.expect("body")?; + /// The alignment. + #[property(fold, skip)] + pub const ALIGNS: Axes> = + Axes::new(GenAlign::Start, GenAlign::Specific(Align::Top)); - if let Axes { x: Some(x), y: None } = aligns { - if !body.has::() || body.has::() { - return Ok(body.styled(ParNode::ALIGN, HorizontalAlign(x))); - } - } - - Ok(Self { aligns, body }.pack()) + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + args.expect("body") } -} -impl Layout for AlignNode { - fn layout( - &self, - vt: &mut Vt, - styles: StyleChain, - regions: Regions, - ) -> SourceResult { - // The child only needs to expand along an axis if there's no alignment. - let mut pod = regions.clone(); - pod.expand &= self.aligns.as_ref().map(Option::is_none); - - // Align paragraphs inside the child. - let mut map = StyleMap::new(); - if let Some(align) = self.aligns.x { - map.set(ParNode::ALIGN, HorizontalAlign(align)); - } - - // Layout the child. - let mut fragment = self.body.layout(vt, styles.chain(&map), pod)?; - for (region, frame) in regions.iter().zip(&mut fragment) { - // Align in the target size. The target size depends on whether we - // should expand. - let target = regions.expand.select(region, frame.size()); - let aligns = self - .aligns - .map(|align| align.resolve(styles)) - .unwrap_or(Axes::new(Align::Left, Align::Top)); - - frame.resize(target, aligns); - } - - Ok(fragment) + fn set(...) { + let aligns: Axes> = args.find()?.unwrap_or_default(); + styles.set(Self::ALIGNS, aligns); } } diff --git a/library/src/layout/flow.rs b/library/src/layout/flow.rs index 0b6454a0..b78f3932 100644 --- a/library/src/layout/flow.rs +++ b/library/src/layout/flow.rs @@ -125,7 +125,7 @@ impl<'a> FlowLayouter<'a> { par: &ParNode, styles: StyleChain, ) -> SourceResult<()> { - let aligns = Axes::new(styles.get(ParNode::ALIGN), Align::Top); + let aligns = styles.get(AlignNode::ALIGNS).resolve(styles); let leading = styles.get(ParNode::LEADING); let consecutive = self.last_was_par; let fragment = par.layout( @@ -172,17 +172,7 @@ impl<'a> FlowLayouter<'a> { } // How to align the block. - let aligns = Axes::new( - // For non-expanding paragraphs it is crucial that we align the - // whole paragraph as it is itself aligned. - styles.get(ParNode::ALIGN), - // Vertical align node alignment is respected by the flow. - block - .to::() - .and_then(|aligned| aligned.aligns.y) - .map(|align| align.resolve(styles)) - .unwrap_or(Align::Top), - ); + let aligns = styles.get(AlignNode::ALIGNS).resolve(styles); // Layout the block itself. let sticky = styles.get(BlockNode::STICKY); diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs index 00b1f9be..afa1344f 100644 --- a/library/src/layout/mod.rs +++ b/library/src/layout/mod.rs @@ -412,7 +412,9 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { bail!(span, "not allowed here"); } self.interrupt_page(styles)?; - } else if map.interruption::().is_some() { + } else if map.interruption::().is_some() + || map.interruption::().is_some() + { self.interrupt_par()?; } else if map.interruption::().is_some() || map.interruption::().is_some() diff --git a/library/src/layout/par.rs b/library/src/layout/par.rs index c0e7c6c9..d93bfba7 100644 --- a/library/src/layout/par.rs +++ b/library/src/layout/par.rs @@ -5,6 +5,7 @@ use xi_unicode::LineBreakIterator; use typst::model::Key; use super::{HNode, RepeatNode, Spacing}; +use crate::layout::AlignNode; use crate::prelude::*; use crate::text::{ shape, LinebreakNode, Quoter, Quotes, ShapedText, SmartQuoteNode, SpaceNode, TextNode, @@ -22,9 +23,6 @@ impl ParNode { /// The spacing between lines. #[property(resolve)] pub const LEADING: Length = Em::new(0.65).into(); - /// How to align text and inline objects in their line. - #[property(resolve)] - pub const ALIGN: HorizontalAlign = HorizontalAlign(GenAlign::Start); /// Whether to justify text in its line. pub const JUSTIFY: bool = false; /// How to determine line breaks. @@ -554,7 +552,7 @@ fn prepare<'a>( styles, hyphenate: shared_get(styles, &par.0, TextNode::HYPHENATE), lang: shared_get(styles, &par.0, TextNode::LANG), - align: styles.get(ParNode::ALIGN), + align: styles.get(AlignNode::ALIGNS).x.resolve(styles), justify: styles.get(ParNode::JUSTIFY), }) } diff --git a/library/src/layout/place.rs b/library/src/layout/place.rs index 2e2c81a1..28d231b7 100644 --- a/library/src/layout/place.rs +++ b/library/src/layout/place.rs @@ -1,9 +1,8 @@ -use super::AlignNode; use crate::prelude::*; /// Place content at an absolute position. #[derive(Debug, Hash)] -pub struct PlaceNode(pub Content); +pub struct PlaceNode(pub Content, bool); #[node(Layout, Behave)] impl PlaceNode { @@ -12,7 +11,8 @@ impl PlaceNode { let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); let body = args.expect::("body")?; - Ok(Self(body.moved(Axes::new(dx, dy)).aligned(aligns)).pack()) + let out_of_flow = aligns.y.is_some(); + Ok(Self(body.moved(Axes::new(dx, dy)).aligned(aligns), out_of_flow).pack()) } } @@ -49,7 +49,7 @@ impl PlaceNode { /// origin. Instead of relative to the parent's current flow/cursor /// position. pub fn out_of_flow(&self) -> bool { - self.0.to::().map_or(false, |node| node.aligns.y.is_some()) + self.1 } } diff --git a/library/src/layout/stack.rs b/library/src/layout/stack.rs index 6432f4ac..d44dcb48 100644 --- a/library/src/layout/stack.rs +++ b/library/src/layout/stack.rs @@ -1,6 +1,6 @@ use typst::model::StyledNode; -use super::{AlignNode, ParNode, Spacing}; +use super::{AlignNode, Spacing}; use crate::prelude::*; /// Arrange content and spacing along an axis. @@ -180,21 +180,13 @@ impl<'a> StackLayouter<'a> { // Block-axis alignment of the `AlignNode` is respected // by the stack node. - let align = block - .to::() - .and_then(|node| node.aligns.get(self.axis)) - .map(|align| align.resolve(styles)) - .unwrap_or_else(|| { - if let Some(styled) = block.to::() { - let map = &styled.map; - if map.contains(ParNode::ALIGN) { - return StyleChain::new(map).get(ParNode::ALIGN); - } - } - - self.dir.start().into() - }); + let aligns = if let Some(styled) = block.to::() { + styles.chain(&styled.map).get(AlignNode::ALIGNS) + } else { + styles.get(AlignNode::ALIGNS) + }; + let align = aligns.get(self.axis).resolve(styles); let fragment = block.layout(vt, styles, self.regions)?; let len = fragment.len(); for (i, frame) in fragment.into_iter().enumerate() { diff --git a/library/src/lib.rs b/library/src/lib.rs index e41e7c0d..86bef0b9 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -208,6 +208,6 @@ fn items() -> LangItems { math_atom: |atom| math::AtomNode(atom).pack(), math_script: |base, sub, sup| math::ScriptNode { base, sub, sup }.pack(), math_frac: |num, denom| math::FracNode { num, denom }.pack(), - math_align: |count| math::AlignNode(count).pack(), + math_align_point: |count| math::AlignPointNode(count).pack(), } } diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index 1139296c..62432b12 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -442,14 +442,14 @@ impl Texify for ScriptNode { } } -/// A math alignment indicator: `&`, `&&`. +/// A math alignment point: `&`, `&&`. #[derive(Debug, Hash)] -pub struct AlignNode(pub usize); +pub struct AlignPointNode(pub usize); #[node(Texify)] -impl AlignNode {} +impl AlignPointNode {} -impl Texify for AlignNode { +impl Texify for AlignPointNode { fn texify(&self, _: &mut Texifier) -> SourceResult<()> { Ok(()) } diff --git a/library/src/shared/ext.rs b/library/src/shared/ext.rs index 811ae757..23db71f9 100644 --- a/library/src/shared/ext.rs +++ b/library/src/shared/ext.rs @@ -57,7 +57,7 @@ impl ContentExt for Content { } fn aligned(self, aligns: Axes>) -> Self { - crate::layout::AlignNode { aligns, body: self }.pack() + self.styled(crate::layout::AlignNode::ALIGNS, aligns) } fn padded(self, padding: Sides>) -> Self { -- cgit v1.2.3