From 38ada8121ea2a76720bb7188940d1d9d4b0a1c1d Mon Sep 17 00:00:00 2001 From: bptato Date: Wed, 20 Sep 2023 12:08:18 +0200 Subject: layout: fix table cell sizing with specified widths Say we have a table
a
aklsdfjaskdfjkl
This should be 20 pixels wide, not as wide as the second row. Also, larger specified widths now always override previous widths specified on the column. (I think this was a regression, but the previous solution to this problem was an ugly hack.) --- src/layout/box.nim | 1 - src/layout/engine.nim | 77 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/layout/box.nim b/src/layout/box.nim index 42701449..4f5eb84d 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -185,7 +185,6 @@ type ColumnContext* = object minwidth*: LayoutUnit - maxwidth*: LayoutUnit width*: LayoutUnit wspecified*: bool weight*: float64 diff --git a/src/layout/engine.nim b/src/layout/engine.nim index cb2bc4ac..46ffff0c 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -671,31 +671,34 @@ proc calcAvailableSizes(box: BlockBox, containingWidth, containingHeight: box.calcAvailableHeight(containingHeight, percHeight) proc calcTableCellAvailableSizes(box: BlockBox, availableWidth, availableHeight: - SizeConstraint) = + SizeConstraint, override: bool) = let viewport = box.viewport let computed = box.computed box.resolvePadding(availableWidth, viewport) box.availableWidth = availableWidth box.availableHeight = availableHeight - let width = computed{"width"} - if not width.auto and width.unit != UNIT_PERC: - box.availableWidth = stretch(width.px(viewport)) + if not override: + let width = computed{"width"} + if not width.auto and width.unit != UNIT_PERC: + box.availableWidth = stretch(width.px(viewport)) box.availableWidth.u -= box.padding_left box.availableWidth.u -= box.padding_right - let height = computed{"height"} - if not height.auto and height.unit != UNIT_PERC: - box.availableHeight = stretch(height.px(viewport)) + if not override: + let height = computed{"height"} + if not height.auto and height.unit != UNIT_PERC: + box.availableHeight = stretch(height.px(viewport)) proc newTableCellBox(viewport: Viewport, builder: BoxBuilder, - availableWidth, availableHeight: SizeConstraint): BlockBox = + availableWidth, availableHeight: SizeConstraint, override: bool): + BlockBox = let box = BlockBox( viewport: viewport, computed: builder.computed, node: builder.node ) - box.calcTableCellAvailableSizes(availableWidth, availableHeight) + box.calcTableCellAvailableSizes(availableWidth, availableHeight, override) return box proc newFlowRootBox(viewport: Viewport, builder: BoxBuilder, @@ -1130,9 +1133,10 @@ proc buildTableCaption(viewport: Viewport, builder: TableCaptionBoxBuilder, return box proc buildTableCell(viewport: Viewport, builder: TableCellBoxBuilder, - availableWidth, availableHeight: SizeConstraint): BlockBox = + availableWidth, availableHeight: SizeConstraint, override: bool): + BlockBox = let tableCell = viewport.newTableCellBox(builder, availableWidth, - availableHeight) + availableHeight, override) tableCell.buildLayout(builder) return tableCell @@ -1195,7 +1199,9 @@ proc preBuildTableRow(pctx: var TableContext, box: TableRowBoxBuilder, else: maxContent() #TODO specified table height should be distributed among rows. - let box = parent.viewport.buildTableCell(cellbuilder, cw, maxContent()) + # Allow the table cell to use its specified width. + let box = parent.viewport.buildTableCell(cellbuilder, cw, maxContent(), + override = false) let wrapper = CellWrapper( box: box, builder: cellbuilder, @@ -1216,11 +1222,35 @@ proc preBuildTableRow(pctx: var TableContext, box: TableRowBoxBuilder, for i in n ..< n + colspan: # Add spacing. ctx.width += pctx.inlinespacing - pctx.cols[i].maxwidth = w - if pctx.cols[i].width < w: - pctx.cols[i].width = w - if ctx.reflow.len <= i: ctx.reflow.setLen(i + 1) - ctx.reflow[i] = true + # Figure out this cell's effect on the column's width. + # Four cases exits: + # 1. colwidth already fixed, cell width is fixed: take maximum + # 2. colwidth already fixed, cell width is auto: take colwidth + # 3. colwidth is not fixed, cell width is fixed: take cell width + # 4. neither of colwidth or cell width are fixed: take maximum + if ctx.reflow.len <= i: ctx.reflow.setLen(i + 1) + if pctx.cols[i].wspecified: + if not computedWidth.auto and computedWidth.unit != UNIT_PERC: + let ww = computedWidth.px(parent.viewport) + # A specified column already exists; we take the larger width. + if ww > pctx.cols[i].width: + pctx.cols[i].width = ww + ctx.reflow[i] = true + else: + if pctx.cols[i].width < w: + wrapper.reflow = true + else: + if not computedWidth.auto and computedWidth.unit != UNIT_PERC: + let ww = computedWidth.px(parent.viewport) + # This is the first specified column. Replace colwidth with whatever + # we have. + ctx.reflow[i] = true + pctx.cols[i].wspecified = true + pctx.cols[i].width = ww + else: + if pctx.cols[i].width < w: + pctx.cols[i].width = w + ctx.reflow[i] = true if not computedWidth.auto and computedWidth.unit != UNIT_PERC: let ww = computedWidth.px(parent.viewport) if pctx.cols[i].wspecified: @@ -1280,8 +1310,19 @@ proc buildTableRow(pctx: TableContext, ctx: RowContext, parent: BlockBox, # Add inline spacing for merged columns. w += pctx.inlinespacing * (cellw.colspan - 1) * 2 if cellw.reflow and cellw.builder != nil: + # Do not allow the table cell to make use of its specified width. + # e.g. in the following table + # + # + # + # + # + # + # + #
5ch
9ch
+ # the TD with a width of 5ch should be 9ch wide as well. cellw.box = parent.viewport.buildTableCell(cellw.builder, stretch(w), - maxContent()) + maxContent(), override = true) w = max(w, cellw.box.width) let cell = cellw.box x += pctx.inlinespacing -- cgit 1.4.1-2-gfad0