Initial attempt at VUMeter
This commit is contained in:
parent
55971adfb6
commit
f4e556aa56
|
@ -0,0 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2/app"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := app.New()
|
||||
w := a.NewWindow("Diagonal")
|
||||
level := binding.NewFloat()
|
||||
levelPB := widget.NewProgressBarWithData(level)
|
||||
levelPB.TextFormatter = func() string { return " " }
|
||||
|
||||
w.SetContent(container.New(layout.NewHBoxLayout(), levelPB))
|
||||
w.ShowAndRun()
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
module git.martyn.berlin/martyn/fyne-widgets
|
||||
|
||||
go 1.17
|
||||
|
||||
require fyne.io/fyne/v2 v2.1.2
|
||||
|
||||
require (
|
||||
fyne.io/fyne v1.4.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.4 // indirect
|
||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
|
||||
github.com/stretchr/testify v1.5.1 // indirect
|
||||
github.com/yuin/goldmark v1.3.8 // indirect
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
||||
)
|
|
@ -0,0 +1,105 @@
|
|||
fyne.io/fyne v1.4.3 h1:356CnXCiYrrfaLGsB7qLK3c6ktzyh8WR05v/2RBu51I=
|
||||
fyne.io/fyne v1.4.3/go.mod h1:8kiPBNSDmuplxs9WnKCkaWYqbcXFy0DeAzwa6PBO9Z8=
|
||||
fyne.io/fyne/v2 v2.1.2 h1:avp9CvLAUdvE7fDMtH1tVKyjxEWHWcpow6aI6L7Kvvw=
|
||||
fyne.io/fyne/v2 v2.1.2/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA=
|
||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
||||
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU=
|
||||
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be h1:Z28GdQBfKOL8tNHjvaDn3wHDO7AzTRkmAXvHvnopp98=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
|
||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
|
||||
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
|
||||
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
|
||||
github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E=
|
||||
github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package vumeter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
)
|
||||
|
||||
// basicBinder stores a DataItem and a function to be called when it changes.
|
||||
// It provides a convenient way to replace data and callback independently.
|
||||
type basicBinder struct {
|
||||
callbackLock sync.RWMutex
|
||||
callback func(binding.DataItem) // access guarded by callbackLock
|
||||
dataListenerPairLock sync.RWMutex
|
||||
dataListenerPair annotatedListener // access guarded by dataListenerPairLock
|
||||
}
|
||||
|
||||
// Bind replaces the data item whose changes are tracked by the callback function.
|
||||
func (binder *basicBinder) Bind(data binding.DataItem) {
|
||||
listener := binding.NewDataListener(func() { // NB: listener captures `data` but always calls the up-to-date callback
|
||||
binder.callbackLock.RLock()
|
||||
f := binder.callback
|
||||
binder.callbackLock.RUnlock()
|
||||
if f != nil {
|
||||
f(data)
|
||||
}
|
||||
})
|
||||
data.AddListener(listener)
|
||||
listenerInfo := annotatedListener{
|
||||
data: data,
|
||||
listener: listener,
|
||||
}
|
||||
|
||||
binder.dataListenerPairLock.Lock()
|
||||
binder.unbindLocked()
|
||||
binder.dataListenerPair = listenerInfo
|
||||
binder.dataListenerPairLock.Unlock()
|
||||
}
|
||||
|
||||
// CallWithData passes the currently bound data item as an argument to the
|
||||
// provided function.
|
||||
func (binder *basicBinder) CallWithData(f func(data binding.DataItem)) {
|
||||
binder.dataListenerPairLock.RLock()
|
||||
data := binder.dataListenerPair.data
|
||||
binder.dataListenerPairLock.RUnlock()
|
||||
f(data)
|
||||
}
|
||||
|
||||
// SetCallback replaces the function to be called when the data changes.
|
||||
func (binder *basicBinder) SetCallback(f func(data binding.DataItem)) {
|
||||
binder.callbackLock.Lock()
|
||||
binder.callback = f
|
||||
binder.callbackLock.Unlock()
|
||||
}
|
||||
|
||||
// Unbind requests the callback to be no longer called when the previously bound
|
||||
// data item changes.
|
||||
func (binder *basicBinder) Unbind() {
|
||||
binder.dataListenerPairLock.Lock()
|
||||
binder.unbindLocked()
|
||||
binder.dataListenerPairLock.Unlock()
|
||||
}
|
||||
|
||||
// unbindLocked expects the caller to hold dataListenerPairLock.
|
||||
func (binder *basicBinder) unbindLocked() {
|
||||
previousListener := binder.dataListenerPair
|
||||
binder.dataListenerPair = annotatedListener{nil, nil}
|
||||
|
||||
if previousListener.listener == nil || previousListener.data == nil {
|
||||
return
|
||||
}
|
||||
previousListener.data.RemoveListener(previousListener.listener)
|
||||
}
|
||||
|
||||
type annotatedListener struct {
|
||||
data binding.DataItem
|
||||
listener binding.DataListener
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
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)
|
||||
}
|
Loading…
Reference in New Issue