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/element"
6 "gui/utils"
7 "slices"
8 "strings"
9)
10
11func Init() cstyle.Plugin {
12 return cstyle.Plugin{
13 Styles: map[string]string{
14 "display": "flex",
15 "justify-content": "*",
16 "align-content": "*",
17 "align-items": "*",
18 "flex-wrap": "*",
19 "flex-direction": "*",
20 },
21 Level: 2,
22 Handler: func(n *element.Node) {
23
24 // Brief: justify does not align the bottom row correctly
25 // y axis also needs to be done
26 verbs := strings.Split(n.Style["flex-direction"], "-")
27
28 orderedNode := order(*n, n.Children, verbs[0], len(verbs) > 1, n.Style["flex-wrap"] == "wrap")
29
30 // var i int
31
32 colWidth := n.Properties.Computed["width"] / float32(len(orderedNode))
33
34 var xOffset, yOffset float32
35 // if n.Style["justify-content"] == "space-evenly" {
36 // b, _ := utils.ConvertToPixels(n.Children[i].Properties.Border.Width, n.Children[i].Properties.EM, n.Properties.Computed["width"])
37 // cwV := utils.Max((colWidth-(n.Children[i].Properties.Computed["width"]+(b*2)))/2, 0)
38 // xOffset = cwV
39 // }
40
41 posTrack := map[int]int{}
42 p := 0
43
44 for a, column := range orderedNode {
45 var maxColumnHeight float32
46 for _, item := range column {
47 maxColumnHeight = utils.Max(item.Properties.Computed["height"], maxColumnHeight)
48 }
49
50 yOffset = n.Children[0].Properties.Y
51 for _, item := range column {
52 var i int
53 for c, v := range n.Children {
54 if v.Properties.Id == item.Properties.Id {
55 i = c
56 }
57 }
58 posTrack[p] = i
59 p++
60 // n.Children[i] = item
61 if n.Style["justify-content"] == "space-between" {
62 cwV := utils.Max((colWidth - (item.Properties.Computed["width"])), 0)
63 if a == 0 {
64 n.Children[i].Properties.X += xOffset
65 } else if a == len(orderedNode)-1 {
66 n.Children[i].Properties.X += xOffset + cwV
67 } else {
68 n.Children[i].Properties.X += xOffset + cwV/2
69 }
70 } else if n.Style["justify-content"] == "flex-end" || n.Style["justify-content"] == "center" {
71 dif := n.Properties.Computed["width"] - (xOffset)
72 if n.Style["justify-content"] == "center" {
73 dif = dif / 2
74 }
75 n.Children[i].Properties.X += dif
76 } else if n.Style["justify-content"] == "flex-start" || n.Style["justify-content"] == "" {
77 n.Children[i].Properties.X += xOffset
78 } else {
79 cwV := utils.Max((colWidth-(item.Properties.Computed["width"]))/2, 0)
80 var offset float32
81 if n.Style["justify-content"] == "space-evenly" {
82 offset = ((cwV * 2) / float32(len(orderedNode))) * float32(a)
83 }
84 n.Children[i].Properties.X += xOffset + (cwV - offset)
85
86 }
87 n.Children[i].Properties.Y = yOffset
88 yOffset += maxColumnHeight
89 i++
90
91 }
92 xOffset += colWidth
93 }
94
95 content := n.Style["align-content"]
96
97 if n.Style["flex-direction"] == "column" {
98 content = n.Style["justify-content"]
99 }
100
101 if content != "" && content != "flex-start" {
102 var min, max, rows, col, currY float32
103 min = 1000000000000
104 for _, v := range n.Children {
105 min = utils.Min(min, v.Properties.Y)
106 max = utils.Max(max, v.Properties.Computed["height"]+v.Properties.Y)
107 if v.Properties.Y > currY {
108 rows++
109 currY = v.Properties.Y
110 }
111 }
112
113 height := max - min
114 rowHeight := ((n.Properties.Computed["height"] - height) / rows)
115 for e := range n.Children {
116 i := posTrack[e]
117 row := float32(int(e % int(rows)))
118 if row == 0 {
119 col++
120 }
121 if len(orderedNode[int(col)-1]) <= int(row) {
122 row = 0
123 }
124
125 if content == "center" {
126 n.Children[i].Properties.Y += (n.Properties.Computed["height"] - height) / 2
127 } else if content == "flex-end" {
128 n.Children[i].Properties.Y += (n.Properties.Computed["height"] - height)
129 } else if content == "space-around" {
130 n.Children[i].Properties.Y += (rowHeight * row) + (rowHeight / 2)
131 } else if content == "space-evenly" {
132 n.Children[i].Properties.Y += (rowHeight * row) + (rowHeight / 2)
133 } else if content == "space-between" {
134 n.Children[i].Properties.Y += (((n.Properties.Computed["height"] - height) / (rows - 1)) * row)
135 } else if content == "stretch" {
136 n.Children[i].Properties.Y += (rowHeight * row)
137 if n.Children[i].Style["height"] == "" {
138 n.Children[i].Properties.Computed["height"] = n.Properties.Computed["height"] / rows
139 }
140 }
141 }
142
143 }
144 },
145 }
146}
147
148func order(p element.Node, elements []element.Node, direction string, reversed, wrap bool) [][]element.Node {
149 var dir, marginStart, marginEnd string
150 if direction == "column" {
151 dir = "Height"
152 marginStart = "Top"
153 marginEnd = "Bottom"
154 } else {
155 dir = "Width"
156 marginStart = "Left"
157 marginEnd = "Right"
158 }
159 max := p.Properties.Computed[dir]
160
161 nodes := [][]element.Node{}
162
163 if wrap {
164 counter := 0
165 if direction == "column" {
166 collector := []element.Node{}
167 for _, v := range elements {
168 m := utils.GetMP(v, "margin")
169 elMax := v.Properties.Computed["height"]
170 elMS, _ := utils.GetStructField(&m, marginStart)
171 elME, _ := utils.GetStructField(&m, marginEnd)
172 tMax := elMax + elMS.(float32) + elME.(float32)
173 if counter+int(tMax) < int(max) {
174 collector = append(collector, v)
175 } else {
176 if reversed {
177 slices.Reverse(collector)
178 }
179 nodes = append(nodes, collector)
180 collector = []element.Node{}
181 collector = append(collector, v)
182 counter = 0
183 }
184 counter += int(tMax)
185 }
186 if len(collector) > 0 {
187 nodes = append(nodes, collector)
188 }
189 } else {
190 var mod int
191 for _, v := range elements {
192 m := utils.GetMP(v, "margin")
193 elMax := v.Properties.Computed["width"]
194 elMS, _ := utils.GetStructField(&m, marginStart)
195 elME, _ := utils.GetStructField(&m, marginEnd)
196 tMax := elMax + elMS.(float32) + elME.(float32)
197 if counter+int(tMax) < int(max) {
198 if len(nodes)-1 < mod {
199 nodes = append(nodes, []element.Node{v})
200 } else {
201 nodes[mod] = append(nodes[mod], v)
202 }
203 } else {
204 mod = 0
205 counter = 0
206 if len(nodes)-1 < mod {
207 nodes = append(nodes, []element.Node{v})
208 } else {
209 nodes[mod] = append(nodes[mod], v)
210 }
211 }
212 counter += int(tMax)
213 mod++
214 }
215 if reversed {
216 slices.Reverse(nodes)
217 }
218 }
219 } else {
220 var tMax float32
221 for _, v := range elements {
222 m := utils.GetMP(v, "margin")
223 elMax := v.Properties.Computed[dir]
224 elMS, _ := utils.GetStructField(&m, marginStart)
225 elME, _ := utils.GetStructField(&m, marginEnd)
226 tMax += elMax + elMS.(float32) + elME.(float32)
227 }
228
229 pMax := p.Properties.Computed[dir]
230
231 // Resize node to fit
232 var newSize float32
233 if tMax > pMax {
234 newSize = pMax / float32(len(elements))
235 }
236 if dir == "Width" {
237 for _, v := range elements {
238 if newSize != 0 {
239 v.Properties.Computed["width"] = newSize
240 }
241 nodes = append(nodes, []element.Node{v})
242 }
243 if reversed {
244 slices.Reverse(nodes)
245 }
246 } else {
247 nodes = append(nodes, []element.Node{})
248 for _, v := range elements {
249 if newSize != 0 {
250 v.Properties.Computed["height"] = newSize
251 }
252 nodes[0] = append(nodes[0], v)
253 }
254 if reversed {
255 slices.Reverse(nodes[0])
256 }
257 }
258
259 }
260
261 return nodes
262}