summaryrefslogtreecommitdiff
path: root/crates/typst-library/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-09-06 10:30:45 +0200
committerLaurenz <laurmaedje@gmail.com>2023-09-06 10:32:54 +0200
commitb76e8d5db9bea8fb63e65fe7a54db6bbae1cf842 (patch)
tree2ccd7f3185b52b44f83f9ed23c1bbc3319e0804a /crates/typst-library/src
parent87c0a5171af2e374cd6b0a0bd6d8d9531aaf796c (diff)
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
Diffstat (limited to 'crates/typst-library/src')
-rw-r--r--crates/typst-library/src/layout/page.rs64
1 files changed, 47 insertions, 17 deletions
diff --git a/crates/typst-library/src/layout/page.rs b/crates/typst-library/src/layout/page.rs
index 8e73c3b3..4ef90753 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<Spanned<Axes<_>>> = 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<Option<GenAlign>>,
/// 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);
+
+ // 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(self.numbering(styles).into_value()),
- Size::zero(),
- );
+ let numbering_meta =
+ FrameItem::Meta(Meta::PageNumbering(numbering.into_value()), Size::zero());
// Post-process pages.
for frame in frames.iter_mut() {