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 // !ISSUE: align-items is not impleamented
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 elMax := vState.Height
182 elMS, _ := utils.GetStructField(&vState.Margin, marginStart)
183 elME, _ := utils.GetStructField(&vState.Margin, marginEnd)
184 tMax := elMax + elMS.(float32) + elME.(float32)
185 if counter+int(tMax) < int(max.(float32)) {
186 collector = append(collector, v)
187 } else {
188 if reversed {
189 slices.Reverse(collector)
190 }
191 nodes = append(nodes, collector)
192 collector = []element.Node{}
193 collector = append(collector, v)
194 counter = 0
195 }
196 counter += int(tMax)
197 }
198 if len(collector) > 0 {
199 nodes = append(nodes, collector)
200 }
201 } else {
202 var mod int
203 for _, v := range elements {
204 vState := s[v.Properties.Id]
205 elMax := vState.Width
206 elMS, _ := utils.GetStructField(&vState.Margin, marginStart)
207 elME, _ := utils.GetStructField(&vState.Margin, 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 elMax, _ := utils.GetStructField(&vState, dir)
236 elMS, _ := utils.GetStructField(&vState.Margin, marginStart)
237 elME, _ := utils.GetStructField(&vState.Margin, marginEnd)
238 tMax += elMax.(float32) + elMS.(float32) + elME.(float32)
239 }
240
241 pMax, _ := utils.GetStructField(&self, dir)
242
243 // Resize node to fit
244 var newSize float32
245 if tMax > pMax.(float32) {
246 newSize = pMax.(float32) / float32(len(elements))
247 }
248 if dir == "Width" {
249 for _, v := range elements {
250 vState := s[v.Properties.Id]
251 if newSize != 0 {
252 vState.Width = newSize
253 }
254 nodes = append(nodes, []element.Node{v})
255 }
256 if reversed {
257 slices.Reverse(nodes)
258 }
259 } else {
260 nodes = append(nodes, []element.Node{})
261 for _, v := range elements {
262 vState := s[v.Properties.Id]
263 if newSize != 0 {
264 vState.Height = newSize
265 }
266 nodes[0] = append(nodes[0], v)
267 }
268 if reversed {
269 slices.Reverse(nodes[0])
270 }
271 }
272
273 }
274 (*state)[p.Properties.Id] = self
275
276 return nodes
277}