all: [API] change op.Offset to take integer coordinates

op.Offset is a convenience function most often used by layouts. Layouts
usually operate in integer coordinates, and the float32 version of op.Offset
needlessly force conversions from int to float32. This change makes op.Offset
take integer coordinates, to better match its intended use.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-04-26 09:22:10 +02:00
parent 14805af367
commit a63e0cb44a
23 changed files with 70 additions and 72 deletions
+2 -2
View File
@@ -825,7 +825,7 @@ func (w *Window) processEvent(d driver, e event.Event) bool {
var signal chan<- struct{}
if frame != nil {
signal = w.frameAck
cl := clip.Rect(image.Rectangle{Max: e2.FrameEvent.Size}).Push(wrapper)
cl := clip.Rect{Max: e2.FrameEvent.Size}.Push(wrapper)
ops.AddCall(&wrapper.Internal, &frame.Internal, ops.PC{}, ops.PCFor(&frame.Internal))
cl.Pop()
}
@@ -990,7 +990,7 @@ func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) image.Point
w.Perform(deco.Actions())
// Offset to place the frame content below the decorations.
size := image.Point{Y: dims.Size.Y}
op.Offset(f32.Point{Y: float32(size.Y)}).Add(o)
op.Offset(image.Pt(0, size.Y)).Add(o)
appSize := e.Size.Sub(size)
if w.decorations.size != size {
w.decorations.size = size
+9 -9
View File
@@ -86,7 +86,7 @@ func BenchmarkDrawUI(b *testing.B) {
resetOps(gtx)
off := float32(math.Mod(float64(i)/10, 10))
t := op.Offset(f32.Pt(off, off)).Push(gtx.Ops)
t := op.Affine(f32.Affine2D{}.Offset(f32.Pt(off, off))).Push(gtx.Ops)
drawCore(gtx, th)
@@ -157,13 +157,13 @@ func Benchmark1000CirclesInstanced(b *testing.B) {
func draw1000Circles(gtx layout.Context) {
ops := gtx.Ops
for x := 0; x < 100; x++ {
op.Offset(f32.Pt(float32(x*10), 0)).Add(ops)
op.Offset(image.Pt(x*10, 0)).Add(ops)
for y := 0; y < 10; y++ {
paint.FillShape(ops,
color.NRGBA{R: 100 + uint8(x), G: 100 + uint8(y), B: 100, A: 120},
clip.RRect{Rect: f32.Rect(0, 0, 10, 10), NE: 5, SE: 5, SW: 5, NW: 5}.Op(ops),
)
op.Offset(f32.Pt(0, float32(100))).Add(ops)
op.Offset(image.Pt(0, 100)).Add(ops)
}
}
}
@@ -178,11 +178,11 @@ func draw1000CirclesInstanced(gtx layout.Context) {
c := r.Stop()
for x := 0; x < 100; x++ {
op.Offset(f32.Pt(float32(x*10), 0)).Add(ops)
op.Offset(image.Pt(x*10, 0)).Add(ops)
for y := 0; y < 10; y++ {
paint.ColorOp{Color: color.NRGBA{R: 100 + uint8(x), G: 100 + uint8(y), B: 100, A: 120}}.Add(ops)
c.Add(ops)
op.Offset(f32.Pt(0, float32(100))).Add(ops)
op.Offset(image.Pt(0, 100)).Add(ops)
}
}
}
@@ -203,13 +203,13 @@ func drawIndividualShapes(gtx layout.Context, th *material.Theme) chan op.CallOp
ops := &op1
c := op.Record(ops)
for x := 0; x < 9; x++ {
op.Offset(f32.Pt(float32(x*50), 0)).Add(ops)
op.Offset(image.Pt(x*50, 0)).Add(ops)
for y := 0; y < 9; y++ {
paint.FillShape(ops,
color.NRGBA{R: 100 + uint8(x), G: 100 + uint8(y), B: 100, A: 120},
clip.RRect{Rect: f32.Rect(0, 0, 25, 25), NE: 10, SE: 10, SW: 10, NW: 10}.Op(ops),
)
op.Offset(f32.Pt(0, float32(50))).Add(ops)
op.Offset(image.Pt(0, 50)).Add(ops)
}
}
c1 <- c.Stop()
@@ -233,7 +233,7 @@ func drawShapeInstances(gtx layout.Context, th *material.Theme) chan op.CallOp {
rad := float32(0)
for x := 0; x < 20; x++ {
for y := 0; y < 20; y++ {
t := op.Offset(f32.Pt(float32(x*50+25), float32(y*50+25))).Push(ops)
t := op.Offset(image.Pt(x*50+25, y*50+25)).Push(ops)
c.Add(ops)
t.Pop()
rad += math.Pi * 2 / 400
@@ -253,7 +253,7 @@ func drawText(gtx layout.Context, th *material.Theme) chan op.CallOp {
txt := material.H6(th, "")
for x := 0; x < 40; x++ {
txt.Text = textRows[x]
t := op.Offset(f32.Pt(float32(0), float32(24*x))).Push(ops)
t := op.Offset(image.Pt(0, 24*x)).Push(ops)
gtx.Ops = ops
txt.Layout(gtx)
t.Pop()
+4 -4
View File
@@ -124,13 +124,13 @@ func TestPaintTexture(t *testing.T) {
func TestTexturedStrokeClipped(t *testing.T) {
run(t, func(o *op.Ops) {
smallSquares.Add(o)
defer op.Offset(f32.Pt(50, 50)).Push(o).Pop()
defer op.Offset(image.Pt(50, 50)).Push(o).Pop()
defer clip.Stroke{
Path: clip.RRect{Rect: f32.Rect(0, 0, 30, 30)}.Path(o),
Width: 10,
}.Op().Push(o).Pop()
defer clip.RRect{Rect: f32.Rect(-30, -30, 60, 60)}.Push(o).Pop()
defer op.Offset(f32.Pt(-10, -10)).Push(o).Pop()
defer op.Offset(image.Pt(-10, -10)).Push(o).Pop()
paint.PaintOp{}.Add(o)
}, func(r result) {
})
@@ -139,12 +139,12 @@ func TestTexturedStrokeClipped(t *testing.T) {
func TestTexturedStroke(t *testing.T) {
run(t, func(o *op.Ops) {
smallSquares.Add(o)
defer op.Offset(f32.Pt(50, 50)).Push(o).Pop()
defer op.Offset(image.Pt(50, 50)).Push(o).Pop()
defer clip.Stroke{
Path: clip.RRect{Rect: f32.Rect(0, 0, 30, 30)}.Path(o),
Width: 10,
}.Op().Push(o).Pop()
defer op.Offset(f32.Pt(-10, -10)).Push(o).Pop()
defer op.Offset(image.Pt(-10, -10)).Push(o).Pop()
paint.PaintOp{}.Add(o)
}, func(r result) {
})
+6 -6
View File
@@ -35,7 +35,7 @@ func TestTransformMacro(t *testing.T) {
m2 := op.Record(o)
paint.ColorOp{Color: red}.Add(o)
// Simulate a draw text call
t := op.Offset(f32.Pt(0, 10)).Push(o)
t := op.Offset(image.Pt(0, 10)).Push(o)
// Apply the clip-path.
cl := c.Push(o)
@@ -47,10 +47,10 @@ func TestTransformMacro(t *testing.T) {
c2 := m2.Stop()
// Call each of them in a transform
t = op.Offset(f32.Pt(0, 0)).Push(o)
t = op.Offset(image.Pt(0, 0)).Push(o)
c1.Add(o)
t.Pop()
t = op.Offset(f32.Pt(0, 0)).Push(o)
t = op.Offset(image.Pt(0, 0)).Push(o)
c2.Add(o)
t.Pop()
}, func(r result) {
@@ -164,7 +164,7 @@ func TestReuseStencil(t *testing.T) {
// lay out the children
c1.Add(ops)
defer op.Offset(f32.Pt(0, 50)).Push(ops).Pop()
defer op.Offset(image.Pt(0, 50)).Push(ops).Pop()
c2.Add(ops)
}, func(r result) {
r.expect(5, 5, colornames.Black)
@@ -178,8 +178,8 @@ func TestBuildOffscreen(t *testing.T) {
// frame.
txt := constSqCirc()
draw := func(off float32, o *op.Ops) {
defer op.Offset(f32.Pt(0, off)).Push(o).Pop()
draw := func(off int, o *op.Ops) {
defer op.Offset(image.Pt(0, off)).Push(o).Pop()
defer txt.Push(o).Pop()
paint.PaintOp{}.Add(o)
}
+5 -5
View File
@@ -17,7 +17,7 @@ import (
func TestPaintOffset(t *testing.T) {
run(t, func(o *op.Ops) {
defer op.Offset(f32.Pt(10, 20)).Push(o).Pop()
defer op.Offset(image.Pt(10, 20)).Push(o).Pop()
paint.FillShape(o, red, clip.Rect(image.Rect(0, 0, 50, 50)).Op())
}, func(r result) {
r.expect(0, 0, transparent)
@@ -53,7 +53,7 @@ func TestPaintShear(t *testing.T) {
func TestClipPaintOffset(t *testing.T) {
run(t, func(o *op.Ops) {
defer clip.RRect{Rect: f32.Rect(10, 10, 30, 30)}.Push(o).Pop()
defer op.Offset(f32.Pt(20, 20)).Push(o).Pop()
defer op.Offset(image.Pt(20, 20)).Push(o).Pop()
paint.FillShape(o, red, clip.Rect(image.Rect(0, 0, 100, 100)).Op())
}, func(r result) {
r.expect(0, 0, transparent)
@@ -65,7 +65,7 @@ func TestClipPaintOffset(t *testing.T) {
func TestClipOffset(t *testing.T) {
run(t, func(o *op.Ops) {
defer op.Offset(f32.Pt(20, 20)).Push(o).Pop()
defer op.Offset(image.Pt(20, 20)).Push(o).Pop()
defer clip.RRect{Rect: f32.Rect(10, 10, 30, 30)}.Push(o).Pop()
paint.FillShape(o, red, clip.Rect(image.Rect(0, 0, 100, 100)).Op())
}, func(r result) {
@@ -105,7 +105,7 @@ func TestClipRotate(t *testing.T) {
func TestOffsetTexture(t *testing.T) {
run(t, func(o *op.Ops) {
defer op.Offset(f32.Pt(15, 15)).Push(o).Pop()
defer op.Offset(image.Pt(15, 15)).Push(o).Pop()
squares.Add(o)
defer scale(50.0/512, 50.0/512).Push(o).Pop()
paint.PaintOp{}.Add(o)
@@ -119,7 +119,7 @@ func TestOffsetTexture(t *testing.T) {
func TestOffsetScaleTexture(t *testing.T) {
run(t, func(o *op.Ops) {
defer op.Offset(f32.Pt(15, 15)).Push(o).Pop()
defer op.Offset(image.Pt(15, 15)).Push(o).Pop()
squares.Add(o)
defer op.Affine(f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(2, 1))).Push(o).Pop()
defer scale(50.0/512, 50.0/512).Push(o).Pop()
+4 -4
View File
@@ -3,9 +3,9 @@
package layout
import (
"image"
"time"
"gioui.org/f32"
"gioui.org/io/event"
"gioui.org/io/system"
"gioui.org/op"
@@ -54,9 +54,9 @@ func NewContext(ops *op.Ops, e system.FrameEvent) Context {
if e.Insets != (system.Insets{}) {
left := e.Metric.Px(e.Insets.Left)
top := e.Metric.Px(e.Insets.Top)
op.Offset(f32.Point{
X: float32(left),
Y: float32(top),
op.Offset(image.Point{
X: left,
Y: top,
}).Add(ops)
size.X -= left + e.Metric.Px(e.Insets.Right)
+1 -1
View File
@@ -184,7 +184,7 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
}
}
pt := f.Axis.Convert(image.Pt(mainSize, cross))
trans := op.Offset(FPt(pt)).Push(gtx.Ops)
trans := op.Offset(pt).Push(gtx.Ops)
child.call.Add(gtx.Ops)
trans.Pop()
mainSize += f.Axis.Convert(dims.Size).X
+2 -2
View File
@@ -142,7 +142,7 @@ func (in Inset) Layout(gtx Context, w Widget) Dimensions {
mcs.Min.Y = mcs.Max.Y
}
gtx.Constraints = mcs
trans := op.Offset(FPt(image.Point{X: left, Y: top})).Push(gtx.Ops)
trans := op.Offset(image.Pt(left, top)).Push(gtx.Ops)
dims := w(gtx)
trans.Pop()
return Dimensions{
@@ -181,7 +181,7 @@ func (d Direction) Layout(gtx Context, w Widget) Dimensions {
}
p := d.Position(dims.Size, sz)
defer op.Offset(FPt(p)).Push(gtx.Ops).Pop()
defer op.Offset(p).Push(gtx.Ops).Pop()
call.Add(gtx.Ops)
return Dimensions{
+1 -1
View File
@@ -292,7 +292,7 @@ func (l *List) layout(ops *op.Ops, macro op.MacroOp) Dimensions {
min = 0
}
pt := l.Axis.Convert(image.Pt(pos, cross))
trans := op.Offset(FPt(pt)).Push(ops)
trans := op.Offset(pt).Push(ops)
child.call.Add(ops)
trans.Pop()
pos += childSize
+1 -1
View File
@@ -104,7 +104,7 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
case SW, S, SE:
p.Y = maxSZ.Y - sz.Y
}
trans := op.Offset(FPt(p)).Push(gtx.Ops)
trans := op.Offset(p).Push(gtx.Ops)
ch.call.Add(gtx.Ops)
trans.Pop()
if baseline == 0 {
+5 -3
View File
@@ -67,6 +67,7 @@ package op
import (
"encoding/binary"
"image"
"math"
"time"
@@ -195,9 +196,10 @@ func (r InvalidateOp) Add(o *Ops) {
}
}
// Offset creates a TransformOp with the offset o.
func Offset(o f32.Point) TransformOp {
return TransformOp{t: f32.Affine2D{}.Offset(o)}
// Offset converts an offset to a TransformOp.
func Offset(off image.Point) TransformOp {
offf := f32.Pt(float32(off.X), float32(off.Y))
return Affine(f32.Affine2D{}.Offset(offf))
}
// Affine creates a TransformOp representing the transformation a.
+2 -3
View File
@@ -3,9 +3,8 @@
package op
import (
"image"
"testing"
"gioui.org/f32"
)
func TestTransformChecks(t *testing.T) {
@@ -15,7 +14,7 @@ func TestTransformChecks(t *testing.T) {
}
}()
var ops Ops
trans := Offset(f32.Point{}).Push(&ops)
trans := Offset(image.Point{}).Push(&ops)
Record(&ops)
trans.Pop()
}
+1 -1
View File
@@ -64,7 +64,7 @@ func (d *Draggable) Layout(gtx layout.Context, w, drag layout.Widget) layout.Dim
if drag != nil && d.drag.Pressed() {
rec := op.Record(gtx.Ops)
op.Offset(pos).Add(gtx.Ops)
op.Offset(pos.Round()).Add(gtx.Ops)
drag(gtx)
op.Defer(gtx.Ops, rec.Stop())
}
+2 -2
View File
@@ -724,7 +724,7 @@ func (e *Editor) PaintSelection(gtx layout.Context) {
dotStart := image.Pt(leftmost.x.Round(), leftmost.y)
dotEnd := image.Pt(rightmost.x.Round(), rightmost.y)
t := op.Offset(layout.FPt(scroll.Mul(-1))).Push(gtx.Ops)
t := op.Offset(scroll.Mul(-1)).Push(gtx.Ops)
size := image.Rectangle{
Min: dotStart.Sub(image.Point{Y: line.Ascent.Ceil()}),
Max: dotEnd.Add(image.Point{Y: line.Descent.Ceil()}),
@@ -760,7 +760,7 @@ func (e *Editor) PaintText(gtx layout.Context) {
}
l := subLayout(line, start, end)
t := op.Offset(layout.FPt(off)).Push(gtx.Ops)
t := op.Offset(off).Push(gtx.Ops)
op := clip.Outline{Path: e.shaper.Shape(e.font, e.textSize, l)}.Op().Push(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
op.Pop()
+1 -3
View File
@@ -3,8 +3,6 @@
package widget
import (
"image"
"gioui.org/gesture"
"gioui.org/io/key"
"gioui.org/io/pointer"
@@ -65,7 +63,7 @@ func (e *Enum) Layout(gtx layout.Context, k string, content layout.Widget) layou
m := op.Record(gtx.Ops)
dims := content(gtx)
c := m.Stop()
defer clip.Rect(image.Rectangle{Max: dims.Size}).Push(gtx.Ops).Pop()
defer clip.Rect{Max: dims.Size}.Push(gtx.Ops).Pop()
state := e.index(k)
if state == nil {
+1 -1
View File
@@ -119,7 +119,7 @@ func (l Label) Layout(gtx layout.Context, s text.Shaper, font text.Font, size un
lt := subLayout(line, start, end)
off := image.Point{X: start.x.Floor(), Y: start.y}
t := op.Offset(layout.FPt(off)).Push(gtx.Ops)
t := op.Offset(off).Push(gtx.Ops)
op := clip.Outline{Path: s.Shape(font, textSize, lt)}.Op().Push(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
op.Pop()
+3 -3
View File
@@ -297,9 +297,9 @@ func drawInk(gtx layout.Context, c widget.Press) {
ink := paint.ColorOp{Color: rgba}
ink.Add(gtx.Ops)
rr := size * .5
defer op.Offset(layout.FPt(c.Position).Add(f32.Point{
X: -rr,
Y: -rr,
defer op.Offset(c.Position.Add(image.Point{
X: -int(rr),
Y: -int(rr),
})).Push(gtx.Ops).Pop()
defer clip.UniformRRect(f32.Rectangle{Max: f32.Pt(size, size)}, rr).Push(gtx.Ops).Pop()
paint.PaintOp{}.Add(gtx.Ops)
+1 -1
View File
@@ -109,7 +109,7 @@ func (d *DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimensio
if size.Y < dims.Size.Y {
size.Y = dims.Size.Y
}
op.Offset(f32.Point{X: float32(dims.Size.X)}).Add(gtx.Ops)
op.Offset(image.Pt(dims.Size.X, 0)).Add(gtx.Ops)
}
return layout.Dimensions{Size: size}
}),
+1 -1
View File
@@ -193,7 +193,7 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
// Lay out the indicator.
offset := axis.Convert(image.Pt(viewStart, 0))
defer op.Offset(layout.FPt(offset)).Push(gtx.Ops).Pop()
defer op.Offset(offset).Push(gtx.Ops).Pop()
paint.FillShape(gtx.Ops, s.Indicator.Color, clip.RRect{
Rect: f32.Rectangle{
Max: indicatorDimsF,
+4 -4
View File
@@ -35,18 +35,18 @@ func (l LoaderStyle) Layout(gtx layout.Context) layout.Dimensions {
diam = gtx.Px(unit.Dp(24))
}
sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
radius := float32(sz.X) * .5
defer op.Offset(f32.Pt(radius, radius)).Push(gtx.Ops).Pop()
radius := sz.X / 2
defer op.Offset(image.Pt(radius, radius)).Push(gtx.Ops).Pop()
dt := float32((time.Duration(gtx.Now.UnixNano()) % (time.Second)).Seconds())
startAngle := dt * math.Pi * 2
endAngle := startAngle + math.Pi*1.5
defer clipLoader(gtx.Ops, startAngle, endAngle, radius).Push(gtx.Ops).Pop()
defer clipLoader(gtx.Ops, startAngle, endAngle, float32(radius)).Push(gtx.Ops).Pop()
paint.ColorOp{
Color: l.Color,
}.Add(gtx.Ops)
defer op.Offset(f32.Pt(-radius, -radius)).Push(gtx.Ops).Pop()
defer op.Offset(image.Pt(-radius, -radius)).Push(gtx.Ops).Pop()
paint.PaintOp{}.Add(gtx.Ops)
op.InvalidateOp{}.Add(gtx.Ops)
return layout.Dimensions{
+3 -4
View File
@@ -7,7 +7,6 @@ import (
"image/color"
"math"
"gioui.org/f32"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/paint"
@@ -35,10 +34,10 @@ func (p ProgressCircleStyle) Layout(gtx layout.Context) layout.Dimensions {
diam = gtx.Px(unit.Dp(24))
}
sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
radius := float32(sz.X) * .5
defer op.Offset(f32.Pt(radius, radius)).Push(gtx.Ops).Pop()
radius := sz.X / 2
defer op.Offset(image.Pt(radius, radius)).Push(gtx.Ops).Pop()
defer clipLoader(gtx.Ops, -math.Pi/2, -math.Pi/2+math.Pi*2*p.Progress, radius).Push(gtx.Ops).Pop()
defer clipLoader(gtx.Ops, -math.Pi/2, -math.Pi/2+math.Pi*2*p.Progress, float32(radius)).Push(gtx.Ops).Pop()
paint.ColorOp{
Color: p.Color,
}.Add(gtx.Ops)
+1 -1
View File
@@ -50,7 +50,7 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
size := axis.Convert(image.Pt(sizeMain, sizeCross))
o := axis.Convert(image.Pt(thumbRadius, 0))
trans := op.Offset(layout.FPt(o)).Push(gtx.Ops)
trans := op.Offset(o).Push(gtx.Ops)
gtx.Constraints.Min = axis.Convert(image.Pt(sizeMain-2*thumbRadius, sizeCross))
s.Float.Layout(gtx, thumbRadius, s.Min, s.Max)
gtx.Constraints.Min = gtx.Constraints.Min.Add(axis.Convert(image.Pt(0, sizeCross)))
+10 -10
View File
@@ -44,7 +44,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
trackWidth := gtx.Px(unit.Dp(36))
trackHeight := gtx.Px(unit.Dp(16))
thumbSize := gtx.Px(unit.Dp(20))
trackOff := float32(thumbSize-trackHeight) * .5
trackOff := (thumbSize - trackHeight) / 2
// Draw track.
trackCorner := float32(trackHeight) / 2
@@ -60,7 +60,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
col = f32color.Disabled(col)
}
trackColor := s.Color.Track
t := op.Offset(f32.Point{Y: trackOff}).Push(gtx.Ops)
t := op.Offset(image.Point{Y: trackOff}).Push(gtx.Ops)
cl := clip.UniformRRect(trackRect, trackCorner).Push(gtx.Ops)
paint.ColorOp{Color: trackColor}.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
@@ -70,9 +70,9 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
// Draw thumb ink.
inkSize := gtx.Px(unit.Dp(44))
rr := float32(inkSize) * .5
inkOff := f32.Point{
X: float32(trackWidth)*.5 - rr,
Y: -rr + float32(trackHeight)*.5 + trackOff,
inkOff := image.Point{
X: trackWidth/2 - int(rr),
Y: -int(rr) + trackHeight/2 + trackOff,
}
t = op.Offset(inkOff).Push(gtx.Ops)
gtx.Constraints.Min = image.Pt(inkSize, inkSize)
@@ -85,8 +85,8 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
// Compute thumb offset.
if s.Switch.Value {
xoff := float32(trackWidth - thumbSize)
defer op.Offset(f32.Point{X: xoff}).Push(gtx.Ops).Pop()
xoff := trackWidth - thumbSize
defer op.Offset(image.Point{X: xoff}).Push(gtx.Ops).Pop()
}
thumbRadius := float32(thumbSize) / 2
@@ -115,9 +115,9 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
// Set up click area.
clickSize := gtx.Px(unit.Dp(40))
clickOff := f32.Point{
X: thumbRadius - float32(clickSize)*.5,
Y: (float32(trackHeight)-float32(clickSize))*.5 + trackOff,
clickOff := image.Point{
X: (thumbSize - clickSize) / 2,
Y: (trackHeight-clickSize)/2 + trackOff,
}
defer op.Offset(clickOff).Push(gtx.Ops).Pop()
sz := image.Pt(clickSize, clickSize)