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

fyne-io / fyne / 13155932935

05 Feb 2025 11:03AM UTC coverage: 62.565% (-0.07%) from 62.633%
13155932935

push

github

web-flow
Merge pull request #5499 from fyne-io/dweymouth-patch-1

Fix a bug with previous GridWrap PR

2 of 2 new or added lines in 1 file covered. (100.0%)

87 existing lines in 4 files now uncovered.

24750 of 39559 relevant lines covered (62.56%)

843.3 hits per line

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

87.79
/data/binding/items.go
1
package binding
2

3
import (
4
        "bytes"
5
        "sync/atomic"
6

7
        "fyne.io/fyne/v2"
8
        "fyne.io/fyne/v2/storage"
9
)
10

11
// Bool supports binding a bool value.
12
//
13
// Since: 2.0
14
type Bool interface {
15
        DataItem
16
        Get() (bool, error)
17
        Set(bool) error
18
}
19

20
// ExternalBool supports binding a bool value to an external value.
21
//
22
// Since: 2.0
23
type ExternalBool interface {
24
        Bool
25
        Reload() error
26
}
27

28
// NewBool returns a bindable bool value that is managed internally.
29
//
30
// Since: 2.0
31
func NewBool() Bool {
2✔
32
        return newBaseItemComparable[bool]()
2✔
33
}
2✔
34

35
// BindBool returns a new bindable value that controls the contents of the provided bool variable.
36
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
37
//
38
// Since: 2.0
39
func BindBool(v *bool) ExternalBool {
13✔
40
        return baseBindExternalComparable(v)
13✔
41
}
13✔
42

43
// Bytes supports binding a []byte value.
44
//
45
// Since: 2.2
46
type Bytes interface {
47
        DataItem
48
        Get() ([]byte, error)
49
        Set([]byte) error
50
}
51

52
// ExternalBytes supports binding a []byte value to an external value.
53
//
54
// Since: 2.2
55
type ExternalBytes interface {
56
        Bytes
57
        Reload() error
58
}
59

60
// NewBytes returns a bindable []byte value that is managed internally.
61
//
62
// Since: 2.2
63
func NewBytes() Bytes {
×
64
        return newBaseItem(bytes.Equal)
×
UNCOV
65
}
×
66

67
// BindBytes returns a new bindable value that controls the contents of the provided []byte variable.
68
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
69
//
70
// Since: 2.2
71
func BindBytes(v *[]byte) ExternalBytes {
×
72
        return baseBindExternal(v, bytes.Equal)
×
UNCOV
73
}
×
74

75
// Float supports binding a float64 value.
76
//
77
// Since: 2.0
78
type Float interface {
79
        DataItem
80
        Get() (float64, error)
81
        Set(float64) error
82
}
83

84
// ExternalFloat supports binding a float64 value to an external value.
85
//
86
// Since: 2.0
87
type ExternalFloat interface {
88
        Float
89
        Reload() error
90
}
91

92
// NewFloat returns a bindable float64 value that is managed internally.
93
//
94
// Since: 2.0
95
func NewFloat() Float {
7✔
96
        return newBaseItemComparable[float64]()
7✔
97
}
7✔
98

99
// BindFloat returns a new bindable value that controls the contents of the provided float64 variable.
100
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
101
//
102
// Since: 2.0
103
func BindFloat(v *float64) ExternalFloat {
6✔
104
        return baseBindExternalComparable(v)
6✔
105
}
6✔
106

107
// Int supports binding a int value.
108
//
109
// Since: 2.0
110
type Int interface {
111
        DataItem
112
        Get() (int, error)
113
        Set(int) error
114
}
115

116
// ExternalInt supports binding a int value to an external value.
117
//
118
// Since: 2.0
119
type ExternalInt interface {
120
        Int
121
        Reload() error
122
}
123

124
// NewInt returns a bindable int value that is managed internally.
125
//
126
// Since: 2.0
127
func NewInt() Int {
5✔
128
        return newBaseItemComparable[int]()
5✔
129
}
5✔
130

