Skip to content

Commit d178c85

Browse files
author
BieHDC
committed
Add Option to CheckGroup to make Rows/Columns
This is fully backwards compatible and helps with very long lists to be better organised.
1 parent de361f6 commit d178c85

File tree

1 file changed

+68
-29
lines changed

1 file changed

+68
-29
lines changed

widget/check_group.go

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package widget
22

33
import (
4+
"math"
45
"strings"
56

67
"fyne.io/fyne/v2"
@@ -15,6 +16,7 @@ import (
1516
type CheckGroup struct {
1617
DisableableWidget
1718
Horizontal bool
19+
numColumns int
1820
Required bool
1921
OnChanged func([]string) `json:"-"`
2022
Options []string
@@ -38,6 +40,10 @@ func NewCheckGroup(options []string, changed func([]string)) *CheckGroup {
3840
return r
3941
}
4042

43+
func (r *CheckGroup) SetColumns(columns int) {
44+
r.numColumns = columns
45+
}
46+
4147
// Append adds a new option to the end of a CheckGroup widget.
4248
func (r *CheckGroup) Append(option string) {
4349
r.Options = append(r.Options, option)
@@ -179,54 +185,87 @@ type checkGroupRenderer struct {
179185
checks *CheckGroup
180186
}
181187

188+
func (r *CheckGroup) countColumns() int {
189+
if r.numColumns < 1 {
190+
r.numColumns = 1
191+
}
192+
return r.numColumns
193+
}
194+
195+
func (r *CheckGroup) countRows() int {
196+
return int(math.Ceil(float64(len(r.items)) / float64(r.countColumns())))
197+
}
198+
199+
func getLeading(size float64, offset int) float32 {
200+
return float32(size * float64(offset))
201+
}
202+
203+
func getTrailing(size float64, offset int) float32 {
204+
return getLeading(size, offset+1)
205+
}
206+
182207
// Layout the components of the checks widget
183208
func (r *checkGroupRenderer) Layout(_ fyne.Size) {
184-
count := 1
185-
if len(r.items) > 0 {
186-
count = len(r.items)
187-
}
188-
var itemHeight, itemWidth float32
189-
minSize := r.checks.MinSize()
209+
cols := r.checks.countColumns()
210+
211+
primaryObjects := cols
212+
secondaryObjects := r.checks.countRows()
190213
if r.checks.Horizontal {
191-
itemHeight = minSize.Height
192-
itemWidth = minSize.Width / float32(count)
193-
} else {
194-
itemHeight = minSize.Height / float32(count)
195-
itemWidth = minSize.Width
214+
primaryObjects, secondaryObjects = secondaryObjects, primaryObjects
196215
}
197216

198-
itemSize := fyne.NewSize(itemWidth, itemHeight)
199-
x, y := float32(0), float32(0)
200-
for _, item := range r.items {
201-
item.Resize(itemSize)
202-
item.Move(fyne.NewPos(x, y))
217+
size := r.checks.MinSize()
218+
cellWidth := float64(size.Width) / float64(primaryObjects)
219+
cellHeight := float64(size.Height) / float64(secondaryObjects)
220+
221+
row, col := 0, 0
222+
i := 0
223+
for _, child := range r.items {
224+
x1 := getLeading(cellWidth, col)
225+
y1 := getLeading(cellHeight, row)
226+
x2 := getTrailing(cellWidth, col)
227+
y2 := getTrailing(cellHeight, row)
228+
229+
child.Move(fyne.NewPos(x1, y1))
230+
child.Resize(fyne.NewSize(x2-x1, y2-y1))
231+
203232
if r.checks.Horizontal {
204-
x += itemWidth
233+
if (i+1)%cols == 0 {
234+
col++
235+
row = 0
236+
} else {
237+
row++
238+
}
205239
} else {
206-
y += itemHeight
240+
if (i+1)%cols == 0 {
241+
row++
242+
col = 0
243+
} else {
244+
col++
245+
}
207246
}
247+
i++
208248
}
209249
}
210250

211251
// MinSize calculates the minimum size of a checks item.
212252
// This is based on the contained text, the checks icon and a standard amount of padding
213253
// between each item.
214254
func (r *checkGroupRenderer) MinSize() fyne.Size {
215-
width := float32(0)
216-
height := float32(0)
217-
for _, item := range r.items {
218-
itemMin := item.MinSize()
219-
220-
width = fyne.Max(width, itemMin.Width)
221-
height = fyne.Max(height, itemMin.Height)
255+
minSize := fyne.NewSize(0, 0)
256+
for _, child := range r.items {
257+
minSize = minSize.Max(child.MinSize())
222258
}
223259

260+
primaryObjects := r.checks.countColumns()
261+
secondaryObjects := r.checks.countRows()
224262
if r.checks.Horizontal {
225-
width = width * float32(len(r.items))
226-
} else {
227-
height = height * float32(len(r.items))
263+
primaryObjects, secondaryObjects = secondaryObjects, primaryObjects
228264
}
229265

266+
width := minSize.Width * float32(primaryObjects)
267+
height := minSize.Height * float32(secondaryObjects)
268+
230269
return fyne.NewSize(width, height)
231270
}
232271

@@ -245,7 +284,7 @@ func (r *checkGroupRenderer) updateItems() {
245284
r.SetObjects(append(r.Objects(), item))
246285
r.items = append(r.items, item)
247286
}
248-
r.Layout(r.checks.Size())
287+
r.Layout(r.checks.Size()) // argument is ignored
249288
} else if len(r.items) > len(r.checks.Options) {
250289
total := len(r.checks.Options)
251290
r.items = r.items[:total]

0 commit comments

Comments
 (0)