From b76e8d5db9bea8fb63e65fe7a54db6bbae1cf842 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 6 Sep 2023 10:30:45 +0200 Subject: [PATCH] Interpret vertical page number alignment differently The vertical alignment of `number-align` now selects header or footer instead of aligning within the footer. This is a minor breaking change because - top behaves differently now - horizon is now forbidden - bottom (the new default) behaves differently, too Typical number-align usage will likely not use the vertical component at all, though. Fixes #645 --- crates/typst-library/src/layout/page.rs | 64 +++++++++++++++++------- docs/guides/page-setup.md | 2 +- tests/ref/layout/page-number-align.png | Bin 0 -> 1343 bytes tests/typ/layout/page-number-align.typ | 25 +++++++++ 4 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 tests/ref/layout/page-number-align.png create mode 100644 tests/typ/layout/page-number-align.typ diff --git a/crates/typst-library/src/layout/page.rs b/crates/typst-library/src/layout/page.rs index 8e73c3b3a..4ef90753f 100644 --- a/crates/typst-library/src/layout/page.rs +++ b/crates/typst-library/src/layout/page.rs @@ -177,7 +177,8 @@ pub struct PageElem { /// How to [number]($func/numbering) the pages. /// - /// If an explicit `footer` is given, the numbering is ignored. + /// If an explicit `footer` (or `header` for top-aligned numbering) is + /// given, the numbering is ignored. /// /// ```example /// #set page( @@ -192,6 +193,11 @@ pub struct PageElem { /// The alignment of the page numbering. /// + /// If the vertical component is `top`, the numbering is placed into the + /// header and if it is `bottom`, it is placed in the footer. Horizon + /// alignment is forbidden. If an explicit matching `header` or `footer` is + /// given, the numbering is ignored. + /// /// ```example /// #set page( /// margin: (top: 16pt, bottom: 24pt), @@ -202,6 +208,15 @@ pub struct PageElem { /// #lorem(30) /// ``` #[default(Align::Center.into())] + #[parse({ + let spanned: Option>> = args.named("number-align")?; + if let Some(Spanned { v, span }) = spanned { + if matches!(v.y, Some(GenAlign::Specific(Align::Horizon))) { + bail!(span, "page number cannot be `horizon`-aligned"); + } + } + spanned.map(|s| s.v) + })] pub number_align: Axes>, /// The page's header. Fills the top margin of each page. @@ -372,25 +387,40 @@ impl PageElem { let fill = self.fill(styles); let foreground = self.foreground(styles); let background = self.background(styles); - let header = self.header(styles); let header_ascent = self.header_ascent(styles); - let footer = self.footer(styles).or_else(|| { - self.numbering(styles).map(|numbering| { - let both = match &numbering { - Numbering::Pattern(pattern) => pattern.pieces() >= 2, - Numbering::Func(_) => true, - }; - Counter::new(CounterKey::Page) - .display(Some(numbering), both) - .aligned(self.number_align(styles)) - }) - }); let footer_descent = self.footer_descent(styles); + let numbering = self.numbering(styles); + let number_align = self.number_align(styles); + let mut header = self.header(styles); + let mut footer = self.footer(styles); - let numbering_meta = FrameItem::Meta( - Meta::PageNumbering(self.numbering(styles).into_value()), - Size::zero(), - ); + // Construct the numbering (for header or footer). + let numbering_marginal = numbering.clone().map(|numbering| { + let both = match &numbering { + Numbering::Pattern(pattern) => pattern.pieces() >= 2, + Numbering::Func(_) => true, + }; + + let mut counter = + Counter::new(CounterKey::Page).display(Some(numbering), both); + + // We interpret the Y alignment as selecting header or footer + // and then ignore it for aligning the actual number. + if let Some(x) = number_align.x { + counter = counter.aligned(Axes::with_x(Some(x))); + } + + counter + }); + + if matches!(number_align.y, Some(GenAlign::Specific(Align::Top))) { + header = header.or(numbering_marginal); + } else { + footer = footer.or(numbering_marginal); + } + + let numbering_meta = + FrameItem::Meta(Meta::PageNumbering(numbering.into_value()), Size::zero()); // Post-process pages. for frame in frames.iter_mut() { diff --git a/docs/guides/page-setup.md b/docs/guides/page-setup.md index 8efcb2cdf..b396a383b 100644 --- a/docs/guides/page-setup.md +++ b/docs/guides/page-setup.md @@ -34,7 +34,7 @@ document or in your template. "iso-b7", header: rect[Header], footer: rect[Footer], - number-align: top + center, + number-align: center, ) #rect(fill: rgb("#565565")) diff --git a/tests/ref/layout/page-number-align.png b/tests/ref/layout/page-number-align.png new file mode 100644 index 0000000000000000000000000000000000000000..b05ca45456a6f06c21a2dbc5590f82eb7017463f GIT binary patch literal 1343 zcmeAS@N?(olHy`uVBq!ia0y~yU}OQ}bsWq<5y!xe4M0wLfKQ0)|NsC0{rmU#@83Uv z{`~&^``52uKY#xG@#Dw$@87?E{rct0myaJme)#a={rmT?U%!6-{Q0wI&z?Sg`sB%z z{crz2eE9Ieg9rET-@kkJ?u{Eau3fu!_3G72mo8nrc=6P!QzuTGICSXHfddEj?c29! z&z{}8ckkS}bH|PyTeoiAvSrKW&6_uD*sy;6`n7AljIdkSrpFX{-tE;1ZkKB~c&(#qBcJPs7_R;En?K{7JdpvX1%a?wvnkp;;3Jwhnj7%&X zmz_KgGJzOy5p+gNlGN(l;ENKOX5gY-O*m3B8qkuWWfMx9uwoBrRO5z-OQ6TEI2=4Si zoFNET!BQGj1Q@bsj-UoM$izR)9N+Kn-LZ3_)ja9C|B3DvE$RJYKCw5VZV2-~bXgi{ zACjrYq$Hy|)mQoE>{F+%ui)7E*V{eb-Q7boww6`#t1~D$x6HbGP;BO<6Vqc#TGpM8 zOiZXQXxY{`Rom*;VWlru*7dNv?6_@En&^9EammA{UrVokJoBN#q2*YO-F$Cj&36)t nn9hQV)Qc+SA^h=2&7N^v!@=X{XRtg6=1K-nS3j3^P6