Fixed page numbering (#594)

This commit is contained in:
Sébastien d'Herbais de Thun 2023-04-05 15:04:31 +02:00 committed by GitHub
parent d569f6b33b
commit 70a909b8ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 8 deletions

View File

@ -324,8 +324,14 @@ impl PageElem {
}); });
let footer_descent = self.footer_descent(styles); let footer_descent = self.footer_descent(styles);
let numbering_meta = FrameItem::Meta(
Meta::PageNumbering(self.numbering(styles).into()),
Size::zero(),
);
// Realize overlays. // Realize overlays.
for frame in &mut fragment { for frame in &mut fragment {
frame.prepend(Point::zero(), numbering_meta.clone());
let size = frame.size(); let size = frame.size();
let pad = padding.resolve(styles).relative_to(size); let pad = padding.resolve(styles).relative_to(size);
let pw = size.x - pad.left - pad.right; let pw = size.x - pad.left - pad.right;

View File

@ -35,6 +35,15 @@ use crate::prelude::*;
/// ///
/// - returns: dictionary /// - returns: dictionary
/// ///
/// ### page-numbering()
/// Returns the page numbering pattern of the page at this location. This can be
/// used when displaying the page counter in order to obtain the local numbering.
/// This is useful if you are building custom indices or outlines.
///
/// If the page numbering is set to `none` at that location, this function returns `none`.
///
/// - returns: string or function or none
///
/// Display: Locate /// Display: Locate
/// Category: meta /// Category: meta
/// Returns: content /// Returns: content

View File

@ -1,4 +1,8 @@
use super::{Counter, CounterKey, HeadingElem, LocalName, Refable}; use std::str::FromStr;
use super::{
Counter, CounterKey, HeadingElem, LocalName, Numbering, NumberingPattern, Refable,
};
use crate::layout::{BoxElem, HElem, HideElem, ParbreakElem, RepeatElem}; use crate::layout::{BoxElem, HElem, HideElem, ParbreakElem, RepeatElem};
use crate::prelude::*; use crate::prelude::*;
use crate::text::{LinebreakElem, SpaceElem, TextElem}; use crate::text::{LinebreakElem, SpaceElem, TextElem};
@ -205,6 +209,15 @@ impl Show for OutlineElem {
// Add the outline of the element. // Add the outline of the element.
seq.push(outline.linked(Destination::Location(location))); seq.push(outline.linked(Destination::Location(location)));
let page_numbering = vt
.introspector
.page_numbering(location)
.cast::<Option<Numbering>>()
.unwrap()
.unwrap_or_else(|| {
Numbering::Pattern(NumberingPattern::from_str("1").unwrap())
});
// Add filler symbols between the section name and page number. // Add filler symbols between the section name and page number.
if let Some(filler) = self.fill(styles) { if let Some(filler) = self.fill(styles) {
seq.push(SpaceElem::new().pack()); seq.push(SpaceElem::new().pack());
@ -221,11 +234,10 @@ impl Show for OutlineElem {
// Add the page number and linebreak. // Add the page number and linebreak.
let page = Counter::new(CounterKey::Page) let page = Counter::new(CounterKey::Page)
// query the page counter state at location of heading
.at(vt, location)? .at(vt, location)?
.first(); .display(vt, &page_numbering)?;
let end = TextElem::packed(eco_format!("{page}"));
seq.push(end.linked(Destination::Location(location))); seq.push(page.linked(Destination::Location(location)));
seq.push(LinebreakElem::new().pack()); seq.push(LinebreakElem::new().pack());
ancestors.push(elem); ancestors.push(elem);

View File

@ -609,6 +609,8 @@ pub enum Meta {
/// An identifiable element that produces something within the area this /// An identifiable element that produces something within the area this
/// metadata is attached to. /// metadata is attached to.
Elem(Content), Elem(Content),
/// The numbering of the current page.
PageNumbering(Value),
/// Indicates that content should be hidden. This variant doesn't appear /// Indicates that content should be hidden. This variant doesn't appear
/// in the final frames as it is removed alongside the content that should /// in the final frames as it is removed alongside the content that should
/// be hidden. /// be hidden.

View File

@ -154,6 +154,7 @@ pub fn call(
match method { match method {
"page" => vm.vt.introspector.page(location).into(), "page" => vm.vt.introspector.page(location).into(),
"position" => vm.vt.introspector.position(location).into(), "position" => vm.vt.introspector.position(location).into(),
"page-numbering" => vm.vt.introspector.page_numbering(location),
_ => return missing(), _ => return missing(),
} }
} else { } else {
@ -308,7 +309,7 @@ pub fn methods_on(type_name: &str) -> &[(&'static str, bool)] {
], ],
"function" => &[("where", true), ("with", true)], "function" => &[("where", true), ("with", true)],
"arguments" => &[("named", false), ("pos", false)], "arguments" => &[("named", false), ("pos", false)],
"location" => &[("page", false), ("position", false)], "location" => &[("page", false), ("position", false), ("page-numbering", false)],
"counter" => &[ "counter" => &[
("display", true), ("display", true),
("at", true), ("at", true),

View File

@ -298,6 +298,7 @@ fn write_frame(ctx: &mut PageContext, frame: &Frame) {
Meta::Link(dest) => write_link(ctx, pos, dest, *size), Meta::Link(dest) => write_link(ctx, pos, dest, *size),
Meta::Elem(_) => {} Meta::Elem(_) => {}
Meta::Hide => {} Meta::Hide => {}
Meta::PageNumbering(_) => {}
}, },
} }
} }

View File

@ -61,6 +61,7 @@ fn render_frame(
FrameItem::Meta(meta, _) => match meta { FrameItem::Meta(meta, _) => match meta {
Meta::Link(_) => {} Meta::Link(_) => {}
Meta::Elem(_) => {} Meta::Elem(_) => {}
Meta::PageNumbering(_) => {}
Meta::Hide => {} Meta::Hide => {}
}, },
} }

View File

@ -5,7 +5,7 @@ use std::num::NonZeroUsize;
use super::{Content, Selector}; use super::{Content, Selector};
use crate::diag::StrResult; use crate::diag::StrResult;
use crate::doc::{Frame, FrameItem, Meta, Position}; use crate::doc::{Frame, FrameItem, Meta, Position};
use crate::eval::cast_from_value; use crate::eval::{cast_from_value, Value};
use crate::geom::{Point, Transform}; use crate::geom::{Point, Transform};
use crate::model::Label; use crate::model::Label;
use crate::util::NonZeroExt; use crate::util::NonZeroExt;
@ -84,12 +84,18 @@ impl StabilityProvider {
pub struct Introspector { pub struct Introspector {
pages: usize, pages: usize,
elems: Vec<(Content, Position)>, elems: Vec<(Content, Position)>,
// Indexed by page number.
page_numberings: Vec<Value>,
} }
impl Introspector { impl Introspector {
/// Create a new introspector. /// Create a new introspector.
pub fn new(frames: &[Frame]) -> Self { pub fn new(frames: &[Frame]) -> Self {
let mut introspector = Self { pages: frames.len(), elems: vec![] }; let mut introspector = Self {
pages: frames.len(),
elems: vec![],
page_numberings: vec![],
};
for (i, frame) in frames.iter().enumerate() { for (i, frame) in frames.iter().enumerate() {
let page = NonZeroUsize::new(1 + i).unwrap(); let page = NonZeroUsize::new(1 + i).unwrap();
introspector.extract(frame, page, Transform::identity()); introspector.extract(frame, page, Transform::identity());
@ -121,6 +127,9 @@ impl Introspector {
let pos = pos.transform(ts); let pos = pos.transform(ts);
self.elems.push((content.clone(), Position { page, point: pos })); self.elems.push((content.clone(), Position { page, point: pos }));
} }
FrameItem::Meta(Meta::PageNumbering(numbering), _) => {
self.page_numberings.push(numbering.clone());
}
_ => {} _ => {}
} }
} }
@ -184,6 +193,12 @@ impl Introspector {
self.position(location).page self.position(location).page
} }
/// Gets the page numbering for the given location, if any.
pub fn page_numbering(&self, location: Location) -> Value {
let page = self.page(location);
self.page_numberings.get(page.get() - 1).cloned().unwrap_or_default()
}
/// Find the position for the given location. /// Find the position for the given location.
pub fn position(&self, location: Location) -> Position { pub fn position(&self, location: Location) -> Position {
self.elems self.elems