Add FormItem field validation

pull/301/head
Mike Schinkel 5 years ago
parent 06a95af2a2
commit 733e0871e4

@ -228,6 +228,11 @@ EventLoop:
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.
if p != nil {
if handler := p.InputHandler(); handler != nil {
@ -503,3 +508,52 @@ func (a *Application) QueueEvent(event tcell.Event) *Application {
a.events <- event
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
}

@ -58,6 +58,11 @@ type Box struct {
// 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)
// 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.
@ -231,6 +236,14 @@ func (b *Box) SetTitleAlign(align int) *Box {
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.
func (b *Box) Draw(screen tcell.Screen) {
// Don't draw anything if there is no space.

@ -42,6 +42,11 @@ type Checkbox struct {
// A callback function set by the Form class and called when the user leaves
// this form item.
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.
@ -142,6 +147,14 @@ func (c *Checkbox) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
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.
func (c *Checkbox) Draw(screen tcell.Screen) {
c.Box.Draw(screen)
@ -254,11 +267,16 @@ type CheckboxArgs struct {
// returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded).
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
// associated properties of the Checkbox.
func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox{
func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox {
c.SetLabel(args.Label)
c.SetChecked(args.Checked)
@ -288,9 +306,11 @@ func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox{
if args.FinishedFunc != nil {
c.SetFinishedFunc(args.FinishedFunc)
}
if args.ValidateFunc != nil {
c.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil {
c.SetInputCapture(args.InputCaptureFunc)
}
return c
}

@ -70,6 +70,11 @@ type DropDown struct {
// A callback function which is called when the user changes the drop-down's
// selection.
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.
@ -256,6 +261,14 @@ func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
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.
func (d *DropDown) Draw(screen tcell.Screen) {
d.Box.Draw(screen)
@ -499,8 +512,10 @@ type DropDownArgs struct {
// returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded).
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
// associated properties of the DropDown.
@ -537,6 +552,9 @@ func (d *DropDown) ApplyArgs(args *DropDownArgs) *DropDown {
if args.FinishedFunc != nil {
d.SetFinishedFunc(args.FinishedFunc)
}
if args.ValidateFunc != nil {
d.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil {
d.SetInputCapture(args.InputCaptureFunc)
}

@ -85,6 +85,11 @@ type InputField struct {
// A callback function set by the Form class and called when the user leaves
// this form item.
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.
@ -226,6 +231,14 @@ func (i *InputField) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
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.
func (i *InputField) Draw(screen tcell.Screen) {
i.Box.Draw(screen)
@ -507,6 +520,9 @@ type InputFieldArgs struct {
// returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded).
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{}
@ -563,10 +579,11 @@ func (i *InputField) applyInputFieldArgs(args *InputFieldArgs) *InputField {
if args.FinishedFunc != nil {
i.SetFinishedFunc(args.FinishedFunc)
}
if args.ValidateFunc != nil {
i.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil {
i.SetInputCapture(args.InputCaptureFunc)
}
return i
}

@ -64,6 +64,9 @@ type PasswordFieldArgs struct {
// returns the event to be forwarded to the primitive's default
// input handler (nil if nothing should be forwarded).
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{}
@ -99,9 +102,11 @@ func (i *InputField) applyPasswordFieldArgs(args *PasswordFieldArgs) *InputField
if args.FinishedFunc != nil {
i.SetFinishedFunc(args.FinishedFunc)
}
if args.ValidateFunc != nil {
i.SetValidateFunc(args.ValidateFunc)
}
if args.InputCaptureFunc != nil {
i.SetInputCapture(args.InputCaptureFunc)
}
return i
}

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