From d572aa23ac363e8048ff6d391a9a2f106f34ae6a Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 9 Jul 2020 18:06:00 +0200 Subject: [PATCH] op/clip: split Rect into pixel-aligned Rect and rounded RRect The pixel-aligned Rect is more efficient and easier to use in the common case of layout clipping. Signed-off-by: Elias Naur --- app/headless/headless_test.go | 4 +- gpu/gpu.go | 25 ++++---- internal/rendertest/bench_test.go | 8 +-- internal/rendertest/clip_test.go | 6 +- internal/rendertest/render_test.go | 4 +- internal/rendertest/transform_test.go | 14 ++--- layout/list.go | 2 +- op/clip/clip.go | 83 ++++----------------------- op/clip/shapes.go | 51 ++++++++++++++++ widget/image.go | 2 +- widget/material/button.go | 8 +-- widget/material/progressbar.go | 2 +- widget/material/slider.go | 6 +- widget/material/switch.go | 6 +- 14 files changed, 105 insertions(+), 116 deletions(-) create mode 100644 op/clip/shapes.go diff --git a/app/headless/headless_test.go b/app/headless/headless_test.go index 2630a840..7774dcd9 100644 --- a/app/headless/headless_test.go +++ b/app/headless/headless_test.go @@ -55,7 +55,7 @@ func TestClipping(t *testing.T) { Y: float32(sz.Y), }}} paint.ColorOp{Color: col}.Add(&ops) - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{ Min: f32.Point{X: 50, Y: 50}, Max: f32.Point{X: 250, Y: 250}, @@ -64,7 +64,7 @@ func TestClipping(t *testing.T) { }.Add(&ops) pop.Add(&ops) paint.ColorOp{Color: col2}.Add(&ops) - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{ Min: f32.Point{X: 100, Y: 100}, Max: f32.Point{X: 350, Y: 350}, diff --git a/gpu/gpu.go b/gpu/gpu.go index 321b2a89..5c80d087 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -116,6 +116,7 @@ type material struct { // clipOp is the shadow of clip.Op. type clipOp struct { + // TODO: Use image.Rectangle? bounds f32.Rectangle } @@ -131,18 +132,18 @@ func (op *clipOp) decode(data []byte) { panic("invalid op") } bo := binary.LittleEndian - r := f32.Rectangle{ - Min: f32.Point{ - X: math.Float32frombits(bo.Uint32(data[1:])), - Y: math.Float32frombits(bo.Uint32(data[5:])), + r := image.Rectangle{ + Min: image.Point{ + X: int(int32(bo.Uint32(data[1:]))), + Y: int(int32(bo.Uint32(data[5:]))), }, - Max: f32.Point{ - X: math.Float32frombits(bo.Uint32(data[9:])), - Y: math.Float32frombits(bo.Uint32(data[13:])), + Max: image.Point{ + X: int(int32(bo.Uint32(data[9:]))), + Y: int(int32(bo.Uint32(data[13:]))), }, } *op = clipOp{ - bounds: r, + bounds: layout.FRect(r), } } @@ -158,12 +159,12 @@ func decodeImageOp(data []byte, refs []interface{}) imageOpData { return imageOpData{ rect: image.Rectangle{ Min: image.Point{ - X: int(bo.Uint32(data[1:])), - Y: int(bo.Uint32(data[5:])), + X: int(int32(bo.Uint32(data[1:]))), + Y: int(int32(bo.Uint32(data[5:]))), }, Max: image.Point{ - X: int(bo.Uint32(data[9:])), - Y: int(bo.Uint32(data[13:])), + X: int(int32(bo.Uint32(data[9:]))), + Y: int(int32(bo.Uint32(data[13:]))), }, }, src: refs[0].(*image.RGBA), diff --git a/internal/rendertest/bench_test.go b/internal/rendertest/bench_test.go index cd5804eb..04ad167f 100644 --- a/internal/rendertest/bench_test.go +++ b/internal/rendertest/bench_test.go @@ -158,7 +158,7 @@ func draw1000Circles(gtx layout.Context) { for y := 0; y < 10; y++ { pi := op.Push(ops) paint.ColorOp{Color: color.RGBA{R: 100 + uint8(x), G: 100 + uint8(y), B: 100, A: 120}}.Add(ops) - clip.Rect{Rect: f32.Rect(0, 0, 10, 10), NE: 5, SE: 5, SW: 5, NW: 5}.Add(ops) + clip.RRect{Rect: f32.Rect(0, 0, 10, 10), NE: 5, SE: 5, SW: 5, NW: 5}.Add(ops) paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(ops) pi.Pop() op.Offset(f32.Pt(0, float32(100))).Add(ops) @@ -171,7 +171,7 @@ func draw1000CirclesInstanced(gtx layout.Context) { ops := gtx.Ops r := op.Record(ops) - clip.Rect{Rect: f32.Rect(0, 0, 10, 10), NE: 5, SE: 5, SW: 5, NW: 5}.Add(ops) + clip.RRect{Rect: f32.Rect(0, 0, 10, 10), NE: 5, SE: 5, SW: 5, NW: 5}.Add(ops) paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(ops) c := r.Stop() @@ -210,7 +210,7 @@ func drawIndividualShapes(gtx layout.Context, th *material.Theme) chan op.CallOp for y := 0; y < 9; y++ { pi := op.Push(ops) paint.ColorOp{Color: color.RGBA{R: 100 + uint8(x), G: 100 + uint8(y), B: 100, A: 120}}.Add(ops) - clip.Rect{Rect: f32.Rect(0, 0, 25, 25), NE: 10, SE: 10, SW: 10, NW: 10}.Add(ops) + clip.RRect{Rect: f32.Rect(0, 0, 25, 25), NE: 10, SE: 10, SW: 10, NW: 10}.Add(ops) paint.PaintOp{Rect: f32.Rect(0, 0, 25, 25)}.Add(ops) pi.Pop() op.Offset(f32.Pt(0, float32(50))).Add(ops) @@ -229,7 +229,7 @@ func drawShapeInstances(gtx layout.Context, th *material.Theme) chan op.CallOp { co := op.Record(ops) r := op.Record(ops) - clip.Rect{Rect: f32.Rect(0, 0, 25, 25), NE: 10, SE: 10, SW: 10, NW: 10}.Add(ops) + clip.RRect{Rect: f32.Rect(0, 0, 25, 25), NE: 10, SE: 10, SW: 10, NW: 10}.Add(ops) paint.PaintOp{Rect: f32.Rect(0, 0, 25, 25)}.Add(ops) c := r.Stop() diff --git a/internal/rendertest/clip_test.go b/internal/rendertest/clip_test.go index fa8f285f..6d205f72 100644 --- a/internal/rendertest/clip_test.go +++ b/internal/rendertest/clip_test.go @@ -25,7 +25,7 @@ func TestPaintRect(t *testing.T) { func TestPaintClippedRect(t *testing.T) { run(t, func(o *op.Ops) { paint.ColorOp{Color: colornames.Red}.Add(o) - clip.Rect{Rect: f32.Rect(25, 25, 60, 60)}.Add(o) + clip.RRect{Rect: f32.Rect(25, 25, 60, 60)}.Add(o) paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) }, func(r result) { r.expect(0, 0, colornames.White) @@ -40,7 +40,7 @@ func TestPaintClippedCirle(t *testing.T) { run(t, func(o *op.Ops) { paint.ColorOp{Color: colornames.Red}.Add(o) r := float32(10) - clip.Rect{Rect: f32.Rect(20, 20, 40, 40), SE: r, SW: r, NW: r, NE: r}.Add(o) + clip.RRect{Rect: f32.Rect(20, 20, 40, 40), SE: r, SW: r, NW: r, NE: r}.Add(o) paint.PaintOp{Rect: f32.Rect(0, 0, 30, 50)}.Add(o) }, func(r result) { r.expect(21, 21, colornames.White) @@ -64,7 +64,7 @@ func TestPaintTexture(t *testing.T) { func TestPaintClippedTexture(t *testing.T) { run(t, func(o *op.Ops) { squares.Add(o) - clip.Rect{Rect: f32.Rect(0, 0, 40, 40)}.Add(o) + clip.RRect{Rect: f32.Rect(0, 0, 40, 40)}.Add(o) paint.PaintOp{Rect: f32.Rect(0, 0, 80, 80)}.Add(o) }, func(r result) { r.expect(40, 40, colornames.White) diff --git a/internal/rendertest/render_test.go b/internal/rendertest/render_test.go index 1078f492..ca11230b 100644 --- a/internal/rendertest/render_test.go +++ b/internal/rendertest/render_test.go @@ -118,7 +118,7 @@ func constSqPath() op.CallOp { func constSqCirc() op.CallOp { innerOps := new(op.Ops) m := op.Record(innerOps) - clip.Rect{Rect: f32.Rect(0, 0, 40, 40), + clip.RRect{Rect: f32.Rect(0, 0, 40, 40), NW: 20, NE: 20, SW: 20, SE: 20}.Add(innerOps) return m.Stop() } @@ -185,7 +185,7 @@ func TestBuildOffscreen(t *testing.T) { func TestNegativeOverlaps(t *testing.T) { run(t, func(ops *op.Ops) { - clip.Rect{Rect: f32.Rect(50, 50, 100, 100)}.Add(ops) + clip.RRect{Rect: f32.Rect(50, 50, 100, 100)}.Add(ops) paint.PaintOp{Rect: f32.Rect(0, 120, 100, 122)}.Add(ops) }, func(r result) { r.expect(60, 60, colornames.White) diff --git a/internal/rendertest/transform_test.go b/internal/rendertest/transform_test.go index ed7a1d2f..67a6f0a6 100644 --- a/internal/rendertest/transform_test.go +++ b/internal/rendertest/transform_test.go @@ -52,7 +52,7 @@ func TestPaintShear(t *testing.T) { func TestClipPaintOffset(t *testing.T) { run(t, func(o *op.Ops) { paint.ColorOp{Color: colornames.Red}.Add(o) - clip.Rect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) + clip.RRect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) op.Offset(f32.Pt(20, 20)).Add(o) paint.PaintOp{Rect: f32.Rect(0, 0, 100, 100)}.Add(o) }, func(r result) { @@ -67,7 +67,7 @@ func TestClipOffset(t *testing.T) { run(t, func(o *op.Ops) { paint.ColorOp{Color: colornames.Red}.Add(o) op.Offset(f32.Pt(20, 20)).Add(o) - clip.Rect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) + clip.RRect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) paint.PaintOp{Rect: f32.Rect(0, 0, 100, 100)}.Add(o) }, func(r result) { r.expect(0, 0, colornames.White) @@ -83,7 +83,7 @@ func TestClipScale(t *testing.T) { paint.ColorOp{Color: colornames.Red}.Add(o) a := f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(2, 2)).Offset(f32.Pt(10, 10)) op.Affine(a).Add(o) - clip.Rect{Rect: f32.Rect(10, 10, 20, 20)}.Add(o) + clip.RRect{Rect: f32.Rect(10, 10, 20, 20)}.Add(o) paint.PaintOp{Rect: f32.Rect(0, 0, 1000, 1000)}.Add(o) }, func(r result) { r.expect(19+10, 19+10, colornames.White) @@ -97,7 +97,7 @@ func TestClipRotate(t *testing.T) { run(t, func(o *op.Ops) { paint.ColorOp{Color: colornames.Red}.Add(o) op.Affine(f32.Affine2D{}.Rotate(f32.Pt(40, 40), -math.Pi/4)).Add(o) - clip.Rect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) + clip.RRect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) paint.PaintOp{Rect: f32.Rect(0, 40, 100, 100)}.Add(o) }, func(r result) { r.expect(39, 39, colornames.White) @@ -148,7 +148,7 @@ func TestRotateClipTexture(t *testing.T) { squares.Add(o) a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), math.Pi/8) op.Affine(a).Add(o) - clip.Rect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) + clip.RRect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) paint.PaintOp{Rect: f32.Rect(10, 10, 70, 70)}.Add(o) }, func(r result) { r.expect(0, 0, colornames.White) @@ -164,11 +164,11 @@ func TestComplicatedTransform(t *testing.T) { run(t, func(o *op.Ops) { squares.Add(o) - clip.Rect{Rect: f32.Rect(0, 0, 100, 100), SE: 50, SW: 50, NW: 50, NE: 50}.Add(o) + clip.RRect{Rect: f32.Rect(0, 0, 100, 100), SE: 50, SW: 50, NW: 50, NE: 50}.Add(o) a := f32.Affine2D{}.Shear(f32.Point{}, math.Pi/4, 0) op.Affine(a).Add(o) - clip.Rect{Rect: f32.Rect(0, 0, 50, 40)}.Add(o) + clip.RRect{Rect: f32.Rect(0, 0, 50, 40)}.Add(o) op.Offset(f32.Pt(-100, -100)).Add(o) paint.PaintOp{Rect: f32.Rect(100, 100, 150, 150)}.Add(o) diff --git a/layout/list.go b/layout/list.go index ebc7f2ee..dad83cf9 100644 --- a/layout/list.go +++ b/layout/list.go @@ -258,7 +258,7 @@ func (l *List) layout() Dimensions { Max: axisPoint(l.Axis, max, inf), } stack := op.Push(ops) - clip.Rect{Rect: FRect(r)}.Add(ops) + clip.Rect(r).Add(ops) op.Offset(FPt(axisPoint(l.Axis, pos, cross))).Add(ops) child.call.Add(ops) stack.Pop() diff --git a/op/clip/clip.go b/op/clip/clip.go index f77d45d7..9f6ced4b 100644 --- a/op/clip/clip.go +++ b/op/clip/clip.go @@ -5,7 +5,6 @@ package clip import ( "encoding/binary" "image" - "math" "gioui.org/f32" "gioui.org/internal/opconst" @@ -35,7 +34,7 @@ type Path struct { // applying a Op, use op.StackOp. type Op struct { call op.CallOp - bounds f32.Rectangle + bounds image.Rectangle } func (p Op) Add(o *op.Ops) { @@ -43,10 +42,10 @@ func (p Op) Add(o *op.Ops) { data := o.Write(opconst.TypeClipLen) data[0] = byte(opconst.TypeClip) bo := binary.LittleEndian - bo.PutUint32(data[1:], math.Float32bits(p.bounds.Min.X)) - bo.PutUint32(data[5:], math.Float32bits(p.bounds.Min.Y)) - bo.PutUint32(data[9:], math.Float32bits(p.bounds.Max.X)) - bo.PutUint32(data[13:], math.Float32bits(p.bounds.Max.Y)) + bo.PutUint32(data[1:], uint32(p.bounds.Min.X)) + bo.PutUint32(data[5:], uint32(p.bounds.Min.Y)) + bo.PutUint32(data[9:], uint32(p.bounds.Max.X)) + bo.PutUint32(data[13:], uint32(p.bounds.Max.Y)) } // Begin the path, storing the path data and final Op into ops. @@ -192,72 +191,10 @@ func (p *Path) End() Op { } } -// Rect represents the clip area of a rectangle with rounded -// corners. -// -// Specify a square with corner radii equal to half the square size to -// construct a circular clip area. -type Rect struct { - Rect f32.Rectangle - // The corner radii. - SE, SW, NW, NE float32 -} +// Rect represents the clip area of a pixel-aligned rectangle. +type Rect image.Rectangle -// op returns the op for the rectangle. -func (rr Rect) op(ops *op.Ops) Op { - r := rr.Rect - // Optimize for the common pixel aligned rectangle with no - // corner rounding. - if rr.SE == 0 && rr.SW == 0 && rr.NW == 0 && rr.NE == 0 { - ri := image.Rectangle{ - Min: image.Point{X: int(r.Min.X), Y: int(r.Min.Y)}, - Max: image.Point{X: int(r.Max.X), Y: int(r.Max.Y)}, - } - // Optimize pixel-aligned rectangles to just its bounds. - if r == fRect(ri) { - return Op{bounds: r} - } - } - return roundRect(ops, r, rr.SE, rr.SW, rr.NW, rr.NE) -} - -// Add the rectangle clip operation. -func (rr Rect) Add(ops *op.Ops) { - rr.op(ops).Add(ops) -} - -// roundRect returns the clip area of a rectangle with rounded -// corners defined by their radii. -func roundRect(ops *op.Ops, r f32.Rectangle, se, sw, nw, ne float32) Op { - size := r.Size() - // https://pomax.github.io/bezierinfo/#circles_cubic. - w, h := float32(size.X), float32(size.Y) - const c = 0.55228475 // 4*(sqrt(2)-1)/3 - var p Path - p.Begin(ops) - p.Move(r.Min) - - p.Move(f32.Point{X: w, Y: h - se}) - p.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE - p.Line(f32.Point{X: sw - w + se, Y: 0}) - p.Cube(f32.Point{X: -sw * c, Y: 0}, f32.Point{X: -sw, Y: -sw + sw*c}, f32.Point{X: -sw, Y: -sw}) // SW - p.Line(f32.Point{X: 0, Y: nw - h + sw}) - p.Cube(f32.Point{X: 0, Y: -nw * c}, f32.Point{X: nw - nw*c, Y: -nw}, f32.Point{X: nw, Y: -nw}) // NW - p.Line(f32.Point{X: w - ne - nw, Y: 0}) - p.Cube(f32.Point{X: ne * c, Y: 0}, f32.Point{X: ne, Y: ne - ne*c}, f32.Point{X: ne, Y: ne}) // NE - return p.End() -} - -// fRect converts a rectangle to a f32.Rectangle. -func fRect(r image.Rectangle) f32.Rectangle { - return f32.Rectangle{ - Min: fPt(r.Min), Max: fPt(r.Max), - } -} - -// fPt converts an point to a f32.Point. -func fPt(p image.Point) f32.Point { - return f32.Point{ - X: float32(p.X), Y: float32(p.Y), - } +// Add the clip operation. +func (r Rect) Add(ops *op.Ops) { + Op{bounds: image.Rectangle(r)}.Add(ops) } diff --git a/op/clip/shapes.go b/op/clip/shapes.go new file mode 100644 index 00000000..bde80e17 --- /dev/null +++ b/op/clip/shapes.go @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package clip + +import ( + "gioui.org/f32" + "gioui.org/op" +) + +// RRect represents the clip area of a rectangle with rounded +// corners. +// +// Specify a square with corner radii equal to half the square size to +// construct a circular clip area. +type RRect struct { + Rect f32.Rectangle + // The corner radii. + SE, SW, NW, NE float32 +} + +// op returns the op for the rectangle. +func (rr RRect) op(ops *op.Ops) Op { + return roundRect(ops, rr.Rect, rr.SE, rr.SW, rr.NW, rr.NE) +} + +// Add the rectangle clip. +func (rr RRect) Add(ops *op.Ops) { + rr.op(ops).Add(ops) +} + +// roundRect returns the clip area of a rectangle with rounded +// corners defined by their radii. +func roundRect(ops *op.Ops, r f32.Rectangle, se, sw, nw, ne float32) Op { + size := r.Size() + // https://pomax.github.io/bezierinfo/#circles_cubic. + w, h := float32(size.X), float32(size.Y) + const c = 0.55228475 // 4*(sqrt(2)-1)/3 + var p Path + p.Begin(ops) + p.Move(r.Min) + + p.Move(f32.Point{X: w, Y: h - se}) + p.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE + p.Line(f32.Point{X: sw - w + se, Y: 0}) + p.Cube(f32.Point{X: -sw * c, Y: 0}, f32.Point{X: -sw, Y: -sw + sw*c}, f32.Point{X: -sw, Y: -sw}) // SW + p.Line(f32.Point{X: 0, Y: nw - h + sw}) + p.Cube(f32.Point{X: 0, Y: -nw * c}, f32.Point{X: nw - nw*c, Y: -nw}, f32.Point{X: nw, Y: -nw}) // NW + p.Line(f32.Point{X: w - ne - nw, Y: 0}) + p.Cube(f32.Point{X: ne * c, Y: 0}, f32.Point{X: ne, Y: ne - ne*c}, f32.Point{X: ne, Y: ne}) // NE + return p.End() +} diff --git a/widget/image.go b/widget/image.go index 979be90d..c951235f 100644 --- a/widget/image.go +++ b/widget/image.go @@ -34,7 +34,7 @@ func (im Image) Layout(gtx layout.Context) layout.Dimensions { cs := gtx.Constraints d := cs.Constrain(image.Pt(w, h)) stack := op.Push(gtx.Ops) - clip.Rect{Rect: f32.Rectangle{Max: layout.FPt(d)}}.Add(gtx.Ops) + clip.Rect(image.Rectangle{Max: d}).Add(gtx.Ops) im.Src.Add(gtx.Ops) paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(w), Y: float32(h)}}}.Add(gtx.Ops) stack.Pop() diff --git a/widget/material/button.go b/widget/material/button.go index c70a2848..5d187c88 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -89,7 +89,7 @@ func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) la return layout.Stack{}.Layout(gtx, layout.Expanded(button.Layout), layout.Expanded(func(gtx layout.Context) layout.Dimensions { - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{Max: f32.Point{ X: float32(gtx.Constraints.Min.X), Y: float32(gtx.Constraints.Min.Y), @@ -122,7 +122,7 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di return layout.Stack{Alignment: layout.Center}.Layout(gtx, layout.Expanded(func(gtx layout.Context) layout.Dimensions { rr := float32(gtx.Px(b.CornerRadius)) - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{Max: f32.Point{ X: float32(gtx.Constraints.Min.X), Y: float32(gtx.Constraints.Min.Y), @@ -153,7 +153,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions { size := gtx.Constraints.Min.X sizef := float32(size) rr := sizef * .5 - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{Max: f32.Point{X: sizef, Y: sizef}}, NE: rr, NW: rr, SE: rr, SW: rr, }.Add(gtx.Ops) @@ -282,7 +282,7 @@ func drawInk(gtx layout.Context, c widget.Press) { X: -rr, Y: -rr, })).Add(gtx.Ops) - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{Max: f32.Point{ X: float32(size), Y: float32(size), diff --git a/widget/material/progressbar.go b/widget/material/progressbar.go index d5d519c0..ca2af8f8 100644 --- a/widget/material/progressbar.go +++ b/widget/material/progressbar.go @@ -35,7 +35,7 @@ func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions { Max: f32.Point{X: float32(d.X), Y: float32(d.Y)}, } - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{Max: f32.Point{X: width, Y: float32(gtx.Px(maxHeight))}}, NE: rr, NW: rr, SE: rr, SW: rr, }.Add(gtx.Ops) diff --git a/widget/material/slider.go b/widget/material/slider.go index 0f49b308..0e788f5b 100644 --- a/widget/material/slider.go +++ b/widget/material/slider.go @@ -70,7 +70,7 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { Y: halfWidth + trackWidth/2, }, } - clip.Rect{Rect: track}.Add(gtx.Ops) + clip.RRect{Rect: track}.Add(gtx.Ops) paint.ColorOp{Color: color}.Add(gtx.Ops) paint.PaintOp{Rect: track}.Add(gtx.Ops) st.Pop() @@ -79,7 +79,7 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { st = op.Push(gtx.Ops) track.Min.X = thumbPos track.Max.X = float32(size.X) - halfWidth - clip.Rect{Rect: track}.Add(gtx.Ops) + clip.RRect{Rect: track}.Add(gtx.Ops) paint.ColorOp{Color: mulAlpha(color, 96)}.Add(gtx.Ops) paint.PaintOp{Rect: track}.Add(gtx.Ops) st.Pop() @@ -97,7 +97,7 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { }, } rr := thumbRadius - clip.Rect{ + clip.RRect{ Rect: thumb, NE: rr, NW: rr, SE: rr, SW: rr, }.Add(gtx.Ops) diff --git a/widget/material/switch.go b/widget/material/switch.go index 9172b99d..4f7cd54d 100644 --- a/widget/material/switch.go +++ b/widget/material/switch.go @@ -56,7 +56,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions { } trackColor := mulAlpha(col, 150) op.Offset(f32.Point{Y: trackOff}).Add(gtx.Ops) - clip.Rect{ + clip.RRect{ Rect: trackRect, NE: trackCorner, NW: trackCorner, SE: trackCorner, SW: trackCorner, }.Add(gtx.Ops) @@ -74,7 +74,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions { } op.Offset(inkOff).Add(gtx.Ops) gtx.Constraints.Min = image.Pt(inkSize, inkSize) - clip.Rect{ + clip.RRect{ Rect: f32.Rectangle{ Max: layout.FPt(gtx.Constraints.Min), }, @@ -127,7 +127,7 @@ func drawDisc(ops *op.Ops, sz float32, col color.RGBA) { defer op.Push(ops).Pop() rr := sz / 2 r := f32.Rectangle{Max: f32.Point{X: sz, Y: sz}} - clip.Rect{ + clip.RRect{ Rect: r, NE: rr, NW: rr, SE: rr, SW: rr, }.Add(ops)