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 // 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
353 fmt.Println("here")
354 var colHeight float32
355 var colIndex int
356 cols := [][][]float32{}
357
358 // Map elements to columns
359 for i, v := range n.Children {
360 vState := s[v.Properties.Id]
361
362 w, _ := getInnerSize(&v, state)
363
364 fmt.Println(w, selfWidth, colIndex)
365
366 height := vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
367 width := w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
368
369 if colHeight+height > selfHeight {
370 colHeight = height
371 colIndex++
372 } else {
373 colHeight += height
374 }
375 if colIndex >= len(cols) {
376 cols = append(cols, [][]float32{})
377 }
378 cols[colIndex] = append(cols[colIndex], []float32{float32(i), height, width, w})
379 }
380
381 // Find the max total width of all columns
382 var totalMaxWidth float32
383 maxWidths := [][]float32{}
384 for _, col := range cols {
385 var maxWidth, maxHeight, actualWidth float32
386 for _, element := range col {
387 maxHeight = utils.Max(utils.Max(element[1], minHeights[int(element[0])]), maxHeight)
388 maxWidth = utils.Max(element[2], maxWidth)
389 if element[2] == maxWidth {
390 actualWidth = element[3]
391 }
392 }
393 rows = append(rows, []int{int(col[0][0]), int(col[len(col)-1][0]), int(maxHeight)})
394 totalMaxWidth += maxWidth
395 maxWidths = append(maxWidths, []float32{actualWidth, maxWidth})
396 fmt.Println(actualWidth)
397 }
398
399 // Move the elements into the correct position
400 var xOffset float32
401 for i, col := range cols {
402 // Move the elements into the correct position
403 yOffset := self.Y + self.Border.Width + self.Padding.Top
404 for _, element := range col {
405 v := n.Children[int(element[0])]
406 vState := s[v.Properties.Id]
407 xStore := vState.X
408 yStore := vState.Y
409 vState.X = self.X + self.Padding.Left + self.Border.Width + xOffset + vState.Margin.Left
410 vState.Y = yOffset + vState.Margin.Top + vState.Border.Width
411 vState.Height = minHeights[int(element[0])]
412 fmt.Println(totalMaxWidth > selfWidth)
413 if totalMaxWidth > selfWidth {
414 if v.Style["width"] == "" && v.Style["max-width"] == "" {
415 vState.Width = maxWidths[i][0]
416 } else {
417 if v.Style["width"] != "" {
418 w := utils.ConvertToPixels(v.Style["width"], vState.EM, self.Width)
419 vState.Width = w + vState.Padding.Left + vState.Padding.Right
420 } else if v.Style["max-width"] != "" {
421 mw := utils.ConvertToPixels(v.Style["max-width"], vState.EM, self.Width)
422 vState.Width = utils.Max(mw, maxWidths[i][0])
423 }
424 }
425 } else {
426 nw := selfWidth / float32(len(rows))
427 vState.Width = nw - (vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2))
428 }
429
430 propagateOffsets(&v, xStore, yStore, vState.X, vState.Y, state)
431
432 yOffset += vState.Margin.Top + vState.Border.Width + minHeights[int(element[0])] + vState.Margin.Bottom + vState.Border.Width
433 (*state)[v.Properties.Id] = vState
434 }
435 if totalMaxWidth <= selfWidth {
436 nw := selfWidth / float32(len(rows))
437 xOffset += nw
438 } else {
439 xOffset += maxWidths[i][1]
440 }
441
442 }
443
444 }
445
446 if flexReversed {
447 colReverse(rows, n, state)
448 }
449
450 if justifyContent != "normal" {
451 justifyCols(rows, n, state, justifyContent, flexReversed)
452 }
453 if alignContent != "normal" || alignItems != "normal" {
454 alignCols(rows, n, state, alignItems, alignContent, innerSizes)
455 }
456 }
457 if n.Style["height"] == "" && n.Style["min-height"] == "" {
458 _, h := getInnerSize(n, state)
459 self.Height = h
460 }
461 (*state)[n.Properties.Id] = self
462 },
463 }
464}
465
466func applyBlock(n *element.Node, state *map[string]element.State) {
467 if len(n.Children) > 0 {
468 accum := float32(0)
469 inlineOffset := float32(0)
470 s := *state
471 lastHeight := float32(0)
472 baseY := s[n.Children[0].Properties.Id].Y
473 for i := 0; i < len(n.Children); i++ {
474 v := &n.Children[i]
475 vState := s[v.Properties.Id]
476
477 if v.Style["display"] != "block" {
478 vState.Y += inlineOffset
479 accum = (vState.Y - baseY)
480 lastHeight = vState.Height
481 } else if v.Style["position"] != "absolute" {
482 vState.Y += accum
483 inlineOffset += (vState.Height + (vState.Border.Width * 2) + vState.Margin.Top + vState.Margin.Bottom + vState.Padding.Top + vState.Padding.Bottom) + lastHeight
484 }
485 (*state)[v.Properties.Id] = vState
486 }
487 }
488}
489
490func deInline(n *element.Node, state *map[string]element.State) {
491 s := *state
492 // self := s[n.Properties.Id]
493 baseX := float32(-1)
494 baseY := float32(-1)
495 for _, v := range n.Children {
496 vState := s[v.Properties.Id]
497
498 if v.Style["display"] == "inline" {
499 if baseX < 0 && baseY < 0 {
500 baseX = vState.X
501 baseY = vState.Y
502 } else {
503 vState.X = baseX
504 vState.Y = baseY
505 (*state)[v.Properties.Id] = vState
506
507 }
508 } else {
509 baseX = float32(-1)
510 baseY = float32(-1)
511 }
512
513 if len(v.Children) > 0 {
514 deInline(&v, state)
515 }
516 }
517
518}
519
520func applyInline(n *element.Node, state *map[string]element.State) {
521 pl := inline.Init()
522 for i := 0; i < len(n.Children); i++ {
523 v := &n.Children[i]
524
525 if len(v.Children) > 0 {
526 applyInline(v, state)
527 }
528
529 if pl.Selector(v) {
530 pl.Handler(v, state)
531 }
532 }
533}
534
535func propagateOffsets(n *element.Node, prevx, prevy, newx, newy float32, state *map[string]element.State) {
536 s := *state
537 for _, v := range n.Children {
538 vState := s[v.Properties.Id]
539 xStore := (vState.X - prevx) + newx
540 yStore := (vState.Y - prevy) + newy
541
542 if len(v.Children) > 0 {
543 propagateOffsets(&v, vState.X, vState.Y, xStore, yStore, state)
544 }
545 vState.X = xStore
546 vState.Y = yStore
547 (*state)[v.Properties.Id] = vState
548 }
549
550}
551
552func countText(n element.Node) int {
553 count := 0
554 groups := []int{}
555 for _, v := range n.Children {
556 if v.TagName == "notaspan" {
557 count += 1
558 }
559 if v.Style["display"] == "block" {
560 groups = append(groups, count)
561 count = 0
562 }
563 if len(v.Children) > 0 {
564 count += countText(v)
565 }
566 }
567 groups = append(groups, count)
568
569 sort.Slice(groups, func(i, j int) bool {
570 return groups[i] > groups[j]
571 })
572 return groups[0]
573}
574
575func minHeight(n element.Node, state *map[string]element.State, prev float32) float32 {
576 s := *state
577 self := s[n.Properties.Id]
578 if n.Style["min-height"] != "" {
579 mw := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
580 return utils.Max(prev, mw)
581 } else {
582 return prev
583 }
584
585}
586
587func getMinHeight(n *element.Node, state *map[string]element.State) float32 {
588 s := *state
589 self := s[n.Properties.Id]
590 selfHeight := float32(0)
591
592 if len(n.Children) > 0 {
593 for _, v := range n.Children {
594 selfHeight = utils.Max(selfHeight, getNodeHeight(&v, state))
595 }
596 } else {
597 selfHeight = self.Height
598 }
599 if n.Style["min-height"] != "" {
600 mh := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
601 selfHeight = utils.Max(mh, selfHeight)
602 }
603
604 selfHeight += self.Padding.Top + self.Padding.Bottom
605 return selfHeight
606}
607
608func getMinWidth(n *element.Node, state *map[string]element.State) float32 {
609 s := *state
610 self := s[n.Properties.Id]
611 selfWidth := float32(0)
612
613 if len(n.Children) > 0 {
614 for _, v := range n.Children {
615 selfWidth = utils.Max(selfWidth, getNodeWidth(&v, state))
616 }
617 } else {
618 selfWidth = self.Width
619 }
620 if n.Style["min-width"] != "" {
621 mw := utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
622 selfWidth = utils.Max(mw, selfWidth)
623 }
624
625 selfWidth += self.Padding.Left + self.Padding.Right
626 return selfWidth
627}
628func getMaxWidth(n *element.Node, state *map[string]element.State) float32 {
629 s := *state
630 self := s[n.Properties.Id]
631 selfWidth := float32(0)
632
633 if len(n.Children) > 0 {
634 var maxRowWidth, rowWidth float32
635
636 for _, v := range n.Children {
637 rowWidth += getNodeWidth(&v, state)
638 if v.Style["display"] != "inline" {
639 maxRowWidth = utils.Max(rowWidth, maxRowWidth)
640 rowWidth = 0
641 }
642 }
643 selfWidth = utils.Max(rowWidth, maxRowWidth)
644 } else {
645 selfWidth = self.Width
646 }
647
648 selfWidth += self.Padding.Left + self.Padding.Right
649 return selfWidth
650}
651
652func getNodeWidth(n *element.Node, state *map[string]element.State) float32 {
653 s := *state
654 self := s[n.Properties.Id]
655 w := float32(0)
656 w += self.Padding.Left
657 w += self.Padding.Right
658
659 w += self.Margin.Left
660 w += self.Margin.Right
661
662 w += self.Width
663
664 w += self.Border.Width * 2
665
666 for _, v := range n.Children {
667 w = utils.Max(w, getNodeWidth(&v, state))
668 }
669
670 return w
671}
672
673func getNodeHeight(n *element.Node, state *map[string]element.State) float32 {
674 s := *state
675 self := s[n.Properties.Id]
676 h := float32(0)
677 h += self.Padding.Top
678 h += self.Padding.Bottom
679
680 h += self.Margin.Top
681 h += self.Margin.Bottom
682
683 h += self.Height
684
685 h += self.Border.Width * 2
686
687 for _, v := range n.Children {
688 h = utils.Max(h, getNodeHeight(&v, state))
689 }
690
691 return h
692}
693
694func getInnerSize(n *element.Node, state *map[string]element.State) (float32, float32) {
695 s := *state
696 self := s[n.Properties.Id]
697
698 minx := float32(10e10)
699 maxw := float32(0)
700 miny := float32(10e10)
701 maxh := float32(0)
702 for _, v := range n.Children {
703 vState := s[v.Properties.Id]
704 minx = utils.Min(vState.X, minx)
705 miny = utils.Min(vState.Y-vState.Margin.Top, miny)
706 // Don't add the top or left because the x&y values already take that into account
707 hOffset := (vState.Border.Width) + vState.Margin.Bottom
708 wOffset := (vState.Border.Width) + vState.Margin.Right
709 maxw = utils.Max(vState.X+vState.Width+wOffset, maxw)
710 maxh = utils.Max(vState.Y+vState.Height+hOffset, maxh)
711 }
712 w := maxw - minx
713 h := maxh - miny
714
715 w += self.Padding.Left + self.Padding.Right
716 h += self.Padding.Top + self.Padding.Bottom
717 if n.Style["width"] != "" {
718 w = self.Width
719 }
720 if n.Style["height"] != "" {
721 h = self.Height
722 }
723
724 return w, h
725}
726
727func add2d(arr [][]float32, index int) float32 {
728 var sum float32
729 if len(arr) == 0 {
730 return sum
731 }
732
733 for i := 0; i < len(arr); i++ {
734 if len(arr[i]) <= index {
735 return sum
736 }
737 sum += arr[i][index]
738 }
739
740 return sum
741}
742
743func colReverse(cols [][]int, n *element.Node, state *map[string]element.State) {
744 s := *state
745 for _, col := range cols {
746 tempNodes := []element.Node{}
747 tempStates := []element.State{}
748
749 for i := col[1]; i >= col[0]; i-- {
750 tempNodes = append(tempNodes, n.Children[i])
751 tempStates = append(tempStates, s[n.Children[i].Properties.Id])
752 }
753
754 for i := 0; i < len(tempStates); i++ {
755 e := col[0] + i
756 vState := s[n.Children[e].Properties.Id]
757 propagateOffsets(&n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
758 vState.Y = tempStates[i].Y
759 (*state)[n.Children[e].Properties.Id] = vState
760 }
761 for i := 0; i < len(tempStates); i++ {
762 e := col[0] + i
763 n.Children[e] = tempNodes[i]
764 }
765 }
766}
767
768func rowReverse(rows [][]int, n *element.Node, state *map[string]element.State) {
769 s := *state
770 for _, row := range rows {
771 tempNodes := []element.Node{}
772 tempStates := []element.State{}
773
774 for i := row[1] - 1; i >= row[0]; i-- {
775 tempNodes = append(tempNodes, n.Children[i])
776 tempStates = append(tempStates, s[n.Children[i].Properties.Id])
777 }
778
779 for i := 0; i < len(tempStates); i++ {
780 e := row[0] + i
781 vState := s[n.Children[e].Properties.Id]
782 propagateOffsets(&n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
783 vState.X = tempStates[i].X
784 (*state)[n.Children[e].Properties.Id] = vState
785 }
786 for i := 0; i < len(tempStates); i++ {
787 e := row[0] + i
788 n.Children[e] = tempNodes[i]
789 }
790
791 for i := row[1] - 1; i >= row[0]; i-- {
792 vState := s[n.Children[i].Properties.Id]
793 var xChng float32
794 if i < row[1]-1 {
795 sib := s[n.Children[i+1].Properties.Id]
796 xChng = sib.X - (sib.Border.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Width + vState.Width)
797 } else {
798 parent := s[n.Properties.Id]
799 xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Width)
800
801 }
802 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
803 vState.X = xChng
804 (*state)[n.Children[i].Properties.Id] = vState
805 }
806 }
807}
808
809func justifyRow(rows [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
810 s := *state
811 for _, row := range rows {
812
813 if (justify == "flex-end" || justify == "end" || justify == "right") && !reversed {
814 for i := row[1] - 1; i >= row[0]; i-- {
815 vState := s[n.Children[i].Properties.Id]
816 var xChng float32
817 if i < row[1]-1 {
818 sib := s[n.Children[i+1].Properties.Id]
819 xChng = sib.X - (sib.Border.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Width + vState.Width)
820 } else {
821 parent := s[n.Properties.Id]
822 xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Width)
823
824 }
825 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
826 vState.X = xChng
827 (*state)[n.Children[i].Properties.Id] = vState
828 }
829 } else if (justify == "flex-end" || justify == "start" || justify == "left" || justify == "normal") && reversed {
830 for i := row[0]; i < row[1]; i++ {
831 vState := s[n.Children[i].Properties.Id]
832 var xChng float32
833 if i > row[0] {
834 sib := s[n.Children[i-1].Properties.Id]
835 xChng = sib.X + sib.Width + (sib.Border.Width * 2) + sib.Margin.Right + vState.Margin.Left + vState.Border.Width
836 } else {
837 parent := s[n.Properties.Id]
838 xChng = parent.X + parent.Padding.Right + vState.Margin.Left + vState.Border.Width + parent.Border.Width
839
840 }
841 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
842 vState.X = xChng
843 (*state)[n.Children[i].Properties.Id] = vState
844 }
845 } else if justify == "center" {
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.X + parent.Border.Width
851 offset := (parent.Width - ((f.X - po) + (l.X - po) + l.Width + f.Border.Width + l.Border.Width)) / 2
852
853 for i := row[0]; i < row[1]; i++ {
854 vState := s[n.Children[i].Properties.Id]
855
856 if !reversed {
857 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
858 vState.X += offset
859 } else {
860 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
861 vState.X -= offset
862 }
863 (*state)[n.Children[i].Properties.Id] = vState
864 }
865
866 } else if justify == "space-between" {
867 // get width of row then center (by getting last x + w + mr + b)
868 f := s[n.Children[row[0]].Properties.Id]
869 l := s[n.Children[row[1]-1].Properties.Id]
870 parent := s[n.Properties.Id]
871 po := parent.Border.Width + parent.Width
872 po -= parent.Padding.Left + parent.Padding.Right
873
874 // make po repersent the total space between elements
875 for i := row[0]; i < row[1]; i++ {
876 vState := s[n.Children[i].Properties.Id]
877 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
878 }
879
880 po /= float32(((row[1]) - row[0]) - 1)
881
882 if (row[1]-1)-row[0] > 0 {
883 for i := row[0]; i < row[1]; i++ {
884 vState := s[n.Children[i].Properties.Id]
885 var offset float32
886 if i == row[0] {
887 offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
888 } else if i == row[1]-1 {
889 offset = (parent.X + parent.Width) - (l.Margin.Right + l.Border.Width + l.Width + parent.Padding.Right)
890 } else {
891 if !reversed {
892 offset = vState.X + (po * float32(i-row[0]))
893 } else {
894 offset = vState.X - (po * float32(((row[1]-1)-row[0])-(i-row[0])))
895 }
896
897 }
898
899 propagateOffsets(&n.Children[i], vState.X, vState.Y, offset, vState.Y, state)
900 vState.X = offset
901 (*state)[n.Children[i].Properties.Id] = vState
902 }
903 }
904 // else {
905
906 // this is/was causing issues, removed and it fixed its self
907
908 // if there is one element move left
909 // vState := s[n.Children[(row[1]-1)-row[0]].Properties.Id]
910 // var offset float32
911
912 // if !reversed {
913 // offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
914 // propagateOffsets(&n.Children[(row[1]-1)-row[0]], vState.X, vState.Y, offset, vState.Y, state)
915 // vState.X = offset
916
917 // (*state)[n.Children[(row[1]-1)-row[0]].Properties.Id] = vState
918 // }
919
920 // }
921
922 } else if justify == "space-evenly" {
923 // get width of row then center (by getting last x + w + mr + b)
924 parent := s[n.Properties.Id]
925 po := parent.Border.Width + parent.Width
926 po -= parent.Padding.Left + parent.Padding.Right
927
928 // make po repersent the total space between elements
929 for i := row[0]; i < row[1]; i++ {
930 vState := s[n.Children[i].Properties.Id]
931 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
932 }
933
934 po /= float32(((row[1]) - row[0]) + 1)
935
936 // get width of row then center (by getting last x + w + mr + b)
937
938 for i := row[0]; i < row[1]; i++ {
939 vState := s[n.Children[i].Properties.Id]
940
941 if !reversed {
942 offset := po * (float32(i-row[0]) + 1)
943 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
944 vState.X += offset
945 } else {
946 offset := po * float32(((row[1]-1)-row[0])-((i-row[0])-1))
947
948 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
949 vState.X -= offset
950 }
951 (*state)[n.Children[i].Properties.Id] = vState
952 }
953
954 } else if justify == "space-around" {
955 // get width of row then center (by getting last x + w + mr + b)
956 parent := s[n.Properties.Id]
957 po := parent.Border.Width + parent.Width
958 po -= parent.Padding.Left + parent.Padding.Right
959
960 // make po repersent the total space between elements
961 for i := row[0]; i < row[1]; i++ {
962 vState := s[n.Children[i].Properties.Id]
963 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
964 }
965
966 po /= float32(((row[1]) - row[0]))
967
968 // get width of row then center (by getting last x + w + mr + b)
969
970 for i := row[0]; i < row[1]; i++ {
971 vState := s[n.Children[i].Properties.Id]
972
973 if !reversed {
974 m := (float32(i-row[0]) + 1)
975 if i-row[0] == 0 {
976 m = 0.5
977 } else {
978 m -= 0.5
979 }
980 offset := po * m
981 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
982 vState.X += offset
983 } else {
984 m := float32(((row[1] - 1) - row[0]) - ((i - row[0]) - 1))
985 m -= 0.5
986 offset := po * m
987
988 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
989 vState.X -= offset
990 }
991 (*state)[n.Children[i].Properties.Id] = vState
992 }
993
994 }
995
996 }
997}
998
999func alignRow(rows [][]int, n *element.Node, state *map[string]element.State, align, content string) {
1000 // !ISSUE: Baseline isn't properly impleamented
1001
1002 s := *state
1003 self := s[n.Properties.Id]
1004
1005 maxes := []float32{}
1006 var maxesTotal float32
1007 for _, row := range rows {
1008 var maxH float32
1009 for i := row[0]; i < row[1]; i++ {
1010 vState := s[n.Children[i].Properties.Id]
1011 _, h := getInnerSize(&n.Children[i], state)
1012 h = minHeight(n.Children[i], state, h)
1013 vState.Height = h
1014 h += vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
1015 maxH = utils.Max(maxH, h)
1016 (*state)[n.Children[i].Properties.Id] = vState
1017 }
1018 maxes = append(maxes, maxH)
1019 maxesTotal += maxH
1020 }
1021
1022 os := ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows))
1023 if os < 0 || content != "normal" {
1024 os = 0
1025 }
1026
1027 var contentOffset float32
1028
1029 if content == "center" {
1030 contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / 2
1031 } else if content == "end" || content == "flex-end" {
1032 contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal)
1033 } else if content == "start" || content == "flex-start" || content == "baseline" {
1034 // This is redundent but it helps keep track
1035 contentOffset = 0
1036 } else if content == "space-between" {
1037 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows)-1)
1038 } else if content == "space-around" {
1039 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows))
1040 contentOffset = os / 2
1041 } else if content == "space-evenly" {
1042 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows)+1)
1043 contentOffset = os
1044 }
1045
1046 for c, row := range rows {
1047 maxH := maxes[c]
1048 var sum float32
1049 for i := 0; i < c; i++ {
1050 sum += maxes[i]
1051 }
1052 if align == "start" || align == "flex-start" || align == "self-start" || align == "normal" {
1053 for i := row[0]; i < row[1]; i++ {
1054 vState := s[n.Children[i].Properties.Id]
1055
1056 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1057
1058 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1059 offset += ((os) * float32(c))
1060 }
1061
1062 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1063 vState.Y = offset
1064 (*state)[n.Children[i].Properties.Id] = vState
1065 }
1066 } else if align == "center" {
1067 for i := row[0]; i < row[1]; i++ {
1068 vState := s[n.Children[i].Properties.Id]
1069
1070 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1071
1072 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1073 offset += (os * float32(c+1)) - (os / 2)
1074 }
1075
1076 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) < maxH {
1077 offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))) / 2
1078 }
1079 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1080 vState.Y = offset
1081 (*state)[n.Children[i].Properties.Id] = vState
1082 }
1083 } else if align == "end" || align == "flex-end" || align == "self-end" {
1084 for i := row[0]; i < row[1]; i++ {
1085 vState := s[n.Children[i].Properties.Id]
1086
1087 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1088
1089 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1090 offset += os * float32(c+1)
1091 }
1092
1093 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) < maxH {
1094 offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)))
1095 }
1096 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1097 vState.Y = offset
1098 (*state)[n.Children[i].Properties.Id] = vState
1099
1100 }
1101 } else if align == "stretch" {
1102 for i := row[0]; i < row[1]; i++ {
1103 vState := s[n.Children[i].Properties.Id]
1104
1105 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top
1106
1107 if n.Style["height"] != "" || n.Style["min-height"] != "" {
1108 offset += ((os) * float32(c))
1109 }
1110
1111 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1112 vState.Y = offset
1113 vState.Height = maxH - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
1114 (*state)[n.Children[i].Properties.Id] = vState
1115
1116 }
1117 }
1118 }
1119}
1120
1121func justifyCols(cols [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
1122 s := *state
1123 self := s[n.Properties.Id]
1124
1125 selfHeight := (self.Height) - (self.Padding.Top + self.Padding.Bottom)
1126 for _, col := range cols {
1127 yCollect := self.Y + self.Padding.Top
1128 var colHeight float32
1129 for i := col[0]; i <= col[1]; i++ {
1130 v := n.Children[i]
1131 vState := s[v.Properties.Id]
1132 colHeight += vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
1133 }
1134
1135 if justify == "center" {
1136 offset := ((selfHeight - colHeight) / 2)
1137 yCollect += offset
1138 for i := col[0]; i <= col[1]; i++ {
1139 v := n.Children[i]
1140 vState := s[v.Properties.Id]
1141 yStore := vState.Y
1142 vState.Y = yCollect + vState.Margin.Top
1143 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1144 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1145 (*state)[v.Properties.Id] = vState
1146 }
1147 }
1148
1149 if justify == "end" || justify == "flex-end" {
1150 offset := (selfHeight - colHeight)
1151 yCollect += offset
1152 for i := col[0]; i <= col[1]; i++ {
1153 v := n.Children[i]
1154 vState := s[v.Properties.Id]
1155 yStore := vState.Y
1156 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top
1157 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1158 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1159 (*state)[v.Properties.Id] = vState
1160 }
1161 }
1162
1163 if justify == "space-evenly" {
1164 offset := (selfHeight - colHeight) / (float32(col[1]-col[0]) + 2)
1165 for i := col[0]; i <= col[1]; i++ {
1166 v := n.Children[i]
1167 vState := s[v.Properties.Id]
1168 yStore := vState.Y
1169 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top + offset
1170 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width + offset
1171 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1172 (*state)[v.Properties.Id] = vState
1173 }
1174 }
1175
1176 if justify == "space-between" {
1177 offset := (selfHeight - colHeight) / (float32(col[1] - col[0]))
1178 for i := col[0]; i <= col[1]; i++ {
1179 v := n.Children[i]
1180 vState := s[v.Properties.Id]
1181 yStore := vState.Y
1182 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top
1183 if col[1]-col[0] != 0 {
1184 vState.Y += offset * float32(i-col[0])
1185 } else if reversed {
1186 vState.Y += selfHeight - (vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width)
1187 }
1188 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1189 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1190 (*state)[v.Properties.Id] = vState
1191 }
1192 }
1193 if justify == "space-around" {
1194 offset := (selfHeight - colHeight) / (float32(col[1]-col[0]) + 1)
1195 for i := col[0]; i <= col[1]; i++ {
1196 v := n.Children[i]
1197 vState := s[v.Properties.Id]
1198 yStore := vState.Y
1199 vState.Y = yCollect + vState.Border.Width + vState.Margin.Top
1200 if col[1]-col[0] == 0 {
1201 vState.Y += offset / 2
1202 } else {
1203 vState.Y += (offset * float32(i-col[0])) + (offset / 2)
1204 }
1205 yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Width + vState.Margin.Top + vState.Border.Width
1206 propagateOffsets(&n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1207 (*state)[v.Properties.Id] = vState
1208 }
1209 }
1210 }
1211}
1212
1213func alignCols(cols [][]int, n *element.Node, state *map[string]element.State, align, content string, minWidths [][]float32) {
1214 s := *state
1215 self := s[n.Properties.Id]
1216
1217 selfWidth := (self.Width - self.Padding.Left) - self.Padding.Right
1218
1219 var minX, maxX, minX2, maxX2 float32
1220 minX += 10e9
1221 minX2 += 10e9
1222 for _, col := range cols {
1223 for i := col[0]; i <= col[1]; i++ {
1224 v := n.Children[i]
1225 vState := s[v.Properties.Id]
1226 if v.Style["width"] == "" && v.Style["min-width"] == "" && align != "stretch" {
1227 vState.Width = minWidths[i][0]
1228 }
1229 minX = utils.Min(vState.X-vState.Border.Width-vState.Margin.Left, minX)
1230 maxX = utils.Max(vState.X+vState.Width+vState.Border.Width+vState.Margin.Right, maxX)
1231 (*state)[v.Properties.Id] = vState
1232
1233 }
1234 }
1235 rowWidth := maxX - minX
1236
1237 for c, col := range cols {
1238
1239 if content == "normal" {
1240 var offset float32
1241 if align == "center" {
1242 offset = ((selfWidth - rowWidth) / 2)
1243 }
1244 if align == "end" || align == "flex-end" || align == "self-end" {
1245 offset = (selfWidth - rowWidth)
1246 }
1247 for i := col[0]; i <= col[1]; i++ {
1248 v := n.Children[i]
1249 vState := s[v.Properties.Id]
1250 xStore := vState.X
1251 vState.X += offset
1252 propagateOffsets(&n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1253 (*state)[v.Properties.Id] = vState
1254 }
1255 if align == "stretch" {
1256 offset = selfWidth / float32(len(col)+1)
1257 for i := col[0]; i <= col[1]; i++ {
1258 v := n.Children[i]
1259 vState := s[v.Properties.Id]
1260 xStore := vState.X
1261 // !ISSUE: Does not account for max/min width
1262 if v.Style["width"] == "" {
1263 vState.Width = offset - (vState.Margin.Left + (vState.Border.Width * 2) + vState.Margin.Right)
1264 }
1265 propagateOffsets(&n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1266 (*state)[v.Properties.Id] = vState
1267 }
1268 }
1269 } else {
1270 var width float32
1271 for i := col[0]; i <= col[1]; i++ {
1272 v := n.Children[i]
1273 vState := s[v.Properties.Id]
1274 width = utils.Max(vState.Width+vState.Margin.Left+vState.Margin.Right, width)
1275 }
1276 var offset float32
1277 if c > 0 {
1278 sib := s[n.Children[cols[c-1][0]].Properties.Id]
1279 offset = sib.X + sib.Width + sib.Border.Width + sib.Margin.Right
1280 }
1281
1282 for i := col[0]; i <= col[1]; i++ {
1283 v := n.Children[i]
1284 vState := s[v.Properties.Id]
1285 xStore := vState.X
1286 vState.Width = width - (vState.Margin.Left + vState.Margin.Right)
1287 if c > 0 {
1288 vState.X = offset + vState.Margin.Left + vState.Border.Width
1289 }
1290 propagateOffsets(&n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1291 minX2 = utils.Min(vState.X-vState.Border.Width-vState.Margin.Left, minX2)
1292 maxX2 = utils.Max(vState.X+vState.Width+vState.Border.Width+vState.Margin.Right, maxX2)
1293 (*state)[v.Properties.Id] = vState
1294 }
1295 }
1296 }
1297
1298 if content != "normal" {
1299 rowWidth2 := maxX2 - minX2
1300 var offset float32
1301 if content == "center" {
1302 offset = ((selfWidth - rowWidth2) / 2)
1303 }
1304 if content == "end" || content == "flex-end" {
1305 offset = (selfWidth - rowWidth2)
1306 }
1307 if content == "space-evenly" {
1308 offset = (selfWidth - rowWidth2) / (float32(len(cols) + 1))
1309 }
1310 if content == "space-between" {
1311 offset = (selfWidth - rowWidth2) / (float32(len(cols) - 1))
1312 }
1313 if content == "space-around" {
1314 offset = (selfWidth - rowWidth2) / (float32(len(cols)))
1315 }
1316 for c, col := range cols {
1317
1318 for i := col[0]; i <= col[1]; i++ {
1319 v := n.Children[i]
1320 vState := s[v.Properties.Id]
1321 xStore := vState.X
1322 if content == "center" || content == "end" || content == "flex-end" {
1323 vState.X += offset
1324 } else if content == "space-evenly" {
1325 vState.X += offset * float32(c+1)
1326 } else if content == "space-between" {
1327 vState.X += offset * float32(c)
1328 } else if content == "space-around" {
1329 if c == 0 {
1330 vState.X += offset / 2
1331 } else {
1332 vState.X += (offset * float32(c)) + (offset / 2)
1333 }
1334 }
1335 propagateOffsets(&n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1336 (*state)[v.Properties.Id] = vState
1337 }
1338 }
1339 }
1340}