diff --git a/layout/list.go b/layout/list.go index 97329f6c..4f7624d7 100644 --- a/layout/list.go +++ b/layout/list.go @@ -249,7 +249,7 @@ func (l *List) layout() Dimensions { } var stack op.StackOp stack.Push(ops) - clip.Rect(ops, toRectF(r)).Add(ops) + clip.Rect{Rect: toRectF(r)}.Op(ops).Add(ops) op.TransformOp{}.Offset(toPointF(axisPoint(l.Axis, pos, cross))).Add(ops) child.macro.Add(ops) stack.Pop() diff --git a/op/clip/clip.go b/op/clip/clip.go index 68e28bb4..f0d40655 100644 --- a/op/clip/clip.go +++ b/op/clip/clip.go @@ -284,25 +284,38 @@ func (p *Path) End() Op { } } -// Rect returns the clip area of a rectangle. -func Rect(ops *op.Ops, r f32.Rectangle) Op { - 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 == toRectF(ri) { - return Op{bounds: r} - } - return RoundRect(ops, r, 0, 0, 0, 0) -} - -// RoundRect returns the clip area of a rectangle with rounded -// corners defined by their radii. The origin is in the upper left +// Rect represents the clip area of a rectangle with rounded +// corners.The origin is in the upper left // corner. // Specify a square with corner radii equal to half the square size to // construct a circular clip area. -func RoundRect(ops *op.Ops, r f32.Rectangle, se, sw, nw, ne float32) Op { +type Rect struct { + Rect f32.Rectangle + // The corner radii. + SE, SW, NW, NE float32 +} + +// 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 == toRectF(ri) { + return Op{bounds: r} + } + } + return roundRect(ops, r, rr.SE, rr.SW, rr.NW, rr.NE) +} + +// 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) diff --git a/widget/material/button.go b/widget/material/button.go index cb6ee089..7f615ff6 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -77,13 +77,13 @@ func (b Button) Layout(gtx *layout.Context, button *widget.Button) { }) bg := st.Expand(gtx, func() { rr := float32(gtx.Px(unit.Dp(4))) - clip.RoundRect(gtx.Ops, - f32.Rectangle{Max: f32.Point{ + clip.Rect{ + Rect: f32.Rectangle{Max: f32.Point{ X: float32(gtx.Constraints.Width.Min), Y: float32(gtx.Constraints.Height.Min), }}, - rr, rr, rr, rr, - ).Add(gtx.Ops) + NE: rr, NW: rr, SE: rr, SW: rr, + }.Op(gtx.Ops).Add(gtx.Ops) fill(gtx, bgcol) for _, c := range button.History() { drawInk(gtx, c) @@ -112,10 +112,10 @@ func (b IconButton) Layout(gtx *layout.Context, button *widget.Button) { bg := st.Expand(gtx, func() { size := float32(gtx.Constraints.Width.Min) rr := float32(size) * .5 - clip.RoundRect(gtx.Ops, - f32.Rectangle{Max: f32.Point{X: size, Y: size}}, - rr, rr, rr, rr, - ).Add(gtx.Ops) + clip.Rect{ + Rect: f32.Rectangle{Max: f32.Point{X: size, Y: size}}, + NE: rr, NW: rr, SE: rr, SW: rr, + }.Op(gtx.Ops).Add(gtx.Ops) fill(gtx, bgcol) for _, c := range button.History() { drawInk(gtx, c) @@ -154,10 +154,13 @@ func drawInk(gtx *layout.Context, c widget.Click) { X: -rr, Y: -rr, }).Add(gtx.Ops) - clip.RoundRect(gtx.Ops, f32.Rectangle{Max: f32.Point{ - X: float32(size), - Y: float32(size), - }}, rr, rr, rr, rr).Add(gtx.Ops) + clip.Rect{ + Rect: f32.Rectangle{Max: f32.Point{ + X: float32(size), + Y: float32(size), + }}, + NE: rr, NW: rr, SE: rr, SW: rr, + }.Op(gtx.Ops).Add(gtx.Ops) paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(size), Y: float32(size)}}}.Add(gtx.Ops) stack.Pop() op.InvalidateOp{}.Add(gtx.Ops) diff --git a/widget/material/image.go b/widget/material/image.go index 6a4c2bef..7b5bd56e 100644 --- a/widget/material/image.go +++ b/widget/material/image.go @@ -37,7 +37,7 @@ func (im Image) Layout(gtx *layout.Context) { d := image.Point{X: cs.Width.Constrain(w), Y: cs.Height.Constrain(h)} var s op.StackOp s.Push(gtx.Ops) - clip.Rect(gtx.Ops, f32.Rectangle{Max: toPointF(d)}).Add(gtx.Ops) + clip.Rect{Rect: f32.Rectangle{Max: toPointF(d)}}.Op(gtx.Ops).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) s.Pop()