Compare commits

..

3 Commits

Author SHA1 Message Date
PgBiel
54443a67c2 move top hline state to row group data 2025-03-12 21:54:15 -03:00
PgBiel
88d72a8689 improve variable names in new_internal 2025-03-12 21:41:48 -03:00
PgBiel
f1eadf7323 top hlines attach to the top of row groups 2025-03-12 21:14:32 -03:00
4 changed files with 96 additions and 11 deletions

View File

@ -671,14 +671,14 @@ impl<'a> CellGrid<'a> {
let mut rows = vec![]; let mut rows = vec![];
// Number of content columns: Always at least one. // Number of content columns: Always at least one.
let columns = tracks.x.len().max(1); let num_cols = tracks.x.len().max(1);
// Number of content rows: At least as many as given, but also at least // Number of content rows: At least as many as given, but also at least
// as many as needed to place each item. // as many as needed to place each item.
let r = { let num_rows = {
let len = entries.len(); let len = entries.len();
let given = tracks.y.len(); let given = tracks.y.len();
let needed = len / columns + (len % columns).clamp(0, 1); let needed = len / num_cols + (len % num_cols).clamp(0, 1);
given.max(needed) given.max(needed)
}; };
@ -690,7 +690,7 @@ impl<'a> CellGrid<'a> {
}; };
// Collect content and gutter columns. // Collect content and gutter columns.
for x in 0..columns { for x in 0..num_cols {
cols.push(get_or(tracks.x, x, auto)); cols.push(get_or(tracks.x, x, auto));
if has_gutter { if has_gutter {
cols.push(get_or(gutter.x, x, zero)); cols.push(get_or(gutter.x, x, zero));
@ -698,7 +698,7 @@ impl<'a> CellGrid<'a> {
} }
// Collect content and gutter rows. // Collect content and gutter rows.
for y in 0..r { for y in 0..num_rows {
rows.push(get_or(tracks.y, y, auto)); rows.push(get_or(tracks.y, y, auto));
if has_gutter { if has_gutter {
rows.push(get_or(gutter.y, y, zero)); rows.push(get_or(gutter.y, y, zero));
@ -936,6 +936,27 @@ struct RowGroupData {
range: Option<Range<usize>>, range: Option<Range<usize>>,
span: Span, span: Span,
kind: RowGroupKind, kind: RowGroupKind,
/// Start of the range of indices of hlines at the top of the row group.
/// This is always the first index after the last hline before we started
/// building the row group - any upcoming hlines would appear at least at
/// this index.
///
/// These hlines were auto-positioned and appeared before any auto-pos
/// cells, so they will appear at the first possible row (above the
/// first row spanned by the row group).
top_hlines_start: usize,
/// End of the range of indices of hlines at the top of the row group.
///
/// This starts as `None`, meaning that, if we stop the loop before we find
/// any auto-pos cells, all auto-pos hlines after the last hline (after the
/// index `top_hlines_start`) should be moved to the top of the row group.
///
/// It becomes `Some(index of last hline at the top)` when an auto-pos cell
/// is found, as auto-pos hlines after any auto-pos cells appear below
/// them, not at the top of the row group.
top_hlines_end: Option<usize>,
} }
impl<'x> CellGridResolver<'_, '_, 'x> { impl<'x> CellGridResolver<'_, '_, 'x> {
@ -1107,8 +1128,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
bail!(span, "cannot have more than one header"); bail!(span, "cannot have more than one header");
} }
row_group_data = row_group_data = Some(RowGroupData {
Some(RowGroupData { range: None, span, kind: RowGroupKind::Header }); range: None,
span,
kind: RowGroupKind::Header,
top_hlines_start: pending_hlines.len(),
top_hlines_end: None,
});
*repeat_header = repeat; *repeat_header = repeat;
@ -1133,8 +1159,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
bail!(span, "cannot have more than one footer"); bail!(span, "cannot have more than one footer");
} }
row_group_data = row_group_data = Some(RowGroupData {
Some(RowGroupData { range: None, span, kind: RowGroupKind::Footer }); range: None,
span,
kind: RowGroupKind::Footer,
top_hlines_start: pending_hlines.len(),
top_hlines_end: None,
});
*repeat_footer = repeat; *repeat_footer = repeat;
@ -1301,8 +1332,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
// Cell's header or footer must expand to include the cell's // Cell's header or footer must expand to include the cell's
// occupied positions, if possible. // occupied positions, if possible.
if let Some(RowGroupData { range: group_range, kind, .. }) = if let Some(RowGroupData {
&mut row_group_data range: group_range, kind, top_hlines_end, ..
}) = &mut row_group_data
{ {
*group_range = Some( *group_range = Some(
expand_row_group( expand_row_group(
@ -1316,6 +1348,14 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
) )
.at(cell_span)?, .at(cell_span)?,
); );
if top_hlines_end.is_none()
&& local_auto_index > first_available_row * columns
{
// Auto index was moved, so upcoming auto-pos hlines should
// no longer appear at the top.
*top_hlines_end = Some(pending_hlines.len());
}
} }
// Let's resolve the cell so it can determine its own fields // Let's resolve the cell so it can determine its own fields
@ -1428,6 +1468,19 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
} }
}; };
let top_hlines_end = row_group.top_hlines_end.unwrap_or(pending_hlines.len());
for (_, top_hline, has_auto_y) in pending_hlines
.get_mut(row_group.top_hlines_start..top_hlines_end)
.unwrap_or(&mut [])
{
if *has_auto_y {
// Move this hline to the top of the child, as it was
// placed before the first automatically positioned cell
// and had an automatic index.
top_hline.index = group_range.start;
}
}
match row_group.kind { match row_group.kind {
RowGroupKind::Header => { RowGroupKind::Header => {
if group_range.start != 0 { if group_range.start != 0 {

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

View File

@ -437,6 +437,38 @@
) )
) )
--- grid-footer-top-hlines-with-only-row-pos-cell ---
// Top hlines should attach to the top of the footer.
#set page(margin: 2pt)
#set text(6pt)
#table(
columns: 3,
inset: 2.5pt,
table.footer(
table.hline(stroke: red),
table.vline(stroke: blue),
table.cell(x: 2, y: 2)[a],
table.hline(stroke: 3pt),
table.vline(stroke: 3pt),
)
)
--- grid-footer-top-hlines-with-row-and-auto-pos-cell ---
#set page(margin: 2pt)
#set text(6pt)
#table(
columns: 3,
inset: 2.5pt,
table.footer(
table.hline(stroke: red),
table.vline(stroke: blue),
table.cell(x: 2, y: 2)[a],
[b],
table.hline(stroke: 3pt),
table.vline(stroke: 3pt),
)
)
--- grid-footer-below-rowspans --- --- grid-footer-below-rowspans ---
// Footer should go below the rowspans. // Footer should go below the rowspans.
#set page(margin: 2pt) #set page(margin: 2pt)