From 3d7a289334b56f39a7b8a5bc005735e0b6484537 Mon Sep 17 00:00:00 2001 From: siddhantdev Date: Tue, 4 Feb 2025 16:34:58 +0530 Subject: [PATCH] Allow augment line at the beginning and end of a matrix Allows augment lines at the begginnig and end of a matrix. Augment 0 draws a line before the first column/row and augment n draws a line after the last column/row of a matrix with n columns/rows. -1 now draws a line after the last column/row of the matrix, not before it. --- crates/typst-layout/src/math/mat.rs | 57 ++++++++++++++++++++-------- tests/ref/math-mat-augment.png | Bin 3563 -> 12445 bytes tests/suite/math/mat.typ | 10 ++++- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/crates/typst-layout/src/math/mat.rs b/crates/typst-layout/src/math/mat.rs index 4a897a03e..5121f4475 100644 --- a/crates/typst-layout/src/math/mat.rs +++ b/crates/typst-layout/src/math/mat.rs @@ -87,7 +87,7 @@ pub fn layout_mat( let augment = elem.augment.resolve(styles); if let Some(aug) = &augment { for &offset in &aug.hline.0 { - if offset == 0 || offset.unsigned_abs() >= rows.len() { + if offset > rows.len() as isize || offset.unsigned_abs() > rows.len() + 1 { bail!( span, "cannot draw a horizontal line after row {} of a matrix with {} rows", @@ -98,7 +98,7 @@ pub fn layout_mat( } for &offset in &aug.vline.0 { - if offset == 0 || offset.unsigned_abs() >= ncols { + if offset > ncols as isize || offset.unsigned_abs() > ncols + 1 { bail!( span, "cannot draw a vertical line after column {} of a matrix with {} columns", @@ -165,7 +165,7 @@ fn layout_body( ..Default::default() }; - let (hline, vline, stroke) = match augment { + let (mut hline, mut vline, stroke) = match augment { Some(augment) => { // We need to get stroke here for ownership. let stroke = augment.stroke.unwrap_or_default().unwrap_or(default_stroke); @@ -216,20 +216,48 @@ fn layout_body( } } + for line in hline.0.iter_mut() { + if *line < 0 { + *line += (nrows as isize) + 1 + } + } + + for line in vline.0.iter_mut() { + if *line < 0 { + *line += (ncols as isize) + 1 + } + } + // For each row, combine maximum ascent and descent into a row height. // Sum the row heights, then add the total height of the gaps between rows. - let total_height = + let mut total_height = heights.iter().map(|&(a, b)| a + b).sum::() + gap.y * (nrows - 1) as f64; + if hline.0.contains(&0_isize) { + total_height += gap.y; + } + + if hline.0.contains(&(nrows as isize)) { + total_height += gap.y; + } + // Width starts at zero because it can't be calculated until later let mut frame = Frame::soft(Size::new(Abs::zero(), total_height)); let mut x = Abs::zero(); + if vline.0.contains(&(0_isize)) { + frame.push( + Point::with_x(x + half_gap.x), + line_item(total_height, true, stroke.clone(), span), + ); + x += gap.x; + } + for (index, col) in cols.into_iter().enumerate() { let AlignmentResult { points, width: rcol } = alignments(&col); - let mut y = Abs::zero(); + let mut y = if hline.0.contains(&0_isize) { gap.y } else { Abs::zero() }; for (cell, &(ascent, descent)) in col.into_iter().zip(&heights) { let cell = cell.into_line_frame(&points, alternator); @@ -251,9 +279,7 @@ fn layout_body( x += rcol; // If a vertical line should be inserted after this column - if vline.0.contains(&(index as isize + 1)) - || vline.0.contains(&(1 - ((ncols - index) as isize))) - { + if vline.0.contains(&(index as isize + 1)) { frame.push( Point::with_x(x + half_gap.x), line_item(total_height, true, stroke.clone(), span), @@ -264,16 +290,17 @@ fn layout_body( x += gap.x; } - // Once all the columns are laid out, the total width can be calculated - let total_width = x - gap.x; + let total_width = if !(vline.0.contains(&(ncols as isize))) { x - gap.x } else { x }; // This allows the horizontal lines to be laid out for line in hline.0 { - let real_line = - if line < 0 { nrows - line.unsigned_abs() } else { line as usize }; - let offset = (heights[0..real_line].iter().map(|&(a, b)| a + b).sum::() - + gap.y * (real_line - 1) as f64) - + half_gap.y; + let offset = if line == 0 { + gap.y + } else { + (heights[0..line as usize].iter().map(|&(a, b)| a + b).sum::() + + gap.y * (line - 1) as f64) + + half_gap.y + }; frame.push( Point::with_y(offset), diff --git a/tests/ref/math-mat-augment.png b/tests/ref/math-mat-augment.png index 306c4b1995f82e367be5442de9253dd9ae69e78e..cede2100873483044463bcefae5408a503a2cdff 100644 GIT binary patch literal 12445 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%0DVZf$i;0-loP=Q;YzoUpX_%x3|enX5!i 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 E1JS7rGXMYp literal 3563 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