icon.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // SPDX-License-Identifier: Unlicense OR MIT
  2. package widget
  3. import (
  4. "image"
  5. "image/color"
  6. "image/draw"
  7. "gioui.org/internal/f32color"
  8. "gioui.org/layout"
  9. "gioui.org/op/clip"
  10. "gioui.org/op/paint"
  11. "gioui.org/unit"
  12. "golang.org/x/exp/shiny/iconvg"
  13. )
  14. type Icon struct {
  15. src []byte
  16. // Cached values.
  17. op paint.ImageOp
  18. imgSize int
  19. imgColor color.NRGBA
  20. }
  21. const defaultIconSize = unit.Dp(24)
  22. // NewIcon returns a new Icon from IconVG data.
  23. func NewIcon(data []byte) (*Icon, error) {
  24. _, err := iconvg.DecodeMetadata(data)
  25. if err != nil {
  26. return nil, err
  27. }
  28. return &Icon{src: data}, nil
  29. }
  30. // Layout displays the icon with its size set to the X minimum constraint.
  31. func (ic *Icon) Layout(gtx layout.Context, color color.NRGBA) layout.Dimensions {
  32. sz := gtx.Constraints.Min.X
  33. if sz == 0 {
  34. sz = gtx.Dp(defaultIconSize)
  35. }
  36. size := gtx.Constraints.Constrain(image.Pt(sz, sz))
  37. defer clip.Rect{Max: size}.Push(gtx.Ops).Pop()
  38. ico := ic.image(size.X, color)
  39. ico.Add(gtx.Ops)
  40. paint.PaintOp{}.Add(gtx.Ops)
  41. return layout.Dimensions{
  42. Size: ico.Size(),
  43. }
  44. }
  45. func (ic *Icon) image(sz int, color color.NRGBA) paint.ImageOp {
  46. if sz == ic.imgSize && color == ic.imgColor {
  47. return ic.op
  48. }
  49. m, _ := iconvg.DecodeMetadata(ic.src)
  50. dx, dy := m.ViewBox.AspectRatio()
  51. img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz, Y: int(float32(sz) * dy / dx)}})
  52. var ico iconvg.Rasterizer
  53. ico.SetDstImage(img, img.Bounds(), draw.Src)
  54. m.Palette[0] = f32color.NRGBAToLinearRGBA(color)
  55. iconvg.Decode(&ico, ic.src, &iconvg.DecodeOptions{
  56. Palette: &m.Palette,
  57. })
  58. ic.op = paint.NewImageOp(img)
  59. ic.imgSize = sz
  60. ic.imgColor = color
  61. return ic.op
  62. }