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