From 0fe03bae6e154c30934d9f25037fa57e7381780f Mon Sep 17 00:00:00 2001 From: Leedehai <18319900+Leedehai@users.noreply.github.com> Date: Thu, 22 Feb 2024 03:49:24 -0500 Subject: Add `number-align` to `math.equation` [Better Equation Numbering Pt.2] (#3446) --- crates/typst/src/layout/align.rs | 8 +++ crates/typst/src/math/equation.rs | 102 +++++++++++++++++++++----------- tests/ref/math/block-alignment.png | Bin 5170 -> 0 bytes tests/ref/math/equation-block-align.png | Bin 0 -> 5170 bytes tests/ref/math/equation-number.png | Bin 0 -> 18851 bytes tests/typ/math/block-alignment.typ | 33 ----------- tests/typ/math/equation-block-align.typ | 33 +++++++++++ tests/typ/math/equation-number.typ | 96 ++++++++++++++++++++++++++++++ 8 files changed, 203 insertions(+), 69 deletions(-) delete mode 100644 tests/ref/math/block-alignment.png create mode 100644 tests/ref/math/equation-block-align.png create mode 100644 tests/ref/math/equation-number.png delete mode 100644 tests/typ/math/block-alignment.typ create mode 100644 tests/typ/math/equation-block-align.typ create mode 100644 tests/typ/math/equation-number.typ diff --git a/crates/typst/src/layout/align.rs b/crates/typst/src/layout/align.rs index 58dc7589..5f516ebe 100644 --- a/crates/typst/src/layout/align.rs +++ b/crates/typst/src/layout/align.rs @@ -356,6 +356,14 @@ impl OuterHAlignment { } } +impl Resolve for OuterHAlignment { + type Output = FixedAlignment; + + fn resolve(self, styles: StyleChain) -> Self::Output { + self.fix(TextElem::dir_in(styles)) + } +} + impl From for HAlignment { fn from(value: OuterHAlignment) -> Self { match value { diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs index e4744aea..a272622e 100644 --- a/crates/typst/src/math/equation.rs +++ b/crates/typst/src/math/equation.rs @@ -10,8 +10,8 @@ use crate::foundations::{ }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; use crate::layout::{ - Abs, AlignElem, Alignment, Axes, Dir, Em, FixedAlignment, Frame, LayoutMultiple, - LayoutSingle, Point, Regions, Size, + Abs, AlignElem, Alignment, Axes, Em, FixedAlignment, Frame, LayoutMultiple, + LayoutSingle, OuterHAlignment, Point, Regions, Size, }; use crate::math::{scaled_font_size, LayoutMath, MathContext, MathSize, MathVariant}; use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement}; @@ -76,6 +76,21 @@ pub struct EquationElem { #[borrowed] pub numbering: Option, + /// The alignment of the equation numbering. + /// + /// By default, the number is put at the `{end}` of the equation block. Both + /// `{start}` and `{end}` respects text direction; for absolute positioning, + /// use `{left}` or `{right}`. + /// + /// ```example + /// #set math.equation(numbering: "(1)", number-align: start) + /// + /// With natural units, we know: + /// $ E^2 = m^2 + p^2 $ + /// ``` + #[default(OuterHAlignment::End)] + pub number_align: OuterHAlignment, + /// A supplement for the equation. /// /// For references to equations, this is added before the referenced number. @@ -192,7 +207,6 @@ impl Packed { ) -> SourceResult> { assert!(!self.block(styles)); - // Find a math font. let font = find_math_font(engine, styles, self.span())?; let mut ctx = MathContext::new(engine, styles, regions, &font); @@ -231,52 +245,34 @@ impl LayoutSingle for Packed { styles: StyleChain, regions: Regions, ) -> SourceResult { - const NUMBER_GUTTER: Em = Em::new(0.5); - assert!(self.block(styles)); - // Find a math font. - let font = find_math_font(engine, styles, self.span())?; + let span = self.span(); + let font = find_math_font(engine, styles, span)?; let mut ctx = MathContext::new(engine, styles, regions, &font); let mut frame = ctx.layout_into_frame(self, styles)?; if let Some(numbering) = (**self).numbering(styles) { let pod = Regions::one(regions.base(), Axes::splat(false)); - let counter = Counter::of(EquationElem::elem()) + let number = Counter::of(EquationElem::elem()) .at(engine, self.location().unwrap())? .display(engine, numbering)? - .spanned(self.span()) + .spanned(span) .layout(engine, styles, pod)? .into_frame(); - let full_counter_width = counter.width() + NUMBER_GUTTER.resolve(styles); - let width = if regions.size.x.is_finite() { - regions.size.x - } else { - frame.width() + 2.0 * full_counter_width - }; - - let height = frame.height().max(counter.height()); - let align = AlignElem::alignment_in(styles).resolve(styles).x; - frame.resize(Size::new(width, height), Axes::splat(align)); - - let dir = TextElem::dir_in(styles); - let offset = match (align, dir) { - (FixedAlignment::Start, Dir::RTL) => full_counter_width, - (FixedAlignment::End, Dir::LTR) => -full_counter_width, - _ => Abs::zero(), - }; - frame.translate(Point::with_x(offset)); - - let x = if dir.is_positive() { - frame.width() - counter.width() - } else { - Abs::zero() - }; - let y = (frame.height() - counter.height()) / 2.0; - - frame.push_frame(Point::new(x, y), counter) + static NUMBER_GUTTER: Em = Em::new(0.5); + let full_number_width = number.width() + NUMBER_GUTTER.resolve(styles); + + add_equation_number( + &mut frame, + number, + self.number_align(styles).resolve(styles), + AlignElem::alignment_in(styles).resolve(styles).x, + regions.size.x, + full_number_width, + ); } Ok(frame) @@ -398,3 +394,37 @@ fn find_math_font( }; Ok(font) } + +fn add_equation_number( + equation: &mut Frame, + number: Frame, + number_align: FixedAlignment, + equation_align: FixedAlignment, + region_size_x: Abs, + full_number_width: Abs, +) { + let width = if region_size_x.is_finite() { + region_size_x + } else { + equation.width() + 2.0 * full_number_width + }; + + let height = equation.height().max(number.height()); + equation.resize(Size::new(width, height), Axes::splat(equation_align)); + + let offset = match (equation_align, number_align) { + (FixedAlignment::Start, FixedAlignment::Start) => full_number_width, + (FixedAlignment::End, FixedAlignment::End) => -full_number_width, + _ => Abs::zero(), + }; + equation.translate(Point::with_x(offset)); + + let x = match number_align { + FixedAlignment::Start => Abs::zero(), + FixedAlignment::End => equation.width() - number.width(), + _ => unreachable!(), + }; + let y = (equation.height() - number.height()) / 2.0; + + equation.push_frame(Point::new(x, y), number); +} diff --git a/tests/ref/math/block-alignment.png b/tests/ref/math/block-alignment.png deleted file mode 100644 index 8736312a..00000000 Binary files a/tests/ref/math/block-alignment.png and /dev/null differ diff --git a/tests/ref/math/equation-block-align.png b/tests/ref/math/equation-block-align.png new file mode 100644 index 00000000..8736312a Binary files /dev/null and b/tests/ref/math/equation-block-align.png differ diff --git a/tests/ref/math/equation-number.png b/tests/ref/math/equation-number.png new file mode 100644 index 00000000..96a1f21a Binary files /dev/null and b/tests/ref/math/equation-number.png differ diff --git a/tests/typ/math/block-alignment.typ b/tests/typ/math/block-alignment.typ deleted file mode 100644 index c6c9cd89..00000000 --- a/tests/typ/math/block-alignment.typ +++ /dev/null @@ -1,33 +0,0 @@ -// Test alignment of block equations. - ---- -// Test unnumbered -#let eq(alignment) = { - show math.equation: set align(alignment) - $ a + b = c $ -} - -#eq(center) -#eq(left) -#eq(right) - -#set text(dir: rtl) -#eq(start) -#eq(end) - ---- -// Test numbered -#let eq(alignment) = { - show math.equation: set align(alignment) - $ a + b = c $ -} - -#set math.equation(numbering: "(1)") - -#eq(center) -#eq(left) -#eq(right) - -#set text(dir: rtl) -#eq(start) -#eq(end) diff --git a/tests/typ/math/equation-block-align.typ b/tests/typ/math/equation-block-align.typ new file mode 100644 index 00000000..c6c9cd89 --- /dev/null +++ b/tests/typ/math/equation-block-align.typ @@ -0,0 +1,33 @@ +// Test alignment of block equations. + +--- +// Test unnumbered +#let eq(alignment) = { + show math.equation: set align(alignment) + $ a + b = c $ +} + +#eq(center) +#eq(left) +#eq(right) + +#set text(dir: rtl) +#eq(start) +#eq(end) + +--- +// Test numbered +#let eq(alignment) = { + show math.equation: set align(alignment) + $ a + b = c $ +} + +#set math.equation(numbering: "(1)") + +#eq(center) +#eq(left) +#eq(right) + +#set text(dir: rtl) +#eq(start) +#eq(end) diff --git a/tests/typ/math/equation-number.typ b/tests/typ/math/equation-number.typ new file mode 100644 index 00000000..aefa308a --- /dev/null +++ b/tests/typ/math/equation-number.typ @@ -0,0 +1,96 @@ +// Test equation number, and its interaction with equation +// block's alignment and text direction. + +--- +#set math.equation(numbering: "(1)") + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- +#set math.equation(numbering: "(1)", number-align: start) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- +#set math.equation(numbering: "(1)", number-align: end) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- +#set math.equation(numbering: "(1)", number-align: left) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- +#set math.equation(numbering: "(1)", number-align: right) + +$ a + b = c $ + +#show math.equation: set align(center) +$ a + b = c $ +#show math.equation: set align(left) +$ a + b = c $ +#show math.equation: set align(right) +$ a + b = c $ + +#set text(dir: rtl) +#show math.equation: set align(start) +$ a + b = c $ +#show math.equation: set align(end) +$ a + b = c $ + +--- +// Error: 52-58 expected `start`, `left`, `right`, or `end`, found center +#set math.equation(numbering: "(1)", number-align: center) -- cgit v1.2.3