checkable.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  package material
   4  
   5  import (
   6  	"image"
   7  	"image/color"
   8  
   9  	"github.com/p9c/p9/pkg/gel/gio/f32"
  10  	"github.com/p9c/p9/pkg/gel/gio/internal/f32color"
  11  	"github.com/p9c/p9/pkg/gel/gio/io/pointer"
  12  	"github.com/p9c/p9/pkg/gel/gio/layout"
  13  	"github.com/p9c/p9/pkg/gel/gio/op/clip"
  14  	"github.com/p9c/p9/pkg/gel/gio/op/paint"
  15  	"github.com/p9c/p9/pkg/gel/gio/text"
  16  	"github.com/p9c/p9/pkg/gel/gio/unit"
  17  	"github.com/p9c/p9/pkg/gel/gio/widget"
  18  )
  19  
  20  type checkable struct {
  21  	Label              string
  22  	Color              color.NRGBA
  23  	Font               text.Font
  24  	TextSize           unit.Value
  25  	IconColor          color.NRGBA
  26  	Size               unit.Value
  27  	shaper             text.Shaper
  28  	checkedStateIcon   *widget.Icon
  29  	uncheckedStateIcon *widget.Icon
  30  }
  31  
  32  func (c *checkable) layout(gtx layout.Context, checked, hovered bool) layout.Dimensions {
  33  	var icon *widget.Icon
  34  	if checked {
  35  		icon = c.checkedStateIcon
  36  	} else {
  37  		icon = c.uncheckedStateIcon
  38  	}
  39  
  40  	dims := layout.Flex{Alignment: layout.Middle}.Layout(gtx,
  41  		layout.Rigid(func(gtx layout.Context) layout.Dimensions {
  42  			return layout.Stack{Alignment: layout.Center}.Layout(gtx,
  43  				layout.Stacked(func(gtx layout.Context) layout.Dimensions {
  44  					size := gtx.Px(c.Size) * 4 / 3
  45  					dims := layout.Dimensions{
  46  						Size: image.Point{X: size, Y: size},
  47  					}
  48  					if !hovered {
  49  						return dims
  50  					}
  51  
  52  					background := f32color.MulAlpha(c.IconColor, 70)
  53  
  54  					radius := float32(size) / 2
  55  					paint.FillShape(gtx.Ops, background,
  56  						clip.Circle{
  57  							Center: f32.Point{X: radius, Y: radius},
  58  							Radius: radius,
  59  						}.Op(gtx.Ops))
  60  
  61  					return dims
  62  				}),
  63  				layout.Stacked(func(gtx layout.Context) layout.Dimensions {
  64  					return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
  65  						size := gtx.Px(c.Size)
  66  						icon.Color = c.IconColor
  67  						if gtx.Queue == nil {
  68  							icon.Color = f32color.Disabled(icon.Color)
  69  						}
  70  						icon.Layout(gtx, unit.Px(float32(size)))
  71  						return layout.Dimensions{
  72  							Size: image.Point{X: size, Y: size},
  73  						}
  74  					})
  75  				}),
  76  			)
  77  		}),
  78  
  79  		layout.Rigid(func(gtx layout.Context) layout.Dimensions {
  80  			return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
  81  				paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
  82  				return widget.Label{}.Layout(gtx, c.shaper, c.Font, c.TextSize, c.Label)
  83  			})
  84  		}),
  85  	)
  86  	pointer.Rect(image.Rectangle{Max: dims.Size}).Add(gtx.Ops)
  87  	return dims
  88  }
  89