Compare commits
No commits in common. "f503732f3854c8245571c295478c956635529b20" and "f4e556aa5651f9bcaedfdd84c3baad2190daaaaf" have entirely different histories.
f503732f38
...
f4e556aa56
5 changed files with 297 additions and 188 deletions
|
@ -6,24 +6,15 @@ import (
|
||||||
"fyne.io/fyne/v2/data/binding"
|
"fyne.io/fyne/v2/data/binding"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"git.martyn.berlin/martyn/fyne-widgets/pkg/vumeter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
a := app.New()
|
a := app.New()
|
||||||
w := a.NewWindow("VUMeter")
|
w := a.NewWindow("Diagonal")
|
||||||
level := binding.NewFloat()
|
level := binding.NewFloat()
|
||||||
levelPB := vumeter.NewVUMeterWithData(level)
|
levelPB := widget.NewProgressBarWithData(level)
|
||||||
level.Set(0.95)
|
|
||||||
levelPB.TextFormatter = func() string { return " " }
|
levelPB.TextFormatter = func() string { return " " }
|
||||||
progress := widget.NewProgressBarWithData(level)
|
|
||||||
setLevel := binding.NewFloat()
|
|
||||||
setLevel.Set(75.0)
|
|
||||||
slider := widget.NewSliderWithData(0.0, 100.0, setLevel)
|
|
||||||
slider.OnChanged = func(data float64) {
|
|
||||||
level.Set(data / 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.SetContent(container.New(layout.NewVBoxLayout(), levelPB, progress, slider))
|
w.SetContent(container.New(layout.NewHBoxLayout(), levelPB))
|
||||||
w.ShowAndRun()
|
w.ShowAndRun()
|
||||||
}
|
}
|
||||||
|
|
52
internal/cache/widget.go
vendored
Normal file
52
internal/cache/widget.go
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var renderers sync.Map
|
||||||
|
|
||||||
|
type isBaseWidget interface {
|
||||||
|
ExtendBaseWidget(fyne.Widget)
|
||||||
|
super() fyne.Widget
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderer looks up the render implementation for a widget
|
||||||
|
func Renderer(wid fyne.Widget) fyne.WidgetRenderer {
|
||||||
|
if wid == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if wd, ok := wid.(isBaseWidget); ok {
|
||||||
|
if wd.super() != nil {
|
||||||
|
wid = wd.super()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderer, ok := renderers.Load(wid)
|
||||||
|
if !ok {
|
||||||
|
renderer = wid.CreateRenderer()
|
||||||
|
renderers.Store(wid, renderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderer == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return renderer.(fyne.WidgetRenderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DestroyRenderer frees a render implementation for a widget.
|
||||||
|
// This is typically for internal use only.
|
||||||
|
func DestroyRenderer(wid fyne.Widget) {
|
||||||
|
Renderer(wid).Destroy()
|
||||||
|
|
||||||
|
renderers.Delete(wid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRendered returns true of the widget currently has a renderer.
|
||||||
|
// One will be created the first time a widget is shown but may be removed after it is hidden.
|
||||||
|
func IsRendered(wid fyne.Widget) bool {
|
||||||
|
_, found := renderers.Load(wid)
|
||||||
|
return found
|
||||||
|
}
|
97
internal/color/color.go
Normal file
97
internal/color/color.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToNRGBA converts a color to RGBA values which are not premultiplied, unlike color.RGBA().
|
||||||
|
func ToNRGBA(c color.Color) (r, g, b, a int) {
|
||||||
|
// We use UnmultiplyAlpha with RGBA, RGBA64, and unrecognized implementations of Color.
|
||||||
|
// It works for all Colors whose RGBA() method is implemented according to spec, but is only necessary for those.
|
||||||
|
// Only RGBA and RGBA64 have components which are already premultiplied.
|
||||||
|
switch col := c.(type) {
|
||||||
|
// NRGBA and NRGBA64 are not premultiplied
|
||||||
|
case color.NRGBA:
|
||||||
|
r = int(col.R)
|
||||||
|
g = int(col.G)
|
||||||
|
b = int(col.B)
|
||||||
|
a = int(col.A)
|
||||||
|
case *color.NRGBA:
|
||||||
|
r = int(col.R)
|
||||||
|
g = int(col.G)
|
||||||
|
b = int(col.B)
|
||||||
|
a = int(col.A)
|
||||||
|
case color.NRGBA64:
|
||||||
|
r = int(col.R) >> 8
|
||||||
|
g = int(col.G) >> 8
|
||||||
|
b = int(col.B) >> 8
|
||||||
|
a = int(col.A) >> 8
|
||||||
|
case *color.NRGBA64:
|
||||||
|
r = int(col.R) >> 8
|
||||||
|
g = int(col.G) >> 8
|
||||||
|
b = int(col.B) >> 8
|
||||||
|
a = int(col.A) >> 8
|
||||||
|
// Gray and Gray16 have no alpha component
|
||||||
|
case *color.Gray:
|
||||||
|
r = int(col.Y)
|
||||||
|
g = int(col.Y)
|
||||||
|
b = int(col.Y)
|
||||||
|
a = 0xff
|
||||||
|
case color.Gray:
|
||||||
|
r = int(col.Y)
|
||||||
|
g = int(col.Y)
|
||||||
|
b = int(col.Y)
|
||||||
|
a = 0xff
|
||||||
|
case *color.Gray16:
|
||||||
|
r = int(col.Y) >> 8
|
||||||
|
g = int(col.Y) >> 8
|
||||||
|
b = int(col.Y) >> 8
|
||||||
|
a = 0xff
|
||||||
|
case color.Gray16:
|
||||||
|
r = int(col.Y) >> 8
|
||||||
|
g = int(col.Y) >> 8
|
||||||
|
b = int(col.Y) >> 8
|
||||||
|
a = 0xff
|
||||||
|
// Alpha and Alpha16 contain only an alpha component.
|
||||||
|
case color.Alpha:
|
||||||
|
r = 0xff
|
||||||
|
g = 0xff
|
||||||
|
b = 0xff
|
||||||
|
a = int(col.A)
|
||||||
|
case *color.Alpha:
|
||||||
|
r = 0xff
|
||||||
|
g = 0xff
|
||||||
|
b = 0xff
|
||||||
|
a = int(col.A)
|
||||||
|
case color.Alpha16:
|
||||||
|
r = 0xff
|
||||||
|
g = 0xff
|
||||||
|
b = 0xff
|
||||||
|
a = int(col.A) >> 8
|
||||||
|
case *color.Alpha16:
|
||||||
|
r = 0xff
|
||||||
|
g = 0xff
|
||||||
|
b = 0xff
|
||||||
|
a = int(col.A) >> 8
|
||||||
|
default: // RGBA, RGBA64, and unknown implementations of Color
|
||||||
|
r, g, b, a = unmultiplyAlpha(c)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmultiplyAlpha returns a color's RGBA components as 8-bit integers by calling c.RGBA() and then removing the alpha premultiplication.
|
||||||
|
// It is only used by ToRGBA.
|
||||||
|
func unmultiplyAlpha(c color.Color) (r, g, b, a int) {
|
||||||
|
red, green, blue, alpha := c.RGBA()
|
||||||
|
if alpha != 0 && alpha != 0xffff {
|
||||||
|
red = (red * 0xffff) / alpha
|
||||||
|
green = (green * 0xffff) / alpha
|
||||||
|
blue = (blue * 0xffff) / alpha
|
||||||
|
}
|
||||||
|
// Convert from range 0-65535 to range 0-255
|
||||||
|
r = int(red >> 8)
|
||||||
|
g = int(green >> 8)
|
||||||
|
b = int(blue >> 8)
|
||||||
|
a = int(alpha >> 8)
|
||||||
|
return
|
||||||
|
}
|
32
pkg/vumeter/base_renderer.go
Normal file
32
pkg/vumeter/base_renderer.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package vumeter
|
||||||
|
|
||||||
|
import "fyne.io/fyne/v2"
|
||||||
|
|
||||||
|
// BaseRenderer is a renderer base providing the most common implementations of a part of the
|
||||||
|
// widget.Renderer interface.
|
||||||
|
type BaseRenderer struct {
|
||||||
|
objects []fyne.CanvasObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBaseRenderer creates a new BaseRenderer.
|
||||||
|
func NewBaseRenderer(objects []fyne.CanvasObject) BaseRenderer {
|
||||||
|
return BaseRenderer{objects}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy does nothing in the base implementation.
|
||||||
|
//
|
||||||
|
// Implements: fyne.WidgetRenderer
|
||||||
|
func (r *BaseRenderer) Destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Objects returns the objects that should be rendered.
|
||||||
|
//
|
||||||
|
// Implements: fyne.WidgetRenderer
|
||||||
|
func (r *BaseRenderer) Objects() []fyne.CanvasObject {
|
||||||
|
return r.objects
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetObjects updates the objects of the renderer.
|
||||||
|
func (r *BaseRenderer) SetObjects(objects []fyne.CanvasObject) {
|
||||||
|
r.objects = objects
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
package vumeter
|
package vumeter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"image/color"
|
"image/color"
|
||||||
"strconv"
|
"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"
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
"fyne.io/fyne/v2/data/binding"
|
"fyne.io/fyne/v2/data/binding"
|
||||||
|
@ -12,172 +14,140 @@ import (
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
type vuRenderer struct {
|
type VUMeter struct {
|
||||||
label *canvas.Text
|
widget.BaseWidget
|
||||||
background, bar,
|
Min, Max, Value float64
|
||||||
optimumBar, peakBar,
|
TextFormatter func() string
|
||||||
lowalphaGreen,
|
|
||||||
lowalphaAmber,
|
|
||||||
lowalphaRed *canvas.Rectangle
|
|
||||||
|
|
||||||
objects []fyne.CanvasObject
|
binder basicBinder
|
||||||
meter *vuMeter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinSize calculates the minimum size of the VU meter. Code shamelessly stolen from progressbar for now.
|
type vuMeterRenderer struct {
|
||||||
func (v *vuRenderer) MinSize() fyne.Size {
|
objects []fyne.CanvasObject
|
||||||
|
background, bar *canvas.Rectangle
|
||||||
|
label *canvas.Text
|
||||||
|
meter *VUMeter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *vuMeterRenderer) MinSize() fyne.Size {
|
||||||
var tsize fyne.Size
|
var tsize fyne.Size
|
||||||
if text := v.meter.TextFormatter; text != nil {
|
if text := p.meter.TextFormatter; text != nil {
|
||||||
tsize = fyne.MeasureText(text(), v.label.TextSize, v.label.TextStyle)
|
tsize = fyne.MeasureText(text(), p.label.TextSize, p.label.TextStyle)
|
||||||
} else {
|
} else {
|
||||||
tsize = fyne.MeasureText("100%", v.label.TextSize, v.label.TextStyle)
|
tsize = fyne.MeasureText("100%", p.label.TextSize, p.label.TextStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fyne.NewSize(tsize.Width+theme.Padding()*4, tsize.Height+theme.Padding()*2)
|
return fyne.NewSize(tsize.Width+theme.Padding()*4, tsize.Height+theme.Padding()*2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vuRenderer) updateBars() {
|
func (p *vuMeterRenderer) updateBar() {
|
||||||
if v.meter.Value < v.meter.Min {
|
if p.meter.Value < p.meter.Min {
|
||||||
v.meter.Value = v.meter.Min
|
p.meter.Value = p.meter.Min
|
||||||
}
|
}
|
||||||
if v.meter.Value > v.meter.Max {
|
if p.meter.Value > p.meter.Max {
|
||||||
v.meter.Value = v.meter.Max
|
p.meter.Value = p.meter.Max
|
||||||
}
|
}
|
||||||
|
|
||||||
delta := float64(v.meter.Max - v.meter.Min)
|
delta := float32(p.meter.Max - p.meter.Min)
|
||||||
ratio := float64(v.meter.Value-v.meter.Min) / delta
|
ratio := float32(p.meter.Value-p.meter.Min) / delta
|
||||||
|
|
||||||
if text := v.meter.TextFormatter; text != nil {
|
if text := p.meter.TextFormatter; text != nil {
|
||||||
v.label.Text = text()
|
p.label.Text = text()
|
||||||
} else {
|
} else {
|
||||||
v.label.Text = strconv.Itoa(int(ratio*100)) + "%"
|
p.label.Text = strconv.Itoa(int(ratio*100)) + "%"
|
||||||
}
|
}
|
||||||
|
|
||||||
size := v.meter.Size()
|
size := p.meter.Size()
|
||||||
greenWidth := 0.0
|
p.bar.Resize(fyne.NewSize(size.Width*ratio, size.Height))
|
||||||
amberWidth := 0.0
|
|
||||||
redWidth := 0.0
|
|
||||||
if ratio > (v.meter.OptimumValueMin / 100) {
|
|
||||||
if ratio > (v.meter.OptimumValueMax / 100) {
|
|
||||||
greenWidth = float64(size.Width) * v.meter.OptimumValueMin / 100
|
|
||||||
amberWidth = float64(size.Width) * v.meter.OptimumValueMax / 100
|
|
||||||
redWidth = float64(size.Width) * ratio
|
|
||||||
} else {
|
|
||||||
greenWidth = float64(size.Width) * v.meter.OptimumValueMin / 100
|
|
||||||
amberWidth = float64(size.Width) * ratio
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
greenWidth = float64(size.Width) * ratio
|
|
||||||
}
|
|
||||||
redWidth = redWidth - amberWidth
|
|
||||||
if redWidth < 0 {
|
|
||||||
redWidth = 0
|
|
||||||
}
|
|
||||||
amberWidth = amberWidth - greenWidth
|
|
||||||
if amberWidth < 0 {
|
|
||||||
amberWidth = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lowalphaGreenWidth := float64(size.Width) * v.meter.OptimumValueMin / 100
|
func (p *vuMeterRenderer) Layout(size fyne.Size) {
|
||||||
lowalphaAmberWidth := float64(size.Width) * v.meter.OptimumValueMax / 100
|
p.background.Resize(size)
|
||||||
lowalphaRedWidth := float64(size.Width)
|
p.label.Resize(size)
|
||||||
lowalphaRedWidth = lowalphaRedWidth - lowalphaAmberWidth
|
p.updateBar()
|
||||||
lowalphaAmberWidth = lowalphaAmberWidth - lowalphaGreenWidth
|
|
||||||
|
|
||||||
v.lowalphaGreen.Resize(fyne.NewSize(float32(lowalphaGreenWidth), size.Height))
|
|
||||||
v.lowalphaAmber.Resize(fyne.NewSize(float32(lowalphaAmberWidth), size.Height))
|
|
||||||
v.lowalphaAmber.Move(fyne.NewPos(float32(lowalphaGreenWidth), 0))
|
|
||||||
v.lowalphaRed.Resize(fyne.NewSize(float32(lowalphaRedWidth), size.Height))
|
|
||||||
v.lowalphaRed.Move(fyne.NewPos(float32(lowalphaAmberWidth+lowalphaGreenWidth), 0))
|
|
||||||
|
|
||||||
v.bar.Resize(fyne.NewSize(float32(greenWidth), size.Height))
|
|
||||||
v.optimumBar.Resize(fyne.NewSize(float32(amberWidth), size.Height))
|
|
||||||
v.optimumBar.Move(fyne.NewPos(float32(greenWidth), 0))
|
|
||||||
v.peakBar.Resize(fyne.NewSize(float32(redWidth), size.Height))
|
|
||||||
v.peakBar.Move(fyne.NewPos(float32(greenWidth+amberWidth), 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout the components of the widget
|
func (p *vuMeterRenderer) applyTheme() {
|
||||||
func (v *vuRenderer) Layout(size fyne.Size) {
|
p.background.FillColor = vuMeterBackgroundColor()
|
||||||
v.background.Resize(size)
|
p.bar.FillColor = theme.PrimaryColor()
|
||||||
v.label.Resize(size)
|
p.label.Color = theme.ForegroundColor()
|
||||||
v.updateBars()
|
p.label.TextSize = theme.TextSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyTheme is called when the vuMeter may need to update it's look
|
func (p *vuMeterRenderer) Refresh() {
|
||||||
func (v *vuRenderer) ApplyTheme() {
|
p.applyTheme()
|
||||||
v.label.Color = theme.ForegroundColor()
|
p.updateBar()
|
||||||
v.Refresh()
|
p.background.Refresh()
|
||||||
|
p.bar.Refresh()
|
||||||
|
p.meter.super()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vuRenderer) BackgroundColor() color.Color {
|
func (r *vuMeterRenderer) Objects() []fyne.CanvasObject {
|
||||||
return theme.ButtonColor()
|
return r.objects
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vuRenderer) Refresh() {
|
// SetObjects updates the objects of the renderer.
|
||||||
v.label.Text = fmt.Sprintf("%f %%", v.meter.Value)
|
func (r *vuMeterRenderer) SetObjects(objects []fyne.CanvasObject) {
|
||||||
fmt.Printf("%f %%\n", v.meter.Value)
|
r.objects = objects
|
||||||
v.Layout(v.meter.Size())
|
|
||||||
canvas.Refresh(v.meter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vuRenderer) Objects() []fyne.CanvasObject {
|
func (r *vuMeterRenderer) Destroy() {
|
||||||
return v.objects
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vuRenderer) Destroy() {
|
func (p *VUMeter) Bind(data binding.Float) {
|
||||||
|
p.binder.SetCallback(p.updateFromData)
|
||||||
|
p.binder.Bind(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// vuMeter widget is a kind of custom progressbar but has "zones" of different color for peaking.
|
func (p *VUMeter) SetValue(v float64) {
|
||||||
type vuMeter struct {
|
p.Value = v
|
||||||
widget.BaseWidget
|
p.Refresh()
|
||||||
TextFormatter func() string
|
|
||||||
Value, Min, Max,
|
|
||||||
OptimumValueMin, OptimumValueMax float64
|
|
||||||
|
|
||||||
binder basicBinder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *vuMeter) CreateRenderer() fyne.WidgetRenderer {
|
func (p *VUMeter) MinSize() fyne.Size {
|
||||||
m.ExtendBaseWidget(m)
|
p.ExtendBaseWidget(p)
|
||||||
if m.Min == 0 && m.Max == 0 {
|
return p.BaseWidget.MinSize()
|
||||||
m.Max = 1.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
background := canvas.NewRectangle(theme.BackgroundColor())
|
func (p *VUMeter) CreateRenderer() fyne.WidgetRenderer {
|
||||||
lowalphaGreen := canvas.NewRectangle(color.RGBA{0, 255, 0, 64})
|
p.ExtendBaseWidget(p)
|
||||||
lowalphaAmber := canvas.NewRectangle(color.RGBA{255, 200, 0, 64})
|
if p.Min == 0 && p.Max == 0 {
|
||||||
lowalphaRed := canvas.NewRectangle(color.RGBA{255, 0, 0, 64})
|
p.Max = 1.0
|
||||||
bar := canvas.NewRectangle(color.RGBA{0, 255, 0, 255})
|
}
|
||||||
optimumBar := canvas.NewRectangle(color.RGBA{255, 200, 0, 255})
|
|
||||||
peakBar := canvas.NewRectangle(color.RGBA{255, 0, 0, 255})
|
background := canvas.NewRectangle(vuMeterBackgroundColor())
|
||||||
|
bar := canvas.NewRectangle(theme.PrimaryColor())
|
||||||
label := canvas.NewText("0%", theme.ForegroundColor())
|
label := canvas.NewText("0%", theme.ForegroundColor())
|
||||||
label.Alignment = fyne.TextAlignCenter
|
label.Alignment = fyne.TextAlignCenter
|
||||||
objects := []fyne.CanvasObject{
|
return &vuMeterRenderer{[]fyne.CanvasObject{background, bar, label}, background, bar, label, p}
|
||||||
background,
|
|
||||||
lowalphaGreen,
|
|
||||||
lowalphaAmber,
|
|
||||||
lowalphaRed,
|
|
||||||
bar,
|
|
||||||
optimumBar,
|
|
||||||
peakBar,
|
|
||||||
label,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &vuRenderer{label, background, bar, optimumBar, peakBar,
|
func (p *VUMeter) Unbind() {
|
||||||
lowalphaGreen,
|
p.binder.Unbind()
|
||||||
lowalphaAmber,
|
|
||||||
lowalphaRed, objects, m}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetValue changes the current value of this progress bar (from p.Min to p.Max).
|
func NewVUMeter() *VUMeter {
|
||||||
// The widget will be refreshed to indicate the change.
|
p := &VUMeter{Min: 0, Max: 1}
|
||||||
func (m *vuMeter) SetValue(v float64) {
|
|
||||||
m.Value = v
|
cache.Renderer(p).Layout(p.MinSize())
|
||||||
m.Refresh()
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *vuMeter) updateFromData(data binding.DataItem) {
|
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 {
|
if data == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -191,38 +161,5 @@ func (m *vuMeter) updateFromData(data binding.DataItem) {
|
||||||
fyne.LogError("Error getting current data value", err)
|
fyne.LogError("Error getting current data value", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.SetValue(val)
|
p.SetValue(val)
|
||||||
}
|
|
||||||
|
|
||||||
func (m *vuMeter) MinSize() fyne.Size {
|
|
||||||
m.ExtendBaseWidget(m)
|
|
||||||
return m.BaseWidget.MinSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *vuMeter) Bind(data binding.Float) {
|
|
||||||
m.binder.SetCallback(m.updateFromData)
|
|
||||||
m.binder.Bind(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *vuMeter) Unbind() {
|
|
||||||
m.binder.Unbind()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVUMeter creates a new meter widget with the specified value
|
|
||||||
func NewVUMeter(value float64) *vuMeter {
|
|
||||||
meter := &vuMeter{Value: value}
|
|
||||||
meter.OptimumValueMin = 75
|
|
||||||
meter.OptimumValueMax = 85
|
|
||||||
meter.ExtendBaseWidget(meter)
|
|
||||||
return meter
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewVUMeterWithData(data binding.Float) *vuMeter {
|
|
||||||
f, err := data.Get()
|
|
||||||
if err != nil {
|
|
||||||
f = 25.0
|
|
||||||
}
|
|
||||||
m := NewVUMeter(f)
|
|
||||||
m.Bind(data)
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue