diff options
author | bptato <nincsnevem662@gmail.com> | 2021-10-03 12:20:39 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-10-03 12:20:39 +0200 |
commit | 71f08f380b233ad415ab6954924c395a85ffc577 (patch) | |
tree | 213d4166ac0bdae343a34bcf260d1385e2cc53e7 /src/layout | |
parent | 9996586865f931b6da19779520eb7671eddc6c4d (diff) | |
download | chawan-71f08f380b233ad415ab6954924c395a85ffc577.tar.gz |
Add RowBox structure
Diffstat (limited to 'src/layout')
-rw-r--r-- | src/layout/layout.nim | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/layout/layout.nim b/src/layout/layout.nim new file mode 100644 index 00000000..043c0e08 --- /dev/null +++ b/src/layout/layout.nim @@ -0,0 +1,121 @@ +import unicode + +import types/enums +import html/dom +import css/box +import css/style +import io/buffer +import io/cell +import utils/twtstr + +proc generateGrids(text: Text, maxwidth: int, maxheight: int, x: int, y: int, fromx: int = x): seq[CSSRowBox] = + var r: Rune + var rowbox: CSSRowBox + var i = 0 + var whitespace = false + if fromx > x: + let m = fromx - x + maxwidth + var w = 0 + while i < text.data.len: + let pi = i + fastRuneAt(text.data, i, r) + let rw = r.width() + if rw + w > m: + i = pi + break + else: + if r.isWhitespace(): + if not whitespace: + whitespace = true + rowbox.runes.add(Rune(' ')) + inc rowbox.width + w += rw + else: + if whitespace: + whitespace = false + rowbox.runes.add(r) + inc rowbox.width + w += rw + + result.add(rowbox) + + if i < text.data.len: + rowbox = CSSRowBox() + var w = 0 + while i < text.data.len: + let pi = i + fastRuneAt(text.data, i, r) + let rw = r.width() + if rw + w > maxwidth: + i = pi + w = 0 + result.add(rowbox) + rowbox = CSSRowBox() + else: + rowbox.runes.add(r) + inc rowbox.width + w += rw + + if rowbox.width > 0: + result.add(rowbox) + +proc generateBox(text: Text, maxwidth: int, maxheight: int, x: int, y: int, fromx: int): CSSInlineBox = + new(result) + result.content = text.generateGrids(maxwidth, maxheight, x, y, fromx) + result.fromx = fromx + result.innerEdge.x1 = x + result.innerEdge.y1 = y + var height = 0 + var width = 0 + for grid in result.content: + inc height + width = max(width, grid.width) + + height = min(height, maxheight) + width = min(width, maxwidth) + result.innerEdge.x2 = x + width + result.innerEdge.y2 = y + height + +proc generateBox(elem: Element, maxwidth: int, maxheight: int, x: int = 0, y: int = 0, fromx: int = x): CSSBox + +proc generateChildBoxes(elem: Element, maxwidth: int, maxheight: int, x: int, y: int, fromx: int = 0): seq[CSSBox] = + var cx = fromx + var cy = y + for child in elem.childNodes: + case child.nodeType + of TEXT_NODE: + let box = Text(child).generateBox(maxwidth, maxheight, x, cy, cx) + if box != nil: + result.add(box) + cy += box.h + if box.content.len > 0: + cx = box.content[^1].width + of ELEMENT_NODE: + let box = Element(child).generateBox(maxwidth, maxheight, x, cy, cx) + if box != nil: + result.add(box) + else: + discard + +proc generateBox(elem: Element, maxwidth: int, maxheight: int, x: int = 0, y: int = 0, fromx: int = x): CSSBox = + if elem.cssvalues[RULE_DISPLAY].display == DISPLAY_NONE: + return nil + + result = CSSBlockBox() + result.innerEdge.x1 = x + result.innerEdge.y1 = y + + var width = 0 + var height = 0 + for box in elem.generateChildBoxes(maxwidth, maxheight, x, y, fromx): + result.children.add(box) + height += box.h + height = min(height, maxheight) + width = max(width, box.w) + width = min(width, maxwidth) + + result.innerEdge.x2 = x + width + result.innerEdge.y2 = y + height + +proc alignBoxes*(buffer: Buffer) = + buffer.rootbox = buffer.document.root.generateBox(buffer.width, buffer.height) |