-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinearlayout.go
141 lines (115 loc) · 3.32 KB
/
linearlayout.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
package main
import "math"
type Scroller interface {
ScrollTo(offset float64)
ScrollOffset() float64
ScrollSize() float64
}
type LinearLayout struct {
Layout
Orientation Orientation
Spacing float64
Margin float64
scrollOffset float64
scrollSize float64
}
func NewLinearLayout(orient Orientation, spacing, margin float64) *LinearLayout {
return &LinearLayout{
Orientation: orient,
Margin: margin,
Spacing: spacing,
}
}
func (s *LinearLayout) Measure(orient Orientation, forsize float64) (minimum, natural float64) {
// Compute minimum and natural size if allocated a height of `forsize`.
// We can accomplish this by adding up the minimum and natural
// widths/heights of all the children along with the total spacing
// between them.
if orient == s.Orientation {
// We are measuring the width of a horizontal scroller.
// Find the sum of all minimum and natural measures of all children
// and add margins.
minimum = 2 * s.Margin
natural = minimum + s.Spacing*float64(s.Len()-1)
for _, child := range s.Layout.Children {
minimumChild, naturalChild := child.Measure(orient, forsize)
minimum += minimumChild
natural += naturalChild
}
} else {
// We are measuring the height of a horizontal scroller.
// Find the largest minimum and natural measure for all children
// and add margins.
minimum = 2 * s.Margin
natural = minimum
var minimumChildMax, naturalChildMax float64
for _, child := range s.Layout.Children {
minimumChild, naturalChild := child.Measure(orient, forsize)
minimumChildMax = math.Max(minimumChildMax, minimumChild)
naturalChildMax = math.Max(naturalChildMax, naturalChild)
}
minimum += minimumChildMax
natural += naturalChildMax
}
return
}
func (s *LinearLayout) Allocate(alloc *Allocation) {
s.Layout.alloc = alloc
var forsize float64
var space float64
switch s.Orientation {
case Horizontal:
forsize, space = alloc.Height, alloc.Width
case Vertical:
forsize, space = alloc.Width, alloc.Height
}
numberOfChildren := len(s.Layout.Children)
if numberOfChildren == 0 {
return
}
// Subtract margin
forsize -= 2 * s.Margin
space -= 2 * s.Margin
// Calculate distribution
var sizesSum float64
sizes := make([]float64, numberOfChildren)
for i, child := range s.Layout.Children {
_, natural := child.Measure(s.Orientation, forsize)
sizes[i] = natural
sizesSum += natural
}
sizeTotal := sizesSum + float64(numberOfChildren-1)*s.Spacing
sizeExtra := space - sizeTotal
if sizeExtra < 0 {
sizeExtra = 0
}
toDistribute := sizeExtra / float64(numberOfChildren)
// Set allocation to all of child nodes
pointer := s.Margin
for i, child := range s.Layout.Children {
natural := sizes[i] + toDistribute
childAlloc := &Allocation{
X: s.scrollOffset + pointer,
Y: s.Margin,
Width: natural,
Height: forsize,
}
if s.Orientation == Vertical {
childAlloc.X, childAlloc.Y = childAlloc.Y, childAlloc.X
childAlloc.Width, childAlloc.Height = childAlloc.Height, childAlloc.Width
}
child.Allocate(childAlloc)
pointer += natural + s.Spacing
}
s.scrollSize = sizeTotal
}
// Scroller interface
func (s *LinearLayout) ScrollTo(offset float64) {
s.scrollOffset = offset
}
func (s *LinearLayout) ScrollOffset() float64 {
return s.scrollOffset
}
func (s *LinearLayout) ScrollSize() float64 {
return s.scrollSize
}