diff options
author | bptato <nincsnevem662@gmail.com> | 2022-11-15 17:47:58 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-11-15 17:47:58 +0100 |
commit | 86d05a993463b49d2bd9cc6cb6a7af9b416f802a (patch) | |
tree | 446c75a668695abc341bc32f2d5e21b7edbd8e4f /src | |
parent | b00b6a1e1cc6d74bb0b76218ddb4dcf37bef7ac7 (diff) | |
download | chawan-86d05a993463b49d2bd9cc6cb6a7af9b416f802a.tar.gz |
Very much WIP table implementation
Diffstat (limited to 'src')
-rw-r--r-- | src/css/values.nim | 18 | ||||
-rw-r--r-- | src/layout/box.nim | 2 | ||||
-rw-r--r-- | src/layout/engine.nim | 112 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 11 |
4 files changed, 124 insertions, 19 deletions
diff --git a/src/css/values.nim b/src/css/values.nim index c3050eae..fcd8e068 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -450,15 +450,15 @@ func cssDisplay(d: CSSDeclaration): CSSDisplay = of "inline": return DISPLAY_INLINE of "list-item": return DISPLAY_LIST_ITEM of "inline-block": return DISPLAY_INLINE_BLOCK - # of "table": return DISPLAY_TABLE - # of "table-row": return DISPLAY_TABLE_ROW - # of "table-cell": return DISPLAY_TABLE_CELL - # of "table-column": return DISPLAY_TABLE_COLUMN - # of "table-column-group": return DISPLAY_TABLE_COLUMN_GROUP - # of "inline-table": return DISPLAY_INLINE_TABLE - # of "table-row-group": return DISPLAY_TABLE_ROW_GROUP - # of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP - # of "table-footer-group": return DISPLAY_TABLE_FOOTER_GROUP + of "table": return DISPLAY_TABLE + of "table-row": return DISPLAY_TABLE_ROW + of "table-cell": return DISPLAY_TABLE_CELL + of "table-column": return DISPLAY_TABLE_COLUMN + of "table-column-group": return DISPLAY_TABLE_COLUMN_GROUP + of "inline-table": return DISPLAY_INLINE_TABLE + of "table-row-group": return DISPLAY_TABLE_ROW_GROUP + of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP + of "table-footer-group": return DISPLAY_TABLE_FOOTER_GROUP of "none": return DISPLAY_NONE else: return DISPLAY_INLINE raise newException(CSSValueError, "Invalid display") diff --git a/src/layout/box.nim b/src/layout/box.nim index 2db2a78a..61e64ee0 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -53,6 +53,7 @@ type TableRowBoxBuilder* = ref object of BoxBuilder TableCellBoxBuilder* = ref object of BoxBuilder + colspan*: int TableBoxBuilder* = ref object of BlockBoxBuilder rowgroups*: seq[TableRowGroupBoxBuilder] @@ -136,6 +137,7 @@ type TableRowBox* = ref object of BlockBox TableBox* = ref object of BlockBox + columns*: seq[int] # offset of each column InlineBlockBox* = ref object of InlineAtom bctx*: BlockBox diff --git a/src/layout/engine.nim b/src/layout/engine.nim index a51c4c55..b5365184 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -639,25 +639,47 @@ proc buildTableCell(box: TableCellBoxBuilder, parent: TableRowBox): TableCellBox result.buildInlineLayout(box.children) else: result.buildBlockLayout(box.children, box.node) + result.offset.x += parent.width proc buildTableRow(box: TableRowBoxBuilder, parent: TableBox): TableRowBox = result = parent.newTableRowBox(box) + var n = 0 for child in box.children: case child.computed{"display"} of DISPLAY_TABLE_CELL: - result.nested.add(buildTableCell(TableCellBoxBuilder(child), result)) + let cellbuilder = TableCellBoxBuilder(child) + let cell = buildTableCell(cellbuilder, result) + result.nested.add(cell) + result.height = max(result.height, cell.height) + if parent.columns.len <= n: + parent.columns.setLen(n + 1) + parent.columns[n] = max(cell.width, parent.columns[n]) + var i = n + n += cellbuilder.colspan + if parent.columns.len <= n: + parent.columns.setLen(n + 1) + while i < n: + result.width += parent.columns[i] + inc i else: - discard - #TODO assert false + assert false + result.offset.y += parent.height proc buildTable(box: TableBoxBuilder, parent: BlockBox): TableBox = result = parent.newTableBox(box) for child in box.children: case child.computed{"display"} of DISPLAY_TABLE_ROW: - result.nested.add(buildTableRow(TableRowBoxBuilder(child), result)) + let row = buildTableRow(TableRowBoxBuilder(child), result) + result.nested.add(row) + result.height += row.height + result.width = max(row.width, result.width) of DISPLAY_TABLE_ROW_GROUP: - discard + for child in TableRowGroupBoxBuilder(child).children: + let row = buildTableRow(TableRowBoxBuilder(child), result) + result.nested.add(row) + result.height += row.height + result.width = max(row.width, result.width) else: discard #TODO assert false @@ -748,6 +770,7 @@ proc getTableRowBox(computed: CSSComputedValues): TableRowBoxBuilder = proc getTableCellBox(computed: CSSComputedValues): TableCellBoxBuilder = new(result) result.computed = computed + result.colspan = 1 type BlockGroup = object parent: BoxBuilder @@ -782,6 +805,7 @@ proc newBlockGroup(parent: BoxBuilder): BlockGroup = result.listItemCounter = 1 proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuilder +proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport): TableRowGroupBoxBuilder proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBoxBuilder proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCellBoxBuilder @@ -830,6 +854,10 @@ proc generateFromElem(styledNode: StyledNode, blockgroup: var BlockGroup, viewpo blockgroup.flush() let childbox = styledNode.generateTableRowBox(viewport) box.children.add(childbox) + of DISPLAY_TABLE_ROW_GROUP: + blockgroup.flush() + let childbox = styledNode.generateTableRowGroupBox(viewport) + box.children.add(childbox) of DISPLAY_TABLE_CELL: blockgroup.flush() let childbox = styledNode.generateTableCellBox(viewport) @@ -909,10 +937,13 @@ func isMisparented(box: BoxBuilder, parent: BoxBuilder): bool = proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCellBoxBuilder = let box = getTableCellBox(styledNode.computed) + if styledNode.node != nil and styledNode.node.nodeType == ELEMENT_NODE: + box.colspan = Element(styledNode.node).attri("colspan").get(1) var blockgroup = newBlockGroup(box) var ibox: InlineBoxBuilder = nil for child in styledNode.children: if child.t == STYLED_ELEMENT: + flush_ibox generateFromElem(child, blockgroup, viewport, ibox) else: if canGenerateAnonymousInline(blockgroup, box.computed, child.text): @@ -920,8 +951,29 @@ proc generateTableCellBox(styledNode: StyledNode, viewport: Viewport): TableCell ibox = getTextBox(styledNode.computed) ibox.node = styledNode ibox.text.add(child.text) + flush_ibox + if blockgroup.boxes.len > 0: + # Avoid unnecessary anonymous block boxes + if box.children.len == 0: + box.children = blockgroup.boxes + box.inlinelayout = true + else: + blockgroup.flush() return box +proc generateTableRowChildWrappers(box: TableRowBoxBuilder) = + var newchildren = newSeqOfCap[BoxBuilder](box.children.len) + var wrappervals = box.computed.inheritProperties() + wrappervals.setDisplay(DISPLAY_TABLE_CELL) + for child in box.children: + if child.computed{"display"} == DISPLAY_TABLE_CELL: + newchildren.add(child) + else: + let wrapper = getTableCellBox(wrappervals) + wrapper.children.add(child) + newchildren.add(wrapper) + box.children = newchildren + proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBoxBuilder = let box = getTableRowBox(styledNode.computed) var blockgroup = newBlockGroup(box) @@ -937,12 +989,53 @@ proc generateTableRowBox(styledNode: StyledNode, viewport: Viewport): TableRowBo ibox.text.add(child.text) return box +proc generateTableRowGroupChildWrappers(box: TableRowGroupBoxBuilder) = + var newchildren = newSeqOfCap[BoxBuilder](box.children.len) + var wrappervals = box.computed.inheritProperties() + wrappervals.setDisplay(DISPLAY_TABLE_CELL) + for child in box.children: + if child.computed{"display"} == DISPLAY_TABLE_ROW: + newchildren.add(child) + else: + let wrapper = getTableRowBox(wrappervals) + wrapper.children.add(child) + newchildren.add(wrapper) + box.children = newchildren + +proc generateTableRowGroupBox(styledNode: StyledNode, viewport: Viewport): TableRowGroupBoxBuilder = + let box = getTableRowGroupBox(styledNode.computed) + var blockgroup = newBlockGroup(box) + var ibox: InlineBoxBuilder = nil + for child in styledNode.children: + if child.t == STYLED_ELEMENT: + generateFromElem(child, blockgroup, viewport, ibox) + else: + if canGenerateAnonymousInline(blockgroup, box.computed, child.text): + if ibox == nil: + ibox = getTextBox(styledNode.computed) + ibox.node = styledNode + ibox.text.add(child.text) + return box + +proc generateTableChildWrappers(box: TableBoxBuilder) = + var newchildren = newSeqOfCap[BoxBuilder](box.children.len) + var wrappervals = box.computed.inheritProperties() + wrappervals.setDisplay(DISPLAY_TABLE_ROW) + for child in box.children: + if child.computed{"display"} in ProperTableChild: + newchildren.add(child) + else: + let wrapper = getTableRowBox(wrappervals) + wrapper.children.add(child) + wrapper.generateTableRowChildWrappers() + newchildren.add(wrapper) + box.children = newchildren + proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuilder = let box = getTableBox(styledNode.computed) - var blockgroup = newBlockGroup(box) + var blockgroup = newBlockGroup(box) #TODO this probably shouldn't exist var ibox: InlineBoxBuilder = nil var listItemCounter = 1 - for child in styledNode.children: if child.t == STYLED_ELEMENT: generateFromElem(child, blockgroup, viewport, ibox) @@ -952,11 +1045,10 @@ proc generateTableBox(styledNode: StyledNode, viewport: Viewport): TableBoxBuild ibox = getTextBox(styledNode.computed) ibox.node = styledNode ibox.text.add(child.text) - flush_ibox blockgroup.flush() - - #TODO Generate missing child wrappers + box.generateTableChildWrappers() + #TODO generate missing parents return box proc renderLayout*(viewport: var Viewport, document: Document, root: StyledNode) = diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim index 484f8fb5..4fddddc7 100644 --- a/src/render/renderdocument.nim +++ b/src/render/renderdocument.nim @@ -261,6 +261,15 @@ proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int, let spacing = InlineSpacing(atom) grid.setSpacing(spacing, x, y, term) +proc renderTable(grid: var FlexibleGrid, ctx: TableBox, x, y: int, term: TermAttributes) = + for row in ctx.nested: + assert row.computed{"display"} == DISPLAY_TABLE_ROW + for cell in row.nested: + let x = x + row.offset.x + let y = y + row.offset.y + assert cell.computed{"display"} == DISPLAY_TABLE_CELL + grid.renderBlockContext(cell, x, y, term) + proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, term: TermAttributes) = var stack = newSeqOfCap[(BlockBox, int, int)](100) stack.add((ctx, x, y)) @@ -281,6 +290,8 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, term: if ctx.inline != nil: assert ctx.nested.len == 0 grid.renderInlineContext(ctx.inline, x, y, term) + elif ctx.computed{"display"} == DISPLAY_TABLE: #TODO INLINE_TABLE + grid.renderTable(TableBox(ctx), x, y, term) else: for i in countdown(ctx.nested.high, 0): stack.add((ctx.nested[i], x, y)) |