icon.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  package widget
   4  
   5  import (
   6  	"image"
   7  	"image/color"
   8  	"image/draw"
   9  
  10  	"golang.org/x/exp/shiny/iconvg"
  11  
  12  	"github.com/p9c/p9/pkg/gel/gio/internal/f32color"
  13  	"github.com/p9c/p9/pkg/gel/gio/layout"
  14  	"github.com/p9c/p9/pkg/gel/gio/op/paint"
  15  	"github.com/p9c/p9/pkg/gel/gio/unit"
  16  )
  17  
  18  type Icon struct {
  19  	Color color.NRGBA
  20  	src   []byte
  21  	// Cached values.
  22  	op       paint.ImageOp
  23  	imgSize  int
  24  	imgColor color.NRGBA
  25  }
  26  
  27  // NewIcon returns a new Icon from IconVG data.
  28  func NewIcon(data []byte) (*Icon, error) {
  29  	_, err := iconvg.DecodeMetadata(data)
  30  	if err != nil {
  31  		return nil, err
  32  	}
  33  	return &Icon{src: data, Color: color.NRGBA{A: 0xff}}, nil
  34  }
  35  
  36  func (ic *Icon) Layout(gtx layout.Context, sz unit.Value) layout.Dimensions {
  37  	ico := ic.image(gtx.Px(sz))
  38  	ico.Add(gtx.Ops)
  39  	paint.PaintOp{}.Add(gtx.Ops)
  40  	return layout.Dimensions{
  41  		Size: ico.Size(),
  42  	}
  43  }
  44  
  45  func (ic *Icon) image(sz int) paint.ImageOp {
  46  	if sz == ic.imgSize && ic.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(ic.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 = ic.Color
  61  	return ic.op
  62  }
  63