From 0b736990a92e962f23d3fce1ea87215dbc51f583 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Sun, 17 Jan 2021 18:22:10 +0200 Subject: [PATCH] widget/material: add hover to CheckBox Signed-off-by: Egon Elbre --- widget/material/checkable.go | 58 +++++++++++++++++++++++++++------- widget/material/checkbox.go | 2 +- widget/material/radiobutton.go | 2 +- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/widget/material/checkable.go b/widget/material/checkable.go index 90f2103e..2c3dc838 100644 --- a/widget/material/checkable.go +++ b/widget/material/checkable.go @@ -5,10 +5,13 @@ package material import ( "image" "image/color" + "math" + "gioui.org/f32" "gioui.org/internal/f32color" "gioui.org/io/pointer" "gioui.org/layout" + "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" @@ -27,7 +30,7 @@ type checkable struct { uncheckedStateIcon *widget.Icon } -func (c *checkable) layout(gtx layout.Context, checked bool) layout.Dimensions { +func (c *checkable) layout(gtx layout.Context, checked, hovered bool) layout.Dimensions { var icon *widget.Icon if checked { icon = c.checkedStateIcon @@ -38,19 +41,39 @@ func (c *checkable) layout(gtx layout.Context, checked bool) layout.Dimensions { min := gtx.Constraints.Min dims := layout.Flex{Alignment: layout.Middle}.Layout(gtx, layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { - return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions { - size := gtx.Px(c.Size) - icon.Color = c.IconColor - if gtx.Queue == nil { - icon.Color = f32color.Disabled(icon.Color) - } - icon.Layout(gtx, unit.Px(float32(size))) - return layout.Dimensions{ + return layout.Stack{Alignment: layout.Center}.Layout(gtx, + layout.Stacked(func(gtx layout.Context) layout.Dimensions { + size := gtx.Px(c.Size) * 4 / 3 + dims := layout.Dimensions{ Size: image.Point{X: size, Y: size}, } - }) - }) + if !hovered { + return dims + } + + background := f32color.MulAlpha(c.IconColor, 70) + + var p clip.Path + p.Begin(gtx.Ops) + addCircle(&p, float32(size)/2) + paint.FillShape(gtx.Ops, background, clip.Outline{Path: p.End()}.Op()) + + return dims + }), + layout.Stacked(func(gtx layout.Context) layout.Dimensions { + return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions { + size := gtx.Px(c.Size) + icon.Color = c.IconColor + if gtx.Queue == nil { + icon.Color = f32color.Disabled(icon.Color) + } + icon.Layout(gtx, unit.Px(float32(size))) + return layout.Dimensions{ + Size: image.Point{X: size, Y: size}, + } + }) + }), + ) }), layout.Rigid(func(gtx layout.Context) layout.Dimensions { @@ -66,3 +89,14 @@ func (c *checkable) layout(gtx layout.Context, checked bool) layout.Dimensions { pointer.Rect(image.Rectangle{Max: dims.Size}).Add(gtx.Ops) return dims } + +// addCircle adds the outline of a circle to a path. +func addCircle(p *clip.Path, r float32) { + // https://pomax.github.io/bezierinfo/#circles_cubic. + const c = 4 * (math.Sqrt2 - 1) / 3 // 4*(sqrt(2)-1)/3 + p.Move(f32.Point{X: 2 * r, Y: 2*r - r}) + p.Cube(f32.Point{X: 0, Y: r * c}, f32.Point{X: -r + r*c, Y: r}, f32.Point{X: -r, Y: r}) + p.Cube(f32.Point{X: -r * c, Y: 0}, f32.Point{X: -r, Y: -r + r*c}, f32.Point{X: -r, Y: -r}) + p.Cube(f32.Point{X: 0, Y: -r * c}, f32.Point{X: r - r*c, Y: -r}, f32.Point{X: r, Y: -r}) + p.Cube(f32.Point{X: r * c, Y: 0}, f32.Point{X: r, Y: r - r*c}, f32.Point{X: r, Y: r}) +} diff --git a/widget/material/checkbox.go b/widget/material/checkbox.go index 914c208e..aac98375 100644 --- a/widget/material/checkbox.go +++ b/widget/material/checkbox.go @@ -31,7 +31,7 @@ func CheckBox(th *Theme, checkBox *widget.Bool, label string) CheckBoxStyle { // Layout updates the checkBox and displays it. func (c CheckBoxStyle) Layout(gtx layout.Context) layout.Dimensions { - dims := c.layout(gtx, c.CheckBox.Value) + dims := c.layout(gtx, c.CheckBox.Value, c.CheckBox.Hovered()) gtx.Constraints.Min = dims.Size c.CheckBox.Layout(gtx) return dims diff --git a/widget/material/radiobutton.go b/widget/material/radiobutton.go index 1546fc3a..1c4f2a88 100644 --- a/widget/material/radiobutton.go +++ b/widget/material/radiobutton.go @@ -36,7 +36,7 @@ func RadioButton(th *Theme, group *widget.Enum, key, label string) RadioButtonSt // Layout updates enum and displays the radio button. func (r RadioButtonStyle) Layout(gtx layout.Context) layout.Dimensions { - dims := r.layout(gtx, r.Group.Value == r.Key) + dims := r.layout(gtx, r.Group.Value == r.Key, false) gtx.Constraints.Min = dims.Size r.Group.Layout(gtx, r.Key) return dims