Equation numbering

This commit is contained in:
Laurenz 2023-03-18 19:28:03 +01:00
parent a69b587455
commit c7f4d6b12e
3 changed files with 82 additions and 2 deletions

View File

@ -39,6 +39,9 @@ use self::fragment::*;
use self::row::*; use self::row::*;
use self::spacing::*; use self::spacing::*;
use crate::layout::{HNode, ParNode, Spacing}; use crate::layout::{HNode, ParNode, Spacing};
use crate::meta::{
Count, Counter, CounterAction, CounterNode, CounterUpdate, LocalName, Numbering,
};
use crate::prelude::*; use crate::prelude::*;
use crate::text::{ use crate::text::{
families, variant, FontFamily, FontList, LinebreakNode, SpaceNode, TextNode, TextSize, families, variant, FontFamily, FontList, LinebreakNode, SpaceNode, TextNode, TextSize,
@ -132,17 +135,37 @@ pub fn module() -> Module {
/// ///
/// Display: Equation /// Display: Equation
/// Category: math /// Category: math
#[node(Show, Finalize, Layout, LayoutMath)] #[node(Locatable, Synthesize, Show, Finalize, Layout, LayoutMath, Count, LocalName)]
pub struct EquationNode { pub struct EquationNode {
/// Whether the equation is displayed as a separate block. /// Whether the equation is displayed as a separate block.
#[default(false)] #[default(false)]
pub block: bool, pub block: bool,
/// How to [number]($func/numbering) block-level equations.
///
/// ```example
/// #set math.equation(numbering: "(1)")
///
/// We define:
/// $ phi.alt := (1 + sqrt(5)) / 2 $ <ratio>
///
/// With @ratio, we get:
/// $ F_n = floor(1 / sqrt(5) phi.alt^n) $
/// ```
pub numbering: Option<Numbering>,
/// The contents of the equation. /// The contents of the equation.
#[required] #[required]
pub body: Content, pub body: Content,
} }
impl Synthesize for EquationNode {
fn synthesize(&mut self, _: &Vt, styles: StyleChain) {
self.push_block(self.block(styles));
self.push_numbering(self.numbering(styles));
}
}
impl Show for EquationNode { impl Show for EquationNode {
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
let mut realized = self.clone().pack().guarded(Guard::Base(NodeId::of::<Self>())); let mut realized = self.clone().pack().guarded(Guard::Base(NodeId::of::<Self>()));
@ -170,6 +193,8 @@ impl Layout for EquationNode {
styles: StyleChain, styles: StyleChain,
regions: Regions, regions: Regions,
) -> SourceResult<Fragment> { ) -> SourceResult<Fragment> {
const NUMBER_GUTTER: Em = Em::new(0.5);
let block = self.block(styles); let block = self.block(styles);
// Find a math font. // Find a math font.
@ -189,7 +214,34 @@ impl Layout for EquationNode {
let mut ctx = MathContext::new(vt, styles, regions, &font, block); let mut ctx = MathContext::new(vt, styles, regions, &font, block);
let mut frame = ctx.layout_frame(self)?; let mut frame = ctx.layout_frame(self)?;
if !block { if block {
if let Some(numbering) = self.numbering(styles) {
let pod = Regions::one(regions.base(), Axes::splat(false));
let counter = CounterNode::new(
Counter::of(Self::id()),
CounterAction::Get(numbering),
);
let sub = counter.pack().layout(vt, styles, pod)?.into_frame();
let width = if regions.size.x.is_finite() {
regions.size.x
} else {
frame.width() + 2.0 * (sub.width() + NUMBER_GUTTER.resolve(styles))
};
let height = frame.height().max(sub.height());
frame.resize(Size::new(width, height), Align::CENTER_HORIZON);
let x = if TextNode::dir_in(styles).is_positive() {
frame.width() - sub.width()
} else {
Abs::zero()
};
let y = (frame.height() - sub.height()) / 2.0;
frame.push_frame(Point::new(x, y), sub)
}
} else {
let slack = ParNode::leading_in(styles) * 0.7; let slack = ParNode::leading_in(styles) * 0.7;
let top_edge = TextNode::top_edge_in(styles).resolve(styles, font.metrics()); let top_edge = TextNode::top_edge_in(styles).resolve(styles, font.metrics());
let bottom_edge = let bottom_edge =
@ -205,6 +257,23 @@ impl Layout for EquationNode {
} }
} }
impl Count for EquationNode {
fn update(&self) -> Option<CounterUpdate> {
(self.block(StyleChain::default())
&& self.numbering(StyleChain::default()).is_some())
.then(|| CounterUpdate::Step(NonZeroUsize::ONE))
}
}
impl LocalName for EquationNode {
fn local_name(&self, lang: Lang) -> &'static str {
match lang {
Lang::GERMAN => "Gleichung",
Lang::ENGLISH | _ => "Equation",
}
}
}
pub trait LayoutMath { pub trait LayoutMath {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()>; fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()>;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,11 @@
// Test equation numbering.
---
#set page(width: 150pt)
#set math.equation(numbering: "(I)")
We define $x$ in preparation of @fib:
$ phi.alt := (1 + sqrt(5)) / 2 $ <ratio>
With @ratio, we get
$ F_n = floor(1 / sqrt(5) phi.alt^n) $ <fib>