110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package widgets
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"log"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
"github.com/dweymouth/supersonic/backend"
|
|
)
|
|
|
|
type WaveformSeekbar struct {
|
|
widget.BaseWidget
|
|
|
|
imgColorL color.Color
|
|
imgColorR color.Color
|
|
imgProgress float64
|
|
|
|
img *canvas.Image
|
|
}
|
|
|
|
func NewWaveformSeekbar() *WaveformSeekbar {
|
|
w := &WaveformSeekbar{
|
|
img: canvas.NewImageFromImage(nil),
|
|
}
|
|
w.ExtendBaseWidget(w)
|
|
return w
|
|
}
|
|
|
|
func (w *WaveformSeekbar) UpdateImage(img *backend.WaveformImage) {
|
|
w.img.Image = img
|
|
w.Refresh()
|
|
}
|
|
|
|
func (w *WaveformSeekbar) Refresh() {
|
|
prm, fg := w.getThemeColors()
|
|
w.recolorImage(prm, fg, w.imgProgress)
|
|
w.img.Refresh()
|
|
//w.BaseWidget.Refresh()
|
|
}
|
|
|
|
func (w *WaveformSeekbar) CreateRenderer() fyne.WidgetRenderer {
|
|
return widget.NewSimpleRenderer(
|
|
container.New(layout.NewCustomPaddedLayout(4, 4, 0, 0), w.img),
|
|
)
|
|
}
|
|
|
|
// SetProgress sets how much of the seekbar has been played
|
|
// (ratio from 0 to 1)
|
|
func (w *WaveformSeekbar) SetProgress(v float64) {
|
|
prm, fg := w.getThemeColors()
|
|
w.recolorImage(prm, fg, v)
|
|
w.Refresh()
|
|
}
|
|
|
|
func (w *WaveformSeekbar) getThemeColors() (primary, foreground color.Color) {
|
|
th := w.Theme()
|
|
vnt := fyne.CurrentApp().Settings().ThemeVariant()
|
|
primary = th.Color(theme.ColorNamePrimary, vnt)
|
|
foreground = th.Color(theme.ColorNameForeground, vnt)
|
|
return primary, foreground
|
|
}
|
|
|
|
func (w *WaveformSeekbar) recolorImage(cL, cR color.Color, progress float64) {
|
|
if w.img.Image == nil {
|
|
return
|
|
}
|
|
if w.imgColorL == cL && w.imgColorR == cR && w.imgProgress == progress {
|
|
return
|
|
}
|
|
|
|
_r, _g, _b, _ := cL.RGBA()
|
|
rL, gL, bL := byte(_r>>8), byte(_g>>8), byte(_b>>8)
|
|
_r, _g, _b, _ = cR.RGBA()
|
|
rR, gR, bR := byte(_r>>8), byte(_g>>8), byte(_b>>8)
|
|
|
|
// TODO- smartly figure out which pixels we need
|
|
// to update for different scenarios (e.g. progress update only)
|
|
// and not iterate the whole thing every time
|
|
img := w.img.Image.(*image.NRGBA)
|
|
bnds := img.Rect.Bounds()
|
|
thresholdPixel := int(float64(bnds.Dx()) * progress)
|
|
log.Println("progress = ", progress, " bounds Dx = ", bnds.Dx())
|
|
log.Println("thresholdPixel = ", thresholdPixel)
|
|
for x := 0; x < bnds.Dx(); x++ {
|
|
for y := 0; y < bnds.Dy(); y++ {
|
|
if x < thresholdPixel {
|
|
setPixelRGB(img, x, y, rL, gL, bL)
|
|
} else {
|
|
setPixelRGB(img, x, y, rR, gR, bR)
|
|
}
|
|
}
|
|
}
|
|
|
|
w.imgColorL, w.imgColorR = cL, cR
|
|
w.imgProgress = progress
|
|
}
|
|
|
|
func setPixelRGB(img *image.NRGBA, x, y int, r, g, b byte) {
|
|
offset := img.PixOffset(x, y)
|
|
img.Pix[offset+0] = r
|
|
img.Pix[offset+1] = g
|
|
img.Pix[offset+2] = b
|
|
}
|