131
// BindInt returns a new bindable value that controls the contents of the provided int variable.
132
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
133
//
134
// Since: 2.0
135
func BindInt(v *int) ExternalInt {
2✔
136
        return baseBindExternalComparable(v)
2✔
137
}
2✔
138

139
// Rune supports binding a rune value.
140
//
141
// Since: 2.0
142
type Rune interface {
143
        DataItem
144
        Get() (rune, error)
145
        Set(rune) error
146
}
147

148
// ExternalRune supports binding a rune value to an external value.
149
//
150
// Since: 2.0
151
type ExternalRune interface {
152
        Rune
153
        Reload() error
154
}
155

156
// NewRune returns a bindable rune value that is managed internally.
157
//
158
// Since: 2.0
159
func NewRune() Rune {
×
160
        return newBaseItemComparable[rune]()
×
UNCOV
161
}
×
162

163
// BindRune returns a new bindable value that controls the contents of the provided rune variable.
164
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
165
//
166
// Since: 2.0
167
func BindRune(v *rune) ExternalRune {
2✔
168
        return baseBindExternalComparable(v)
2✔
169
}
2✔
170

171
// String supports binding a string value.
172
//
173
// Since: 2.0
174
type String interface {
175
        DataItem
176
        Get() (string, error)
177
        Set(string) error
178
}
179

180
// ExternalString supports binding a string value to an external value.
181
//
182
// Since: 2.0
183
type ExternalString interface {
184
        String
185
        Reload() error
186
}
187

188
// NewString returns a bindable string value that is managed internally.
189
//
190
// Since: 2.0
191
func NewString() String {
7✔
192
        return newBaseItemComparable[string]()
7✔
193
}
7✔
194

195
// BindString returns a new bindable value that controls the contents of the provided string variable.
196
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
197
//
198
// Since: 2.0
199
func BindString(v *string) ExternalString {
6✔
200
        return baseBindExternalComparable(v)
6✔
201
}
6✔
202

203
// URI supports binding a fyne.URI value.
204
//
205
// Since: 2.1
206
type URI interface {
207
        DataItem
208
        Get() (fyne.URI, error)
209
        Set(fyne.URI) error
210
}
211

212
// ExternalURI supports binding a fyne.URI value to an external value.
213
//
214
// Since: 2.1
215
type ExternalURI interface {
216
        URI
217
        Reload() error
218
}
219

220
// NewURI returns a bindable fyne.URI value that is managed internally.
221
//
222
// Since: 2.1
223
func NewURI() URI {
3✔
224
        return newBaseItem(storage.EqualURI)
3✔
225
}
3✔
226

227
// BindURI returns a new bindable value that controls the contents of the provided fyne.URI variable.
228
// If your code changes the content of the variable this refers to you should call Reload() to inform the bindings.
229
//
230
// Since: 2.1
231
func BindURI(v *fyne.URI) ExternalURI {
4✔
232
        return baseBindExternal(v, storage.EqualURI)
4✔
233
}
4✔
234

235
type bindableItem[T any] interface {
236
        DataItem
237
        Get() (T, error)
238
        Set(T) error
239
}
240

241
func newBaseItem[T any](comparator func(T, T) bool) *baseItem[T] {
24✔
242
        return &baseItem[T]{val: new(T), comparator: comparator}
24✔
243
}
24✔
244

245
func newBaseItemComparable[T bool | float64 | int | rune | string]() *baseItem[T] {
21✔
246
        return newBaseItem[T](func(a, b T) bool { return a == b })
84✔
247
}
248

249
type baseItem[T any] struct {
250
        base
251

252
        comparator func(T, T) bool
253
        val        *T
254
}
255

256
func (b *baseItem[T]) Get() (T, error) {
359✔
257
        b.lock.RLock()
359✔
258
        defer b.lock.RUnlock()
359✔
259

359✔
260
        if b.val == nil {
359✔
UNCOV
261
                return *new(T), nil
×
UNCOV
262
        }
×
263
        return *b.val, nil
359✔
264
}
265

