entry_validation.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package widget
  2. import (
  3. "errors"
  4. "fyne.io/fyne/v2"
  5. "fyne.io/fyne/v2/canvas"
  6. "fyne.io/fyne/v2/theme"
  7. )
  8. var _ fyne.Validatable = (*Entry)(nil)
  9. // Validate validates the current text in the widget
  10. func (e *Entry) Validate() error {
  11. if e.Validator == nil {
  12. return nil
  13. }
  14. err := e.Validator(e.Text)
  15. e.SetValidationError(err)
  16. return err
  17. }
  18. // SetOnValidationChanged is intended for parent widgets or containers to hook into the validation.
  19. // The function might be overwritten by a parent that cares about child validation (e.g. widget.Form).
  20. func (e *Entry) SetOnValidationChanged(callback func(error)) {
  21. e.onValidationChanged = callback
  22. }
  23. // SetValidationError manually updates the validation status until the next input change
  24. func (e *Entry) SetValidationError(err error) {
  25. if e.Validator == nil {
  26. return
  27. }
  28. if err == nil && e.validationError == nil {
  29. return
  30. }
  31. if !errors.Is(err, e.validationError) {
  32. e.validationError = err
  33. if e.onValidationChanged != nil {
  34. e.onValidationChanged(err)
  35. }
  36. e.Refresh()
  37. }
  38. }
  39. var _ fyne.Widget = (*validationStatus)(nil)
  40. type validationStatus struct {
  41. BaseWidget
  42. entry *Entry
  43. }
  44. func newValidationStatus(e *Entry) *validationStatus {
  45. rs := &validationStatus{
  46. entry: e,
  47. }
  48. rs.ExtendBaseWidget(rs)
  49. return rs
  50. }
  51. func (r *validationStatus) CreateRenderer() fyne.WidgetRenderer {
  52. icon := &canvas.Image{}
  53. icon.Hide()
  54. return &validationStatusRenderer{
  55. WidgetRenderer: NewSimpleRenderer(icon),
  56. icon: icon,
  57. entry: r.entry,
  58. }
  59. }
  60. var _ fyne.WidgetRenderer = (*validationStatusRenderer)(nil)
  61. type validationStatusRenderer struct {
  62. fyne.WidgetRenderer
  63. entry *Entry
  64. icon *canvas.Image
  65. }
  66. func (r *validationStatusRenderer) Layout(size fyne.Size) {
  67. r.icon.Resize(fyne.NewSize(theme.IconInlineSize(), theme.IconInlineSize()))
  68. r.icon.Move(fyne.NewPos((size.Width-theme.IconInlineSize())/2, (size.Height-theme.IconInlineSize())/2))
  69. }
  70. func (r *validationStatusRenderer) MinSize() fyne.Size {
  71. return fyne.NewSize(theme.IconInlineSize(), theme.IconInlineSize())
  72. }
  73. func (r *validationStatusRenderer) Refresh() {
  74. r.entry.propertyLock.RLock()
  75. defer r.entry.propertyLock.RUnlock()
  76. if r.entry.disabled {
  77. r.icon.Hide()
  78. return
  79. }
  80. if r.entry.validationError == nil && r.entry.Text != "" {
  81. r.icon.Resource = theme.ConfirmIcon()
  82. r.icon.Show()
  83. } else if r.entry.validationError != nil && !r.entry.focused && r.entry.dirty {
  84. r.icon.Resource = theme.NewErrorThemedResource(theme.ErrorIcon())
  85. r.icon.Show()
  86. } else {
  87. r.icon.Hide()
  88. }
  89. r.icon.Refresh()
  90. }