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