forked from fyne-io/fyne
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgridlayout.go
145 lines (119 loc) · 4.13 KB
/
gridlayout.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package layout
import (
"math"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"
)
// Declare conformity with Layout interface
var _ fyne.Layout = (*gridLayout)(nil)
type gridLayout struct {
Cols int
vertical, adapt bool
}
// NewAdaptiveGridLayout returns a new grid layout which uses columns when horizontal but rows when vertical.
func NewAdaptiveGridLayout(rowcols int) fyne.Layout {
return &gridLayout{Cols: rowcols, adapt: true}
}
// NewGridLayout returns a grid layout arranged in a specified number of columns.
// The number of rows will depend on how many children are in the container that uses this layout.
func NewGridLayout(cols int) fyne.Layout {
return NewGridLayoutWithColumns(cols)
}
// NewGridLayoutWithColumns returns a new grid layout that specifies a column count and wrap to new rows when needed.
func NewGridLayoutWithColumns(cols int) fyne.Layout {
return &gridLayout{Cols: cols}
}
// NewGridLayoutWithRows returns a new grid layout that specifies a row count that creates new rows as required.
func NewGridLayoutWithRows(rows int) fyne.Layout {
return &gridLayout{Cols: rows, vertical: true}
}
func (g *gridLayout) horizontal() bool {
if g.adapt {
return fyne.IsHorizontal(fyne.CurrentDevice().Orientation())
}
return !g.vertical
}
func (g *gridLayout) countRows(objects []fyne.CanvasObject) int {
count := 0
for _, child := range objects {
if child.Visible() {
count++
}
}
return int(math.Ceil(float64(count) / float64(g.Cols)))
}
// Get the leading (top or left) edge of a grid cell.
// size is the ideal cell size and the offset is which col or row its on.
func getLeading(size float64, offset int) float32 {
ret := (size + float64(theme.Padding())) * float64(offset)
return float32(math.Round(ret))
}
// Get the trailing (bottom or right) edge of a grid cell.
// size is the ideal cell size and the offset is which col or row its on.
func getTrailing(size float64, offset int) float32 {
return getLeading(size, offset+1) - theme.Padding()
}
// Layout is called to pack all child objects into a specified size.
// For a GridLayout this will pack objects into a table format with the number
// of columns specified in our constructor.
func (g *gridLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
rows := g.countRows(objects)
padWidth := float32(g.Cols-1) * theme.Padding()
padHeight := float32(rows-1) * theme.Padding()
cellWidth := float64(size.Width-padWidth) / float64(g.Cols)
cellHeight := float64(size.Height-padHeight) / float64(rows)
if !g.horizontal() {
padWidth, padHeight = padHeight, padWidth
cellWidth = float64(size.Width-padWidth) / float64(rows)
cellHeight = float64(size.Height-padHeight) / float64(g.Cols)
}
row, col := 0, 0
i := 0
for _, child := range objects {
if !child.Visible() {
continue
}
x1 := getLeading(cellWidth, col)
y1 := getLeading(cellHeight, row)
x2 := getTrailing(cellWidth, col)
y2 := getTrailing(cellHeight, row)
child.Move(fyne.NewPos(x1, y1))
child.Resize(fyne.NewSize(x2-x1, y2-y1))
if g.horizontal() {
if (i+1)%g.Cols == 0 {
row++
col = 0
} else {
col++
}
} else {
if (i+1)%g.Cols == 0 {
col++
row = 0
} else {
row++
}
}
i++
}
}
// MinSize finds the smallest size that satisfies all the child objects.
// For a GridLayout this is the size of the largest child object multiplied by
// the required number of columns and rows, with appropriate padding between
// children.
func (g *gridLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
rows := g.countRows(objects)
minSize := fyne.NewSize(0, 0)
for _, child := range objects {
if !child.Visible() {
continue
}
minSize = minSize.Max(child.MinSize())
}
if g.horizontal() {
minContentSize := fyne.NewSize(minSize.Width*float32(g.Cols), minSize.Height*float32(rows))
return minContentSize.Add(fyne.NewSize(theme.Padding()*fyne.Max(float32(g.Cols-1), 0), theme.Padding()*fyne.Max(float32(rows-1), 0)))
}
minContentSize := fyne.NewSize(minSize.Width*float32(rows), minSize.Height*float32(g.Cols))
return minContentSize.Add(fyne.NewSize(theme.Padding()*fyne.Max(float32(rows-1), 0), theme.Padding()*fyne.Max(float32(g.Cols-1), 0)))
}