mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Add number-align
to math.equation
[Better Equation Numbering Pt.2] (#3446)
This commit is contained in:
parent
4eab6deed6
commit
0fe03bae6e
@ -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<OuterHAlignment> for HAlignment {
|
impl From<OuterHAlignment> for HAlignment {
|
||||||
fn from(value: OuterHAlignment) -> Self {
|
fn from(value: OuterHAlignment) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
@ -10,8 +10,8 @@ use crate::foundations::{
|
|||||||
};
|
};
|
||||||
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
|
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
Abs, AlignElem, Alignment, Axes, Dir, Em, FixedAlignment, Frame, LayoutMultiple,
|
Abs, AlignElem, Alignment, Axes, Em, FixedAlignment, Frame, LayoutMultiple,
|
||||||
LayoutSingle, Point, Regions, Size,
|
LayoutSingle, OuterHAlignment, Point, Regions, Size,
|
||||||
};
|
};
|
||||||
use crate::math::{scaled_font_size, LayoutMath, MathContext, MathSize, MathVariant};
|
use crate::math::{scaled_font_size, LayoutMath, MathContext, MathSize, MathVariant};
|
||||||
use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement};
|
use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement};
|
||||||
@ -76,6 +76,21 @@ pub struct EquationElem {
|
|||||||
#[borrowed]
|
#[borrowed]
|
||||||
pub numbering: Option<Numbering>,
|
pub numbering: Option<Numbering>,
|
||||||
|
|
||||||
|
/// 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.
|
/// A supplement for the equation.
|
||||||
///
|
///
|
||||||
/// For references to equations, this is added before the referenced number.
|
/// For references to equations, this is added before the referenced number.
|
||||||
@ -192,7 +207,6 @@ impl Packed<EquationElem> {
|
|||||||
) -> SourceResult<Vec<MathParItem>> {
|
) -> SourceResult<Vec<MathParItem>> {
|
||||||
assert!(!self.block(styles));
|
assert!(!self.block(styles));
|
||||||
|
|
||||||
// Find a math font.
|
|
||||||
let font = find_math_font(engine, styles, self.span())?;
|
let font = find_math_font(engine, styles, self.span())?;
|
||||||
|
|
||||||
let mut ctx = MathContext::new(engine, styles, regions, &font);
|
let mut ctx = MathContext::new(engine, styles, regions, &font);
|
||||||
@ -231,52 +245,34 @@ impl LayoutSingle for Packed<EquationElem> {
|
|||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
regions: Regions,
|
regions: Regions,
|
||||||
) -> SourceResult<Frame> {
|
) -> SourceResult<Frame> {
|
||||||
const NUMBER_GUTTER: Em = Em::new(0.5);
|
|
||||||
|
|
||||||
assert!(self.block(styles));
|
assert!(self.block(styles));
|
||||||
|
|
||||||
// Find a math font.
|
let span = self.span();
|
||||||
let font = find_math_font(engine, styles, self.span())?;
|
let font = find_math_font(engine, styles, span)?;
|
||||||
|
|
||||||
let mut ctx = MathContext::new(engine, styles, regions, &font);
|
let mut ctx = MathContext::new(engine, styles, regions, &font);
|
||||||
let mut frame = ctx.layout_into_frame(self, styles)?;
|
let mut frame = ctx.layout_into_frame(self, styles)?;
|
||||||
|
|
||||||
if let Some(numbering) = (**self).numbering(styles) {
|
if let Some(numbering) = (**self).numbering(styles) {
|
||||||
let pod = Regions::one(regions.base(), Axes::splat(false));
|
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())?
|
.at(engine, self.location().unwrap())?
|
||||||
.display(engine, numbering)?
|
.display(engine, numbering)?
|
||||||
.spanned(self.span())
|
.spanned(span)
|
||||||
.layout(engine, styles, pod)?
|
.layout(engine, styles, pod)?
|
||||||
.into_frame();
|
.into_frame();
|
||||||
|
|
||||||
let full_counter_width = counter.width() + NUMBER_GUTTER.resolve(styles);
|
static NUMBER_GUTTER: Em = Em::new(0.5);
|
||||||
let width = if regions.size.x.is_finite() {
|
let full_number_width = number.width() + NUMBER_GUTTER.resolve(styles);
|
||||||
regions.size.x
|
|
||||||
} else {
|
|
||||||
frame.width() + 2.0 * full_counter_width
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = frame.height().max(counter.height());
|
add_equation_number(
|
||||||
let align = AlignElem::alignment_in(styles).resolve(styles).x;
|
&mut frame,
|
||||||
frame.resize(Size::new(width, height), Axes::splat(align));
|
number,
|
||||||
|
self.number_align(styles).resolve(styles),
|
||||||
let dir = TextElem::dir_in(styles);
|
AlignElem::alignment_in(styles).resolve(styles).x,
|
||||||
let offset = match (align, dir) {
|
regions.size.x,
|
||||||
(FixedAlignment::Start, Dir::RTL) => full_counter_width,
|
full_number_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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(frame)
|
Ok(frame)
|
||||||
@ -398,3 +394,37 @@ fn find_math_font(
|
|||||||
};
|
};
|
||||||
Ok(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);
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
BIN
tests/ref/math/equation-number.png
Normal file
BIN
tests/ref/math/equation-number.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
96
tests/typ/math/equation-number.typ
Normal file
96
tests/typ/math/equation-number.typ
Normal file
@ -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)
|
Loading…
x
Reference in New Issue
Block a user