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