diff --git a/crates/typst/src/math/matrix.rs b/crates/typst/src/math/matrix.rs index 9f9b82bca..5b9b17a7d 100644 --- a/crates/typst/src/math/matrix.rs +++ b/crates/typst/src/math/matrix.rs @@ -7,7 +7,8 @@ use crate::foundations::{ Smart, StyleChain, Value, }; use crate::layout::{ - Abs, Axes, Em, FixedAlignment, Frame, FrameItem, Length, Point, Ratio, Rel, Size, + Abs, Axes, Em, FixedAlignment, Frame, FrameItem, HAlignment, Length, Point, Ratio, + Rel, Size, }; use crate::math::{ alignments, scaled_font_size, stack, style_for_denominator, AlignmentResult, @@ -29,7 +30,8 @@ const DEFAULT_STROKE_THICKNESS: Em = Em::new(0.05); /// A column vector. /// -/// Content in the vector's elements can be aligned with the `&` symbol. +/// Content in the vector's elements can be aligned with the +/// [`align`]($math.vec.align) parameter, or the `&` symbol. /// /// # Example /// ```example @@ -47,6 +49,16 @@ pub struct VecElem { #[default(DelimiterPair::PAREN)] pub delim: DelimiterPair, + /// The horizontal alignment that each element should have. + /// + /// ```example + /// #set math.vec(align: right) + /// $ vec(-1, 1, -1) $ + /// ``` + #[resolve] + #[default(HAlignment::Center)] + pub align: HAlignment, + /// The gap between elements. /// /// ```example @@ -70,7 +82,7 @@ impl LayoutMath for Packed { ctx, styles, self.children(), - FixedAlignment::Center, + self.align(styles), self.gap(styles), LeftRightAlternator::Right, )?; @@ -87,7 +99,9 @@ impl LayoutMath for Packed { /// special syntax of math function calls to define custom functions that take /// 2D data. /// -/// Content in cells that are in the same row can be aligned with the `&` symbol. +/// Content in cells can be aligned with the [`align`]($math.mat.align) +/// parameter, or content in cells that are in the same row can be aligned with +/// the `&` symbol. /// /// # Example /// ```example @@ -109,6 +123,16 @@ pub struct MatElem { #[default(DelimiterPair::PAREN)] pub delim: DelimiterPair, + /// The horizontal alignment that each cell should have. + /// + /// ```example + /// #set math.mat(align: right) + /// $ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1) $ + /// ``` + #[resolve] + #[default(HAlignment::Center)] + pub align: HAlignment, + /// Draws augmentation lines in a matrix. /// /// - `{none}`: No lines are drawn. @@ -249,6 +273,7 @@ impl LayoutMath for Packed { ctx, styles, rows, + self.align(styles), augment, Axes::new(self.column_gap(styles), self.row_gap(styles)), self.span(), @@ -454,6 +479,7 @@ fn layout_mat_body( ctx: &mut MathContext, styles: StyleChain, rows: &[Vec], + align: FixedAlignment, augment: Option>, gap: Axes>, span: Span, @@ -538,7 +564,11 @@ fn layout_mat_body( for (cell, &(ascent, descent)) in col.into_iter().zip(&heights) { let cell = cell.into_line_frame(&points, LeftRightAlternator::Right); let pos = Point::new( - if points.is_empty() { x + (rcol - cell.width()) / 2.0 } else { x }, + if points.is_empty() { + x + align.position(rcol - cell.width()) + } else { + x + }, y + ascent - cell.ascent(), ); diff --git a/crates/typst/src/math/underover.rs b/crates/typst/src/math/underover.rs index f1789b7ad..5ad7f4579 100644 --- a/crates/typst/src/math/underover.rs +++ b/crates/typst/src/math/underover.rs @@ -476,7 +476,11 @@ pub(super) fn stack( let mut y = Abs::zero(); for (i, row) in rows.into_iter().enumerate() { - let x = align.position(width - row.width()); + let x = if points.is_empty() { + align.position(width - row.width()) + } else { + Abs::zero() + }; let ascent_padded_part = minimum_ascent_descent .map_or(Abs::zero(), |(a, _)| (a - row.ascent())) .max(Abs::zero()); diff --git a/tests/ref/math-mat-align-explicit--alternating.png b/tests/ref/math-mat-align-explicit-alternating.png similarity index 100% rename from tests/ref/math-mat-align-explicit--alternating.png rename to tests/ref/math-mat-align-explicit-alternating.png diff --git a/tests/ref/math-mat-align-explicit-mixed.png b/tests/ref/math-mat-align-explicit-mixed.png new file mode 100644 index 000000000..88ccd6de7 Binary files /dev/null and b/tests/ref/math-mat-align-explicit-mixed.png differ diff --git a/tests/ref/math-mat-align.png b/tests/ref/math-mat-align.png new file mode 100644 index 000000000..66513dd53 Binary files /dev/null and b/tests/ref/math-mat-align.png differ diff --git a/tests/ref/math-vec-align.png b/tests/ref/math-vec-align.png new file mode 100644 index 000000000..680d0936d Binary files /dev/null and b/tests/ref/math-vec-align.png differ diff --git a/tests/suite/math/mat.typ b/tests/suite/math/mat.typ index 1f6716d7c..baec53eee 100644 --- a/tests/suite/math/mat.typ +++ b/tests/suite/math/mat.typ @@ -92,7 +92,12 @@ $ mat(1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 1) $ // Error: 3-37 cannot draw a vertical line after column 3 of a matrix with 3 columns $ mat(1, 0, 0; 0, 1, 1; augment: #3) $, ---- math-mat-align-explicit--alternating --- +--- math-mat-align --- +$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1; align: #left) $ +$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1; align: #center) $ +$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1; align: #right) $ + +--- math-mat-align-explicit-alternating --- // Test alternating explicit alignment in a matrix. $ mat( "a" & "a a a" & "a a"; @@ -124,6 +129,17 @@ $ mat( "a a a"&, "a"&, "a a a"&; ) $ +--- math-mat-align-explicit-mixed --- +// Test explicit alignment in some columns with align parameter in a matrix. +#let data = ( + ($&18&&.02$, $1$, $+1$), + ($-&9&&.3$, $-1$, $-&21$), + ($&&&.011$, $1$, $&0$) +) +$ #math.mat(align: left, ..data) $ +$ #math.mat(align: center, ..data) $ +$ #math.mat(align: right, ..data) $ + --- math-mat-align-complex --- // Test #460 equations. #let stop = { diff --git a/tests/suite/math/vec.typ b/tests/suite/math/vec.typ index d7bc0b6c0..cf7057f33 100644 --- a/tests/suite/math/vec.typ +++ b/tests/suite/math/vec.typ @@ -4,6 +4,10 @@ #set math.vec(gap: 1em) $ vec(1, 2) $ +--- math-vec-align --- +$ vec(-1, 1, -1, align: #left) + vec(-1, 1, -1, align: #center) + vec(-1, 1, -1, align: #right) $ --- math-vec-align-explicit-alternating --- // Test alternating alignment in a vector.