219 lines
4.0 KiB
Go
219 lines
4.0 KiB
Go
|
package binding
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"fyne.io/fyne/v2/storage"
|
||
|
)
|
||
|
|
||
|
type sprintfString struct {
|
||
|
String
|
||
|
|
||
|
format string
|
||
|
source []DataItem
|
||
|
err error
|
||
|
}
|
||
|
|
||
|
// NewSprintf returns a String binding that format its content using the
|
||
|
// format string and the provide additional parameter that must be other
|
||
|
// data bindings. This data binding use fmt.Sprintf and fmt.Scanf internally
|
||
|
// and will have all the same limitation as those function.
|
||
|
//
|
||
|
// Since: 2.2
|
||
|
func NewSprintf(format string, b ...DataItem) String {
|
||
|
ret := &sprintfString{
|
||
|
String: NewString(),
|
||
|
format: format,
|
||
|
source: append(make([]DataItem, 0, len(b)), b...),
|
||
|
}
|
||
|
|
||
|
for _, value := range b {
|
||
|
value.AddListener(ret)
|
||
|
}
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (s *sprintfString) DataChanged() {
|
||
|
data := make([]interface{}, 0, len(s.source))
|
||
|
|
||
|
s.err = nil
|
||
|
for _, value := range s.source {
|
||
|
switch x := value.(type) {
|
||
|
case Bool:
|
||
|
b, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, b)
|
||
|
case Bytes:
|
||
|
b, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, b)
|
||
|
case Float:
|
||
|
f, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, f)
|
||
|
case Int:
|
||
|
i, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, i)
|
||
|
case Rune:
|
||
|
r, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, r)
|
||
|
case String:
|
||
|
str, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
// Set error?
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, str)
|
||
|
case URI:
|
||
|
u, err := x.Get()
|
||
|
if err != nil {
|
||
|
s.err = err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data = append(data, u)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
r := fmt.Sprintf(s.format, data...)
|
||
|
s.String.Set(r)
|
||
|
}
|
||
|
|
||
|
func (s *sprintfString) Get() (string, error) {
|
||
|
if s.err != nil {
|
||
|
return "", s.err
|
||
|
}
|
||
|
return s.String.Get()
|
||
|
}
|
||
|
|
||
|
func (s *sprintfString) Set(str string) error {
|
||
|
data := make([]interface{}, 0, len(s.source))
|
||
|
|
||
|
s.err = nil
|
||
|
for _, value := range s.source {
|
||
|
switch value.(type) {
|
||
|
case Bool:
|
||
|
data = append(data, new(bool))
|
||
|
case Bytes:
|
||
|
return fmt.Errorf("impossible to convert '%s' to []bytes type", str)
|
||
|
case Float:
|
||
|
data = append(data, new(float64))
|
||
|
case Int:
|
||
|
data = append(data, new(int))
|
||
|
case Rune:
|
||
|
data = append(data, new(rune))
|
||
|
case String:
|
||
|
data = append(data, new(string))
|
||
|
case URI:
|
||
|
data = append(data, new(string))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
count, err := fmt.Sscanf(str, s.format, data...)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if count != len(data) {
|
||
|
return fmt.Errorf("impossible to decode more than %v parameters in '%s' with format '%s'", count, str, s.format)
|
||
|
}
|
||
|
|
||
|
for i, value := range s.source {
|
||
|
switch x := value.(type) {
|
||
|
case Bool:
|
||
|
v := data[i].(*bool)
|
||
|
|
||
|
err := x.Set(*v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case Bytes:
|
||
|
return fmt.Errorf("impossible to convert '%s' to []bytes type", str)
|
||
|
case Float:
|
||
|
v := data[i].(*float64)
|
||
|
|
||
|
err := x.Set(*v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case Int:
|
||
|
v := data[i].(*int)
|
||
|
|
||
|
err := x.Set(*v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case Rune:
|
||
|
v := data[i].(*rune)
|
||
|
|
||
|
err := x.Set(*v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case String:
|
||
|
v := data[i].(*string)
|
||
|
|
||
|
err := x.Set(*v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case URI:
|
||
|
v := data[i].(*string)
|
||
|
|
||
|
if v == nil {
|
||
|
return fmt.Errorf("URI can not be nil in '%s'", str)
|
||
|
}
|
||
|
|
||
|
uri, err := storage.ParseURI(*v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = x.Set(uri)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// StringToStringWithFormat creates a binding that converts a string to another string using the specified format.
|
||
|
// Changes to the returned String will be pushed to the passed in String and setting a new string value will parse and
|
||
|
// set the underlying String if it matches the format and the parse was successful.
|
||
|
//
|
||
|
// Since: 2.2
|
||
|
func StringToStringWithFormat(str String, format string) String {
|
||
|
if format == "%s" { // Same as not using custom formatting.
|
||
|
return str
|
||
|
}
|
||
|
|
||
|
return NewSprintf(format, str)
|
||
|
}
|