266
func (b *baseItem[T]) Set(val T) error {
72✔
267
        b.lock.Lock()
72✔
268
        equal := b.comparator(*b.val, val)
72✔
269
        *b.val = val
72✔
270
        b.lock.Unlock()
72✔
271

72✔
272
        if !equal {
126✔
273
                b.trigger()
54✔
274
        }
54✔
275

276
        return nil
72✔
277
}
278

279
func baseBindExternal[T any](val *T, comparator func(T, T) bool) *baseExternalItem[T] {
4✔
280
        if val == nil {
4✔
UNCOV
281
                val = new(T) // never allow a nil value pointer
×
UNCOV
282
        }
×
283
        b := &baseExternalItem[T]{}
4✔
284
        b.comparator = comparator
4✔
285
        b.val = val
4✔
286
        b.old = *val
4✔
287
        return b
4✔
288
}
289

290
func baseBindExternalComparable[T bool | float64 | int | rune | string](val *T) *baseExternalItem[T] {
29✔
291
        if val == nil {
29✔
UNCOV
292
                val = new(T) // never allow a nil value pointer
×
UNCOV
293
        }
×
294
        b := &baseExternalItem[T]{}
29✔
295
        b.comparator = func(a, b T) bool { return a == b }
381✔
296
        b.val = val
29✔
297
        b.old = *val
29✔
298
        return b
29✔
299
}
300

301
type baseExternalItem[T any] struct {
302
        baseItem[T]
303

304
        old T
305
}
306

307
func (b *baseExternalItem[T]) Set(val T) error {
364✔
308
        b.lock.Lock()
364✔
309
        if b.comparator(b.old, val) {
580✔
310
                b.lock.Unlock()
216✔
311
                return nil
216✔
312
        }
216✔
313
        *b.val = val
148✔
314
        b.old = val
148✔
315
        b.lock.Unlock()
148✔
316

148✔
317
        b.trigger()
148✔
318
        return nil
148✔
319
}
320

321
func (b *baseExternalItem[T]) Reload() error {
6✔
322
        return b.Set(*b.val)
6✔
323
}
6✔
324

325
type prefBoundBase[T bool | float64 | int | string] struct {
326
        base
327
        key   string
328
        get   func(string) T
329
        set   func(string, T)
330
        cache atomic.Pointer[T]
331
}
332

333
func (b *prefBoundBase[T]) Get() (T, error) {
12✔
334
        cache := b.get(b.key)
12✔
335
        b.cache.Store(&cache)
12✔
336
        return cache, nil
12✔
337
}
12✔
338

339
func (b *prefBoundBase[T]) Set(v T) error {
6✔
340
        b.set(b.key, v)
6✔
341

6✔
342
        b.lock.RLock()
6✔
343
        defer b.lock.RUnlock()
6✔
344
        b.trigger()
6✔
345
        return nil
6✔
346
}
6✔
347

348
func (b *prefBoundBase[T]) setKey(key string) {
6✔
349
        b.key = key
6✔
350
}
6✔
351

352
func (b *prefBoundBase[T]) checkForChange() {
17✔
353
        val := b.cache.Load()
17✔
354
        if val != nil && b.get(b.key) == *val {
21✔
355
                return
4✔
356
        }
4✔
357
        b.trigger()
13✔
358
}
359

360
func lookupExistingBinding[T any](key string, p fyne.Preferences) (bindableItem[T], bool) {
108✔
361
        binds := prefBinds.getBindings(p)
108✔
362
        if binds == nil {
110✔
363
                return nil, false
2✔
364
        }
2✔
365

366
        if listen, ok := binds.Load(key); listen != nil && ok {
208✔
367
                if l, ok := listen.(bindableItem[T]); ok {
204✔
368
                        return l, ok
102✔
369
                }
102✔
UNCOV
370
                fyne.LogError(keyTypeMismatchError+key, nil)
×
371
        }
372

373
        return nil, false
4✔
374
}
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