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(self.Style["flex-direction"], "-")
30
31 orderedNode := order(*n, state, n.Children, verbs[0], len(verbs) > 1, self.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 self.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 self.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 self.Style["justify-content"] == "flex-end" || self.Style["justify-content"] == "center" {
78 dif := self.Width - (xOffset)
79 if self.Style["justify-content"] == "center" {
80 dif = dif / 2
81 }
82 cState.X += dif
83 } else if self.Style["justify-content"] == "flex-start" || self.Style["justify-content"] == "" {
84 cState.X += xOffset
85 } else {
86 cwV := utils.Max((colWidth-(itemState.Width))/2, 0)
87 var offset float32
88 if self.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 := self.Style["align-content"]
102
103 if self.Style["flex-direction"] == "column" {
104 content = self.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 elMax := vState.Height
183 elMS, _ := utils.GetStructField(&vState.Margin, marginStart)
184 elME, _ := utils.GetStructField(&vState.Margin, 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 elMax := vState.Width
207 elMS, _ := utils.GetStructField(&vState.Margin, marginStart)
208 elME, _ := utils.GetStructField(&vState.Margin, marginEnd)
209 tMax := elMax + elMS.(float32) + elME.(float32)
210 if counter+int(tMax) < int(max.(float32)) {
211 if len(nodes)-1 < mod {
212 nodes = append(nodes, []element.Node{v})
213 } else {
214 nodes[mod] = append(nodes[mod], v)
215 }
216 } else {
217 mod = 0
218 counter = 0
219 if len(nodes)-1 < mod {
220 nodes = append(nodes, []element.Node{v})
221 } else {
222 nodes[mod] = append(nodes[mod], v)
223 }
224 }
225 counter += int(tMax)
226 mod++
227 }
228 if reversed {
229 slices.Reverse(nodes)
230 }
231 }
232 } else {
233 var tMax float32
234 for _, v := range elements {
235 vState := s[v.Properties.Id]
236 elMax, _ := utils.GetStructField(&vState, dir)
237 elMS, _ := utils.GetStructField(&vState.Margin, marginStart)
238 elME, _ := utils.GetStructField(&vState.Margin, 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}