Specific commits ported, to update the layouts and reduce differences with upstream Fyne code: * https://github.com/fyne-io/fyne/commit/a9a66f60d2167d7945bcf7718a781335541317c0 * https://github.com/fyne-io/fyne/commit/2cde868904092382ca5f645802ee9d444d8ae6e8 * https://github.com/fyne-io/fyne/commit/99fa7e3a7dc83dd273ad366cc7d336a1e1cee5f6 * https://github.com/fyne-io/fyne/commit/4ea8a5762f1744401ede9f7bd35b3b75890f925e
165 lines
4.4 KiB
Go
165 lines
4.4 KiB
Go
package layouts
|
|
|
|
// Forked from fyne.io/fyne/v2/layout/gridlayout.go
|
|
|
|
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
|
|
Padding float32
|
|
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 NewGridLayoutWithColumnsAndPadding(cols int, padding float32) fyne.Layout {
|
|
return &gridLayout{Cols: cols, Padding: padding}
|
|
}
|
|
|
|
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 {
|
|
if g.Cols < 1 {
|
|
g.Cols = 1
|
|
}
|
|
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, padding float32, offset int) float32 {
|
|
ret := (size + float64(padding)) * float64(offset)
|
|
|
|
return float32(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, padding float32, offset int) float32 {
|
|
return getLeading(size, padding, offset+1) - 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)
|
|
|
|
padding := theme.Padding() + g.Padding
|
|
|
|
primaryObjects := rows
|
|
secondaryObjects := g.Cols
|
|
if g.horizontal() {
|
|
primaryObjects, secondaryObjects = secondaryObjects, primaryObjects
|
|
}
|
|
|
|
padWidth := float32(primaryObjects-1) * padding
|
|
padHeight := float32(secondaryObjects-1) * padding
|
|
cellWidth := float64(size.Width-padWidth) / float64(primaryObjects)
|
|
cellHeight := float64(size.Height-padHeight) / float64(secondaryObjects)
|
|
|
|
row, col := 0, 0
|
|
i := 0
|
|
for _, child := range objects {
|
|
if !child.Visible() {
|
|
continue
|
|
}
|
|
|
|
x1 := getLeading(cellWidth, padding, col)
|
|
y1 := getLeading(cellHeight, padding, row)
|
|
x2 := getTrailing(cellWidth, padding, col)
|
|
y2 := getTrailing(cellHeight, padding, 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())
|
|
}
|
|
|
|
padding := theme.Padding() + g.Padding
|
|
|
|
primaryObjects := rows
|
|
secondaryObjects := g.Cols
|
|
if g.horizontal() {
|
|
primaryObjects, secondaryObjects = secondaryObjects, primaryObjects
|
|
}
|
|
|
|
width := minSize.Width * float32(primaryObjects)
|
|
height := minSize.Height * float32(secondaryObjects)
|
|
xpad := padding * fyne.Max(float32(primaryObjects-1), 0)
|
|
ypad := padding * fyne.Max(float32(secondaryObjects-1), 0)
|
|
|
|
return fyne.NewSize(width+xpad, height+ypad)
|
|
}
|