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