-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
formlayout.go
120 lines (98 loc) · 3.92 KB
/
formlayout.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
package layout
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
)
const formLayoutCols = 2
// Declare conformity with Layout interface
var _ fyne.Layout = (*formLayout)(nil)
// formLayout is two column grid where each row has a label and a widget.
type formLayout struct{}
// calculateTableSizes calculates the izes of the table.
// This includes the width of the label column (maximum width of all labels),
// the width of the content column (maximum width of all content cells and remaining space in container)
// and the total minimum height of the form.
func (f *formLayout) calculateTableSizes(objects []fyne.CanvasObject, containerWidth float32) (labelWidth float32, contentWidth float32, height float32) {
if len(objects)%formLayoutCols != 0 {
return 0, 0, 0
}
rows := 0
innerPadding := theme.InnerPadding()
for i := 0; i < len(objects); i += formLayoutCols {
labelCell, contentCell := objects[i], objects[i+1]
if !labelCell.Visible() && !contentCell.Visible() {
continue
}
// Label column width is the maximum of all labels.
labelSize := labelCell.MinSize()
if _, ok := labelCell.(*canvas.Text); ok {
labelSize.Width += innerPadding * 2
}
labelWidth = fyne.Max(labelWidth, labelSize.Width)
// Content column width is the maximum of all content items.
contentSize := contentCell.MinSize()
contentWidth = fyne.Max(contentWidth, contentSize.Width)
rowHeight := fyne.Max(labelSize.Height, contentSize.Height)
height += rowHeight
rows++
}
padding := theme.Padding()
contentWidth = fyne.Max(contentWidth, containerWidth-labelWidth-padding)
return labelWidth, contentWidth, height + float32(rows-1)*padding
}
// Layout is called to pack all child objects into a table format with two columns.
func (f *formLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
labelWidth, contentWidth, _ := f.calculateTableSizes(objects, size.Width)
y := float32(0)
padding := theme.Padding()
innerPadding := theme.InnerPadding()
// Calculate size and position of object. Position and size is returned (instead of calling Move() and Resize()) to make inlineable.
objectLayout := func(obj fyne.CanvasObject, offset, width, rowHeight, itemHeight float32) (fyne.Position, fyne.Size) {
pos := fyne.NewPos(offset, y)
size := fyne.NewSize(width, rowHeight)
if _, ok := obj.(*canvas.Text); ok {
pos = pos.AddXY(innerPadding, innerPadding)
size.Width -= innerPadding * 2
size.Height = itemHeight
}
return pos, size
}
remainer := len(objects) % formLayoutCols
for i := 0; i < len(objects)-remainer; i += formLayoutCols {
labelCell, contentCell := objects[i], objects[i+1]
if !labelCell.Visible() && !contentCell.Visible() {
continue
}
labelMin := labelCell.MinSize()
contentMin := contentCell.MinSize()
rowHeight := fyne.Max(labelMin.Height, contentMin.Height)
pos, size := objectLayout(labelCell, 0, labelWidth, rowHeight, labelMin.Height)
labelCell.Move(pos)
labelCell.Resize(size)
pos, size = objectLayout(contentCell, labelWidth+padding, contentWidth, rowHeight, contentMin.Height)
contentCell.Move(pos)
contentCell.Resize(size)
y += rowHeight + padding
}
// Handle remaining item in the case of uneven number of objects:
if remainer == 1 {
lastCell := objects[len(objects)-1]
lastMin := lastCell.MinSize()
objectLayout(lastCell, 0, labelWidth, lastMin.Height, lastMin.Height)
}
}
// MinSize finds the smallest size that satisfies all the child objects.
// For a FormLayout this is the width of the widest label and content items and the height is
// the sum of all column children combined with padding between each.
func (f *formLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
labelWidth, contentWidth, height := f.calculateTableSizes(objects, 0)
return fyne.Size{
Width: labelWidth + contentWidth + theme.Padding(),
Height: height,
}
}
// NewFormLayout returns a new FormLayout instance
func NewFormLayout() fyne.Layout {
return &formLayout{}
}