108 lines
2.6 KiB
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
|
|
}
|