-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Repeatable Table Headers [More Flexible Tables Pt.5a] #3545
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
482c11c
to
a2ebe32
Compare
Relevant for rowspans with full colspan spanning multiple auto rows (the first N - 1 will be empty and removed)
I've added a fix for a small bug I found while, well, pondering about things. :P Turns out lines above empty auto rows were being ignored since the auto rows were removed. Now they are still considered, but have less priority than lines above whatever is below. |
Needs merge/rebase for status checks to be okay again. |
Doesn't matter much right now since headers always start at the first row, but doing this mostly for correctness
- Delay gutter adjustment for header end index - Cells always check if they are in a header, if so expand it
- Ensure rowspans aren't laid out through the same rows twice - Ensure multi-page auto rows cause previous rowspans to be laid out even at their first regions
- It only checked if there were '(amount of header rows)' rows or less in the region to determine if the header was an orphan. The problem is that empty auto rows are omitted, so the header can have less rows than 'header.end'. Now, we just check if the last row is a header. If so, no other rows were laid out.
- We were enumerating since the start of all regions, not since the first region spanned by the rowspan. Therefore, the rowspan wouldn't apply its `dy` correctly, only in the first page of the entire table.
- Line position filtering has been moved to 'render_fills_strokes'
Alright, turns out there were several little logic bugs I could think of. There could perhaps be more, but in principle the most relevant ones should be gone. We can probably figure the rest out during testing. |
Safer alternative in case a header row is removed
Ready. 👍 |
Great, thank you! |
Allows specifying a
grid.header
andtable.header
to have some rows repeat across a grid's or table's pages.NOTE: This PR depends on #3501, so the PR diff is larger than it really is; as such, here is the link to the real diff: PgBiel/typst@rowspans...PgBiel:typst:repeatable-headers(EDIT: PR rebased!)First part of the fifth task in #3001. Closes #400 (as the initially desired feature set is available), although more header features are intended to be added over time.
For now, a header may only start at the top of the table, and end at its last page.
User-facing API
table.header
andgrid.header
to place a repeatable header in your grid or table. It will repeat across pages.table.header(repeat: false, ...)
to not repeat it, though that's generally not very useful (other than for organizational purposes), so the default isrepeat: true
.Without gutter:
With gutter:
Implementation details
The implementation is actually rather simple (compared to other PRs, such as rowspans - that one was very complex). Here are the most important tricks I used for layout:
Header
struct inCellGrid
. It currently only contains where the header stops, since the header always starts aty == 0
.finish_region
, we calllayout_header
, which will layout, for the next region, each individual header row as an unbreakable row group, and thus calculate the header height for the current region.layout_header
will usesimulate_header
(which just callssimulate_unbreakable_row_group
from the rowspans PR) to calculate the header height and skip to the first fitting region.finish_region
).self.regions.in_last()
is true, currently. In this PR, however, I created a newin_last_with_offset
function. It's very similar to the former, but instead of checking if we're in theregions.last
region and all the full height is remaining, we check iffull height - header height
is remaining, since skipping a region will always add a header to the top. So, if we're at the last region and there's just the header above us, we stop skipping.prepare_auto_row_cell_measurement
, where we prepare the information needed to construct thepod
, we now useself.regions.map
to modify the backlog and the last region by subtracting the current header height from both. This makes sure cells in breakable auto rows won't overlap with the header.Regions::next
to automatically subtract an automatically-calculated header height from the new region size and not change the value offull
, which is probably more technically appropriate, but I didn't take this approach not only to keep the implementation simple, but also becausefull
is already reduced when we're effectively laying out the rowspan, so it wouldn't make much of a difference in practice, other than through possibly very unusual setups. We can always change this in a future update as users give their feedback.And that's it!
Other details
Grid/TableChild
to accept both headers andGrid/TableItem
(the old children); headers can contain items too (but not other headers, of course - there are helpful errors for that). InCellGrid::resolve
, there are now two for loops - one for children and one for items inside the children (if the child is a header, then one child iteration will correspond to N item iterations (inside the header); if the child is a single item, then there's only a single item iteration, and everything behaves as usual).