mirror of
https://github.com/typst/typst
synced 2025-08-12 14:17:55 +08:00
check for conflict between row-pos cells and headers/footers
This commit is contained in:
parent
b950aa579c
commit
4103be5138
@ -1134,6 +1134,34 @@ impl<'a> CellGrid<'a> {
|
||||
|
||||
child_start = new_child_start;
|
||||
child_end = new_child_end;
|
||||
} else {
|
||||
// TODO: Perhaps do this during cell resolving?
|
||||
// This is unnecessary for non-row-positioned cells, as
|
||||
// they skip headers and footers already.
|
||||
if let Some(header) = &header {
|
||||
// TODO: check start (right now zero, always satisfied)
|
||||
if y < header.end {
|
||||
bail!(
|
||||
cell_span,
|
||||
"cell would conflict with header spanning the same position";
|
||||
hint: "try moving the cell or the header"
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some((footer_end, _, footer)) = &footer {
|
||||
// NOTE: y + rowspan >, not >=, footer.start, to
|
||||
// check if the rowspan enters the footer. For example,
|
||||
// rowspan of 1: y + 1 = footer.start means
|
||||
// `y < footer.start`, and it only occupies one row
|
||||
// (`y`), so the cell is safe.
|
||||
if y < *footer_end && y + rowspan > footer.start {
|
||||
bail!(
|
||||
cell_span,
|
||||
"cell would conflict with footer spanning the same position";
|
||||
hint: "try reducing the cell's rowspan or moving the footer"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if largest_index >= resolved_cells.len() {
|
||||
@ -1278,23 +1306,6 @@ impl<'a> CellGrid<'a> {
|
||||
));
|
||||
}
|
||||
|
||||
if is_header || is_footer {
|
||||
// Next automatically positioned cell goes under this header.
|
||||
// FIXME: Consider only doing this if the header has any fully
|
||||
// automatically positioned cells. Otherwise,
|
||||
// `resolve_cell_position` should be smart enough to skip
|
||||
// upcoming headers.
|
||||
// Additionally, consider that cells with just an 'x' override
|
||||
// could end up going too far back and making previous
|
||||
// non-header rows into header rows (maybe they should be
|
||||
// placed at the first row that is fully empty or something).
|
||||
// Nothing we can do when both 'x' and 'y' were overridden, of
|
||||
// course.
|
||||
// None of the above are concerns for now, as headers must
|
||||
// start at the first row.
|
||||
local_auto_index = local_auto_index.max(c * child_end);
|
||||
}
|
||||
|
||||
if !is_row_group {
|
||||
// The child was a single cell outside headers or footers.
|
||||
// Therefore, 'local_auto_index' for this table child was
|
||||
@ -1326,51 +1337,6 @@ impl<'a> CellGrid<'a> {
|
||||
.enumerate()
|
||||
.map(|(i, cell)| {
|
||||
if let Some(cell) = cell {
|
||||
if let Some(parent_cell) = cell.as_cell() {
|
||||
if let Some(header) = &mut header
|
||||
{
|
||||
let y = i / c;
|
||||
if y < header.end {
|
||||
// Ensure the header expands enough such that
|
||||
// all cells inside it, even those added later,
|
||||
// are fully contained within the header.
|
||||
// FIXME: check if start < y < end when start can
|
||||
// be != 0.
|
||||
// FIXME: when start can be != 0, decide what
|
||||
// happens when a cell after the header placed
|
||||
// above it tries to span the header (either
|
||||
// error or expand upwards).
|
||||
header.end = header.end.max(y + parent_cell.rowspan.get());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((end, footer_span, footer)) = &mut footer {
|
||||
let x = i % c;
|
||||
let y = i / c;
|
||||
let cell_end = y + parent_cell.rowspan.get();
|
||||
if y < footer.start && cell_end > footer.start {
|
||||
// Don't allow a cell before the footer to span
|
||||
// it. Surely, we could move the footer to
|
||||
// start at where this cell starts, so this is
|
||||
// more of a design choice, as it's unlikely
|
||||
// for the user to intentionally include a cell
|
||||
// before the footer spanning it but not
|
||||
// being repeated with it.
|
||||
bail!(
|
||||
*footer_span,
|
||||
"footer would conflict with a cell placed before it at column {x} row {y}";
|
||||
hint: "try reducing that cell's rowspan or moving the footer"
|
||||
);
|
||||
}
|
||||
if y >= footer.start && y < *end {
|
||||
// Expand the footer to include all rows
|
||||
// spanned by this cell, as it is inside the
|
||||
// footer.
|
||||
*end = (*end).max(cell_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(cell)
|
||||
} else {
|
||||
let x = i % c;
|
||||
@ -1533,10 +1499,6 @@ impl<'a> CellGrid<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if header_end.is_some_and(|header_end| header_end > footer.start) {
|
||||
bail!(footer_span, "header and footer must not have common rows");
|
||||
}
|
||||
|
||||
Ok(footer)
|
||||
})
|
||||
.transpose()?
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 365 B |
BIN
tests/ref/grid-footer-moved-to-bottom-of-rowspans.png
Normal file
BIN
tests/ref/grid-footer-moved-to-bottom-of-rowspans.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB |
@ -95,12 +95,28 @@
|
||||
grid.cell(x: 1)[c]
|
||||
)
|
||||
|
||||
--- grid-footer-expand ---
|
||||
// Ensure footer properly expands
|
||||
--- grid-footer-no-expand ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
[a], [],
|
||||
[b], [],
|
||||
fill: (_, y) => if calc.odd(y) { blue } else { red },
|
||||
inset: 5pt,
|
||||
grid.cell(x: 1, y: 3, rowspan: 4)[b],
|
||||
grid.cell(y: 2, rowspan: 2)[a],
|
||||
grid.footer(),
|
||||
// Error: 3-33 cell would conflict with footer spanning the same position
|
||||
// Hint: 3-33 try reducing the cell's rowspan or moving the footer
|
||||
grid.cell(y: 6, rowspan: 2)[d],
|
||||
)
|
||||
|
||||
--- grid-footer-moved-to-bottom-of-rowspans ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
[a], [],
|
||||
[b], [],
|
||||
stroke: red,
|
||||
inset: 5pt,
|
||||
grid.cell(x: 1, y: 3, rowspan: 4)[b],
|
||||
grid.cell(y: 2, rowspan: 2)[a],
|
||||
grid.footer(),
|
||||
@ -125,13 +141,13 @@
|
||||
)
|
||||
|
||||
--- grid-footer-overlap ---
|
||||
// Error: 4:3-4:19 footer would conflict with a cell placed before it at column 1 row 0
|
||||
// Hint: 4:3-4:19 try reducing that cell's rowspan or moving the footer
|
||||
#grid(
|
||||
columns: 2,
|
||||
grid.header(),
|
||||
grid.footer([a]),
|
||||
grid.cell(x: 1, y: 0, rowspan: 2)[a],
|
||||
grid.footer(grid.cell(y: 2)[a]),
|
||||
// Error: 3-39 cell would conflict with footer spanning the same position
|
||||
// Hint: 3-39 try reducing the cell's rowspan or moving the footer
|
||||
grid.cell(x: 1, y: 1, rowspan: 2)[a],
|
||||
)
|
||||
|
||||
--- grid-footer-multiple ---
|
||||
@ -386,8 +402,8 @@
|
||||
table.hline(stroke: red),
|
||||
table.vline(stroke: green),
|
||||
[b],
|
||||
[c]
|
||||
),
|
||||
table.cell(x: 1, y: 3)[c]
|
||||
)
|
||||
|
||||
--- grid-footer-hline-and-vline-2 ---
|
||||
|
@ -284,8 +284,7 @@
|
||||
)
|
||||
#context count.display()
|
||||
|
||||
--- grid-header-expand ---
|
||||
// Ensure header expands to fit cell placed in it after its declaration
|
||||
--- grid-header-no-expand ---
|
||||
#set page(height: 10em)
|
||||
#table(
|
||||
columns: 2,
|
||||
@ -293,6 +292,8 @@
|
||||
[a], [b],
|
||||
[c],
|
||||
),
|
||||
// Error: 3-48 cell would conflict with header spanning the same position
|
||||
// Hint: 3-48 try moving the cell or the header
|
||||
table.cell(x: 1, y: 1, rowspan: 2, lorem(80))
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user