• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fyne-io / fyne / 13237462739

10 Feb 2025 09:20AM UTC coverage: 62.562% (-0.009%) from 62.571%
13237462739

push

github

andydotxyz
Deprecate this fyne_demo before we release

0 of 6 new or added lines in 1 file covered. (0.0%)

7 existing lines in 2 files now uncovered.

24902 of 39804 relevant lines covered (62.56%)

826.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.16
/data/binding/binding.go
1
//go:generate go run gen.go
2

3
// Package binding provides support for binding data to widgets.
4
// All APIs in the binding package are safe to invoke directly from any goroutine.
5
package binding
6

7
import (
8
        "errors"
9
        "reflect"
10
        "sync"
11

12
        "fyne.io/fyne/v2"
13
)
14

15
var (
16
        errKeyNotFound = errors.New("key not found")
17
        errOutOfBounds = errors.New("index out of bounds")
18
        errParseFailed = errors.New("format did not match 1 value")
19

20
        // As an optimisation we connect any listeners asking for the same key, so that there is only 1 per preference item.
21
        prefBinds = newPreferencesMap()
22
)
23

24
// DataItem is the base interface for all bindable data items.
25
// All APIs on bindable data items are safe to invoke directly fron any goroutine.
26
//
27
// Since: 2.0
28
type DataItem interface {
29
        // AddListener attaches a new change listener to this DataItem.
30
        // Listeners are called each time the data inside this DataItem changes.
31
        // Additionally, the listener will be triggered upon successful connection to get the current value.
32
        AddListener(DataListener)
33
        // RemoveListener will detach the specified change listener from the DataItem.
34
        // Disconnected listener will no longer be triggered when changes occur.
35
        RemoveListener(DataListener)
36
}
37

38
// DataListener is any object that can register for changes in a bindable DataItem.
39
// See NewDataListener to define a new listener using just an inline function.
40
//
41
// Since: 2.0
42
type DataListener interface {
43
        DataChanged()
44
}
45

46
// NewDataListener is a helper function that creates a new listener type from a simple callback function.
47
//
48
// Since: 2.0
49
func NewDataListener(fn func()) DataListener {
27✔
50
        return &listener{fn}
27✔
51
}
27✔
52

53
type listener struct {
54
        callback func()
55
}
56

57
func (l *listener) DataChanged() {
76✔
58
        l.callback()
76✔
59
}
76✔
60

61
type base struct {
62
        listeners []DataListener
63

64
        lock sync.RWMutex
65
}
66

67
// AddListener allows a data listener to be informed of changes to this item.
68
func (b *base) AddListener(l DataListener) {
52✔
69
        fyne.Do(func() {
104✔
70
                b.listeners = append(b.listeners, l)
52✔
71
                l.DataChanged()
52✔
72
        })
52✔
73
}
74

75
// RemoveListener should be called if the listener is no longer interested in being informed of data change events.
76
func (b *base) RemoveListener(l DataListener) {
3✔
77
        fyne.Do(func() {
6✔
78
                for i, listener := range b.listeners {
6✔
79
                        if listener == l {
6✔
80
                                // Delete without preserving order:
3✔
81
                                lastIndex := len(b.listeners) - 1
3✔
82
                                b.listeners[i] = b.listeners[lastIndex]
3✔
83
                                b.listeners[lastIndex] = nil
3✔
84
                                b.listeners = b.listeners[:lastIndex]
3✔
85
                                return
3✔
86
                        }
3✔
87
                }
88
        })
89
}
90

91
func (b *base) trigger() {
429✔
92
        fyne.Do(func() {
858✔
93
                for _, listen := range b.listeners {
530✔
94
                        listen.DataChanged()
101✔
95
                }
101✔
96
        })
97
}
98

99
// Untyped supports binding a any value.
100
//
101
// Since: 2.1
102
type Untyped interface {
103
        DataItem
104
        Get() (any, error)
105
        Set(any) error
106
}
107

108
// NewUntyped returns a bindable any value that is managed internally.
109
//
110
// Since: 2.1
111
func NewUntyped() Untyped {
2✔
112
        var blank any = nil
2✔
113
        v := &blank
2✔
114
        return &boundUntyped{val: reflect.ValueOf(v).Elem()}
2✔
115
}
2✔
116

117
type boundUntyped struct {
118
        base
119

120
        val reflect.Value
121
}
122

123
func (b *boundUntyped) Get() (any, error) {
7✔
124
        b.lock.RLock()
7✔
125
        defer b.lock.RUnlock()
7✔
126

7✔
127
        return b.val.Interface(), nil
7✔
128
}
7✔
129

130
func (b *boundUntyped) Set(val any) error {
5✔
131
        b.lock.Lock()
5✔
132
        if b.val.Interface() == val {
6✔
133
                b.lock.Unlock()
1✔
134
                return nil
1✔
135
        }
1✔
136
        if val == nil {
5✔
137
                zeroValue := reflect.Zero(b.val.Type())
1✔
138
                b.val.Set(zeroValue)
1✔
139
        } else {
4✔
140
                b.val.Set(reflect.ValueOf(val))
3✔
141
        }
3✔
142
        b.lock.Unlock()
4✔
143

4✔
144
        fyne.Do(b.trigger)
4✔
145
        return nil
4✔
146
}
147

148
// ExternalUntyped supports binding a any value to an external value.
149
//
150
// Since: 2.1
151
type ExternalUntyped interface {
152
        Untyped
153
        Reload() error
154
}
155

156
// BindUntyped returns a bindable any value that is bound to an external type.
157
// The parameter must be a pointer to the type you wish to bind.
158
//
159
// Since: 2.1
160
func BindUntyped(v any) ExternalUntyped {
2✔
161
        t := reflect.TypeOf(v)
2✔
162
        if t.Kind() != reflect.Ptr {
2✔
163
                fyne.LogError("Invalid type passed to BindUntyped, must be a pointer", nil)
×
UNCOV
164
                v = nil
×
UNCOV
165
        }
×
166

167
        if v == nil {
2✔
168
                var blank any
×
UNCOV
169
                v = &blank // never allow a nil value pointer
×
UNCOV
170
        }
×
171

172
        b := &boundExternalUntyped{}
2✔
173
        b.val = reflect.ValueOf(v).Elem()
2✔
174
        b.old = b.val.Interface()
2✔
175
        return b
2✔
176
}
177

178
type boundExternalUntyped struct {
179
        boundUntyped
180

181
        old any
182
}
183

184
func (b *boundExternalUntyped) Set(val any) error {
5✔
185
        b.lock.Lock()
5✔
186
        if b.old == val {
5✔
187
                b.lock.Unlock()
×
UNCOV
188
                return nil
×
UNCOV
189
        }
×
190
        b.val.Set(reflect.ValueOf(val))
5✔
191
        b.old = val
5✔
192
        b.lock.Unlock()
5✔
193

5✔
194
        fyne.Do(b.trigger)
5✔
195
        return nil
5✔
196
}
197

198
func (b *boundExternalUntyped) Reload() error {
3✔
199
        return b.Set(b.val.Interface())
3✔
200
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc