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