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 }