Flexbox
Flexbox is a high level positioning plugin that allows for dynamic positioning of elements based apon container sizing. To learn more about flexbox refer to this MDN article, in this document we will go into the impleamentation of flexbox rather than the usage of it.
"display": "flex", "justify-content": "*", "align-content": "*", "align-items": "*", "flex-wrap": "*", "flex-direction": "*",
# Flex Properties
justify-content | align-content | align-items | flex-wrap | flex-direction |
---|---|---|---|---|
normal | normal | normal | nowrap | row |
center | center | center | wrap | column |
flex-start | flex-start | flex-start | row-reverse | |
flex-end | flex-end | flex-end | column-reverse | |
space-between | space-between | stretch | ||
space-around | space-around | baseline | ||
space-evenly | stretch |
# order?(go)
asd
1package flex
2
3import (
4 "gui/cstyle"
5 "gui/cstyle/plugins/inline"
6 "gui/element"
7 "gui/utils"
8 "sort"
9 "strings"
10)
11
12func Init() cstyle.Plugin {
13 return cstyle.Plugin{
14 Selector: func(n *element.Node) bool {
15 styles := map[string]string{
16 "display": "flex",
17 }
18 matches := true
19 for name, value := range styles {
20 if (n.Style[name] != value || n.Style[name] == "") && !(value == "*") {
21 matches = false
22 }
23 }
24 return matches
25 },
26 Level: 3,
27 Handler: func(n *element.Node, state *map[string]element.State) {
28 s := *state
29 self := s[n.Properties.Id]
30
31 verbs := strings.Split(n.Style["flex-direction"], "-")
32 flexDirection := verbs[0]
33 if flexDirection == "" {
34 flexDirection = "row"
35 }
36 flexReversed := false
37 if len(verbs) > 1 {
38 flexReversed = true
39 }
40
41 var flexWrapped bool
42 if n.Style["flex-wrap"] == "wrap" {
43 flexWrapped = true
44 } else {
45 flexWrapped = false
46 }
47
48 alignContent := n.Style["align-content"]
49 if alignContent == "" {
50 alignContent = "normal"
51 }
52 alignItems := n.Style["align-items"]
53 if alignItems == "" {
54 alignItems = "normal"
55 }
56 justifyItems := n.Style["justify-items"]
57 if justifyItems == "" {
58 justifyItems = "normal"
59 }
60
61 justifyContent := n.Style["justify-content"]
62 if justifyContent == "" {
63 justifyContent = "normal"
64 }
65 // fmt.Println(flexDirection, flexReversed, flexWrapped, hAlign, vAlign, justifyItems, justifyContent)
66 rows := [][]int{}
67 maxH := float32(0)
68 // maxW := float32(0)
69
70 // Get inital sizing
71 textTotal := 0
72 textCounts := []int{}
73 widths := []float32{}
74 // heights := []float32{}
75 innerSizes := [][]float32{}
76 minWidths := []float32{}
77 minHeights := []float32{}
78 maxWidths := []float32{}
79 maxHeights := []float32{}
80 for _, v := range n.Children {
81 count := countText(v)
82 textTotal += count
83 textCounts = append(textCounts, count)
84
85 minw := getMinWidth(&v, state)
86 minWidths = append(minWidths, minw)
87
88 maxw := getMaxWidth(&v, state)
89 maxWidths = append(maxWidths, maxw)
90
91 w, h := getInnerSize(&v, state)
92
93 minh := getMinHeight(&v, state)
94 minHeights = append(minHeights, minh)
95
96 maxh := getMaxHeight(&v, state)
97 maxHeights = append(maxHeights, maxh)
98 innerSizes = append(innerSizes, []float32{w, h})
99 }
100 selfWidth := (self.Width - self.Padding.Left) - self.Padding.Right
101 selfHeight := (self.Height - self.Padding.Top) - self.Padding.Bottom
102
103 if flexDirection == "row" {
104 // if the elements are less than the size of the parent, don't change widths. Just set mins
105 if !flexWrapped {
106 if add2d(innerSizes, 0) < selfWidth {
107 for i, v := range n.Children {
108 vState := s[v.Properties.Id]
109
110 w := innerSizes[i][0]
111 w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
112 widths = append(widths, w)
113 }
114 } else {
115 // Modifiy the widths so they aren't under the mins
116 for i, v := range n.Children {
117 vState := s[v.Properties.Id]
118
119 w := ((selfWidth / float32(textTotal)) * float32(textCounts[i]))
120 w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
121
122 if w < minWidths[i] {
123 selfWidth -= minWidths[i] + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
124 textTotal -= textCounts[i]
125 textCounts[i] = 0
126 }
127
128 }
129 for i, v := range n.Children {
130 vState := s[v.Properties.Id]
131
132 w := ((selfWidth / float32(textTotal)) * float32(textCounts[i]))
133 w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
134 // (w!=w) is of NaN
135 if w < minWidths[i] || (w != w) {
136 w = minWidths[i]
137 }
138 widths = append(widths, w)
139 }
140 }
141 // Apply the new widths
142 fState := s[n.Children[0].Properties.Id]
143 for i, v := range n.Children {
144 vState := s[v.Properties.Id]
145
146 vState.Width = widths[i]
147 xStore := vState.X
148 if i > 0 {
149 sState := s[n.Children[i-1].Properties.Id]
150 vState.X = sState.X + sState.Width + sState.Margin.Right + vState.Margin.Left + sState.Border.Width + vState.Border.Width
151 propagateOffsets(&v, xStore, vState.Y, vState.X, fState.Y+vState.Margin.Top, state)
152 }
153
154 vState.Y = fState.Y + vState.Margin.Top
155
156 (*state)[v.Properties.Id] = vState
157 deInline(&v, state)
158 applyInline(&v, state)
159 applyBlock(&v, state)
160 _, h := getInnerSize(&v, state)
161 h = utils.Max(h, vState.Height)
162 maxH = utils.Max(maxH, h)
163 }
164 // When not wrapping everything will be on the same row
165 rows = append(rows, []int{0, len(n.Children), int(maxH)})
166 } else {
167 // Flex Wrapped
168 sum := innerSizes[0][0]
169 for i := 0; i < len(n.Children); i++ {
170 v := n.Children[i]
171 vState := s[v.Properties.Id]
172
173 // if the next plus current will break then
174 w := innerSizes[i][0]
175 if i > 0 {
176 sib := s[n.Children[i-1].Properties.Id]
177 if maxWidths[i] > selfWidth {
178 w = selfWidth - vState.Margin.Left - vState.Margin.Right - (vState.Border.Width * 2)
179 }
180 if w+sum > selfWidth {
181 sum = w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
182 } else {
183 propagateOffsets(&v, vState.X, vState.Y, vState.X, sib.Y, state)
184 vState.Y = sib.Y
185 (*state)[v.Properties.Id] = vState
186 sum += w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
187 }
188 }
189
190 widths = append(widths, w)
191 }
192
193 // Move the elements into the correct position
194 start := 0
195 var prevOffset float32
196 for i := 0; i < len(n.Children); i++ {
197 v := n.Children[i]
198 vState := s[v.Properties.Id]
199
200 vState.Width = widths[i]
201 xStore := vState.X
202 yStore := vState.Y
203
204 if i > 0 {
205 sib := s[n.Children[i-1].Properties.Id]
206 if vState.Y+prevOffset == sib.Y {
207 yStore += prevOffset
208
209 if vState.Height < sib.Height {
210 vState.Height = minHeight(v, state, sib.Height)
211 }
212 // Shift right if on a row with sibling
213 xStore = sib.X + sib.Width + sib.Margin.Right + sib.Border.Width + vState.Margin.Left + vState.Border.Width
214 } else {
215 // Shift under sibling
216 yStore = sib.Y + sib.Height + sib.Margin.Top + sib.Margin.Bottom + sib.Border.Width*2
217 prevOffset = yStore - vState.Y
218 rows = append(rows, []int{start, i, int(maxH)})
219 start = i
220 maxH = 0
221 }
222 propagateOffsets(&v, vState.X, vState.Y, xStore, yStore, state)
223 }
224 vState.X = xStore
225 vState.Y = yStore
226
227 (*state)[v.Properties.Id] = vState
228 deInline(&v, state)
229 applyInline(&v, state)
230 applyBlock(&v, state)
231 _, h := getInnerSize(&v, state)
232 h = utils.Max(h, vState.Height)
233 maxH = utils.Max(maxH, h)
234 vState.Height = minHeight(v, state, h)
235 (*state)[v.Properties.Id] = vState
236 }
237 if start < len(n.Children) {
238 rows = append(rows, []int{start, len(n.Children), int(maxH)})
239 }
240 }
241
242 for _, v := range rows {
243 for i := v[0]; i < v[1]; i++ {
244 vState := s[n.Children[i].Properties.Id]
245 height := float32(v[2])
246 if (n.Style["height"] != "" || n.Style["min-height"] != "") && !flexWrapped {
247 height = self.Height - self.Padding.Top - self.Padding.Bottom - vState.Margin.Top - vState.Margin.Bottom - (vState.Border.Width * 2)
248 }
249 vState.Height = minHeight(n.Children[i], state, height)
250 (*state)[n.Children[i].Properties.Id] = vState
251 }
252 }
253 // Reverse elements
254 if flexReversed {
255 rowReverse(rows, n, state)
256 }
257
258 if justifyContent != "" && justifyContent != "normal" {
259 justifyRow(rows, n, state, justifyContent, flexReversed)
260 }
261
262 alignRow(rows, n, state, alignItems, alignContent)
263
264 }
265
266 // Column doesn't really need a lot done bc it is basically block styling rn
267 if flexDirection == "column" {
268 if !flexWrapped {
269 if n.Style["height"] != "" || n.Style["min-height"] != "" {
270 h := selfHeight / float32(len(n.Children))
271 for i, v := range n.Children {
272 vState := s[v.Properties.Id]
273 yStore := vState.Y
274 adjH := h - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
275 if adjH < vState.Height {
276
277 if minHeights[i] > adjH {
278 vState.Height = minHeights[i]
279 if i > 0 {
280 sib := s[n.Children[i-1].Properties.Id]
281 vState.Y = sib.Y + sib.Height + sib.Margin.Bottom + sib.Border.Width + vState.Margin.Top + vState.Border.Width
282 }
283 } else {
284 vState.Height = adjH
285 vState.Y = self.Y + self.Padding.Top + self.Border.Width + (h * float32(i)) + vState.Margin.Top
286 }
287 propagateOffsets(&v, vState.X, yStore, vState.X, vState.Y, state)
288 (*state)[v.Properties.Id] = vState
289 }
290 }
291 }
292 for i, v := range n.Children {
293 vState := s[v.Properties.Id]
294 rows = append(rows, []int{i, i + 1, int(vState.Height)})
295 }
296
297 }
298 if flexReversed {
299 colReverse(n, state)
300 }
301 }
302 if n.Style["height"] == "" || n.Style["min-height"] == "" {
303 _, h := getInnerSize(n, state)
304 // fmt.Println(h)
305 self.Height = h
306 }
307 (*state)[n.Properties.Id] = self
308 },
309 }
310}
311
312func applyBlock(n *element.Node, state *map[string]element.State) {
313 if len(n.Children) > 0 {
314 accum := float32(0)
315 inlineOffset := float32(0)
316 s := *state
317 lastHeight := float32(0)
318 baseY := s[n.Children[0].Properties.Id].Y
319 for i := 0; i < len(n.Children); i++ {
320 v := &n.Children[i]
321 vState := s[v.Properties.Id]
322
323 if v.Style["display"] != "block" {
324 vState.Y += inlineOffset
325 accum = (vState.Y - baseY)
326 lastHeight = vState.Height
327 } else if v.Style["position"] != "absolute" {
328 vState.Y += accum
329 inlineOffset += (vState.Height + (vState.Border.Width * 2) + vState.Margin.Top + vState.Margin.Bottom + vState.Padding.Top + vState.Padding.Bottom) + lastHeight
330 }
331 (*state)[v.Properties.Id] = vState
332 }
333 }
334}
335
336func deInline(n *element.Node, state *map[string]element.State) {
337 s := *state
338 // self := s[n.Properties.Id]
339 baseX := float32(-1)
340 baseY := float32(-1)
341 for _, v := range n.Children {
342 vState := s[v.Properties.Id]
343
344 if v.Style["display"] == "inline" {
345 if baseX < 0 && baseY < 0 {
346 baseX = vState.X
347 baseY = vState.Y
348 } else {
349 vState.X = baseX
350 vState.Y = baseY
351 (*state)[v.Properties.Id] = vState
352
353 }
354 } else {
355 baseX = float32(-1)
356 baseY = float32(-1)
357 }
358
359 if len(v.Children) > 0 {
360 deInline(&v, state)
361 }
362 }
363
364}
365
366func applyInline(n *element.Node, state *map[string]element.State) {
367 pl := inline.Init()
368 for i := 0; i < len(n.Children); i++ {
369 v := &n.Children[i]
370
371 if len(v.Children) > 0 {
372 applyInline(v, state)
373 }
374
375 if pl.Selector(v) {
376 pl.Handler(v, state)
377 }
378 }
379}
380
381func propagateOffsets(n *element.Node, prevx, prevy, newx, newy float32, state *map[string]element.State) {
382 s := *state
383 for _, v := range n.Children {
384 vState := s[v.Properties.Id]
385 xStore := (vState.X - prevx) + newx
386 yStore := (vState.Y - prevy) + newy
387
388 if len(v.Children) > 0 {
389 propagateOffsets(&v, vState.X, vState.Y, xStore, yStore, state)
390 }
391 vState.X = xStore
392 vState.Y = yStore
393 (*state)[v.Properties.Id] = vState
394 }
395
396}
397
398func countText(n element.Node) int {
399 count := 0
400 groups := []int{}
401 for _, v := range n.Children {
402 if v.TagName == "notaspan" {
403 count += 1
404 }
405 if v.Style["display"] == "block" {
406 groups = append(groups, count)
407 count = 0
408 }
409 if len(v.Children) > 0 {
410 count += countText(v)
411 }
412 }
413 groups = append(groups, count)
414
415 sort.Slice(groups, func(i, j int) bool {
416 return groups[i] > groups[j]
417 })
418 return groups[0]
419}
420
421func minHeight(n element.Node, state *map[string]element.State, prev float32) float32 {
422 s := *state
423 self := s[n.Properties.Id]
424 if n.Style["min-height"] != "" {
425 mw := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
426 return utils.Max(prev, mw)
427 } else {
428 return prev
429 }
430
431}
432
433func getMinHeight(n *element.Node, state *map[string]element.State) float32 {
434 s := *state
435 self := s[n.Properties.Id]
436 selfHeight := float32(0)
437
438 if len(n.Children) > 0 {
439 for _, v := range n.Children {
440 selfHeight = utils.Max(selfHeight, getNodeHeight(&v, state))
441 }
442 } else {
443 selfHeight = self.Height
444 }
445 if n.Style["min-height"] != "" {
446 mh := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
447 selfHeight = utils.Max(mh, selfHeight)
448 }
449
450 selfHeight += self.Padding.Top + self.Padding.Bottom
451 return selfHeight
452}
453
454func getMinWidth(n *element.Node, state *map[string]element.State) float32 {
455 s := *state
456 self := s[n.Properties.Id]
457 selfWidth := float32(0)
458
459 if len(n.Children) > 0 {
460 for _, v := range n.Children {
461 selfWidth = utils.Max(selfWidth, getNodeWidth(&v, state))
462 }
463 } else {
464 selfWidth = self.Width
465 }
466 if n.Style["min-width"] != "" {
467 mw := utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
468 selfWidth = utils.Max(mw, selfWidth)
469 }
470
471 selfWidth += self.Padding.Left + self.Padding.Right
472 return selfWidth
473}
474func getMaxWidth(n *element.Node, state *map[string]element.State) float32 {
475 s := *state
476 self := s[n.Properties.Id]
477 selfWidth := float32(0)
478
479 if len(n.Children) > 0 {
480 var maxRowWidth, rowWidth float32
481
482 for _, v := range n.Children {
483 rowWidth += getNodeWidth(&v, state)
484 if v.Style["display"] != "inline" {
485 maxRowWidth = utils.Max(rowWidth, maxRowWidth)
486 rowWidth = 0
487 }
488 }
489 selfWidth = utils.Max(rowWidth, maxRowWidth)
490 } else {
491 selfWidth = self.Width
492 }
493
494 selfWidth += self.Padding.Left + self.Padding.Right
495 return selfWidth
496}
497
498func getNodeWidth(n *element.Node, state *map[string]element.State) float32 {
499 s := *state
500 self := s[n.Properties.Id]
501 w := float32(0)
502 w += self.Padding.Left
503 w += self.Padding.Right
504
505 w += self.Margin.Left
506 w += self.Margin.Right
507
508 w += self.Width
509
510 w += self.Border.Width * 2
511
512 for _, v := range n.Children {
513 w = utils.Max(w, getNodeWidth(&v, state))
514 }
515
516 return w
517}
518func getMaxHeight(n *element.Node, state *map[string]element.State) float32 {
519 s := *state
520 self := s[n.Properties.Id]
521 selfHeight := float32(0)
522
523 if len(n.Children) > 0 {
524 var maxRowHeight, rowHeight float32
525
526 for _, v := range n.Children {
527 rowHeight += getNodeHeight(&v, state)
528 if v.Style["display"] != "inline" {
529 maxRowHeight = utils.Max(rowHeight, maxRowHeight)
530 rowHeight = 0
531 }
532 }
533 selfHeight = utils.Max(rowHeight, maxRowHeight)
534 } else {
535 selfHeight = self.Height
536 }
537
538 selfHeight += self.Padding.Top + self.Padding.Bottom
539 return selfHeight
540}
541
542func getNodeHeight(n *element.Node, state *map[string]element.State) float32 {
543 s := *state
544 self := s[n.Properties.Id]
545 h := float32(0)
546 h += self.Padding.Top
547 h += self.Padding.Bottom
548
549 h += self.Margin.Top
550 h += self.Margin.Bottom
551
552 h += self.Height
553
554 h += self.Border.Width * 2
555
556 for _, v := range n.Children {
557 h = utils.Max(h, getNodeHeight(&v, state))
558 }
559
560 return h
561}
562
563func getInnerSize(n *element.Node, state *map[string]element.State) (float32, float32) {
564 s := *state
565 self := s[n.Properties.Id]
566
567 minx := float32(10e10)
568 maxw := float32(0)
569 miny := float32(10e10)
570 maxh := float32(0)
571 for _, v := range n.Children {
572 vState := s[v.Properties.Id]
573 minx = utils.Min(vState.X, minx)
574 miny = utils.Min(vState.Y-vState.Margin.Top, miny)
575 // Don't add the top or left because the x&y values already take that into account
576 hOffset := (vState.Border.Width * 2) + vState.Margin.Bottom
577 wOffset := (vState.Border.Width * 2) + vState.Margin.Right
578 maxw = utils.Max(vState.X+vState.Width+wOffset, maxw)
579 maxh = utils.Max(vState.Y+vState.Height+hOffset, maxh)
580 }
581 w := maxw - minx
582 h := maxh - miny
583
584 w += self.Padding.Left + self.Padding.Right
585 h += self.Padding.Top + self.Padding.Bottom
586 if n.Style["width"] != "" {
587 w = self.Width
588 }
589 if n.Style["height"] != "" {
590 h = self.Height
591 }
592
593 return w, h
594}
595
596func add2d(arr [][]float32, index int) float32 {
597 var sum float32
598 if len(arr) == 0 {
599 return sum
600 }
601
602 for i := 0; i < len(arr); i++ {
603 if len(arr[i]) <= index {
604 return sum
605 }
606 sum += arr[i][index]
607 }
608
609 return sum
610}
611
612func colReverse(n *element.Node, state *map[string]element.State) {
613 s := *state
614 tempNodes := []element.Node{}
615 tempStates := []element.State{}
616 for i := len(n.Children) - 1; i >= 0; i-- {
617 tempNodes = append(tempNodes, n.Children[i])
618 tempStates = append(tempStates, s[n.Children[i].Properties.Id])
619 }
620
621 for i := 0; i < len(tempStates); i++ {
622 vState := s[n.Children[i].Properties.Id]
623 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, tempStates[i].Y, state)
624 vState.Y = tempStates[i].Y
625 (*state)[n.Children[i].Properties.Id] = vState
626 }
627
628 n.Children = tempNodes
629}
630
631func rowReverse(rows [][]int, n *element.Node, state *map[string]element.State) {
632 s := *state
633 for _, row := range rows {
634 tempNodes := []element.Node{}
635 tempStates := []element.State{}
636
637 for i := row[1] - 1; i >= row[0]; i-- {
638 tempNodes = append(tempNodes, n.Children[i])
639 tempStates = append(tempStates, s[n.Children[i].Properties.Id])
640 }
641
642 for i := 0; i < len(tempStates); i++ {
643 e := row[0] + i
644 vState := s[n.Children[e].Properties.Id]
645 propagateOffsets(&n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
646 vState.X = tempStates[i].X
647 (*state)[n.Children[e].Properties.Id] = vState
648 }
649 for i := 0; i < len(tempStates); i++ {
650 e := row[0] + i
651 n.Children[e] = tempNodes[i]
652 }
653
654 for i := row[1] - 1; i >= row[0]; i-- {
655 vState := s[n.Children[i].Properties.Id]
656 var xChng float32
657 if i < row[1]-1 {
658 sib := s[n.Children[i+1].Properties.Id]
659 xChng = sib.X - (sib.Border.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Width + vState.Width)
660 } else {
661 parent := s[n.Properties.Id]
662 xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Width)
663
664 }
665 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
666 vState.X = xChng
667 (*state)[n.Children[i].Properties.Id] = vState
668 }
669 }
670}
671
672func justifyRow(rows [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
673 s := *state
674 for _, row := range rows {
675
676 if (justify == "flex-end" || justify == "end" || justify == "right") && !reversed {
677 for i := row[1] - 1; i >= row[0]; i-- {
678 vState := s[n.Children[i].Properties.Id]
679 var xChng float32
680 if i < row[1]-1 {
681 sib := s[n.Children[i+1].Properties.Id]
682 xChng = sib.X - (sib.Border.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Width + vState.Width)
683 } else {
684 parent := s[n.Properties.Id]
685 xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Width)
686
687 }
688 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
689 vState.X = xChng
690 (*state)[n.Children[i].Properties.Id] = vState
691 }
692 } else if (justify == "flex-end" || justify == "start" || justify == "left" || justify == "normal") && reversed {
693 for i := row[0]; i < row[1]; i++ {
694 vState := s[n.Children[i].Properties.Id]
695 var xChng float32
696 if i > row[0] {
697 sib := s[n.Children[i-1].Properties.Id]
698 xChng = sib.X + sib.Width + (sib.Border.Width * 2) + sib.Margin.Right + vState.Margin.Left + vState.Border.Width
699 } else {
700 parent := s[n.Properties.Id]
701 xChng = parent.X + parent.Padding.Right + vState.Margin.Left + vState.Border.Width + parent.Border.Width
702
703 }
704 propagateOffsets(&n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
705 vState.X = xChng
706 (*state)[n.Children[i].Properties.Id] = vState
707 }
708 } else if justify == "center" {
709 // get width of row then center (by getting last x + w + mr + b)
710 f := s[n.Children[row[0]].Properties.Id]
711 l := s[n.Children[row[1]-1].Properties.Id]
712 parent := s[n.Properties.Id]
713 po := parent.X + parent.Border.Width
714 offset := (parent.Width - ((f.X - po) + (l.X - po) + l.Width + f.Border.Width + l.Border.Width)) / 2
715
716 for i := row[0]; i < row[1]; i++ {
717 vState := s[n.Children[i].Properties.Id]
718
719 if !reversed {
720 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
721 vState.X += offset
722 } else {
723 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
724 vState.X -= offset
725 }
726 (*state)[n.Children[i].Properties.Id] = vState
727 }
728
729 } else if justify == "space-between" {
730 // get width of row then center (by getting last x + w + mr + b)
731 f := s[n.Children[row[0]].Properties.Id]
732 l := s[n.Children[row[1]-1].Properties.Id]
733 parent := s[n.Properties.Id]
734 po := parent.Border.Width + parent.Width
735 po -= parent.Padding.Left + parent.Padding.Right
736
737 // make po repersent the total space between elements
738 for i := row[0]; i < row[1]; i++ {
739 vState := s[n.Children[i].Properties.Id]
740 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
741 }
742
743 po /= float32(((row[1]) - row[0]) - 1)
744
745 if (row[1]-1)-row[0] > 0 {
746 for i := row[0]; i < row[1]; i++ {
747 vState := s[n.Children[i].Properties.Id]
748 var offset float32
749 if i == row[0] {
750 offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
751 } else if i == row[1]-1 {
752 offset = (parent.X + parent.Width) - (l.Margin.Right + l.Border.Width + l.Width + parent.Padding.Right)
753 } else {
754 if !reversed {
755 offset = vState.X + (po * float32(i-row[0]))
756 } else {
757 offset = vState.X - (po * float32(((row[1]-1)-row[0])-(i-row[0])))
758 }
759
760 }
761
762 propagateOffsets(&n.Children[i], vState.X, vState.Y, offset, vState.Y, state)
763 vState.X = offset
764 (*state)[n.Children[i].Properties.Id] = vState
765 }
766 }
767 // else {
768
769 // this is/was causing issues, removed and it fixed its self
770
771 // if there is one element move left
772 // vState := s[n.Children[(row[1]-1)-row[0]].Properties.Id]
773 // var offset float32
774
775 // if !reversed {
776 // offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
777 // propagateOffsets(&n.Children[(row[1]-1)-row[0]], vState.X, vState.Y, offset, vState.Y, state)
778 // vState.X = offset
779
780 // (*state)[n.Children[(row[1]-1)-row[0]].Properties.Id] = vState
781 // }
782
783 // }
784
785 } else if justify == "space-evenly" {
786 // get width of row then center (by getting last x + w + mr + b)
787 parent := s[n.Properties.Id]
788 po := parent.Border.Width + parent.Width
789 po -= parent.Padding.Left + parent.Padding.Right
790
791 // make po repersent the total space between elements
792 for i := row[0]; i < row[1]; i++ {
793 vState := s[n.Children[i].Properties.Id]
794 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
795 }
796
797 po /= float32(((row[1]) - row[0]) + 1)
798
799 // get width of row then center (by getting last x + w + mr + b)
800
801 for i := row[0]; i < row[1]; i++ {
802 vState := s[n.Children[i].Properties.Id]
803
804 if !reversed {
805 offset := po * (float32(i-row[0]) + 1)
806 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
807 vState.X += offset
808 } else {
809 offset := po * float32(((row[1]-1)-row[0])-((i-row[0])-1))
810
811 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
812 vState.X -= offset
813 }
814 (*state)[n.Children[i].Properties.Id] = vState
815 }
816
817 } else if justify == "space-around" {
818 // get width of row then center (by getting last x + w + mr + b)
819 parent := s[n.Properties.Id]
820 po := parent.Border.Width + parent.Width
821 po -= parent.Padding.Left + parent.Padding.Right
822
823 // make po repersent the total space between elements
824 for i := row[0]; i < row[1]; i++ {
825 vState := s[n.Children[i].Properties.Id]
826 po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
827 }
828
829 po /= float32(((row[1]) - row[0]))
830
831 // get width of row then center (by getting last x + w + mr + b)
832
833 for i := row[0]; i < row[1]; i++ {
834 vState := s[n.Children[i].Properties.Id]
835
836 if !reversed {
837 m := (float32(i-row[0]) + 1)
838 if i-row[0] == 0 {
839 m = 0.5
840 } else {
841 m -= 0.5
842 }
843 offset := po * m
844 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
845 vState.X += offset
846 } else {
847 m := float32(((row[1] - 1) - row[0]) - ((i - row[0]) - 1))
848 m -= 0.5
849 offset := po * m
850
851 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
852 vState.X -= offset
853 }
854 (*state)[n.Children[i].Properties.Id] = vState
855 }
856
857 }
858
859 }
860}
861
862func alignRow(rows [][]int, n *element.Node, state *map[string]element.State, align, content string) {
863 // !ISSUE: Baseline isn't properly impleamented
864
865 s := *state
866 self := s[n.Properties.Id]
867
868 maxes := []float32{}
869 var maxesTotal float32
870 for _, row := range rows {
871 var maxH float32
872 for i := row[0]; i < row[1]; i++ {
873 vState := s[n.Children[i].Properties.Id]
874 _, h := getInnerSize(&n.Children[i], state)
875 h = minHeight(n.Children[i], state, h)
876 vState.Height = h
877 h += vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)
878 maxH = utils.Max(maxH, h)
879 (*state)[n.Children[i].Properties.Id] = vState
880 }
881 maxes = append(maxes, maxH)
882 maxesTotal += maxH
883 }
884
885 os := ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows))
886 if os < 0 || content != "normal" {
887 os = 0
888 }
889
890 var contentOffset float32
891
892 if content == "center" {
893 contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / 2
894 } else if content == "end" || content == "flex-end" {
895 contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal)
896 } else if content == "start" || content == "flex-start" || content == "baseline" {
897 // This is redundent but it helps keep track
898 contentOffset = 0
899 } else if content == "space-between" {
900 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows)-1)
901 } else if content == "space-around" {
902 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows))
903 contentOffset = os / 2
904 } else if content == "space-evenly" {
905 os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Width * 2))) - maxesTotal) / float32(len(rows)+1)
906 contentOffset = os
907 }
908
909 for c, row := range rows {
910 maxH := maxes[c]
911 var sum float32
912 for i := 0; i < c; i++ {
913 sum += maxes[i]
914 }
915 if align == "start" || align == "flex-start" || align == "self-start" || align == "normal" {
916 for i := row[0]; i < row[1]; i++ {
917 vState := s[n.Children[i].Properties.Id]
918
919 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
920
921 if n.Style["height"] != "" || n.Style["min-height"] != "" {
922 offset += ((os) * float32(c))
923 }
924
925 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
926 vState.Y = offset
927 (*state)[n.Children[i].Properties.Id] = vState
928 }
929 } else if align == "center" {
930 for i := row[0]; i < row[1]; i++ {
931 vState := s[n.Children[i].Properties.Id]
932
933 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
934
935 if n.Style["height"] != "" || n.Style["min-height"] != "" {
936 offset += (os * float32(c+1)) - (os / 2)
937 }
938
939 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) < maxH {
940 offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))) / 2
941 }
942 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
943 vState.Y = offset
944 (*state)[n.Children[i].Properties.Id] = vState
945 }
946 } else if align == "end" || align == "flex-end" || align == "self-end" {
947 for i := row[0]; i < row[1]; i++ {
948 vState := s[n.Children[i].Properties.Id]
949
950 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
951
952 if n.Style["height"] != "" || n.Style["min-height"] != "" {
953 offset += os * float32(c+1)
954 }
955
956 if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Width*2) < maxH {
957 offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2)))
958 }
959 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
960 vState.Y = offset
961 (*state)[n.Children[i].Properties.Id] = vState
962
963 }
964 } else if align == "stretch" {
965 for i := row[0]; i < row[1]; i++ {
966 vState := s[n.Children[i].Properties.Id]
967
968 offset := sum + self.Y + self.Padding.Top + vState.Margin.Top
969
970 if n.Style["height"] != "" || n.Style["min-height"] != "" {
971 offset += ((os) * float32(c))
972 }
973
974 propagateOffsets(&n.Children[i], vState.X, vState.Y, vState.X, offset, state)
975 vState.Y = offset
976 vState.Height = maxH - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Width * 2))
977 (*state)[n.Children[i].Properties.Id] = vState
978
979 }
980 }
981 }
982}