...
1 package etk
2
3 import (
4 "image"
5
6 "github.com/hajimehoshi/ebiten/v2"
7 )
8
9
10
11 type Grid struct {
12 *Box
13
14 columnSizes []int
15 rowSizes []int
16
17 columnPadding int
18 rowPadding int
19
20 cellPositions [][2]int
21 cellSpans [][2]int
22
23 numColumns int
24 numRows int
25
26 updated bool
27 }
28
29
30 func NewGrid() *Grid {
31 return &Grid{
32 Box: NewBox(),
33 }
34 }
35
36
37 func (g *Grid) SetRect(r image.Rectangle) {
38 g.Lock()
39 defer g.Unlock()
40
41 g.Box.rect = r
42 g.updated = true
43 }
44
45
46
47 func (g *Grid) SetColumnSizes(size ...int) {
48 g.Lock()
49 defer g.Unlock()
50
51 g.columnSizes = size
52 g.updated = true
53 }
54
55
56 func (g *Grid) SetColumnPadding(padding int) {
57 g.Lock()
58 defer g.Unlock()
59
60 g.columnPadding = padding
61 g.updated = true
62 }
63
64
65
66 func (g *Grid) SetRowSizes(size ...int) {
67 g.Lock()
68 defer g.Unlock()
69
70 g.rowSizes = size
71 g.updated = true
72 }
73
74
75 func (g *Grid) SetRowPadding(padding int) {
76 g.Lock()
77 defer g.Unlock()
78
79 g.rowPadding = padding
80 g.updated = true
81 }
82
83
84 func (g *Grid) Columns() int {
85 g.Lock()
86 defer g.Unlock()
87
88 if g.updated {
89 g.reposition()
90 g.updated = false
91 }
92 return g.numColumns
93 }
94
95
96 func (g *Grid) Rows() int {
97 g.Lock()
98 defer g.Unlock()
99
100 if g.updated {
101 g.reposition()
102 g.updated = false
103 }
104 return g.numRows
105 }
106
107
108
109 func (g *Grid) AddChild(wgt ...Widget) {
110 g.Box.AddChild(wgt...)
111
112 for i := 0; i < len(wgt); i++ {
113 g.cellPositions = append(g.cellPositions, [2]int{0, 0})
114 g.cellSpans = append(g.cellSpans, [2]int{1, 1})
115 }
116
117 g.updated = true
118 }
119
120
121
122 func (g *Grid) AddChildAt(wgt Widget, x int, y int, columns int, rows int) {
123 g.Box.AddChild(wgt)
124
125 g.cellPositions = append(g.cellPositions, [2]int{x, y})
126 g.cellSpans = append(g.cellSpans, [2]int{columns, rows})
127
128 g.updated = true
129 }
130
131
132 func (g *Grid) Clear() {
133 g.Lock()
134 defer g.Unlock()
135
136 g.children = g.children[:0]
137 g.cellPositions = g.cellPositions[:0]
138 g.cellSpans = g.cellSpans[:0]
139 g.updated = true
140 }
141
142
143 func (g *Grid) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
144 if g.updated {
145 g.reposition()
146 g.updated = false
147 }
148
149 return false, nil
150 }
151
152
153 func (g *Grid) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
154 if g.updated {
155 g.reposition()
156 g.updated = false
157 }
158
159 return false, nil
160 }
161
162
163 func (g *Grid) Draw(screen *ebiten.Image) error {
164 g.Lock()
165 defer g.Unlock()
166
167 if g.updated {
168 g.reposition()
169 g.updated = false
170 }
171
172 return nil
173 }
174
175 func (g *Grid) reposition() {
176 if g.rect.Min.X == 0 && g.rect.Min.Y == 0 && g.rect.Max.X == 0 && g.rect.Max.Y == 0 {
177 return
178 }
179
180 gridX, gridY := g.rect.Min.X, g.rect.Min.Y
181 gridW, gridH := g.rect.Dx(), g.rect.Dy()
182
183
184 var (
185 numColumns int
186 numRows int
187
188 maxColumnProportion = 1
189 maxRowProportion = 1
190
191 numColumnProportions = make(map[int]int)
192 numRowProportions = make(map[int]int)
193 )
194 for i := range g.children {
195 position := g.cellPositions[i]
196 x, y := position[0], position[1]
197
198 span := g.cellSpans[i]
199 w, h := span[0], span[1]
200
201 if x+w > numColumns {
202 numColumns = x + w
203 }
204 if y+h > numRows {
205 numRows = y + h
206 }
207
208 if -w > maxColumnProportion {
209 maxColumnProportion = -w
210 }
211 if -h > maxRowProportion {
212 maxRowProportion = -h
213 }
214 }
215
216
217 numColumnSizes := len(g.columnSizes)
218 numRowSizes := len(g.rowSizes)
219
220 columnWidths := make([]int, numColumns)
221 var usedWidth int
222 for i := 0; i < numColumns; i++ {
223 if i >= numColumnSizes {
224 columnWidths[i] = -1
225 } else {
226 columnWidths[i] = g.columnSizes[i]
227
228 if g.columnSizes[i] > 0 {
229 usedWidth += g.columnSizes[i]
230 }
231 }
232
233 if columnWidths[i] < 0 {
234 numColumnProportions[-columnWidths[i]]++
235 }
236 }
237 remainingWidth := gridW - usedWidth - (g.columnPadding * (numColumns + 1))
238 columnProportions := make([]int, maxColumnProportion)
239 for i := 0; i < maxColumnProportion; i++ {
240 columnProportions[i] = remainingWidth / (i + 1)
241 }
242 for i := 0; i < numColumns; i++ {
243 if columnWidths[i] < 0 {
244 columnWidths[i] = columnProportions[-columnWidths[i]-1] / numColumnProportions[-columnWidths[i]]
245 }
246 }
247
248 rowHeights := make([]int, numRows)
249 var usedHeight int
250 for i := 0; i < numRows; i++ {
251 if i >= numRowSizes {
252 rowHeights[i] = -1
253 } else {
254 rowHeights[i] = g.rowSizes[i]
255
256 if g.rowSizes[i] > 0 {
257 usedHeight += g.rowSizes[i]
258 }
259 }
260
261 if rowHeights[i] < 0 {
262 numRowProportions[-rowHeights[i]]++
263 }
264 }
265 remainingHeight := gridH - usedHeight - (g.rowPadding * (numRows + 1))
266 rowProportions := make([]int, maxRowProportion)
267 for i := 0; i < maxRowProportion; i++ {
268 rowProportions[i] = remainingHeight / (i + 1)
269 }
270 for i := 0; i < numRows; i++ {
271 if rowHeights[i] < 0 {
272 rowHeights[i] = rowProportions[-rowHeights[i]-1] / numRowProportions[-rowHeights[i]]
273 }
274 }
275
276 columnPositions := make([]int, numColumns)
277 {
278 x := g.columnPadding
279 for i := 0; i < numColumns; i++ {
280 columnPositions[i] = x
281 x += columnWidths[i] + g.columnPadding
282 }
283 }
284
285 rowPositions := make([]int, numRows)
286 {
287 y := g.rowPadding
288 for i := 0; i < numRows; i++ {
289 rowPositions[i] = y
290 y += rowHeights[i] + g.rowPadding
291 }
292 }
293
294
295 g.numColumns, g.numRows = numColumns, numRows
296
297
298 for i, child := range g.children {
299 position := g.cellPositions[i]
300 span := g.cellSpans[i]
301
302 x := columnPositions[position[0]]
303 y := rowPositions[position[1]]
304
305 var w, h int
306 for j := 0; j < span[0]; j++ {
307 if j > 0 {
308 w += g.columnPadding
309 }
310 w += columnWidths[position[0]+j]
311 }
312 for j := 0; j < span[1]; j++ {
313 if j > 0 {
314 h += g.rowPadding
315 }
316 h += rowHeights[position[1]+j]
317 }
318
319 child.SetRect(image.Rect(gridX+x, gridY+y, gridX+x+w, gridY+y+h))
320 }
321 }
322
View as plain text