about summary refs log tree commit diff stats
path: root/src/layout/box.nim
blob: b9d18f79129dcdd1e5401bf712de5b16cf93eae5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import css/cssvalues
import css/stylednode
import types/bitmap
import layout/layoutunit

type
  DimensionType* = enum
    dtHorizontal, dtVertical

  Offset* = array[DimensionType, LayoutUnit]

  Size* = array[DimensionType, LayoutUnit]

  Overflow* = array[DimensionType, Span]

  InlineAtomType* = enum
    iatWord, iatInlineBlock, iatImage

  InlineAtom* = ref object
    offset*: Offset
    size*: Size
    case t*: InlineAtomType
    of iatWord:
      str*: string
    of iatInlineBlock:
      innerbox*: BlockBox
    of iatImage:
      bmp*: NetworkBitmap

  RootInlineFragmentState* = object
    # offset relative to parent
    offset*: Offset
    # padding size
    size*: Size
    # overflow relative to offset
    overflow*: Overflow
    # minimum content width
    xminwidth*: LayoutUnit
    # baseline of the first line box
    firstBaseline*: LayoutUnit
    # baseline of the last line box
    baseline*: LayoutUnit

  RootInlineFragment* = ref object
    fragment*: InlineFragment # root fragment
    state*: RootInlineFragmentState

  SplitType* = enum
    stSplitStart, stSplitEnd

  Area* = object
    offset*: Offset
    size*: Size

  InlineFragmentState* = object
    startOffset*: Offset # offset of the first word, for position: absolute
    areas*: seq[Area] # background that should be painted by fragment
    atoms*: seq[InlineAtom]

  InlineFragmentType* = enum
    iftParent, iftText, iftNewline, iftBitmap, iftBox

  InlineFragment* = ref object
    state*: InlineFragmentState
    computed*: CSSComputedValues
    node*: StyledNode
    splitType*: set[SplitType]
    case t*: InlineFragmentType
    of iftParent:
      children*: seq[InlineFragment]
    of iftText:
      text*: StyledNode # note: this has no parent.
    of iftNewline:
      discard
    of iftBitmap:
      bmp*: NetworkBitmap
    of iftBox:
      box*: BlockBox

  Span* = object
    start*: LayoutUnit
    send*: LayoutUnit

  RelativeRect* = array[DimensionType, Span]

  BlockBoxLayoutState* = object
    # offset relative to parent
    offset*: Offset
    # padding size
    size*: Size
    margin*: RelativeRect #TODO get rid of this?
    positioned*: RelativeRect #TODO ditto
    # overflow relative to offset
    overflow*: Overflow
    # minimum content width (usually shortest word)
    xminwidth*: LayoutUnit
    # baseline of the first line box of all descendants
    firstBaseline*: LayoutUnit
    # baseline of the last line box of all descendants
    baseline*: LayoutUnit

  BlockBox* = ref object
    state*: BlockBoxLayoutState
    computed*: CSSComputedValues
    node*: StyledNode
    inline*: RootInlineFragment
    nested*: seq[BlockBox]

func offset*(x, y: LayoutUnit): Offset =
  return [dtHorizontal: x, dtVertical: y]

func x*(offset: Offset): LayoutUnit {.inline.} =
  return offset[dtHorizontal]

func x*(offset: var Offset): var LayoutUnit {.inline.} =
  return offset[dtHorizontal]

func `x=`*(offset: var Offset; x: LayoutUnit) {.inline.} =
  offset[dtHorizontal] = x

func y*(offset: Offset): LayoutUnit {.inline.} =
  return offset[dtVertical]

func y*(offset: var Offset): var LayoutUnit {.inline.} =
  return offset[dtVertical]

func `y=`*(offset: var Offset; y: LayoutUnit) {.inline.} =
  offset[dtVertical] = y

func size*(w, h: LayoutUnit): Size =
  return [dtHorizontal: w, dtVertical: h]

func w*(size: Size): LayoutUnit {.inline.} =
  return size[dtHorizontal]

func w*(size: var Size): var LayoutUnit {.inline.} =
  return size[dtHorizontal]

func `w=`*(size: var Size; w: LayoutUnit) {.inline.} =
  size[dtHorizontal] = w

func h*(size: Size): LayoutUnit {.inline.} =
  return size[dtVertical]

func h*(size: var Size): var LayoutUnit {.inline.} =
  return size[dtVertical]

func `h=`*(size: var Size; h: LayoutUnit) {.inline.} =
  size[dtVertical] = h

func `+`*(a, b: Offset): Offset =
  return offset(x = a.x + b.x, y = a.y + b.y)

func `-`*(a, b: Offset): Offset =
  return offset(x = a.x - b.x, y = a.y - b.y)

proc `+=`*(a: var Offset; b: Offset) =
  a.x += b.x
  a.y += b.y

proc `-=`*(a: var Offset; b: Offset) =
  a.x -= b.x
  a.y -= b.y

func left*(s: RelativeRect): LayoutUnit =
  return s[dtHorizontal].start

func right*(s: RelativeRect): LayoutUnit =
  return s[dtHorizontal].send

func top*(s: RelativeRect): LayoutUnit =
  return s[dtVertical].start

func bottom*(s: RelativeRect): LayoutUnit =
  return s[dtVertical].send

proc `+=`*(span: var Span; u: LayoutUnit) =
  span.start += u
  span.send += u