/
fit.go
106 lines (89 loc) · 2.62 KB
/
fit.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
// SPDX-License-Identifier: Unlicense OR MIT
package widget
import (
"image"
"github.com/audrenbdb/gio/f32"
"github.com/audrenbdb/gio/layout"
"github.com/audrenbdb/gio/op"
"github.com/audrenbdb/gio/op/clip"
)
// Fit scales a widget to fit and clip to the constraints.
type Fit uint8
const (
// Unscaled does not alter the scale of a widget.
Unscaled Fit = iota
// Contain scales widget as large as possible without cropping
// and it preserves aspect-ratio.
Contain
// Cover scales the widget to cover the constraint area and
// preserves aspect-ratio.
Cover
// ScaleDown scales the widget smaller without cropping,
// when it exceeds the constraint area.
// It preserves aspect-ratio.
ScaleDown
// Fill stretches the widget to the constraints and does not
// preserve aspect-ratio.
Fill
)
// scale adds clip and scale operations to fit dims to the constraints.
// It positions the widget to the appropriate position.
// It returns dimensions modified accordingly.
func (fit Fit) scale(gtx layout.Context, pos layout.Direction, dims layout.Dimensions) layout.Dimensions {
widgetSize := dims.Size
if fit == Unscaled || dims.Size.X == 0 || dims.Size.Y == 0 {
dims.Size = gtx.Constraints.Constrain(dims.Size)
clip.Rect{Max: dims.Size}.Add(gtx.Ops)
offset := pos.Position(widgetSize, dims.Size)
op.Offset(layout.FPt(offset)).Add(gtx.Ops)
dims.Baseline += offset.Y
return dims
}
scale := f32.Point{
X: float32(gtx.Constraints.Max.X) / float32(dims.Size.X),
Y: float32(gtx.Constraints.Max.Y) / float32(dims.Size.Y),
}
switch fit {
case Contain:
if scale.Y < scale.X {
scale.X = scale.Y
} else {
scale.Y = scale.X
}
case Cover:
if scale.Y > scale.X {
scale.X = scale.Y
} else {
scale.Y = scale.X
}
case ScaleDown:
if scale.Y < scale.X {
scale.X = scale.Y
} else {
scale.Y = scale.X
}
// The widget would need to be scaled up, no change needed.
if scale.X >= 1 {
dims.Size = gtx.Constraints.Constrain(dims.Size)
clip.Rect{Max: dims.Size}.Add(gtx.Ops)
offset := pos.Position(widgetSize, dims.Size)
op.Offset(layout.FPt(offset)).Add(gtx.Ops)
dims.Baseline += offset.Y
return dims
}
case Fill:
}
var scaledSize image.Point
scaledSize.X = int(float32(widgetSize.X) * scale.X)
scaledSize.Y = int(float32(widgetSize.Y) * scale.Y)
dims.Size = gtx.Constraints.Constrain(scaledSize)
dims.Baseline = int(float32(dims.Baseline) * scale.Y)
clip.Rect{Max: dims.Size}.Add(gtx.Ops)
offset := pos.Position(scaledSize, dims.Size)
op.Affine(f32.Affine2D{}.
Scale(f32.Point{}, scale).
Offset(layout.FPt(offset)),
).Add(gtx.Ops)
dims.Baseline += offset.Y
return dims
}