From 4f30b985eb34935ab36ef4b4817138ded15f46d7 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 9 Nov 2019 19:20:47 +0100 Subject: [PATCH] op/clip: add RoundRect Signed-off-by: Elias Naur --- op/clip/clip.go | 24 ++++++++++++++++++++++++ widget/material/button.go | 23 ++++++++++++++--------- widget/material/material.go | 19 ------------------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/op/clip/clip.go b/op/clip/clip.go index 5f64a20b..47a44470 100644 --- a/op/clip/clip.go +++ b/op/clip/clip.go @@ -289,6 +289,30 @@ func Rect(r image.Rectangle) Op { return Op{bounds: toRectF(r)} } +// RoundRect returns the clip area of a rectangle with rounded +// corners defined by their radii. 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 { + 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() +} + func toRectF(r image.Rectangle) f32.Rectangle { return f32.Rectangle{ Min: f32.Point{X: float32(r.Min.X), Y: float32(r.Min.Y)}, diff --git a/widget/material/button.go b/widget/material/button.go index ae79ca84..cb6ee089 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -10,6 +10,7 @@ import ( "gioui.org/io/pointer" "gioui.org/layout" "gioui.org/op" + "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" @@ -76,11 +77,13 @@ func (b Button) Layout(gtx *layout.Context, button *widget.Button) { }) bg := st.Expand(gtx, func() { rr := float32(gtx.Px(unit.Dp(4))) - rrect(gtx.Ops, - float32(gtx.Constraints.Width.Min), - float32(gtx.Constraints.Height.Min), + clip.RoundRect(gtx.Ops, + f32.Rectangle{Max: f32.Point{ + X: float32(gtx.Constraints.Width.Min), + Y: float32(gtx.Constraints.Height.Min), + }}, rr, rr, rr, rr, - ) + ).Add(gtx.Ops) fill(gtx, bgcol) for _, c := range button.History() { drawInk(gtx, c) @@ -109,11 +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 - rrect(gtx.Ops, - size, - size, + clip.RoundRect(gtx.Ops, + f32.Rectangle{Max: f32.Point{X: size, Y: size}}, rr, rr, rr, rr, - ) + ).Add(gtx.Ops) fill(gtx, bgcol) for _, c := range button.History() { drawInk(gtx, c) @@ -152,7 +154,10 @@ func drawInk(gtx *layout.Context, c widget.Click) { X: -rr, Y: -rr, }).Add(gtx.Ops) - rrect(gtx.Ops, float32(size), float32(size), rr, rr, rr, rr) + clip.RoundRect(gtx.Ops, f32.Rectangle{Max: f32.Point{ + X: float32(size), + Y: float32(size), + }}, rr, rr, rr, rr).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/material.go b/widget/material/material.go index d42cea18..20d1ee7c 100644 --- a/widget/material/material.go +++ b/widget/material/material.go @@ -9,8 +9,6 @@ import ( "gioui.org/f32" "gioui.org/font" "gioui.org/layout" - "gioui.org/op" - "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" @@ -75,20 +73,3 @@ func fill(gtx *layout.Context, col color.RGBA) { paint.PaintOp{Rect: dr}.Add(gtx.Ops) gtx.Dimensions = layout.Dimensions{Size: d} } - -// https://pomax.github.io/bezierinfo/#circles_cubic. -func rrect(ops *op.Ops, width, height, se, sw, nw, ne float32) { - w, h := float32(width), float32(height) - const c = 0.55228475 // 4*(sqrt(2)-1)/3 - var b clip.Path - b.Begin(ops) - b.Move(f32.Point{X: w, Y: h - se}) - b.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE - b.Line(f32.Point{X: sw - w + se, Y: 0}) - b.Cube(f32.Point{X: -sw * c, Y: 0}, f32.Point{X: -sw, Y: -sw + sw*c}, f32.Point{X: -sw, Y: -sw}) // SW - b.Line(f32.Point{X: 0, Y: nw - h + sw}) - b.Cube(f32.Point{X: 0, Y: -nw * c}, f32.Point{X: nw - nw*c, Y: -nw}, f32.Point{X: nw, Y: -nw}) // NW - b.Line(f32.Point{X: w - ne - nw, Y: 0}) - b.Cube(f32.Point{X: ne * c, Y: 0}, f32.Point{X: ne, Y: ne - ne*c}, f32.Point{X: ne, Y: ne}) // NE - b.End().Add(ops) -}