circular profile button

This commit is contained in:
Martyn 2021-12-24 00:00:44 +00:00
parent 7a4673ab3d
commit 5a8a14f63d
5 changed files with 193 additions and 0 deletions

View File

@ -0,0 +1,31 @@
package main
import (
"bytes"
"fmt"
"image"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"git.martyn.berlin/martyn/fyne-widgets/pkg/profilebtn"
)
func main() {
a := app.New()
w := a.NewWindow("ProfileBtn")
b := profilebtn.NewProfileBtn()
i, s, err := image.Decode(bytes.NewReader(resourceProfilepicdoesnotexistJpg.StaticContent))
fmt.Println(s)
if err != nil {
fmt.Println(err)
panic(err)
}
fmt.Println(i.Bounds())
b.SetProfileImage(i)
b.OutlineWidth = 5
w.SetContent(container.NewBorder(nil, nil, nil, nil, b))
w.Resize(fyne.NewSize(640, 480))
w.ShowAndRun()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

File diff suppressed because one or more lines are too long

27
pkg/profilebtn/circle.go Normal file
View File

@ -0,0 +1,27 @@
package profilebtn
import (
"image"
"image/color"
)
type circle struct {
p image.Point
r int
}
func (c *circle) ColorModel() color.Model {
return color.AlphaModel
}
func (c *circle) Bounds() image.Rectangle {
return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}
func (c *circle) At(x, y int) color.Color {
xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
if xx*xx+yy*yy < rr*rr {
return color.Alpha{255}
}
return color.Alpha{0}
}

View File

@ -0,0 +1,123 @@
package profilebtn
import (
"image"
"image/color"
"image/draw"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
type profileBtn struct {
widget.BaseWidget
OutlineWidth int
OutlineColor color.Color
profileImage image.Image
}
func (b *profileBtn) Resize(s fyne.Size) {
b.BaseWidget.Resize(s)
}
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))),
canvas.NewCircle(b.OutlineColor),
b,
}
b.ExtendBaseWidget(b)
return r
}
func NewProfileBtn() *profileBtn {
w := &profileBtn{}
w.ExtendBaseWidget(w)
w.OutlineWidth = 0
w.OutlineColor = color.White
return w
}
func (b *profileBtn) SetProfileResource(r fyne.Resource) {
b.profileImage = canvas.NewImageFromResource(r).Image
}
func (b *profileBtn) SetProfileImage(i image.Image) {
b.profileImage = i
}
type profileBtnRenderer struct {
rast *canvas.Raster
background *canvas.Circle
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
b := src.Bounds().Size()
dst := image.NewRGBA(image.Rect(0, 0, b.X, b.Y))
draw.DrawMask(dst, dst.Bounds(), src, 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 {
return fyne.NewSize(theme.Padding()*4, theme.Padding()*4)
}
func (r *profileBtnRenderer) Layout(size fyne.Size) {
r.background.Resize(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.background, r.rast}
}