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