166 lines
3.5 KiB
Go
166 lines
3.5 KiB
Go
package vumeter
|
|
|
|
import (
|
|
"image/color"
|
|
"strconv"
|
|
|
|
"git.martyn.berlin/martyn/fyne-widgets/internal/cache"
|
|
col "git.martyn.berlin/martyn/fyne-widgets/internal/color"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/data/binding"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
type VUMeter struct {
|
|
widget.BaseWidget
|
|
Min, Max, Value float64
|
|
TextFormatter func() string
|
|
|
|
binder basicBinder
|
|
}
|
|
|
|
type vuMeterRenderer struct {
|
|
objects []fyne.CanvasObject
|
|
background, bar *canvas.Rectangle
|
|
label *canvas.Text
|
|
meter *VUMeter
|
|
}
|
|
|
|
func (p *vuMeterRenderer) MinSize() fyne.Size {
|
|
var tsize fyne.Size
|
|
if text := p.meter.TextFormatter; text != nil {
|
|
tsize = fyne.MeasureText(text(), p.label.TextSize, p.label.TextStyle)
|
|
} else {
|
|
tsize = fyne.MeasureText("100%", p.label.TextSize, p.label.TextStyle)
|
|
}
|
|
|
|
return fyne.NewSize(tsize.Width+theme.Padding()*4, tsize.Height+theme.Padding()*2)
|
|
}
|
|
|
|
func (p *vuMeterRenderer) updateBar() {
|
|
if p.meter.Value < p.meter.Min {
|
|
p.meter.Value = p.meter.Min
|
|
}
|
|
if p.meter.Value > p.meter.Max {
|
|
p.meter.Value = p.meter.Max
|
|
}
|
|
|
|
delta := float32(p.meter.Max - p.meter.Min)
|
|
ratio := float32(p.meter.Value-p.meter.Min) / delta
|
|
|
|
if text := p.meter.TextFormatter; text != nil {
|
|
p.label.Text = text()
|
|
} else {
|
|
p.label.Text = strconv.Itoa(int(ratio*100)) + "%"
|
|
}
|
|
|
|
size := p.meter.Size()
|
|
p.bar.Resize(fyne.NewSize(size.Width*ratio, size.Height))
|
|
}
|
|
|
|
func (p *vuMeterRenderer) Layout(size fyne.Size) {
|
|
p.background.Resize(size)
|
|
p.label.Resize(size)
|
|
p.updateBar()
|
|
}
|
|
|
|
func (p *vuMeterRenderer) applyTheme() {
|
|
p.background.FillColor = vuMeterBackgroundColor()
|
|
p.bar.FillColor = theme.PrimaryColor()
|
|
p.label.Color = theme.ForegroundColor()
|
|
p.label.TextSize = theme.TextSize()
|
|
}
|
|
|
|
func (p *vuMeterRenderer) Refresh() {
|
|
p.applyTheme()
|
|
p.updateBar()
|
|
p.background.Refresh()
|
|
p.bar.Refresh()
|
|
p.meter.super()
|
|
}
|
|
|
|
func (r *vuMeterRenderer) Objects() []fyne.CanvasObject {
|
|
return r.objects
|
|
}
|
|
|
|
// SetObjects updates the objects of the renderer.
|
|
func (r *vuMeterRenderer) SetObjects(objects []fyne.CanvasObject) {
|
|
r.objects = objects
|
|
}
|
|
|
|
func (r *vuMeterRenderer) Destroy() {
|
|
|
|
}
|
|
|
|
func (p *VUMeter) Bind(data binding.Float) {
|
|
p.binder.SetCallback(p.updateFromData)
|
|
p.binder.Bind(data)
|
|
}
|
|
|
|
func (p *VUMeter) SetValue(v float64) {
|
|
p.Value = v
|
|
p.Refresh()
|
|
}
|
|
|
|
func (p *VUMeter) MinSize() fyne.Size {
|
|
p.ExtendBaseWidget(p)
|
|
return p.BaseWidget.MinSize()
|
|
}
|
|
|
|
func (p *VUMeter) CreateRenderer() fyne.WidgetRenderer {
|
|
p.ExtendBaseWidget(p)
|
|
if p.Min == 0 && p.Max == 0 {
|
|
p.Max = 1.0
|
|
}
|
|
|
|
background := canvas.NewRectangle(vuMeterBackgroundColor())
|
|
bar := canvas.NewRectangle(theme.PrimaryColor())
|
|
label := canvas.NewText("0%", theme.ForegroundColor())
|
|
label.Alignment = fyne.TextAlignCenter
|
|
return &vuMeterRenderer{[]fyne.CanvasObject{background, bar, label}, background, bar, label, p}
|
|
}
|
|
|
|
func (p *VUMeter) Unbind() {
|
|
p.binder.Unbind()
|
|
}
|
|
|
|
func NewVUMeter() *VUMeter {
|
|
p := &VUMeter{Min: 0, Max: 1}
|
|
|
|
cache.Renderer(p).Layout(p.MinSize())
|
|
return p
|
|
}
|
|
|
|
func NewVUMeterWithData(data binding.Float) *VUMeter {
|
|
p := NewVUMeter()
|
|
p.Bind(data)
|
|
|
|
return p
|
|
}
|
|
|
|
func vuMeterBackgroundColor() color.Color {
|
|
r, g, b, a := col.ToNRGBA(theme.PrimaryColor())
|
|
faded := uint8(a) / 3
|
|
return &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: faded}
|
|
}
|
|
|
|
func (p *VUMeter) updateFromData(data binding.DataItem) {
|
|
if data == nil {
|
|
return
|
|
}
|
|
floatSource, ok := data.(binding.Float)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
val, err := floatSource.Get()
|
|
if err != nil {
|
|
fyne.LogError("Error getting current data value", err)
|
|
return
|
|
}
|
|
p.SetValue(val)
|
|
}
|