| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- 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 {
- 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, offset int) float32 {
- ret := (size + float64(theme.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, 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)
- padding := theme.Padding()
- padWidth := float32(g.Cols-1) * padding
- padHeight := float32(rows-1) * 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)))
- }
|