From 06a95af2a234918edf0b7507018fbe534391968b Mon Sep 17 00:00:00 2001 From: Mike Schinkel Date: Sun, 9 Jun 2019 23:05:06 -0400 Subject: [PATCH] Add feature-complete FormItemArgs for testing --- checkbox.go | 93 +++++++++++++++++++++++++++++++++++ dropdown.go | 103 ++++++++++++++++++++++++++++++++++++++ form.go | 74 ++++++++++++++++++++++++++-- formitemargs.go | 48 ++++++++++++++++++ inputfield.go | 125 +++++++++++++++++++++++++++++++++++++++++++++++ passwordfield.go | 107 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 545 insertions(+), 5 deletions(-) create mode 100644 formitemargs.go create mode 100644 passwordfield.go diff --git a/checkbox.go b/checkbox.go index 8f099d8..b684de7 100644 --- a/checkbox.go +++ b/checkbox.go @@ -201,3 +201,96 @@ func (c *Checkbox) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr } }) } + +// CheckboxArgs provides a concise and readable way to initialize +// all the properties of the Checkbox struct by passing to the +//
.AddFormItem(item,args). +type CheckboxArgs struct { + baseFormItemArgs + + // The text to be displayed before the input area. + Label string + + // Whether or not this box is checked. + Checked bool + + // An optional function which is called when the user changes + // the checked state of this checkbox. + ChangedFunc func(checked bool) + + // The screen width of the input area. A value of 0 means extend + // as much as possible. + FieldWidth int + + // The screen width of the label area. A value of 0 means use + // the width of the label text. + LabelWidth int + + // The label color. + LabelColor tcell.Color + + // The background color of the input area. + FieldBackgroundColor tcell.Color + + // The text color of the input area. + FieldTextColor tcell.Color + + // The background color of the input area. + BackgroundColor tcell.Color + + // An optional function which is called when the user indicated + // that they are done entering text. The key which was pressed + // is provided (tab, shift-tab, enter, or escape). + DoneFunc func(key tcell.Key) + + // A callback function set by the Form class and called when + // the user leaves this form item. + FinishedFunc func(key tcell.Key) + + // An optional function which is called before the box is drawn. + DrawFunc func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) + + // An optional capture function which receives a key event and + // 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 +} + +// ApplyArgs applies the values from a CheckboxArgs{} struct to the +// associated properties of the Checkbox. +func (c *Checkbox) ApplyArgs(args *CheckboxArgs) *Checkbox{ + + c.SetLabel(args.Label) + c.SetChecked(args.Checked) + c.SetChangedFunc(args.ChangedFunc) + + if args.LabelWidth > 0 { + c.SetLabelWidth(args.LabelWidth) + } + if args.LabelColor != 0 { + c.SetLabelColor(args.LabelColor) + } + if args.FieldBackgroundColor != 0 { + c.SetFieldBackgroundColor(args.FieldBackgroundColor) + } + if args.FieldTextColor != 0 { + c.SetFieldTextColor(args.FieldTextColor) + } + if args.BackgroundColor != 0 { + c.SetBackgroundColor(args.BackgroundColor) + } + if args.DoneFunc != nil { + c.SetDoneFunc(args.DoneFunc) + } + if args.DrawFunc != nil { + c.SetDrawFunc(args.DrawFunc) + } + if args.FinishedFunc != nil { + c.SetFinishedFunc(args.FinishedFunc) + } + if args.InputCaptureFunc != nil { + c.SetInputCapture(args.InputCaptureFunc) + } + return c +} + diff --git a/dropdown.go b/dropdown.go index c839844..7842a68 100644 --- a/dropdown.go +++ b/dropdown.go @@ -439,3 +439,106 @@ func (d *DropDown) HasFocus() bool { } return d.hasFocus } + +// DropDownArgs provides a concise and readable way to initialize +// all the properties of the DropDown struct by passing to the +// .AddFormItem(item,args). +type DropDownArgs struct { + baseFormItemArgs + + // The text to be displayed before the input area. + Label string + + // The options from which the user can choose. + Options []string + + // The index of the initial selected option. Negative if no option + // should be selected. + InitialOption int + + // The color for prefixes. + PrefixTextColor tcell.Color + + // A callback function which is called when the user changes + // the drop-down's selection. + SelectedFunc func(option string, optionIndex int) + + // The screen width of the input area. A value of 0 means extend + // as much as possible. + FieldWidth int + + // The screen width of the label area. A value of 0 means use + // the width of the label text. + LabelWidth int + + // The label color. + LabelColor tcell.Color + + // The background color of the input area. + FieldBackgroundColor tcell.Color + + // The text color of the input area. + FieldTextColor tcell.Color + + // The background color of the input area. + BackgroundColor tcell.Color + + // An optional function which is called when the user indicated + // that they are done entering text. The key which was pressed + // is provided (tab, shift-tab, enter, or escape). + DoneFunc func(key tcell.Key) + + // A callback function set by the Form class and called when + // the user leaves this form item. + FinishedFunc func(key tcell.Key) + + // An optional function which is called before the box is drawn. + DrawFunc func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) + + // An optional capture function which receives a key event and + // 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 +} + + +// ApplyArgs applies the values from a DropDownArgs{} struct to the +// associated properties of the DropDown. +func (d *DropDown) ApplyArgs(args *DropDownArgs) *DropDown { + d.SetLabel(args.Label) + d.SetFieldWidth(args.FieldWidth) + d.SetOptions(args.Options, args.SelectedFunc) + d.SetCurrentOption(args.InitialOption) + + if args.LabelWidth > 0 { + d.SetLabelWidth(args.LabelWidth) + } + if args.LabelColor != 0 { + d.SetLabelColor(args.LabelColor) + } + if args.FieldBackgroundColor != 0 { + d.SetFieldBackgroundColor(args.FieldBackgroundColor) + } + if args.FieldTextColor != 0 { + d.SetFieldTextColor(args.FieldTextColor) + } + if args.BackgroundColor != 0 { + d.SetBackgroundColor(args.BackgroundColor) + } + if args.PrefixTextColor != 0 { + d.SetPrefixTextColor(args.PrefixTextColor) + } + if args.DoneFunc != nil { + d.SetDoneFunc(args.DoneFunc) + } + if args.DrawFunc != nil { + d.SetDrawFunc(args.DrawFunc) + } + if args.FinishedFunc != nil { + d.SetFinishedFunc(args.FinishedFunc) + } + if args.InputCaptureFunc != nil { + d.SetInputCapture(args.InputCaptureFunc) + } + return d +} diff --git a/form.go b/form.go index cbf3c54..c7afc28 100644 --- a/form.go +++ b/form.go @@ -281,17 +281,25 @@ func (f *Form) ClearButtons() *Form { } // AddFormItem adds a new item to the form. This can be used to add your own -// objects to the form. Note, however, that the Form class will override some -// of its attributes to make it work in the form context. Specifically, these -// are: +// objects to the form, or you can use it to pass a FormItemArgsImplementor +// of the type for your FormItem as a 2nd parameter to enable initialization +// of properties that FormItem currently does not provide access to set. + +// Note, however, that the Form class will override some of its attributes to +// make it work in the form context. Specifically, these are: // // - The label width // - The label color // - The background color // - The field text color // - The field background color -func (f *Form) AddFormItem(item FormItem) *Form { - f.items = append(f.items, item) +// +func (f *Form) AddFormItem(item FormItem, args ...FormItemArgsImplementor) *Form { + if len(args) == 0 { + f.items = append(f.items, item) + } else { + f.items = append(f.items, f.ApplyFormItemArgs(item, args...)) + } return f } @@ -587,3 +595,59 @@ func (f *Form) HasFocus() bool { } return false } + +// ApplyFormItemArgs applies the values from the `args` parameters to the +// properties of the FormItem associated with its FormItemArgsImplementor +// type e.g. InputFieldArgs, PasswordFieldArgs, DropDownArgs and CheckboxArgs +// respectively. +// See docs for each of the args struct types for the values they accept. +func (f *Form) ApplyFormItemArgs(item FormItem, args ...FormItemArgsImplementor) FormItem { + if len(args) > 0 { + switch args[0].(type) { + case *InputFieldArgs: + f.ApplyInputFieldArgs(item, args[0].(*InputFieldArgs)) + case *PasswordFieldArgs: + f.ApplyPasswordFieldArgs(item, args[0].(*PasswordFieldArgs)) + case *DropDownArgs: + f.ApplyDropDownArgs(item, args[0].(*DropDownArgs)) + case *CheckboxArgs: + f.ApplySetCheckboxArgs(item, args[0].(*CheckboxArgs)) + default: + if fi,ok := item.(FormItemArgsApplier); ok { + fi.ApplyArgs(args[0].(*CheckboxArgs)) + } + } + } + return item +} + +// ApplyInputFieldArgs applies the values from an InputFieldArgs{} struct to +// the associated properties of the InputField passed as item, an instance of +// a struct that implements FormItem. +func (f *Form) ApplyInputFieldArgs(item FormItem, args *InputFieldArgs) FormItem { + return item.(*InputField).ApplyArgs(args) +} + +// ApplyPasswordFieldArgs applies the values from a PasswordFieldArgs{} struct to +// the associated properties of the PasswordField passed as item, an instance of +// a struct that implements FormItem. +func (f *Form) ApplyPasswordFieldArgs(item FormItem, args *PasswordFieldArgs) FormItem { + return item.(*InputField).ApplyArgs(args) +} + +// ApplyDropDownArgs applies the values from a DropDownArgs{} struct to +// the associated properties of the DropDown passed as item, an instance of +// a struct that implements FormItem. +func (f *Form) ApplyDropDownArgs(item FormItem, args *DropDownArgs) FormItem { + return item.(*DropDown).ApplyArgs(args) +} + +// ApplySetCheckboxArgs applies the values from a CheckboxArgs{} struct to +// the associated properties of the Checkbox passed as item, an instance of +// a struct that implements FormItem. +func (f *Form) ApplySetCheckboxArgs(item FormItem, args *CheckboxArgs) FormItem { + return item.(*Checkbox).ApplyArgs(args) +} + + + diff --git a/formitemargs.go b/formitemargs.go new file mode 100644 index 0000000..bf8f10d --- /dev/null +++ b/formitemargs.go @@ -0,0 +1,48 @@ +package tview + +// FormItemArgs is a collection of interfaces and structs to effectively +// provide a concise and readable method to initialize all the properties +// of the various FormItem structs provided by tview, e.g. InputFieldArgs, +// PasswordFieldArgs, DropDownArgs and CheckboxArgs. +// +// This is an alternate to calling the .Add___() methods like +// AddInputField(), AddPasswordField(), AddDropDown() and AddCheckbox(). +// +// To use these structs pass them to .AddFormItem(item,args) +// +// See https://github.com/rivo/tview/wiki/FormItemArgs for an example. + +// FormItemArgsImplementor is an interface that indicates to Go +// that the implementing struct should be allowed to be used as +// a valid `args` parameter in the collection of `Apply___Args()` +// methods. +// Someone implementing their own FormItem struct may also want +// to implement their own associated "Args" struct and implement +// this interface to allow uses of their FormItem to fully +// instantiate it using .AddFormItem(item,args) +type FormItemArgsImplementor interface { + ImplementsFormItemArgs() +} + +// FormItemArgsApplier is an interface that allows someone to +// implement their an ApplyArgs(arg) method for their own custom +// FormItem so that .ApplyFormItemArgs(item,args) can be +// called by the user of the FormItem in the same manner that +// the tview-builtin FormItem types can be used. +type FormItemArgsApplier interface { + ApplyArgs(FormItemArgsImplementor) FormItem +} + +// baseFormItemArgs is merely a convenience struct that can be +// embedded in another struct — e.g. InputFieldArgs, PasswordFieldArgs, +// DropDownArgs and CheckboxArgs — as a shortcut to having to +// add an ImplementsFormItemArgs() method in order to implement +// the FormItemArgsImplementor interface +type baseFormItemArgs struct{} + +// ImplementsFormItemArgs implements the FormItemArgsImplementor +// interface in the baseFormItemArgs struct so the struct can be +// embedded in other structs — e.g. InputFieldArgs, PasswordFieldArgs, +// DropDownArgs and CheckboxArgs — as a shortcut to them having +// to each add their own ImplementsFormItemArgs() method. +func (baseFormItemArgs) ImplementsFormItemArgs() {} diff --git a/inputfield.go b/inputfield.go index 897df2e..957e873 100644 --- a/inputfield.go +++ b/inputfield.go @@ -445,3 +445,128 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p } }) } + +// InputFieldArgs provides a concise and readable way to initialize +// all the properties of the InputField struct by passing to the +// .AddFormItem(item,args). +type InputFieldArgs struct { + baseFormItemArgs + + // The text to be displayed before the input area. + Label string + + // The text that was entered. + Text string + + // The text to be displayed in the input area when "text" is empty. + Placeholder string + + // The text color of the placeholder. + PlaceholderTextColor tcell.Color + + // An optional function which may reject the last character that + // was entered. + AcceptanceFunc func(textToCheck string, lastChar rune) bool + + // An optional function which is called when the input has changed. + ChangedFunc func(text string) + + // The screen width of the input area. A value of 0 means extend + // as much as possible. + FieldWidth int + + // The screen width of the label area. A value of 0 means use + // the width of the label text. + LabelWidth int + + // The label color. + LabelColor tcell.Color + + // The background color of the input area. + FieldBackgroundColor tcell.Color + + // The text color of the input area. + FieldTextColor tcell.Color + + // The background color of the input area. + BackgroundColor tcell.Color + + // An optional function which is called when the user indicated + // that they are done entering text. The key which was pressed + // is provided (tab, shift-tab, enter, or escape). + DoneFunc func(key tcell.Key) + + // A callback function set by the Form class and called when + // the user leaves this form item. + FinishedFunc func(key tcell.Key) + + // An optional function which is called before the box is drawn. + DrawFunc func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) + + // An optional capture function which receives a key event and + // 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 +} + +// ApplyArgs applies the values from a InputFieldArgs{} or PasswordFieldArgs{} +// struct to the associated properties of the PasswordField of its respective +// field. +func (i *InputField) ApplyArgs(args FormItemArgsImplementor) (item FormItem) { + switch args.(type) { + case *InputFieldArgs: + item = i.applyInputFieldArgs(args.(*InputFieldArgs)) + break + case *PasswordFieldArgs: + item = i.applyPasswordFieldArgs(args.(*PasswordFieldArgs)) + break + } + return item +} + +// applyInputFieldArgs applies the values from a InputFieldArgs{} +// struct to the associated properties of the InputField. +func (i *InputField) applyInputFieldArgs(args *InputFieldArgs) *InputField { + i.SetLabel(args.Label) + i.SetText(args.Text) + i.SetFieldWidth(args.FieldWidth) + i.SetAcceptanceFunc(args.AcceptanceFunc) + i.SetChangedFunc(args.ChangedFunc) + + if args.Placeholder != "" { + i.SetPlaceholder(args.Placeholder) + } + if args.LabelWidth > 0 { + i.SetLabelWidth(args.LabelWidth) + } + if args.LabelColor != 0 { + i.SetLabelColor(args.LabelColor) + } + if args.FieldBackgroundColor != 0 { + i.SetFieldBackgroundColor(args.FieldBackgroundColor) + } + if args.FieldTextColor != 0 { + i.SetFieldTextColor(args.FieldTextColor) + } + if args.BackgroundColor != 0 { + i.SetBackgroundColor(args.BackgroundColor) + } + if args.PlaceholderTextColor != 0 { + i.SetPlaceholderTextColor(args.PlaceholderTextColor) + } + if args.DoneFunc != nil { + i.SetDoneFunc(args.DoneFunc) + } + if args.DrawFunc != nil { + i.SetDrawFunc(args.DrawFunc) + } + if args.FinishedFunc != nil { + i.SetFinishedFunc(args.FinishedFunc) + } + if args.InputCaptureFunc != nil { + i.SetInputCapture(args.InputCaptureFunc) + } + return i +} + + diff --git a/passwordfield.go b/passwordfield.go new file mode 100644 index 0000000..9a6a04c --- /dev/null +++ b/passwordfield.go @@ -0,0 +1,107 @@ +package tview + +import "github.com/gdamore/tcell" + +// NewPasswordField returns a new input field intended for use as a password. +// This is primarily here to make addition of a password field more readable +// when calling Form.AddFormItem(NewPasswordField(),&PasswordFieldArgs{...}) +func NewPasswordField() *InputField { + return NewInputField() +} + +// PasswordFieldArgs provides a concise and readable way to initialize +// all the properties of the PasswordField struct by passing to the +// .AddFormItem(item,args). +type PasswordFieldArgs struct { + baseFormItemArgs + + // The text to be displayed before the input area. + Label string + + // The text that was entered. + Text string + + // A character to mask entered text (useful for password fields). + // A value of 0 disables masking. + MaskCharacter rune + + // An optional function which is called when the input has changed. + ChangedFunc func(text string) + + // The screen width of the input area. A value of 0 means extend + // as much as possible. + FieldWidth int + + // The screen width of the label area. A value of 0 means use + // the width of the label text. + LabelWidth int + + // The label color. + LabelColor tcell.Color + + // The background color of the input area. + FieldBackgroundColor tcell.Color + + // The text color of the input area. + FieldTextColor tcell.Color + + // The background color of the input area. + BackgroundColor tcell.Color + + // An optional function which is called when the user indicated + // that they are done entering text. The key which was pressed + // is provided (tab, shift-tab, enter, or escape). + DoneFunc func(key tcell.Key) + + // A callback function set by the Form class and called when + // the user leaves this form item. + FinishedFunc func(key tcell.Key) + + // An optional function which is called before the box is drawn. + DrawFunc func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) + + // An optional capture function which receives a key event and + // 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 +} + +// applyPasswordFieldArgs applies the values from a PasswordFieldArgs{} +// struct to the associated properties of the PasswordField. +func (i *InputField) applyPasswordFieldArgs(args *PasswordFieldArgs) *InputField { + i.SetLabel(args.Label) + i.SetText(args.Text) + i.SetFieldWidth(args.FieldWidth) + i.SetMaskCharacter(args.MaskCharacter) + i.SetChangedFunc(args.ChangedFunc) + + if args.LabelWidth > 0 { + i.SetLabelWidth(args.LabelWidth) + } + if args.LabelColor != 0 { + i.SetLabelColor(args.LabelColor) + } + if args.FieldBackgroundColor != 0 { + i.SetFieldBackgroundColor(args.FieldBackgroundColor) + } + if args.FieldTextColor != 0 { + i.SetFieldTextColor(args.FieldTextColor) + } + if args.BackgroundColor != 0 { + i.SetBackgroundColor(args.BackgroundColor) + } + if args.DoneFunc != nil { + i.SetDoneFunc(args.DoneFunc) + } + if args.DrawFunc != nil { + i.SetDrawFunc(args.DrawFunc) + } + if args.FinishedFunc != nil { + i.SetFinishedFunc(args.FinishedFunc) + } + if args.InputCaptureFunc != nil { + i.SetInputCapture(args.InputCaptureFunc) + } + return i +} +