icon.go raw
1 package gel
2
3 import (
4 "image"
5 "image/color"
6 "image/draw"
7
8 l "github.com/p9c/gio/layout"
9 "github.com/p9c/gio/op/paint"
10 "github.com/p9c/gio/unit"
11 "golang.org/x/exp/shiny/iconvg"
12 )
13
14 type Icon struct {
15 *Window
16 color string
17 src *[]byte
18 size unit.Value
19 // Cached values.
20 sz int
21 op paint.ImageOp
22 imgSize int
23 imgColor string
24 }
25
26 type IconByColor map[color.NRGBA]paint.ImageOp
27 type IconBySize map[float32]IconByColor
28 type IconCache map[*[]byte]IconBySize
29
30 // Icon returns a new Icon from iconVG data.
31 func (w *Window) Icon() *Icon {
32 return &Icon{Window: w, size: w.TextSize, color: "DocText"}
33 }
34
35 // Color sets the color of the icon image. It must be called before creating the image
36 func (i *Icon) Color(color string) *Icon {
37 i.color = color
38 return i
39 }
40
41 // Src sets the icon source to draw from
42 func (i *Icon) Src(data *[]byte) *Icon {
43 _, e := iconvg.DecodeMetadata(*data)
44 if E.Chk(e) {
45 D.Ln("no image data, crashing")
46 panic(e)
47 // return nil
48 }
49 i.src = data
50 return i
51 }
52
53 // Scale changes the size relative to the base font size
54 func (i *Icon) Scale(scale float32) *Icon {
55 i.size = i.Theme.TextSize.Scale(scale)
56 return i
57 }
58
59 func (i *Icon) Size(size unit.Value) *Icon {
60 i.size = size
61 return i
62 }
63
64 // Fn renders the icon
65 func (i *Icon) Fn(gtx l.Context) l.Dimensions {
66 ico := i.image(gtx.Px(i.size))
67 if i.src == nil {
68 panic("icon is nil")
69 }
70 ico.Add(gtx.Ops)
71 paint.PaintOp{
72 // Rect: f32.Rectangle{
73 // Max: Fpt(ico.Size()),
74 // },
75 }.Add(gtx.Ops)
76 return l.Dimensions{Size: ico.Size()}
77 }
78
79 func (i *Icon) image(sz int) paint.ImageOp {
80 // if sz == i.imgSize && i.color == i.imgColor {
81 // // D.Ln("reusing old icon")
82 // return i.op
83 // }
84 if ico, ok := i.Theme.iconCache[i.src]; ok {
85 if isz, ok := ico[i.size.V]; ok {
86 if icl, ok := isz[i.Theme.Colors.GetNRGBAFromName(i.color)]; ok {
87 return icl
88 }
89 }
90 }
91 m, _ := iconvg.DecodeMetadata(*i.src)
92 dx, dy := m.ViewBox.AspectRatio()
93 img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz,
94 Y: int(float32(sz) * dy / dx)}})
95 var ico iconvg.Rasterizer
96 ico.SetDstImage(img, img.Bounds(), draw.Src)
97 m.Palette[0] = color.RGBA(i.Theme.Colors.GetNRGBAFromName(i.color))
98 if e := iconvg.Decode(&ico, *i.src, &iconvg.DecodeOptions{
99 Palette: &m.Palette,
100 }); E.Chk(e) {
101 }
102 operation := paint.NewImageOp(img)
103 // create the maps if they don't exist
104 if _, ok := i.Theme.iconCache[i.src]; !ok {
105 i.Theme.iconCache[i.src] = make(IconBySize)
106 }
107 if _, ok := i.Theme.iconCache[i.src][i.size.V]; !ok {
108 i.Theme.iconCache[i.src][i.size.V] = make(IconByColor)
109 }
110 i.Theme.iconCache[i.src][i.size.V][i.Theme.Colors.GetNRGBAFromName(i.color)] = operation
111 return operation
112 }
113