• 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

81.42
/data/binding/convert.go
1
package binding
2

3
import (
4
        "fmt"
5

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

10
// BoolToString creates a binding that connects a Bool data item to a String.
11
// Changes to the Bool will be pushed to the String and setting the string will parse and set the
12
// Bool if the parse was successful.
13
//
14
// Since: 2.0
15
func BoolToString(v Bool) String {
1✔
16
        return toStringComparable[bool](v, formatBool, parseBool)
1✔
17
}
1✔
18

19
// BoolToStringWithFormat creates a binding that connects a Bool data item to a String and is
20
// presented using the specified format. Changes to the Bool will be pushed to the String and setting
21
// the string will parse and set the Bool if the string matches the format and its parse was successful.
22
//
23
// Since: 2.0
24
func BoolToStringWithFormat(v Bool, format string) String {
1✔
25
        return toStringWithFormatComparable[bool](v, format, "%t", formatBool, parseBool)
1✔
26
}
1✔
27

28
// FloatToString creates a binding that connects a Float data item to a String.
29
// Changes to the Float will be pushed to the String and setting the string will parse and set the
30
// Float if the parse was successful.
31
//
32
// Since: 2.0
33
func FloatToString(v Float) String {
1✔
34
        return toStringComparable[float64](v, formatFloat, parseFloat)
1✔
35
}
1✔
36

37
// FloatToStringWithFormat creates a binding that connects a Float data item to a String and is
38
// presented using the specified format. Changes to the Float will be pushed to the String and setting
39
// the string will parse and set the Float if the string matches the format and its parse was successful.
40
//
41
// Since: 2.0
42
func FloatToStringWithFormat(v Float, format string) String {
1✔
43
        return toStringWithFormatComparable[float64](v, format, "%f", formatFloat, parseFloat)
1✔
44
}
1✔
45

46
// IntToFloat creates a binding that connects an Int data item to a Float.
47
//
48
// Since: 2.5
49
func IntToFloat(val Int) Float {
1✔
50
        v := &fromIntTo[float64]{from: val, parser: internalFloatToInt, formatter: internalIntToFloat}
1✔
51
        val.AddListener(v)
1✔
52
        return v
1✔
53
}
1✔
54

55
// FloatToInt creates a binding that connects a Float data item to an Int.
56
//
57
// Since: 2.5
58
func FloatToInt(v Float) Int {
1✔
59
        i := &toInt[float64]{from: v, parser: internalFloatToInt, formatter: internalIntToFloat}
1✔
60
        v.AddListener(i)
1✔
61
        return i
1✔
62
}
1✔
63

64
// IntToString creates a binding that connects a Int data item to a String.
65
// Changes to the Int will be pushed to the String and setting the string will parse and set the
66
// Int if the parse was successful.
67
//
68
// Since: 2.0
69
func IntToString(v Int) String {
1✔
70
        return toStringComparable[int](v, formatInt, parseInt)
1✔
71
}
1✔
72

73
// IntToStringWithFormat creates a binding that connects a Int data item to a String and is
74
// presented using the specified format. Changes to the Int will be pushed to the String and setting
75
// the string will parse and set the Int if the string matches the format and its parse was successful.
76
//
77
// Since: 2.0
78
func IntToStringWithFormat(v Int, format string) String {
1✔
79
        return toStringWithFormatComparable[int](v, format, "%d", formatInt, parseInt)
1✔
80
}
1✔
81

82
// URIToString creates a binding that connects a URI data item to a String.
83
// Changes to the URI will be pushed to the String and setting the string will parse and set the
84
// URI if the parse was successful.
85
//
86
// Since: 2.1
87
func URIToString(v URI) String {
1✔
88
        return toString[fyne.URI](v, uriToString, storage.EqualURI, uriFromString)
1✔
89
}
1✔
90

91
// StringToBool creates a binding that connects a String data item to a Bool.
92
// Changes to the String will be parsed and pushed to the Bool if the parse was successful, and setting
93
// the Bool update the String binding.
94
//
95
// Since: 2.0
96
func StringToBool(str String) Bool {
1✔
97
        v := &fromStringTo[bool]{from: str, formatter: parseBool, parser: formatBool}
1✔
98
        str.AddListener(v)
1✔
99
        return v
1✔
100
}
1✔
101

102
// StringToBoolWithFormat creates a binding that connects a String data item to a Bool and is
103
// presented using the specified format. Changes to the Bool will be parsed and if the format matches and
104
// the parse is successful it will be pushed to the String. Setting the Bool will push a formatted value
105
// into the String.
106
//
107
// Since: 2.0
108
func StringToBoolWithFormat(str String, format string) Bool {
1✔
109
        if format == "%t" { // Same as not using custom format.
1✔
UNCOV
110
                return StringToBool(str)
×
UNCOV
111
        }
×
112

113
        v := &fromStringTo[bool]{from: str, format: format}
1✔
114
        str.AddListener(v)
1✔
115
        return v
1✔
116
}
117

118
// StringToFloat creates a binding that connects a String data item to a Float.
119
// Changes to the String will be parsed and pushed to the Float if the parse was successful, and setting
120
// the Float update the String binding.
121
//
122
// Since: 2.0
123
func StringToFloat(str String) Float {
1✔
124
        v := &fromStringTo[float64]{from: str, formatter: parseFloat, parser: formatFloat}
1✔
125
        str.AddListener(v)
1✔
126
        return v
1✔
127
}
1✔
128

129
// StringToFloatWithFormat creates a binding that connects a String data item to a Float and is
130
// presented using the specified format. Changes to the Float will be parsed and if the format matches and
131
// the parse is successful it will be pushed to the String. Setting the Float will push a formatted value
132
// into the String.
133
//
134
// Since: 2.0
135
func StringToFloatWithFormat(str String, format string) Float {
1✔
136
        if format == "%f" { // Same as not using custom format.
1✔
UNCOV
137
                return StringToFloat(str)
×
UNCOV
138
        }
×
139

140
        v := &fromStringTo[float64]{from: str, format: format}
1✔
141
        str.AddListener(v)
1✔
142
        return v
1✔
143
}
144

145
// StringToInt creates a binding that connects a String data item to a Int.
146
// Changes to the String will be parsed and pushed to the Int if the parse was successful, and setting
147
// the Int update the String binding.
148
//
149
// Since: 2.0
150
func StringToInt(str String) Int {
1✔
151
        v := &fromStringTo[int]{from: str, parser: formatInt, formatter: parseInt}
1✔
152
        str.AddListener(v)
1✔
153
        return v
1✔
154
}
1✔
155

156
// StringToIntWithFormat creates a binding that connects a String data item to a Int and is
157
// presented using the specified format. Changes to the Int will be parsed and if the format matches and
158
// the parse is successful it will be pushed to the String. Setting the Int will push a formatted value
159
// into the String.
160
//
161
// Since: 2.0
162
func StringToIntWithFormat(str String, format string) Int {
1✔
163
        if format == "%d" { // Same as not using custom format.
1✔
UNCOV
164
                return StringToInt(str)
×
UNCOV
165
        }
×
166

167
        v := &fromStringTo[int]{from: str, format: format}
1✔
168
        str.AddListener(v)
1✔
169
        return v
1✔
170
}
171

172
// StringToURI creates a binding that connects a String data item to a URI.
173
// Changes to the String will be parsed and pushed to the URI if the parse was successful, and setting
174
// the URI update the String binding.
175
//
176
// Since: 2.1
177
func StringToURI(str String) URI {
1✔
178
        v := &fromStringTo[fyne.URI]{from: str, parser: uriToString, formatter: uriFromString}
1✔
179
        str.AddListener(v)
1✔
180
        return v
1✔
181
}
1✔
182

183
func toString[T any](v bindableItem[T], formatter func(T) (string, error), comparator func(T, T) bool, parser func(string) (T, error)) *toStringFrom[T] {
7✔
184
        str := &toStringFrom[T]{from: v, formatter: formatter, comparator: comparator, parser: parser}
7✔
185
        v.AddListener(str)
7✔
186
        return str
7✔
187
}
7✔
188

189
func toStringComparable[T bool | float64 | int](v bindableItem[T], formatter func(T) (string, error), parser func(string) (T, error)) *toStringFrom[T] {
3✔
190
        return toString(v, formatter, func(t1, t2 T) bool { return t1 == t2 }, parser)
6✔
191
}
192

193
func toStringWithFormat[T any](v bindableItem[T], format, defaultFormat string, formatter func(T) (string, error), comparator func(T, T) bool, parser func(string) (T, error)) String {
3✔
194
        str := toString(v, formatter, comparator, parser)
3✔
195
        if format != defaultFormat { // Same as not using custom formatting.
6✔
196
                str.format = format
3✔
197
        }
3✔
198

199
        return str
3✔
200
}
201

202
func toStringWithFormatComparable[T bool | float64 | int](v bindableItem[T], format, defaultFormat string, formatter func(T) (string, error), parser func(string) (T, error)) String {
3✔
203
        return toStringWithFormat(v, format, defaultFormat, formatter, func(t1, t2 T) bool { return t1 == t2 }, parser)
6✔
204
}
205

206
type toStringFrom[T any] struct {
207
        base
208

209
        format string
210

211
        formatter  func(T) (string, error)
212
        comparator func(T, T) bool
213
        parser     func(string) (T, error)
214

215
        from bindableItem[T]
216
}
217

218
func (s *toStringFrom[T]) Get() (string, error) {
14✔
219
        val, err := s.from.Get()
14✔
220
        if err != nil {
14✔
UNCOV
221
                return "", err
×
222
        }
×
223

224
        if s.format != "" {
20✔
225
                return fmt.Sprintf(s.format, val), nil
6✔
226
        }
6✔
227

228
        return s.formatter(val)
8✔
229
}
230

231
func (s *toStringFrom[T]) Set(str string) error {
13✔
232
        var val T
13✔
233
        if s.format != "" {
19✔
234
                safe := stripFormatPrecision(s.format)
6✔
235
                n, err := fmt.Sscanf(str, safe+" ", &val) // " " denotes match to end of string
6✔
236
                if err != nil {
9✔
237
                        return err
3✔
238
                }
3✔
239
                if n != 1 {
3✔
UNCOV
240
                        return errParseFailed
×
UNCOV
241
                }
×
242
        } else {
7✔
243
                new, err := s.parser(str)
7✔
244
                if err != nil {
10✔
245
                        return err
3✔
246
                }
3✔
247
                val = new
4✔
248
        }
249

250
        old, err := s.from.Get()
7✔
251
        if err != nil {
7✔
UNCOV
252
                return err
×
253
        }
×
254
        if s.comparator(val, old) {
8✔
255
                return nil
1✔
256
        }
1✔
257
        if err = s.from.Set(val); err != nil {
6✔
UNCOV
258
                return err
×
UNCOV
259
        }
×
260

261
        queueItem(s.DataChanged)
6✔
262
        return nil
6✔
263
}
264

265
func (s *toStringFrom[T]) DataChanged() {
26✔
266
        s.trigger()
26✔
267
}
26✔
268

269
type fromStringTo[T any] struct {
270
        base
271

272
        format    string
273
        formatter func(string) (T, error)
274
        parser    func(T) (string, error)
275

276
        from String
277
}
278

279
func (s *fromStringTo[T]) Get() (T, error) {
20✔
280
        str, err := s.from.Get()
20✔
281
        if str == "" || err != nil {
24✔
282
                return *new(T), err
4✔
283
        }
4✔
284

285
        var val T
16✔
286
        if s.format != "" {
25✔
287
                n, err := fmt.Sscanf(str, s.format+" ", &val) // " " denotes match to end of string
9✔
288
                if err != nil {
12✔
289
                        return *new(T), err
3✔
290
                }
3✔
291
                if n != 1 {
6✔
UNCOV
292
                        return *new(T), errParseFailed
×
UNCOV
293
                }
×
294
        } else {
7✔
295
                formatted, err := s.formatter(str)
7✔
296
                if err != nil {
10✔
297
                        return *new(T), err
3✔
298
                }
3✔
299
                val = formatted
4✔
300
        }
301

302
        return val, nil
10✔
303
}
304

305
func (s *fromStringTo[T]) Set(val T) error {
7✔
306
        var str string
7✔
307
        if s.format != "" {
10✔
308
                str = fmt.Sprintf(s.format, val)
3✔
309
        } else {
7✔
310
                parsed, err := s.parser(val)
4✔
311
                if err != nil {
4✔
UNCOV
312
                        return err
×
UNCOV
313
                }
×
314
                str = parsed
4✔
315
        }
316

317
        old, err := s.from.Get()
7✔
318
        if str == old {
7✔
UNCOV
319
                return err
×
320
        }
×
321

322
        err = s.from.Set(str)
7✔
323
        if err != nil {
7✔
UNCOV
324
                return err
×
UNCOV
325
        }
×
326

327
        queueItem(s.DataChanged)
7✔
328
        return nil
7✔
329
}
330

331
func (s *fromStringTo[T]) DataChanged() {
34✔
332
        s.trigger()
34✔
333
}
34✔
334

335
type toInt[T float64] struct {
336
        base
337

338
        formatter func(int) (T, error)
339
        parser    func(T) (int, error)
340

341
        from bindableItem[T]
342
}
343

344
func (s *toInt[T]) Get() (int, error) {
2✔
345
        val, err := s.from.Get()
2✔
346
        if err != nil {
2✔
UNCOV
347
                return 0, err
×
UNCOV
348
        }
×
349
        return s.parser(val)
2✔
350
}
351

352
func (s *toInt[T]) Set(v int) error {
1✔
353
        val, err := s.formatter(v)
1✔
354
        if err != nil {
1✔
355
                return err
×
UNCOV
356
        }
×
357

358
        old, err := s.from.Get()
1✔
359
        if err != nil {
1✔
UNCOV
360
                return err
×
UNCOV
361
        }
×
362
        if val == old {
1✔
UNCOV
363
                return nil
×
UNCOV
364
        }
×
365
        err = s.from.Set(val)
1✔
366
        if err != nil {
1✔
UNCOV
367
                return err
×
UNCOV
368
        }
×
369

370
        queueItem(s.DataChanged)
1✔
371
        return nil
1✔
372
}
373

374
func (s *toInt[T]) DataChanged() {
4✔
375
        s.trigger()
4✔
376
}
4✔
377

378
type fromIntTo[T float64] struct {
379
        base
380

381
        formatter func(int) (T, error)
382
        parser    func(T) (int, error)
383
        from      bindableItem[int]
384
}
385

386
func (s *fromIntTo[T]) Get() (T, error) {
2✔
387
        val, err := s.from.Get()
2✔
388
        if err != nil {
2✔
389
                return *new(T), err
×
UNCOV
390
        }
×
391
        return s.formatter(val)
2✔
392
}
393

394
func (s *fromIntTo[T]) Set(val T) error {
1✔
395
        i, err := s.parser(val)
1✔
396
        if err != nil {
1✔
397
                return err
×
398
        }
×
399
        old, err := s.from.Get()
1✔
400
        if i == old {
1✔
UNCOV
401
                return nil
×
402
        }
×
403
        if err != nil {
1✔
UNCOV
404
                return err
×
405
        }
×
406
        err = s.from.Set(i)
1✔
407
        if err != nil {
1✔
408
                return err
×
409
        }
×
410

411
        queueItem(s.DataChanged)
1✔
412
        return nil
1✔
413
}
414

415
func (s *fromIntTo[T]) DataChanged() {
4✔
416
        s.trigger()
4✔
417
}
4✔
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