fyne-widgets/pkg/profilebtn/profilebtn.go

218 lines
5.0 KiB
Go

package profilebtn
import (
"bytes"
"image"
"image/color"
"image/draw"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
var _ fyne.Focusable = (*ProfileBtn)(nil)
type ProfileBtn struct {
widget.DisableableWidget
OutlineWidth int
OutlineColor color.Color
profileImage image.Image
minSizeOverridden bool
minSizeRequested fyne.Size
disabled bool
OnTapped func() `json:"-"`
}
// FocusGained is a hook called by the focus handling logic after this object gained the focus.
func (b *ProfileBtn) FocusGained() {
// b.focused = true
b.Refresh()
}
// FocusLost is a hook called by the focus handling logic after this object lost the focus.
func (b *ProfileBtn) FocusLost() {
// b.focused = false
b.Refresh()
}
// TypedRune is a hook called by the input handling logic on text input events if this object is focused.
func (b *ProfileBtn) TypedRune(rune) {
}
// TypedKey is a hook called by the input handling logic on key events if this object is focused.
func (b *ProfileBtn) TypedKey(ev *fyne.KeyEvent) {
if ev.Name == fyne.KeySpace {
b.Tapped(nil)
}
}
func (b *ProfileBtn) Resize(s fyne.Size) {
b.BaseWidget.Resize(s)
}
func (b *ProfileBtn) Disable() {
b.disabled = true
}
func (b *ProfileBtn) Ensable() {
b.disabled = false
}
func (b *ProfileBtn) Disabled() bool {
return b.disabled
}
func (b *ProfileBtn) Tapped(*fyne.PointEvent) {
if b.Disabled() {
return
}
//b.tapAnimation()
b.Refresh()
if b.OnTapped != nil {
b.OnTapped()
}
}
func (b *ProfileBtn) CreateRenderer() fyne.WidgetRenderer {
return NewProfileBtnRenderer(b)
}
func NewProfileBtnRenderer(b *ProfileBtn) *profileBtnRenderer {
r := &profileBtnRenderer{
canvas.NewRasterFromImage(image.NewRGBA(image.Rect(0, 0, 10, 10))),
b,
}
b.ExtendBaseWidget(b)
return r
}
func NewProfileBtn() *ProfileBtn {
w := &ProfileBtn{}
w.ExtendBaseWidget(w)
w.OutlineWidth = 0
w.OutlineColor = color.White
w.SetProfileResource(nil)
w.minSizeOverridden = false
w.disabled = false
return w
}
func (b *ProfileBtn) SetProfileResource(r fyne.Resource) {
if r != nil {
i, _, err := image.Decode(bytes.NewReader(r.Content()))
if err == nil {
b.profileImage = i
return
}
}
t, _, _ := image.Decode(bytes.NewReader(resourceProfileBtnPng.StaticContent))
b.profileImage = t
}
func (b *ProfileBtn) SetMinSize(s fyne.Size) {
if s.Height > 0 && s.Width > 0 {
b.minSizeRequested = s
b.minSizeOverridden = true
return
}
b.minSizeOverridden = false
}
func (b *ProfileBtn) SetProfileImage(i image.Image) {
b.profileImage = i
}
type profileBtnRenderer struct {
rast *canvas.Raster
w *ProfileBtn
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func minf(x, y float32) float32 {
if x < y {
return x
}
return y
}
func (r *profileBtnRenderer) Render(w, h int) image.Image {
i := image.NewRGBA(image.Rect(0, 0, w, h))
if r.w.profileImage != nil {
src := r.w.profileImage
// convert src to srcRGBA
srcb := src.Bounds()
srcRGBA := image.NewRGBA(image.Rect(0, 0, srcb.Dx(), srcb.Dy()))
draw.Draw(srcRGBA, srcRGBA.Bounds(), src, srcb.Min, draw.Src)
b := src.Bounds().Size()
wh := image.NewUniform(r.w.OutlineColor)
dst := image.NewRGBA(image.Rect(0, 0, b.X, b.Y))
draw.DrawMask(dst, dst.Bounds(), wh, image.ZP, &circle{image.Point{b.X / 2, b.Y / 2}, (min(b.Y, b.Y) / 2)}, image.ZP, draw.Over)
if r.w.Disabled() {
for x := 0; x < srcRGBA.Bounds().Dx(); x++ {
for y := 0; y < srcRGBA.Bounds().Dx(); y++ {
c := srcRGBA.RGBA64At(x, y)
avg := (c.R / 3) + (c.G / 3) + (c.B / 3)
c = color.RGBA64{avg, avg, avg, c.A}
srcRGBA.SetRGBA64(x, y, c)
}
}
}
draw.DrawMask(dst, dst.Bounds(), srcRGBA, image.ZP, &circle{image.Point{b.X / 2, b.Y / 2}, (min(b.Y, b.Y) / 2) - r.w.OutlineWidth}, image.ZP, draw.Over)
return dst
} else {
return i
}
}
func (r *profileBtnRenderer) MinSize() fyne.Size {
if r.w.minSizeOverridden {
return r.w.minSizeRequested
}
return fyne.NewSize(theme.Padding()*4, theme.Padding()*4)
}
func (r *profileBtnRenderer) Layout(size fyne.Size) {
squareSize := fyne.NewSize(minf(size.Width, size.Height), minf(size.Width, size.Height))
r.rast.Resize(squareSize)
if squareSize.Width < size.Width {
r.rast.Move(fyne.NewPos((size.Width-squareSize.Width)/2, 0))
} else if squareSize.Height < size.Height {
r.rast.Move(fyne.NewPos(0, (size.Height-squareSize.Height)/2))
}
}
func (r *profileBtnRenderer) ApplyTheme() {
r.Refresh()
}
func (r *profileBtnRenderer) BackgprofileColor() color.Color {
return theme.ButtonColor()
}
func (r *profileBtnRenderer) Refresh() {
r.rast = canvas.NewRaster(r.Render)
r.Layout(r.w.Size())
}
func (r *profileBtnRenderer) Destroy() {
}
func (r *profileBtnRenderer) Objects() []fyne.CanvasObject {
r.Refresh()
return []fyne.CanvasObject{r.rast}
}