binding.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. //go:generate go run gen.go
  2. // Package binding provides support for binding data to widgets.
  3. package binding
  4. import (
  5. "errors"
  6. "reflect"
  7. "sync"
  8. "fyne.io/fyne/v2"
  9. )
  10. var (
  11. errKeyNotFound = errors.New("key not found")
  12. errOutOfBounds = errors.New("index out of bounds")
  13. errParseFailed = errors.New("format did not match 1 value")
  14. // As an optimisation we connect any listeners asking for the same key, so that there is only 1 per preference item.
  15. prefBinds = newPreferencesMap()
  16. )
  17. // DataItem is the base interface for all bindable data items.
  18. //
  19. // Since: 2.0
  20. type DataItem interface {
  21. // AddListener attaches a new change listener to this DataItem.
  22. // Listeners are called each time the data inside this DataItem changes.
  23. // Additionally the listener will be triggered upon successful connection to get the current value.
  24. AddListener(DataListener)
  25. // RemoveListener will detach the specified change listener from the DataItem.
  26. // Disconnected listener will no longer be triggered when changes occur.
  27. RemoveListener(DataListener)
  28. }
  29. // DataListener is any object that can register for changes in a bindable DataItem.
  30. // See NewDataListener to define a new listener using just an inline function.
  31. //
  32. // Since: 2.0
  33. type DataListener interface {
  34. DataChanged()
  35. }
  36. // NewDataListener is a helper function that creates a new listener type from a simple callback function.
  37. //
  38. // Since: 2.0
  39. func NewDataListener(fn func()) DataListener {
  40. return &listener{fn}
  41. }
  42. type listener struct {
  43. callback func()
  44. }
  45. func (l *listener) DataChanged() {
  46. l.callback()
  47. }
  48. type base struct {
  49. listeners sync.Map // map[DataListener]bool
  50. lock sync.RWMutex
  51. }
  52. // AddListener allows a data listener to be informed of changes to this item.
  53. func (b *base) AddListener(l DataListener) {
  54. b.listeners.Store(l, true)
  55. queueItem(l.DataChanged)
  56. }
  57. // RemoveListener should be called if the listener is no longer interested in being informed of data change events.
  58. func (b *base) RemoveListener(l DataListener) {
  59. b.listeners.Delete(l)
  60. }
  61. func (b *base) trigger() {
  62. b.listeners.Range(func(key, _ interface{}) bool {
  63. queueItem(key.(DataListener).DataChanged)
  64. return true
  65. })
  66. }
  67. // Untyped supports binding a interface{} value.
  68. //
  69. // Since: 2.1
  70. type Untyped interface {
  71. DataItem
  72. Get() (interface{}, error)
  73. Set(interface{}) error
  74. }
  75. // NewUntyped returns a bindable interface{} value that is managed internally.
  76. //
  77. // Since: 2.1
  78. func NewUntyped() Untyped {
  79. var blank interface{} = nil
  80. v := &blank
  81. return &boundUntyped{val: reflect.ValueOf(v).Elem()}
  82. }
  83. type boundUntyped struct {
  84. base
  85. val reflect.Value
  86. }
  87. func (b *boundUntyped) Get() (interface{}, error) {
  88. b.lock.RLock()
  89. defer b.lock.RUnlock()
  90. return b.val.Interface(), nil
  91. }
  92. func (b *boundUntyped) Set(val interface{}) error {
  93. b.lock.Lock()
  94. defer b.lock.Unlock()
  95. if b.val.Interface() == val {
  96. return nil
  97. }
  98. b.val.Set(reflect.ValueOf(val))
  99. b.trigger()
  100. return nil
  101. }
  102. // ExternalUntyped supports binding a interface{} value to an external value.
  103. //
  104. // Since: 2.1
  105. type ExternalUntyped interface {
  106. Untyped
  107. Reload() error
  108. }
  109. // BindUntyped returns a bindable interface{} value that is bound to an external type.
  110. // The parameter must be a pointer to the type you wish to bind.
  111. //
  112. // Since: 2.1
  113. func BindUntyped(v interface{}) ExternalUntyped {
  114. t := reflect.TypeOf(v)
  115. if t.Kind() != reflect.Ptr {
  116. fyne.LogError("Invalid type passed to BindUntyped, must be a pointer", nil)
  117. v = nil
  118. }
  119. if v == nil {
  120. var blank interface{}
  121. v = &blank // never allow a nil value pointer
  122. }
  123. b := &boundExternalUntyped{}
  124. b.val = reflect.ValueOf(v).Elem()
  125. b.old = b.val.Interface()
  126. return b
  127. }
  128. type boundExternalUntyped struct {
  129. boundUntyped
  130. old interface{}
  131. }
  132. func (b *boundExternalUntyped) Set(val interface{}) error {
  133. b.lock.Lock()
  134. defer b.lock.Unlock()
  135. if b.old == val {
  136. return nil
  137. }
  138. b.val.Set(reflect.ValueOf(val))
  139. b.old = val
  140. b.trigger()
  141. return nil
  142. }
  143. func (b *boundExternalUntyped) Reload() error {
  144. return b.Set(b.val.Interface())
  145. }