2021-12-24 00:00:44 +00:00
|
|
|
package profilebtn
|
|
|
|
|
|
|
|
import (
|
2021-12-24 12:32:03 +00:00
|
|
|
"bytes"
|
2021-12-24 00:00:44 +00:00
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
"image/draw"
|
|
|
|
|
|
|
|
"fyne.io/fyne/v2"
|
|
|
|
"fyne.io/fyne/v2/canvas"
|
|
|
|
"fyne.io/fyne/v2/theme"
|
|
|
|
"fyne.io/fyne/v2/widget"
|
|
|
|
)
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
var _ fyne.Focusable = (*ProfileBtn)(nil)
|
2021-12-24 13:02:59 +00:00
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
type ProfileBtn struct {
|
2021-12-24 13:02:59 +00:00
|
|
|
widget.DisableableWidget
|
2021-12-24 00:00:44 +00:00
|
|
|
|
|
|
|
OutlineWidth int
|
|
|
|
OutlineColor color.Color
|
|
|
|
|
2021-12-24 12:40:19 +00:00
|
|
|
profileImage image.Image
|
|
|
|
minSizeOverridden bool
|
|
|
|
minSizeRequested fyne.Size
|
2021-12-25 11:49:34 +00:00
|
|
|
disabled bool
|
2021-12-24 13:02:59 +00:00
|
|
|
|
|
|
|
OnTapped func() `json:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// FocusGained is a hook called by the focus handling logic after this object gained the focus.
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) FocusGained() {
|
2021-12-24 13:02:59 +00:00
|
|
|
// b.focused = true
|
|
|
|
b.Refresh()
|
|
|
|
}
|
|
|
|
|
|
|
|
// FocusLost is a hook called by the focus handling logic after this object lost the focus.
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) FocusLost() {
|
2021-12-24 13:02:59 +00:00
|
|
|
// b.focused = false
|
|
|
|
b.Refresh()
|
|
|
|
}
|
|
|
|
|
|
|
|
// TypedRune is a hook called by the input handling logic on text input events if this object is focused.
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) TypedRune(rune) {
|
2021-12-24 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TypedKey is a hook called by the input handling logic on key events if this object is focused.
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) TypedKey(ev *fyne.KeyEvent) {
|
2021-12-24 13:02:59 +00:00
|
|
|
if ev.Name == fyne.KeySpace {
|
|
|
|
b.Tapped(nil)
|
|
|
|
}
|
2021-12-24 00:00:44 +00:00
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) Resize(s fyne.Size) {
|
2021-12-24 00:00:44 +00:00
|
|
|
b.BaseWidget.Resize(s)
|
|
|
|
}
|
|
|
|
|
2021-12-25 11:49:34 +00:00
|
|
|
func (b *ProfileBtn) Disable() {
|
|
|
|
b.disabled = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *ProfileBtn) Ensable() {
|
|
|
|
b.disabled = false
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) Disabled() bool {
|
2021-12-25 11:49:34 +00:00
|
|
|
return b.disabled
|
2021-12-24 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) Tapped(*fyne.PointEvent) {
|
2021-12-24 13:02:59 +00:00
|
|
|
if b.Disabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//b.tapAnimation()
|
|
|
|
b.Refresh()
|
|
|
|
|
|
|
|
if b.OnTapped != nil {
|
|
|
|
b.OnTapped()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) CreateRenderer() fyne.WidgetRenderer {
|
2021-12-24 00:00:44 +00:00
|
|
|
return NewProfileBtnRenderer(b)
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func NewProfileBtnRenderer(b *ProfileBtn) *profileBtnRenderer {
|
2021-12-24 00:00:44 +00:00
|
|
|
r := &profileBtnRenderer{
|
|
|
|
canvas.NewRasterFromImage(image.NewRGBA(image.Rect(0, 0, 10, 10))),
|
|
|
|
b,
|
|
|
|
}
|
|
|
|
b.ExtendBaseWidget(b)
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func NewProfileBtn() *ProfileBtn {
|
|
|
|
w := &ProfileBtn{}
|
2021-12-24 00:00:44 +00:00
|
|
|
w.ExtendBaseWidget(w)
|
|
|
|
w.OutlineWidth = 0
|
|
|
|
w.OutlineColor = color.White
|
2021-12-24 12:32:03 +00:00
|
|
|
w.SetProfileResource(nil)
|
2021-12-24 12:40:19 +00:00
|
|
|
w.minSizeOverridden = false
|
2021-12-25 11:49:34 +00:00
|
|
|
w.disabled = false
|
2021-12-24 00:00:44 +00:00
|
|
|
return w
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) SetProfileResource(r fyne.Resource) {
|
2021-12-24 12:32:03 +00:00
|
|
|
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
|
|
|
|
|
2021-12-24 00:00:44 +00:00
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) SetMinSize(s fyne.Size) {
|
2021-12-24 12:40:19 +00:00
|
|
|
if s.Height > 0 && s.Width > 0 {
|
|
|
|
b.minSizeRequested = s
|
|
|
|
b.minSizeOverridden = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
b.minSizeOverridden = false
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:15:11 +00:00
|
|
|
func (b *ProfileBtn) SetProfileImage(i image.Image) {
|
2021-12-24 00:00:44 +00:00
|
|
|
b.profileImage = i
|
|
|
|
}
|
|
|
|
|
|
|
|
type profileBtnRenderer struct {
|
2021-12-24 00:11:44 +00:00
|
|
|
rast *canvas.Raster
|
2021-12-24 15:15:11 +00:00
|
|
|
w *ProfileBtn
|
2021-12-24 00:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2021-12-25 11:49:34 +00:00
|
|
|
// 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)
|
|
|
|
|
2021-12-24 00:00:44 +00:00
|
|
|
b := src.Bounds().Size()
|
2021-12-24 00:11:44 +00:00
|
|
|
wh := image.NewUniform(r.w.OutlineColor)
|
2021-12-24 00:00:44 +00:00
|
|
|
dst := image.NewRGBA(image.Rect(0, 0, b.X, b.Y))
|
2021-12-24 00:11:44 +00:00
|
|
|
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)
|
2021-12-25 11:49:34 +00:00
|
|
|
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)
|
2021-12-24 00:00:44 +00:00
|
|
|
return dst
|
|
|
|
} else {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *profileBtnRenderer) MinSize() fyne.Size {
|
2021-12-24 12:40:19 +00:00
|
|
|
if r.w.minSizeOverridden {
|
|
|
|
return r.w.minSizeRequested
|
|
|
|
}
|
2021-12-24 00:00:44 +00:00
|
|
|
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()
|
2021-12-24 00:11:44 +00:00
|
|
|
return []fyne.CanvasObject{r.rast}
|
2021-12-24 00:00:44 +00:00
|
|
|
}
|