Files
prevara/icon.go

108 lines
2.6 KiB
Go

package gel
import (
"image"
"image/color"
"image/draw"
l "gioui.org/layout"
"gioui.org/op/paint"
"gioui.org/unit"
"golang.org/x/exp/shiny/iconvg"
)
type Icon struct {
*Window
color string
src *[]byte
size unit.Sp
// Cached values.
sz int
op paint.ImageOp
imgSize int
imgColor string
}
type IconByColor map[color.NRGBA]paint.ImageOp
type IconBySize map[float32]IconByColor
type IconCache map[*[]byte]IconBySize
// Icon returns a new Icon from iconVG data.
func (w *Window) Icon() *Icon {
return &Icon{Window: w, size: w.TextSize, color: "DocText"}
}
// Color sets the color of the icon image. It must be called before creating the image
func (i *Icon) Color(color string) *Icon {
i.color = color
return i
}
// Src sets the icon source to draw from.
// If data is nil or invalid, the icon will render as empty.
func (i *Icon) Src(data *[]byte) *Icon {
if data == nil {
return i
}
_, e := iconvg.DecodeMetadata(*data)
if E.Chk(e) {
D.Ln("invalid icon data, icon will not render")
return i
}
i.src = data
return i
}
// Scale changes the size relative to the base font size
func (i *Icon) Scale(scale float32) *Icon {
i.size = unit.Sp(float32(i.Theme.TextSize) * scale)
return i
}
func (i *Icon) Size(size unit.Sp) *Icon {
i.size = size
return i
}
// Fn renders the icon. Returns zero dimensions if no source is set.
func (i *Icon) Fn(gtx l.Context) l.Dimensions {
if i.src == nil {
return l.Dimensions{}
}
ico := i.image(gtx.Sp(i.size))
ico.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
return l.Dimensions{Size: ico.Size()}
}
func (i *Icon) image(sz int) paint.ImageOp {
if ico, ok := i.Theme.iconCache[i.src]; ok {
if isz, ok := ico[float32(i.size)]; ok {
if icl, ok := isz[i.Theme.Colors.GetNRGBAFromName(i.color)]; ok {
return icl
}
}
}
m, _ := iconvg.DecodeMetadata(*i.src)
dx, dy := m.ViewBox.AspectRatio()
img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz,
Y: int(float32(sz) * dy / dx)}})
var ico iconvg.Rasterizer
ico.SetDstImage(img, img.Bounds(), draw.Src)
m.Palette[0] = color.RGBA(i.Theme.Colors.GetNRGBAFromName(i.color))
if e := iconvg.Decode(&ico, *i.src, &iconvg.DecodeOptions{
Palette: &m.Palette,
}); E.Chk(e) {
}
operation := paint.NewImageOp(img)
// create the maps if they don't exist
if _, ok := i.Theme.iconCache[i.src]; !ok {
i.Theme.iconCache[i.src] = make(IconBySize)
}
if _, ok := i.Theme.iconCache[i.src][float32(i.size)]; !ok {
i.Theme.iconCache[i.src][float32(i.size)] = make(IconByColor)
}
i.Theme.iconCache[i.src][float32(i.size)][i.Theme.Colors.GetNRGBAFromName(i.color)] = operation
return operation
}