Small fixes for table line priority in headers/footers (#3602)

This commit is contained in:
PgBiel 2024-03-11 07:24:51 -03:00 committed by GitHub
parent c29db5f27e
commit 288f7da4d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 105 additions and 19 deletions

View File

@ -1731,21 +1731,44 @@ impl<'a> GridLayouter<'a> {
})
.unwrap_or(LinePosition::Before);
// FIXME: In the future, directly specify in 'self.rrows' when
// we place a repeated header rather than its original rows.
// That would let us remove most of those verbose checks, both
// in 'lines.rs' and here. Those checks also aren't fully
// accurate either, since they will also trigger when some rows
// have been removed between the header and what's below it.
let is_under_repeated_header = self
.grid
.header
.as_ref()
.and_then(Repeatable::as_repeated)
.zip(prev_y)
.is_some_and(|(header, prev_y)| {
// Note: 'y == header.end' would mean we're right below
// the NON-REPEATED header, so that case should return
// false.
prev_y < header.end && y > header.end
});
// If some grid rows were omitted between the previous resolved
// row and the current one, we ensure lines below the previous
// row don't "disappear" and are considered, albeit with less
// priority. However, don't do this when we're below a header,
// as it must have more priority instead of less, so it is
// chained later instead of before.
// chained later instead of before. The exception is when the
// last row in the header is removed, in which case we append
// both the lines under the row above us and also (later) the
// lines under the header's (removed) last row.
let prev_lines = prev_y
.filter(|prev_y| {
prev_y + 1 != y
&& !self
.grid
.header
.as_ref()
.and_then(Repeatable::as_repeated)
.is_some_and(|header| prev_y + 1 == header.end)
&& (!is_under_repeated_header
|| self
.grid
.header
.as_ref()
.and_then(Repeatable::as_repeated)
.is_some_and(|header| prev_y + 1 != header.end))
})
.map(|prev_y| get_hlines_at(prev_y + 1))
.unwrap_or(&[]);
@ -1765,15 +1788,16 @@ impl<'a> GridLayouter<'a> {
&[]
};
// The header lines, if any, will correspond to the lines under
// the previous row, so they function similarly to 'prev_lines'.
let expected_header_line_position = expected_prev_line_position;
let mut expected_header_line_position = LinePosition::Before;
let header_hlines = if let Some((Repeatable::Repeated(header), prev_y)) =
self.grid.header.as_ref().zip(prev_y)
{
if prev_y + 1 != y
&& prev_y + 1 == header.end
&& !self.grid.has_gutter
if is_under_repeated_header
&& (!self.grid.has_gutter
|| matches!(
self.grid.rows[prev_y],
Sizing::Rel(length) if length.is_zero()
))
{
// For lines below a header, give priority to the
// lines originally below the header rather than
@ -1783,10 +1807,18 @@ impl<'a> GridLayouter<'a> {
// lines being normally laid out then will be
// precisely the lines below the header.
//
// Additionally, we don't append header lines when
// gutter is enabled, since, in that case, there will
// be a gutter row between header and content, so no
// lines should overlap.
// Additionally, we don't repeat lines above the row
// below the header when gutter is enabled, since, in
// that case, there will be a gutter row between header
// and content, so no lines should overlap. The
// exception is when the gutter at the end of the
// header has a size of zero, which happens when only
// column-gutter is specified, for example. In that
// case, we still repeat the line under the gutter.
expected_header_line_position = expected_line_position(
header.end,
header.end == self.grid.rows.len(),
);
get_hlines_at(header.end)
} else {
&[]

View File

@ -547,7 +547,7 @@ pub(super) fn hline_stroke_at_column(
// Ensure the row above us is a repeated header.
// FIXME: Make this check more robust when headers at arbitrary
// positions are added.
local_top_y + 1 == header.end && y != header.end
local_top_y < header.end && y > header.end
});
// Prioritize the footer's top stroke as well where applicable.
@ -559,7 +559,7 @@ pub(super) fn hline_stroke_at_column(
// Ensure the row below us is a repeated footer.
// FIXME: Make this check more robust when footers at arbitrary
// positions are added.
local_top_y.unwrap_or(0) + 1 != footer.start && y == footer.start
local_top_y.unwrap_or(0) + 1 < footer.start && y >= footer.start
});
let (prioritized_cell_stroke, deprioritized_cell_stroke) =

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -26,3 +26,16 @@
gutter: 3pt,
table.footer[a][b][c]
)
---
// Test footer stroke priority edge case
#set page(height: 10em)
#table(
columns: 2,
stroke: black,
..(table.cell(stroke: aqua)[d],) * 8,
table.footer(
table.cell(rowspan: 2, colspan: 2)[a],
[c], [d]
)
)

View File

@ -56,3 +56,44 @@
),
[a\ b]
)
---
// Test header stroke priority edge case (last header row removed)
#set page(height: 8em)
#table(
columns: 2,
stroke: black,
gutter: (auto, 3pt),
table.header(
[c], [d],
),
..(table.cell(stroke: aqua)[d],) * 8,
)
---
// Yellow line should be kept here
#set text(6pt)
#table(
column-gutter: 3pt,
inset: 1pt,
table.header(
[a],
table.hline(stroke: yellow),
),
table.cell(rowspan: 2)[b]
)
---
// Red line should be kept here
#set page(height: 6em)
#set text(6pt)
#table(
column-gutter: 3pt,
inset: 1pt,
table.header(
table.hline(stroke: red, position: bottom),
[a],
),
[a],
table.cell(stroke: aqua)[b]
)