| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- 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)
- }
|