2
0
mirror of https://github.com/rivo/tview.git synced 2024-11-15 06:12:46 +00:00

Add FormItem field validation

This commit is contained in:
Mike Schinkel 2019-06-10 03:19:36 -04:00
parent 06a95af2a2
commit 733e0871e4
7 changed files with 140 additions and 6 deletions

View File

@ -228,6 +228,11 @@ EventLoop:
a.Stop() a.Stop()
} }
// Allow a validation to short-circuit input handling
if !a.ValidatePrimitive(p, event) {
continue
}
// Pass other key events to the currently focused primitive. // Pass other key events to the currently focused primitive.
if p != nil { if p != nil {
if handler := p.InputHandler(); handler != nil { if handler := p.InputHandler(); handler != nil {
@ -503,3 +508,52 @@ func (a *Application) QueueEvent(event tcell.Event) *Application {
a.events <- event a.events <- event
return a return a
} }
// ValidatePrimitive will call a validation function specific to
// a FormItem set using the SetValidateFunc() methods when one of
// the field exit keys — Enter, Tab, Backtab, or Escape — is used.
// If the validation function returns false the focus will stay on
// the non-valid form field.
func (a *Application) ValidatePrimitive(p Primitive, event *tcell.EventKey) bool {
switch event.Key() {
case tcell.KeyEnter, tcell.KeyTab, tcell.KeyBacktab, tcell.KeyEscape:
// We will check validation below
default:
// No need to check
return true
}
switch p.(type) {
case *InputField:
i := p.(*InputField)
if i.valid == nil {
break
}
return i.valid(i, event)
case *DropDown:
dd := p.(*DropDown)
if dd.valid == nil {
break
}
return dd.valid(dd, event)
case *Checkbox:
cb := p.(*Checkbox)
if cb.valid == nil {
break
}
return cb.valid(cb, event)
default:
b, ok := p.(*Box)
if !ok {
break
}
if b.valid == nil {
break
}
return b.valid(p, event)
}
return true
}

13
box.go
View File

@ -58,6 +58,11 @@ type Box struct {
// An optional function which is called before the box is drawn. // An optional function which is called before the box is drawn.
draw func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) draw func(screen tcell.Screen, x, y, width, height int) (int, int, int, int)
// A callback function to be called when one of the field exit keys — Enter,
// Tab, Backtab, or Escape — is used. If this callback returns false it will
// bypass the input handler and leave the focus on the non-valid field.
valid func(Primitive, *tcell.EventKey) bool
} }
// NewBox returns a Box without a border. // NewBox returns a Box without a border.
@ -231,6 +236,14 @@ func (b *Box) SetTitleAlign(align int) *Box {
return b return b
} }
// SetValidateFunc sets a callback to be called when one of the field exit keys —
// Enter, Tab, Backtab, or Escape — is used. If this callback returns false it
// will stop the input handler from moving focus to a different field.
func (b *Box) SetValidateFunc(handler func(Primitive, *tcell.EventKey) bool) *Box {
b.valid = handler
return b
}
// Draw draws this primitive onto the screen. // Draw draws this primitive onto the screen.
func (b *Box) Draw(screen tcell.Screen) { func (b *Box) Draw(screen tcell.Screen) {
// Don't draw anything if there is no space. // Don't draw anything if there is no space.

View File

@ -42,6 +42,11 @@ type Checkbox struct {
// A callback function set by the Form class and called when the user leaves // A callback function set by the Form class and called when the user leaves
// this form item. // this form item.
finished func(tcell.Key) finished func(tcell.Key)
// A callback function to be called when one of the field exit keys — Enter,
// Tab, Backtab, or Escape — is used. If this callback returns false it will
// bypass the input handler and leave the focus on the non-valid field.
valid func(*Checkbox, *tcell.EventKey) bool
} }
// NewCheckbox returns a new input field. // NewCheckbox returns a new input field.
@ -142,6 +147,14 @@ func (c *Checkbox) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
return c return c
} }
// SetValidateFunc sets a callback to be called when one of the field exit keys —
// Enter, Tab, Backtab, or Escape — is used. If this callback returns false it
// will stop the input handler from moving focus to a different field.
func (c *Checkbox) SetValidateFunc(handler func(*Checkbox, *tcell.EventKey) bool) *Checkbox {
c.valid = handler
return c
}
// Draw draws this primitive onto the screen. // Draw draws this primitive onto the screen.
func (c *Checkbox) Draw(screen tcell.Screen) { func (c *Checkbox) Draw(screen tcell.Screen) {
c.Box.Draw(screen) c.Box.Draw(screen)
@ -254,11 +267,16 @@ type CheckboxArgs struct {
// returns the event to be forwarded to the primitive's default // returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded). // input handler (nil if nothing should be forwarded).
InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey
// A callback function to be called when one of the field exit keys — Enter,
// Tab, Backtab, or Escape — is used. If this callback returns false it will
// bypass the input handler and leave the focus on the non-valid field.
ValidateFunc func(*Checkbox, *tcell.EventKey) bool
} }
// ApplyArgs applies the values from a CheckboxArgs{} struct to the // ApplyArgs applies the values from a CheckboxArgs{} struct to the
// associated properties of the Checkbox. // associated properties of the Checkbox.
func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox{ func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox {
c.SetLabel(args.Label) c.SetLabel(args.Label)
c.SetChecked(args.Checked) c.SetChecked(args.Checked)
@ -288,9 +306,11 @@ func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox{
if args.FinishedFunc != nil { if args.FinishedFunc != nil {
c.SetFinishedFunc(args.FinishedFunc) c.SetFinishedFunc(args.FinishedFunc)
} }
if args.ValidateFunc != nil {
c.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil { if args.InputCaptureFunc != nil {
c.SetInputCapture(args.InputCaptureFunc) c.SetInputCapture(args.InputCaptureFunc)
} }
return c return c
} }

View File

@ -70,6 +70,11 @@ type DropDown struct {
// A callback function which is called when the user changes the drop-down's // A callback function which is called when the user changes the drop-down's
// selection. // selection.
selected func(text string, index int) selected func(text string, index int)
// A callback function to be called when one of the field exit keys — Enter,
// Tab, Backtab, or Escape — is used. If this callback returns false it will
// bypass the input handler and leave the focus on the non-valid field.
valid func(*DropDown, *tcell.EventKey) bool
} }
// NewDropDown returns a new drop-down. // NewDropDown returns a new drop-down.
@ -256,6 +261,14 @@ func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
return d return d
} }
// SetValidateFunc sets a callback to be called when one of the field exit keys —
// Enter, Tab, Backtab, or Escape — is used. If this callback returns false it
// will stop the input handler from moving focus to a different field.
func (d *DropDown) SetValidateFunc(handler func(*DropDown, *tcell.EventKey) bool) *DropDown {
d.valid = handler
return d
}
// Draw draws this primitive onto the screen. // Draw draws this primitive onto the screen.
func (d *DropDown) Draw(screen tcell.Screen) { func (d *DropDown) Draw(screen tcell.Screen) {
d.Box.Draw(screen) d.Box.Draw(screen)
@ -499,8 +512,10 @@ type DropDownArgs struct {
// returns the event to be forwarded to the primitive's default // returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded). // input handler (nil if nothing should be forwarded).
InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey
}
// An optional function which is called before the box is drawn.
ValidateFunc func(*DropDown, *tcell.EventKey) bool
}
// ApplyArgs applies the values from a DropDownArgs{} struct to the // ApplyArgs applies the values from a DropDownArgs{} struct to the
// associated properties of the DropDown. // associated properties of the DropDown.
@ -537,6 +552,9 @@ func (d *DropDown) ApplyArgs(args *DropDownArgs) *DropDown {
if args.FinishedFunc != nil { if args.FinishedFunc != nil {
d.SetFinishedFunc(args.FinishedFunc) d.SetFinishedFunc(args.FinishedFunc)
} }
if args.ValidateFunc != nil {
d.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil { if args.InputCaptureFunc != nil {
d.SetInputCapture(args.InputCaptureFunc) d.SetInputCapture(args.InputCaptureFunc)
} }

View File

@ -85,6 +85,11 @@ type InputField struct {
// A callback function set by the Form class and called when the user leaves // A callback function set by the Form class and called when the user leaves
// this form item. // this form item.
finished func(tcell.Key) finished func(tcell.Key)
// A callback function to be called when one of the field exit keys — Enter,
// Tab, Backtab, or Escape — is used. If this callback returns false it will
// bypass the input handler and leave the focus on the non-valid field.
valid func(*InputField, *tcell.EventKey) bool
} }
// NewInputField returns a new input field. // NewInputField returns a new input field.
@ -226,6 +231,14 @@ func (i *InputField) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
return i return i
} }
// SetValidateFunc sets a callback to be called when one of the field exit keys —
// Enter, Tab, Backtab, or Escape — is used. If this callback returns false it
// will stop the input handler from moving focus to a different field.
func (i *InputField) SetValidateFunc(handler func(*InputField, *tcell.EventKey) bool) *InputField {
i.valid = handler
return i
}
// Draw draws this primitive onto the screen. // Draw draws this primitive onto the screen.
func (i *InputField) Draw(screen tcell.Screen) { func (i *InputField) Draw(screen tcell.Screen) {
i.Box.Draw(screen) i.Box.Draw(screen)
@ -507,6 +520,9 @@ type InputFieldArgs struct {
// returns the event to be forwarded to the primitive's default // returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded). // input handler (nil if nothing should be forwarded).
InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey
// An optional function which is called before the box is drawn.
ValidateFunc func(*InputField, *tcell.EventKey) bool
} }
// ApplyArgs applies the values from a InputFieldArgs{} or PasswordFieldArgs{} // ApplyArgs applies the values from a InputFieldArgs{} or PasswordFieldArgs{}
@ -563,10 +579,11 @@ func (i *InputField) applyInputFieldArgs(args *InputFieldArgs) *InputField {
if args.FinishedFunc != nil { if args.FinishedFunc != nil {
i.SetFinishedFunc(args.FinishedFunc) i.SetFinishedFunc(args.FinishedFunc)
} }
if args.ValidateFunc != nil {
i.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil { if args.InputCaptureFunc != nil {
i.SetInputCapture(args.InputCaptureFunc) i.SetInputCapture(args.InputCaptureFunc)
} }
return i return i
} }

View File

@ -64,6 +64,9 @@ type PasswordFieldArgs struct {
// returns the event to be forwarded to the primitive's default // returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded). // input handler (nil if nothing should be forwarded).
InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey InputCaptureFunc func(event *tcell.EventKey) *tcell.EventKey
// An optional function which is called before the box is drawn.
ValidateFunc func(*InputField, *tcell.EventKey) bool
} }
// applyPasswordFieldArgs applies the values from a PasswordFieldArgs{} // applyPasswordFieldArgs applies the values from a PasswordFieldArgs{}
@ -99,9 +102,11 @@ func (i *InputField) applyPasswordFieldArgs(args *PasswordFieldArgs) *InputField
if args.FinishedFunc != nil { if args.FinishedFunc != nil {
i.SetFinishedFunc(args.FinishedFunc) i.SetFinishedFunc(args.FinishedFunc)
} }
if args.ValidateFunc != nil {
i.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil { if args.InputCaptureFunc != nil {
i.SetInputCapture(args.InputCaptureFunc) i.SetInputCapture(args.InputCaptureFunc)
} }
return i return i
} }

7
validation.go Normal file
View File

@ -0,0 +1,7 @@
package tview
import "github.com/gdamore/tcell"
type PrimitiveValidationHandler interface {
Validate(p Primitive, key *tcell.EventKey) bool
}