Flexbox
Flexbox is a high level positioning plugin that allows for dynamic positioning of elements based apon container sizing. To learn more about flexbox refer to this MDN article, in this document we will go into the impleamentation of flexbox rather than the usage of it.
"display": "flex", "justify-content": "*", "align-content": "*", "align-items": "*", "flex-wrap": "*", "flex-direction": "*",
# Flex Properties
justify-content | align-content | align-items | flex-wrap | flex-direction |
---|---|---|---|---|
normal | normal | normal | nowrap | row |
center | center | center | wrap | column |
flex-start | flex-start | flex-start | row-reverse | |
flex-end | flex-end | flex-end | column-reverse | |
space-between | space-between | stretch | ||
space-around | space-around | baseline | ||
space-evenly | stretch |
# order?(go)
asd
1package flex
2
3import (
4 "gui/cstyle"
5 "gui/cstyle/plugins/inline"
6 "gui/element"
7 "gui/utils"
8 "sort"
9 "strings"
10)
11
12func Init() cstyle.Plugin {
13 return cstyle.Plugin{
14 Selector: func(n *element.Node) bool {
15 styles := map[string]string{
16 "display": "flex",
17 }
18 matches := true
19 for name, value := range styles {
20 if (n.Style[name] != value || n.Style[name] == "") && !(value == "*") {
21 matches = false
22 }
23 }
24 return matches
25 },
26 Level: 3,
27 Handler: func(n *element.Node, state *map[string]element.State) {
28 s := *state
29 self := s[n.Properties.Id]
30
31 verbs := strings.Split(n.Style["flex-direction"], "-")
32 flexDirection := verbs[0]
33 if flexDirection == "" {
34 flexDirection = "row"
35 }
36 flexReversed := false
37 if len(verbs) > 1 {
38 flexReversed = true
39 }
40
41 var flexWrapped bool
42 if n.Style["flex-wrap"] == "wrap" {
43 flexWrapped = true
44 } else {
45 flexWrapped = false
46 }
47
48 alignContent := n.Style["align-content"]
49 if alignContent == "" {
50 alignContent = "normal"
51 }
52 alignItems := n.Style["align-items"]
53 if alignItems == "" {
54 alignItems = "normal"
55 }
56 justifyItems := n.Style["justify-items"]
57 if justifyItems == "" {
58 justifyItems = "normal"
59 }
60
61 justifyContent := n.Style["justify-content"]
62 if justifyContent == "" {
63 justifyContent = "normal"
64 }
65 // fmt.Println(flexDirection, flexReversed, flexWrapped, hAlign, vAlign, justifyItems, justifyContent)
66 rows := [][]int{}
67 maxH := float32(0)
68 // maxW := float32(0)
69
70 // Get inital sizing
71 textTotal := 0
72 textCounts := []int{}
73 widths := []float32{}
74 // heights := []float32{}
75 innerSizes := [][]float32{}
76 minWidths := []float32{}
77 minHeights := []float32{}
78 maxWidths := []float32{}
79 // maxHeights := []float32{}
80 for _, v := range n.Children {
81 count := countText(v)
82 textTotal += count
83 textCounts = append(textCounts, count)
84
85 minw := getMinWidth(&v, state)
86 minWidths = append(minWidths, minw)
87
88 maxw := getMaxWidth(&v, state)
89 maxWidths = append(maxWidths, maxw)
90
91 w, h := getInnerSize(&v, state)
92
93 minh := getMinHeight(&v, state)
94 minHeights = append(minHeights, minh)
95
96 // maxh := getMaxHeight(&v, state)
97 // maxHeights = append(maxHeights, maxh)
98 innerSizes = append(innerSizes, []float32{w, h})
99 }
100 selfWidth := (self.Width - self.Padding.Left) - self.Padding.Right
101 selfHeight := (self.Height - self.Padding.Top) - self.Padding.Bottom
102
103 if flexDirection == "row" {
104 // if the elements are less than the size of the parent, don't change widths. Just set mins
105 if !flexWrapped {
106 if add2d(innerSizes, 0) < selfWidth {
107 for i := range innerSizes {
108 // for i, _ := range n.Children {
109 // vState := s[v.Properties.Id]
110
111 w := innerSizes[i][0]
112 // w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
113 widths = append(widths, w)
114 }
115 } else {
116 // Modifiy the widths so they aren't under the mins
117 for i, v := range n.Children {
118 vState := s[v.Properties.Id]
119
120 w := ((selfWidth / float32(textTotal)) * float32(textCounts[i]))
121 w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
122
123 if w < minWidths[i] {
124 selfWidth -= minWidths[i] + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
125 textTotal -= textCounts[i]
126 textCounts[i] = 0
127 }
128
129 }
130 for i, v := range n.Children {
131 vState := s[v.Properties.Id]
132
133 w := ((selfWidth / float32(textTotal)) * float32(textCounts[i]))
134 w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
135 // (w!=w) is of NaN
136 if w < minWidths[i] || (w != w) {
137 w = minWidths[i]
138 }
139 widths = append(widths, w)
140 }
141 }
142 // Apply the new widths
143 fState := s[n.Children[0].Properties.Id]
144 for i, v := range n.Children {
145 vState := s[v.Properties.Id]
146
147 vState.Width = widths[i]
148 xStore := vState.X
149 if i > 0 {
150 sState := s[n.Children[i-1].Properties.Id]
151 vState.X = sState.X + sState.Width + sState.Margin.Right + vState.Margin.Left + sState.Border.Width + vState.Border.Width
152 propagateOffsets(&v, xStore, vState.Y, vState.X, fState.Y+vState.Margin.Top, state)
153 }
154
155 vState.Y = fState.Y + vState.Margin.Top
156
157 (*state)[v.Properties.Id] = vState
158 deInline(&v, state)
159 applyInline(&v, state)
160 applyBlock(&v, state)
161 _, h := getInnerSize(&v, state)
162 h = utils.Max(h, vState.Height)
163 maxH = utils.Max(maxH, h)
164 }
165 // When not wrapping everything will be on the same row
166 rows = append(rows, []int{0, len(n.Children), int(maxH)})
167 } else {
168 // Flex Wrapped
169 sum := innerSizes[0][0]
170 for i := 0; i < len(n.Children); i++ {
171 v := n.Children[i]
172 vState := s[v.Properties.Id]
173
174 // if the next plus current will break then
175 w := innerSizes[i][0]
176 if i > 0 {
177 sib := s[n.Children[i-1].Properties.Id]
178 if maxWidths[i] > selfWidth {
179 w = selfWidth - vState.Margin.Left - vState.Margin.Right - (vState.Border.Width * 2)
180 }
181 if w+sum > selfWidth {
182 sum = w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
183 } else {
184 propagateOffsets(&v, vState.X, vState.Y, vState.X, sib.Y, state)
185 vState.Y = sib.Y
186 (*state)[v.Properties.Id] = vState
187 sum += w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
188 }
189 }
190
191 widths = append(widths, w)
192 }
193
194 // Move the elements into the correct position
195 start := 0
196 var prevOffset float32
197 for i := 0; i < len(n.Children); i++ {
198 v := n.Children[i]
199 vState := s[v.Properties.Id]
200
201 vState.Width = widths[i]
202 xStore := vState.X
203 yStore := vState.Y
204
205 if i > 0 {
206 sib := s[n.Children[i-1].Properties.Id]
207 if vState.Y+prevOffset == sib.Y {
208 yStore += prevOffset
209
210 if vState.Height < sib.Height {
211 vState.Height = minHeight(v, state, sib.Height)
212 }
213 // Shift right if on a row with sibling
214 xStore = sib.X + sib.Width + sib.Margin.Right + sib.Border.Width + vState.Margin.Left + vState.Border.Width
215 } else {
216 // Shift under sibling
217 yStore = sib.Y + sib.Height + sib.Margin.Top + sib.Margin.Bottom + sib.Border.Width*2
218 prevOffset = yStore - vState.Y
219 rows = append(rows, []int{start, i, int(maxH)})
220 start = i
221 maxH = 0
222 }
223 propagateOffsets(&v, vState.X, vState.Y, xStore, yStore, state)
224 }
225 vState.X = xStore
226 vState.Y = yStore
227
228 (*state)[v.Properties.Id] = vState
229 deInline(&v, state)
230 applyInline(&v, state)
231 applyBlock(&v, state)
232 _, h := getInnerSize(&v, state)
233 h = utils.Max(h, vState.Height)
234 maxH = utils.Max(maxH, h)
235 vState.Height = minHeight(v, state, h)
236 (*state)[v.Properties.Id] = vState
237 }
238 if start < len(n.Children) {
239 rows = append(rows, []int{start, len(n.Children), int(maxH)})
240 }
241 }
242
243 var totalHeight float32
244
245 for _, v := range rows {
246 totalHeight += float32(v[2])
247 for i := v[0]; i < v[1]; i++ {
248 vState := s[n.Children[i].Properties.Id]
249 if vState.Height == float32(v[2]) {
250 totalHeight += vState.Margin.Top + vState.Margin.Bottom
251 v[2] += int(vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
252 }
253 }
254 }
255 var yOffset float32
256 for _, v := range rows {
257 for i := v[0]; i < v[1]; i++ {
258 vState := s[n.Children[i].Properties.Id]
259 // height := float32(v[2])
260 if n.Children[i].Style["height"] == "" && n.Children[i].Style["min-height"] == "" && !flexWrapped {
261 height := self.Height - self.Padding.Top - self.Padding.Bottom - vState.Margin.Top - vState.Margin.Bottom - (vState.Border.Width * 2)
262 vState.Height = minHeight(n.Children[i], state, height)
263 } else if flexWrapped && (n.Style["height"] != "" || n.Style["min-height"] != "") {
264 height := ((selfHeight / totalHeight) * float32(v[2])) - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
265 vState.Height = minHeight(n.Children[i], state, height)
266 yStore := vState.Y
267 vState.Y = self.Y + self.Padding.Top + yOffset + vState.Margin.Top + vState.Border.Width
268 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
269 } else if flexWrapped {
270 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) != float32(v[2]) {
271 height := vState.Height - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
272 vState.Height = minHeight(n.Children[i], state, height)
273 }
274 yStore := vState.Y
275 vState.Y = self.Y + self.Padding.Top + yOffset + vState.Margin.Top + vState.Border.Width
276 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
277 }
278 (*state)[n.Children[i].Properties.Id] = vState
279 }
280 if flexWrapped && (n.Style["height"] != "" || n.Style["min-height"] != "") {
281 yOffset += ((selfHeight / totalHeight) * float32(v[2]))
282 } else if flexWrapped {
283 yOffset += float32(v[2])
284 }
285 }
286 // Reverse elements
287 if flexReversed {
288 rowReverse(rows, n, state)
289 }
290
291 if justifyContent != "" && justifyContent != "normal" {
292 justifyRow(rows, n, state, justifyContent, flexReversed)
293 }
294
295 if alignContent != "normal" && flexWrapped {
296 alignRow(rows, n, state, alignItems, alignContent)
297 }
298
299 }
300
301 if flexDirection == "column" {
302 if !flexWrapped {
303 // if the container has a size restriction
304 var totalHeight, maxH float32
305 var fixedHeightElements int
306 for i, v := range n.Children {
307 vState := s[v.Properties.Id]
308 if v.Style["min-height"] != "" {
309 selfHeight -= vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
310 fixedHeightElements++
311 maxH = utils.Max(maxH, vState.Height)
312 } else {
313 // accoutn for element min height
314 totalHeight += minHeights[i] + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
315 maxH = utils.Max(maxH, minHeights[i])
316 }
317 }
318
319 heightDelta := selfHeight - totalHeight
320 if heightDelta < 0 {
321 heightDelta = -heightDelta
322 }
323 heightAdj := heightDelta / float32(len(n.Children)-fixedHeightElements)
324 if heightAdj < 0 {
325 heightAdj = -heightAdj
326 }
327 // We are calculating the amount a element needs to shrink because of its siblings
328 for i, v := range n.Children {
329 vState := s[v.Properties.Id]
330 yStore := vState.Y
331 vState.Height = setHeight(&v, state, minHeights[i]-heightAdj)
332 if i > 0 {
333 sib := s[n.Children[i-1].Properties.Id]
334
335 vState.Y = sib.Y + sib.Height + sib.Margin.Bottom + sib.Border.Width + vState.Margin.Top + vState.Border.Width
336 }
337 propagateOffsets(&v, vState.X, yStore, vState.X, vState.Y, state)
338
339 (*state)[v.Properties.Id] = vState
340 }
341
342 rows = append(rows, []int{0, len(n.Children) - 1, int(maxH)})
343
344 } else {
345 // need to redo this, with col wrap make each row the width of the longest element unless set otherwise (width, max-width) get width with min-width
346 var colHeight float32
347 var colIndex int
348 cols := [][][]float32{}
349
350 // Map elements to columns
351 for i, v := range n.Children {
352 vState := s[v.Properties.Id]
353
354 height := vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
355 if colHeight+height > selfHeight {
356 colHeight = height
357 colIndex++
358 width := vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
359 if colIndex >= len(cols) {
360 cols = append(cols, [][]float32{})
361 }
362 cols[colIndex] = append(cols[colIndex], []float32{float32(i), height, width})
363 } else {
364 colHeight += height
365 width := vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
366 if colIndex >= len(cols) {
367 cols = append(cols, [][]float32{})
368 }
369 cols[colIndex] = append(cols[colIndex], []float32{float32(i), height, width})
370 }
371 }
372
373 // Find the max total width of all columns
374 var totalMaxWidth float32
375 maxWidths := []float32{}
376 for _, col := range cols {
377 var maxWidth, maxHeight float32
378 for _, element := range col {
379 maxHeight = utils.Max(utils.Max(element[1], minHeights[int(element[0])]), maxHeight)
380 maxWidth = utils.Max(element[2], maxWidth)
381 }
382 rows = append(rows, []int{int(col[0][0]), int(col[len(col)-1][0]), int(maxHeight)})
383 totalMaxWidth += maxWidth
384 maxWidths = append(maxWidths, maxWidth)
385 }
386 offset := (selfWidth - totalMaxWidth) / float32(len(cols))
387 // Move the elements into the correct position
388 var xOffset float32
389 for i, col := range cols {
390 // Move the elements into the correct position
391 yOffset := self.Y + self.Border.Width + self.Padding.Top
392 for _, element := range col {
393 v := n.Children[int(element[0])]
394 vState := s[v.Properties.Id]
395 xStore := vState.X
396 yStore := vState.Y
397 vState.X = self.X + self.Padding.Left + self.Border.Width + xOffset + vState.Margin.Left + vState.Border.Width
398 vState.Y = yOffset + vState.Margin.Top + vState.Border.Width
399 propagateOffsets(&v, xStore, yStore, vState.X, vState.Y, state)
400
401 vState.Width = setWidth(&v, state, (maxWidths[i]+offset)-(vState.Margin.Left+vState.Margin.Right+(vState.Border.Width*2)))
402 yOffset += vState.Margin.Top + vState.Border.Width + vState.Height + vState.Margin.Bottom + vState.Border.Width
403 (*state)[v.Properties.Id] = vState
404 }
405 xOffset += maxWidths[i] + offset
406 }
407
408 }
409
410 if flexReversed {
411 colReverse(rows, n, state)
412 }
413
414 if justifyContent != "normal" {
415 justifyCols(rows, n, state, justifyContent, flexReversed)
416 }
417 if alignContent != "normal" || alignItems != "normal" {
418 alignCols(rows, n, state, alignItems, alignContent, innerSizes)
419 }
420 }
421 if n.Style["height"] == "" && n.Style["min-height"] == "" {
422 _, h := getInnerSize(n, state)
423 self.Height = h
424 }
425 (*state)[n.Properties.Id] = self
426 },
427 }
428}
429
430func applyBlock(n *element.Node, state *map[string]element.State) {
431 if len(n.Children) > 0 {
432 accum := float32(0)
433 inlineOffset := float32(0)
434 s := *state
435 lastHeight := float32(0)
436 baseY := s[n.Children[0].Properties.Id].Y
437 for i := 0; i < len(n.Children); i++ {
438 v := &n.Children[i]
439 vState := s[v.Properties.Id]
440
441 if v.Style["display"] != "block" {
442 vState.Y += inlineOffset
443 accum = (vState.Y - baseY)
444 lastHeight = vState.Height
445 } else if v.Style["position"] != "absolute" {
446 vState.Y += accum
447 inlineOffset += (vState.Height + (vState.Border.Width * 2) + vState.Margin.Top + vState.Margin.Bottom + vState.Padding.Top + vState.Padding.Bottom) + lastHeight
448 }
449 (*state)[v.Properties.Id] = vState
450 }
451 }
452}
453
454func deInline(n *element.Node, state *map[string]element.State) {
455 s := *state
456 // self := s[n.Properties.Id]
457 baseX := float32(-1)
458 baseY := float32(-1)
459 for _, v := range n.Children {
460 vState := s[v.Properties.Id]
461
462 if v.Style["display"] == "inline" {
463 if baseX < 0 && baseY < 0 {
464 baseX = vState.X
465 baseY = vState.Y
466 } else {
467 vState.X = baseX
468 vState.Y = baseY
469 (*state)[v.Properties.Id] = vState
470
471 }
472 } else {
473 baseX = float32(-1)
474 baseY = float32(-1)
475 }
476
477 if len(v.Children) > 0 {
478 deInline(&v, state)
479 }
480 }
481
482}
483
484func applyInline(n *element.Node, state *map[string]element.State) {
485 pl := inline.Init()
486 for i := 0; i < len(n.Children); i++ {
487 v := &n.Children[i]
488
489 if len(v.Children) > 0 {
490 applyInline(v, state)
491 }
492
493 if pl.Selector(v) {
494 pl.Handler(v, state)
495 }
496 }
497}
498
499func propagateOffsets(n *element.Node, prevx, prevy, newx, newy float32, state *map[string]element.State) {
500 s := *state
501 for _, v := range n.Children {
502 vState := s[v.Properties.Id]
503 xStore := (vState.X - prevx) + newx
504 yStore := (vState.Y - prevy) + newy
505
506 if len(v.Children) > 0 {
507 propagateOffsets(&v, vState.X, vState.Y, xStore, yStore, state)
508 }
509 vState.X = xStore
510 vState.Y = yStore
511 (*state)[v.Properties.Id] = vState
512 }
513
514}
515
516func countText(n element.Node) int {
517 count := 0
518 groups := []int{}
519 for _, v := range n.Children {
520 if v.TagName == "notaspan" {
521 count += 1
522 }
523 if v.Style["display"] == "block" {
524 groups = append(groups, count)
525 count = 0
526 }
527 if len(v.Children) > 0 {
528 count += countText(v)
529 }
530 }
531 groups = append(groups, count)
532
533 sort.Slice(groups, func(i, j int) bool {
534 return groups[i] > groups[j]
535 })
536 return groups[0]
537}
538
539func minHeight(n element.Node, state *map[string]element.State, prev float32) float32 {
540 s := *state
541 self := s[n.Properties.Id]
542 if n.Style["min-height"] != "" {
543 mw := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
544 return utils.Max(prev, mw)
545 } else {
546 return prev
547 }
548
549}
550
551func getMinHeight(n *element.Node, state *map[string]element.State) float32 {
552 s := *state
553 self := s[n.Properties.Id]
554 selfHeight := float32(0)
555
556 if len(n.Children) > 0 {
557 for _, v := range n.Children {
558 selfHeight = utils.Max(selfHeight, getNodeHeight(&v, state))
559 }
560 } else {
561 selfHeight = self.Height
562 }
563 if n.Style["min-height"] != "" {
564 mh := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
565 selfHeight = utils.Max(mh, selfHeight)
566 }
567
568 selfHeight += self.Padding.Top + self.Padding.Bottom
569 return selfHeight
570}
571
572func getMinWidth(n *element.Node, state *map[string]element.State) float32 {
573 s := *state
574 self := s[n.Properties.Id]
575 selfWidth := float32(0)
576
577 if len(n.Children) > 0 {
578 for _, v := range n.Children {
579 selfWidth = utils.Max(selfWidth, getNodeWidth(&v, state))
580 }
581 } else {
582 selfWidth = self.Width
583 }
584 if n.Style["min-width"] != "" {
585 mw := utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
586 selfWidth = utils.Max(mw, selfWidth)
587 }
588
589 selfWidth += self.Padding.Left + self.Padding.Right
590 return selfWidth
591}
592func getMaxWidth(n *element.Node, state *map[string]element.State) float32 {
593 s := *state
594 self := s[n.Properties.Id]
595 selfWidth := float32(0)
596
597 if len(n.Children) > 0 {
598 var maxRowWidth, rowWidth float32
599
600 for _, v := range n.Children {
601 rowWidth += getNodeWidth(&v, state)
602 if v.Style["display"] != "inline" {
603 maxRowWidth = utils.Max(rowWidth, maxRowWidth)
604 rowWidth = 0
605 }
606 }
607 selfWidth = utils.Max(rowWidth, maxRowWidth)
608 } else {
609 selfWidth = self.Width
610 }
611
612 selfWidth += self.Padding.Left + self.Padding.Right
613 return selfWidth
614}
615
616func getNodeWidth(n *element.Node, state *map[string]element.State) float32 {
617 s := *state
618 self := s[n.Properties.Id]
619 w := float32(0)
620 w += self.Padding.Left
621 w += self.Padding.Right
622
623 w += self.Margin.Left
624 w += self.Margin.Right
625
626 w += self.Width
627
628 w += self.Border.Width * 2
629
630 for _, v := range n.Children {
631 w = utils.Max(w, getNodeWidth(&v, state))
632 }
633
634 return w
635}
636
637func setWidth(n *element.Node, state *map[string]element.State, width float32) float32 {
638 s := *state
639 self := s[n.Properties.Id]
640
641 if n.Style["width"] != "" {
642 return utils.ConvertToPixels(n.Style["width"], self.EM, s[n.Parent.Properties.Id].Width)
643 }
644
645 var maxWidth, minWidth float32
646 maxWidth = 10e9
647 if n.Style["min-width"] != "" {
648 minWidth = utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
649 }
650 if n.Style["max-width"] != "" {
651 maxWidth = utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
652 }
653
654 return utils.Max(minWidth, utils.Min(width, maxWidth))
655}
656
657func setHeight(n *element.Node, state *map[string]element.State, height float32) float32 {
658 s := *state
659 self := s[n.Properties.Id]
660
661 if n.Style["height"] != "" {
662 return utils.ConvertToPixels(n.Style["height"], self.EM, s[n.Parent.Properties.Id].Height)
663 }
664
665 var maxHeight, minHeight float32
666 maxHeight = 10e9
667 if n.Style["min-height"] != "" {
668 minHeight = utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Height)
669 }
670 if n.Style["max-height"] != "" {
671 maxHeight = utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Height)
672 }
673
674 return utils.Max(minHeight, utils.Min(height, maxHeight))
675}
676
677func getNodeHeight(n *element.Node, state *map[string]element.State) float32 {
678 s := *state
679 self := s[n.Properties.Id]
680 h := float32(0)
681 h += self.Padding.Top
682 h += self.Padding.Bottom
683
684 h += self.Margin.Top
685 h += self.Margin.Bottom
686
687 h += self.Height
688
689 h += self.Border.Width * 2
690
691 for _, v := range n.Children {
692 h = utils.Max(h, getNodeHeight(&v, state))
693 }
694
695 return h
696}
697
698func getInnerSize(n *element.Node, state *map[string]element.State) (float32, float32) {
699 s := *state
700 self := s[n.Properties.Id]
701
702 minx := float32(10e10)
703 maxw := float32(0)
704 miny := float32(10e10)
705 maxh := float32(0)
706 for _, v := range n.Children {
707 vState := s[v.Properties.Id]
708 minx = utils.Min(vState.X, minx)
709 miny = utils.Min(vState.Y-vState.Margin.Top, miny)
710 // Don't add the top or left because the x&y values already take that into account
711 hOffset := (vState.Border.Width) + vState.Margin.Bottom
712 wOffset := (vState.Border.Width) + vState.Margin.Right
713 maxw = utils.Max(vState.X+vState.Width+wOffset, maxw)
714 maxh = utils.Max(vState.Y+vState.Height+hOffset, maxh)
715 }
716 w := maxw - minx
717 h := maxh - miny
718
719 w += self.Padding.Left + self.Padding.Right
720 h += self.Padding.Top + self.Padding.Bottom
721 if n.Style["width"] != "" {
722 w = self.Width
723 }
724 if n.Style["height"] != "" {
725 h = self.Height
726 }
727
728 return w, h
729}
730
731func add2d(arr [][]float32, index int) float32 {
732 var sum float32
733 if len(arr) == 0 {
734 return sum
735 }
736
737 for i := 0; i < len(arr); i++ {
738 if len(arr[i]) <= index {
739 return sum
740 }
741 sum += arr[i][index]
742 }
743
744 return sum
745}
746
747func colReverse(cols [][]int, n *element.Node, state *map[string]element.State) {
748 s := *state
749 for _, col := range cols {
750 tempNodes := []element.Node{}
751 tempStates := []element.State{}
752
753 for i := col[1]; i >= col[0]; i-- {
754 tempNodes = append(tempNodes, n.Children[i])
755 tempStates = append(tempStates, s[n.Children[i].Properties.Id])
756 }
757
758 for i := 0; i < len(tempStates); i++ {
759 e := col[0] + i
760 vState := s[n.Children[e].Properties.Id]
761 propagateOffsets(&n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
762 vState.Y = tempStates[i].Y
763 (*state)[n.Children[e].Properties.Id] = vState
764 }
765 for i := 0; i < len(tempStates); i++ {
766 e := col[0] + i
767 n.Children[e] = tempNodes[i]
768 }
769 }
770}
771
772func rowReverse(rows [][]int, n *element.Node, state *map[string]element.State) {
773 s := *state
774 for _, row := range rows {
775 tempNodes := []element.Node{}
776 tempStates := []element.State{}
777
778 for i := row[1] - 1; i >= row[0]; i-- {
779 tempNodes = append(tempNodes, n.Children[i])
780 tempStates = append(tempStates, s[n.Children[i].Properties.Id])
781 }
782
783 for i := 0; i < len(tempStates); i++ {
784 e := row[0] + i
785 vState := s[n.Children[e].Properties.Id]
786 propagateOffsets(&n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
787 vState.X = tempStates[i].X
788 (*state)[n.Children[e].Properties.Id] = vState
789 }
790 for i := 0; i < len(tempStates); i++ {
791 e := row[0] + i
792 n.Children[e] = tempNodes[i]
793 }
794
795 for i := row[1] - 1; i >= row[0]; i-- {
796 vState := s[n.Children[i].Properties.Id]
797 var xChng float32
798 if i < row[1]-1 {
799 sib := s[n.Children[i+1].Properties.Id]
800 xChng = sib.X - (sib.Border.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Width + vState.Width)
801 } else {
802 parent := s[n.Properties.Id]
803 xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Width)
804
805 }
806 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
807 vState.X = xChng
808 (*state)[n.Children[i].Properties.Id] = vState
809 }
810 }
811}
812
813func justifyRow(rows [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
814 s := *state
815 for _, row := range rows {
816
817 if (justify == "flex-end" || justify == "end" || justify == "right") && !reversed {
818 for i := row[1] - 1; i >= row[0]; i-- {
819 vState := s[n.Children[i].Properties.Id]
820 var xChng float32
821 if i < row[1]-1 {
822 sib := s[n.Children[i+1].Properties.Id]
823 xChng = sib.X - (sib.Border.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Width + vState.Width)
824 } else {
825 parent := s[n.Properties.Id]
826 xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Width)
827
828 }
829 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
830 vState.X = xChng
831 (*state)[n.Children[i].Properties.Id] = vState
832 }
833 } else if (justify == "flex-end" || justify == "start" || justify == "left" || justify == "normal") && reversed {
834 for i := row[0]; i < row[1]; i++ {
835 vState := s[n.Children[i].Properties.Id]
836 var xChng float32
837 if i > row[0] {
838 sib := s[n.Children[i-1].Properties.Id]
839 xChng = sib.X + sib.Width + (sib.Border.Width * 2) + sib.Margin.Right + vState.Margin.Left + vState.Border.Width
840 } else {
841 parent := s[n.Properties.Id]
842 xChng = parent.X + parent.Padding.Right + vState.Margin.Left + vState.Border.Width + parent.Border.Width
843
844 }
845 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
846 vState.X = xChng
847 (*state)[n.Children[i].Properties.Id] = vState
848 }
849 } else if justify == "center" {
850 // get width of row then center (by getting last x + w + mr + b)
851 f := s[n.Children[row[0]].Properties.Id]
852 l := s[n.Children[row[1]-1].Properties.Id]
853 parent := s[n.Properties.Id]
854 po := parent.X + parent.Border.Width
855 offset := (parent.Width - ((f.X - po) + (l.X - po) + l.Width + f.Border.Width + l.Border.Width)) / 2
856
857 for i := row[0]; i < row[1]; i++ {
858 vState := s[n.Children[i].Properties.Id]
859
860 if !reversed {
861 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
862 vState.X += offset
863 } else {
864 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
865 vState.X -= offset
866 }
867 (*state)[n.Children[i].Properties.Id] = vState
868 }
869
870 } else if justify == "space-between" {
871 // get width of row then center (by getting last x + w + mr + b)
872 f := s[n.Children[row[0]].Properties.Id]
873 l := s[n.Children[row[1]-1].Properties.Id]
874 parent := s[n.Properties.Id]
875 po := parent.Border.Width + parent.Width
876 po -= parent.Padding.Left + parent.Padding.Right
877
878 // make po repersent the total space between elements
879 for i := row[0]; i < row[1]; i++ {
880 vState := s[n.Children[i].Properties.Id]
881 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
882 }
883
884 po /= float32(((row[1]) - row[0]) - 1)
885
886 if (row[1]-1)-row[0] > 0 {
887 for i := row[0]; i < row[1]; i++ {
888 vState := s[n.Children[i].Properties.Id]
889 var offset float32
890 if i == row[0] {
891 offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
892 } else if i == row[1]-1 {
893 offset = (parent.X + parent.Width) - (l.Margin.Right + l.Border.Width + l.Width + parent.Padding.Right)
894 } else {
895 if !reversed {
896 offset = vState.X + (po * float32(i-row[0]))
897 } else {
898 offset = vState.X - (po * float32(((row[1]-1)-row[0])-(i-row[0])))
899 }
900
901 }
902
903 propagateOffsets(&n.Children[i], vState.X, vState.Y, offset, vState.Y, state)
904 vState.X = offset
905 (*state)[n.Children[i].Properties.Id] = vState
906 }
907 }
908 // else {
909
910 // this is/was causing issues, removed and it fixed its self
911
912 // if there is one element move left
913 // vState := s[n.Children[(row[1]-1)-row[0]].Properties.Id]
914 // var offset float32
915
916 // if !reversed {
917 // offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
918 // propagateOffsets(&n.Children[(row[1]-1)-row[0]], vState.X, vState.Y, offset, vState.Y, state)
919 // vState.X = offset
920
921 // (*state)[n.Children[(row[1]-1)-row[0]].Properties.Id] = vState
922 // }
923
924 // }
925
926 } else if justify == "space-evenly" {
927 // get width of row then center (by getting last x + w + mr + b)
928 parent := s[n.Properties.Id]
929 po := parent.Border.Width + parent.Width
930 po -= parent.Padding.Left + parent.Padding.Right
931
932 // make po repersent the total space between elements
933 for i := row[0]; i < row[1]; i++ {
934 vState := s[n.Children[i].Properties.Id]
935 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
936 }
937
938 po /= float32(((row[1]) - row[0]) + 1)
939
940 // get width of row then center (by getting last x + w + mr + b)
941
942 for i := row[0]; i < row[1]; i++ {
943 vState := s[n.Children[i].Properties.Id]
944
945 if !reversed {
946 offset := po * (float32(i-row[0]) + 1)
947 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
948 vState.X += offset
949 } else {
950 offset := po * float32(((row[1]-1)-row[0])-((i-row[0])-1))
951
952 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
953 vState.X -= offset
954 }
955 (*state)[n.Children[i].Properties.Id] = vState
956 }
957
958 } else if justify == "space-around" {
959 // get width of row then center (by getting last x + w + mr + b)
960 parent := s[n.Properties.Id]
961 po := parent.Border.Width + parent.Width
962 po -= parent.Padding.Left + parent.Padding.Right
963
964 // make po repersent the total space between elements
965 for i := row[0]; i < row[1]; i++ {
966 vState := s[n.Children[i].Properties.Id]
967 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
968 }
969
970 po /= float32(((row[1]) - row[0]))
971
972 // get width of row then center (by getting last x + w + mr + b)
973
974 for i := row[0]; i < row[1]; i++ {
975 vState := s[n.Children[i].Properties.Id]
976
977 if !reversed {
978 m := (float32(i-row[0]) + 1)
979 if i-row[0] == 0 {
980 m = 0.5
981 } else {
982 m -= 0.5
983 }
984 offset := po * m
985 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
986 vState.X += offset
987 } else {
988 m := float32(((row[1] - 1) - row[0]) - ((i - row[0]) - 1))
989 m -= 0.5
990 offset := po * m
991
992 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
993 vState.X -= offset
994 }
995 (*state)[n.Children[i].Properties.Id] = vState
996 }
997
998 }
999
1000 }
1001}
1002
1003func alignRow(rows [][]int, n *element.Node, state *map[string]element.State, align, content string) {
1004 // !ISSUE: Baseline isn't properly impleamented
1005
1006 s := *state
1007 self := s[n.Properties.Id]
1008
1009 maxes := []float32{}
1010 var maxesTotal float32
1011 for _, row := range rows {
1012 var maxH float32
1013 for i := row[0]; i < row[1]; i++ {
1014 vState := s[n.Children[i].Properties.Id]
1015 _, h := getInnerSize(&n.Children[i], state)
1016 h = minHeight(n.Children[i], state, h)
1017 vState.Height = h
1018 h += vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
1019 maxH = utils.Max(maxH, h)
1020 (*state)[n.Children[i].Properties.Id] = vState
1021 }
1022 maxes = append(maxes, maxH)
1023 maxesTotal += maxH
1024 }
1025
1026 os := ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows))
1027 if os < 0 || content != "normal" {
1028 os = 0
1029 }
1030
1031 var contentOffset float32
1032
1033 if content == "center" {
1034 contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / 2
1035 } else if content == "end" || content == "flex-end" {
1036 contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal)
1037 } else if content == "start" || content == "flex-start" || content == "baseline" {
1038 // This is redundent but it helps keep track
1039 contentOffset = 0
1040 } else if content == "space-between" {
1041 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows)-1)
1042 } else if content == "space-around" {
1043 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows))
1044 contentOffset = os / 2
1045 } else if content == "space-evenly" {
1046 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows)+1)
1047 contentOffset = os
1048 }
1049
1050 for c, row := range rows {
1051 maxH := maxes[c]
1052 var sum float32
1053 for i := 0; i < c; i++ {
1054 sum += maxes[i]
1055 }
1056 if align == "start" || align == "flex-start" || align == "self-start" || align == "normal" {
1057 for i := row[0]; i < row[1]; i++ {
1058 vState := s[n.Children[i].Properties.Id]
1059
1060 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1061
1062 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1063 offset += ((os) * float32(c))
1064 }
1065
1066 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1067 vState.Y = offset
1068 (*state)[n.Children[i].Properties.Id] = vState
1069 }
1070 } else if align == "center" {
1071 for i := row[0]; i < row[1]; i++ {
1072 vState := s[n.Children[i].Properties.Id]
1073
1074 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1075
1076 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1077 offset += (os * float32(c+1)) - (os / 2)
1078 }
1079
1080 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) < maxH {
1081 offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))) / 2
1082 }
1083 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1084 vState.Y = offset
1085 (*state)[n.Children[i].Properties.Id] = vState
1086 }
1087 } else if align == "end" || align == "flex-end" || align == "self-end" {
1088 for i := row[0]; i < row[1]; i++ {
1089 vState := s[n.Children[i].Properties.Id]
1090
1091 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1092
1093 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1094 offset += os * float32(c+1)
1095 }
1096
1097 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) < maxH {
1098 offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)))
1099 }
1100 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1101 vState.Y = offset
1102 (*state)[n.Children[i].Properties.Id] = vState
1103
1104 }
1105 } else if align == "stretch" {
1106 for i := row[0]; i < row[1]; i++ {
1107 vState := s[n.Children[i].Properties.Id]
1108
1109 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top
1110
1111 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1112 offset += ((os) * float32(c))
1113 }
1114
1115 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1116 vState.Y = offset
1117 vState.Height = maxH - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
1118 (*state)[n.Children[i].Properties.Id] = vState
1119
1120 }
1121 }
1122 }
1123}
1124
1125func justifyCols(cols [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
1126 s := *state
1127 self := s[n.Properties.Id]
1128
1129 selfHeight := (self.Height) - (self.Padding.Top + self.Padding.Bottom)
1130 for _, col := range cols {
1131 yCollect := self.Y + self.Padding.Top
1132 var colHeight float32
1133 for i := col[0]; i <= col[1]; i++ {
1134 v := n.Children[i]
1135 vState := s[v.Properties.Id]
1136 colHeight += vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
1137 }
1138
1139 if justify == "center" {
1140 offset := ((selfHeight - colHeight) / 2)
1141 yCollect += offset
1142 for i := col[0]; i <= col[1]; i++ {
1143 v := n.Children[i]
1144 vState := s[v.Properties.Id]
1145 yStore := vState.Y
1146 vState.Y = yCollect + vState.Margin.Top
1147 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1148 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1149 (*state)[v.Properties.Id] = vState
1150 }
1151 }
1152
1153 if justify == "end" || justify == "flex-end" {
1154 offset := (selfHeight - colHeight)
1155 yCollect += offset
1156 for i := col[0]; i <= col[1]; i++ {
1157 v := n.Children[i]
1158 vState := s[v.Properties.Id]
1159 yStore := vState.Y
1160 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top
1161 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1162 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1163 (*state)[v.Properties.Id] = vState
1164 }
1165 }
1166
1167 if justify == "space-evenly" {
1168 offset := (selfHeight - colHeight) / (float32(col[1]-col[0]) + 2)
1169 for i := col[0]; i <= col[1]; i++ {
1170 v := n.Children[i]
1171 vState := s[v.Properties.Id]
1172 yStore := vState.Y
1173 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top + offset
1174 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width + offset
1175 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1176 (*state)[v.Properties.Id] = vState
1177 }
1178 }
1179
1180 if justify == "space-between" {
1181 offset := (selfHeight - colHeight) / (float32(col[1] - col[0]))
1182 for i := col[0]; i <= col[1]; i++ {
1183 v := n.Children[i]
1184 vState := s[v.Properties.Id]
1185 yStore := vState.Y
1186 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top
1187 if col[1]-col[0] != 0 {
1188 vState.Y += offset * float32(i-col[0])
1189 } else if reversed {
1190 vState.Y += selfHeight - (vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width)
1191 }
1192 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1193 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1194 (*state)[v.Properties.Id] = vState
1195 }
1196 }
1197 if justify == "space-around" {
1198 offset := (selfHeight - colHeight) / (float32(col[1]-col[0]) + 1)
1199 for i := col[0]; i <= col[1]; i++ {
1200 v := n.Children[i]
1201 vState := s[v.Properties.Id]
1202 yStore := vState.Y
1203 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top
1204 if col[1]-col[0] == 0 {
1205 vState.Y += offset / 2
1206 } else {
1207 vState.Y += (offset * float32(i-col[0])) + (offset / 2)
1208 }
1209 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1210 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1211 (*state)[v.Properties.Id] = vState
1212 }
1213 }
1214 }
1215}
1216
1217func alignCols(cols [][]int, n *element.Node, state *map[string]element.State, align, content string, minWidths [][]float32) {
1218 s := *state
1219 self := s[n.Properties.Id]
1220
1221 if (align == "stretch" && content == "stretch") || (align == "stretch" && content == "normal") || (align == "normal" && content == "stretch") {
1222 return
1223 }
1224
1225 selfWidth := (self.Width - self.Padding.Left) - self.Padding.Right
1226
1227 var rowWidth float32
1228 colWidths := []float32{}
1229 for _, col := range cols {
1230 var maxWidth float32
1231 for i := col[0]; i <= col[1]; i++ {
1232 v := n.Children[i]
1233 vState := s[v.Properties.Id]
1234 vState.Width = setWidth(&v, state, minWidths[i][0])
1235 maxWidth = utils.Max(maxWidth, vState.Width+vState.Margin.Left+vState.Margin.Right+(vState.Border.Width*2))
1236 (*state)[v.Properties.Id] = vState
1237 }
1238 colWidths = append(colWidths, maxWidth)
1239 rowWidth += maxWidth
1240 }
1241 var xOffset float32
1242 for c, col := range cols {
1243
1244 if align != "normal" {
1245 // var offset float32
1246 for i := col[0]; i <= col[1]; i++ {
1247 v := n.Children[i]
1248 vState := s[v.Properties.Id]
1249 xStore := vState.X
1250 vState.X = self.X + self.Padding.Left + self.Border.Width + xOffset + vState.Margin.Left + vState.Border.Width
1251 if align == "center" {
1252 vState.X += ((colWidths[c] - (vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2))) / 2)
1253 } else if align == "end" || align == "flex-end" || align == "self-end" {
1254 vState.X += (colWidths[c] - (vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)))
1255 } else if align == "stretch" {
1256 vState.Width = (colWidths[c] - (vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)))
1257 }
1258 propagateOffsets(&n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1259 (*state)[v.Properties.Id] = vState
1260 }
1261 xOffset += colWidths[c]
1262 } else {
1263 // if align is set to normal then make the elements the size of the column
1264 // the size of the column is
1265 for i := col[0]; i <= col[1]; i++ {
1266 v := n.Children[i]
1267 vState := s[v.Properties.Id]
1268 vState.Width = colWidths[c] - (vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2))
1269 (*state)[v.Properties.Id] = vState
1270 }
1271 }
1272 }
1273
1274 var offset float32
1275 if content == "center" {
1276 offset = ((selfWidth - rowWidth) / 2)
1277 }
1278 if content == "end" || content == "flex-end" {
1279 offset = (selfWidth - rowWidth)
1280 }
1281 if content == "space-evenly" {
1282 offset = (selfWidth - rowWidth) / (float32(len(cols) + 1))
1283 }
1284 if content == "space-between" {
1285 offset = (selfWidth - rowWidth) / (float32(len(cols) - 1))
1286 }
1287 if content == "space-around" {
1288 offset = (selfWidth - rowWidth) / (float32(len(cols)))
1289 }
1290 if content == "normal" || content == "stretch" {
1291 if align == "start" || align == "end" || content == "flex-end" {
1292 offset = (selfWidth - rowWidth) / (float32(len(cols)))
1293 }
1294 if align == "center" {
1295 offset = ((selfWidth - rowWidth) / (float32(len(cols))))
1296 }
1297 }
1298 for c, col := range cols {
1299
1300 for i := col[0]; i <= col[1]; i++ {
1301 v := n.Children[i]
1302 vState := s[v.Properties.Id]
1303 xStore := vState.X
1304 if content == "center" || content == "end" || content == "flex-end" {
1305 vState.X += offset
1306 } else if content == "space-evenly" {
1307 vState.X += offset * float32(c+1)
1308 } else if content == "space-between" {
1309 vState.X += offset * float32(c)
1310 } else if content == "space-around" {
1311 if c == 0 {
1312 vState.X += offset / 2
1313 } else {
1314 vState.X += (offset * float32(c)) + (offset / 2)
1315 }
1316 } else if content == "normal" || content == "stretch" {
1317 if align == "start" {
1318 vState.X += offset * float32(c)
1319 }
1320 if align == "end" || content == "flex-end" {
1321 vState.X += offset * float32(c+1)
1322 }
1323 if align == "center" {
1324 if c == 0 {
1325 vState.X += offset / 2
1326 } else {
1327 vState.X += (offset * float32(c)) + (offset / 2)
1328 }
1329 }
1330 }
1331 propagateOffsets(&n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1332 (*state)[v.Properties.Id] = vState
1333 }
1334 }
1335}