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