brick-0.63: A declarative terminal user interface library
Safe HaskellNone
LanguageHaskell2010

Brick.Forms

Description

Note - This API is experimental and will probably change. Please try it out! Feedback is very much appreciated, and your patience in the face of breaking API changes is also appreciated! It's also worth bearing in mind that this API is designed to support a narrow range of use cases. If you find that you need more customization than this offers, then you will need to consider building your own layout and event handling for input fields.

For a fuller introduction to this API, see the "Input Forms" section of the Brick User Guide. Also see the demonstration programs for examples of forms in action.

This module provides an input form API. This API allows you to construct an input interface based on a data type of your choice. Each input in the form corresponds to a field in your data type. This API then automatically dispatches keyboard and mouse input events to each form input field, manages rendering of the form, notifies the user when a form field's value is invalid, and stores valid inputs in your data type when possible.

A form has both a visual representation and a corresponding data structure representing the latest valid values for that form (referred to as the "state" of the form). A FormField is a single input component in the form and a FormFieldState defines the linkage between that visual input and the corresponding portion of the state represented by that visual; there may be multiple FormFields combined for a single FormFieldState (e.g. a radio button sequence).

To use a Form, you must include it within your application state type. You can use formState to access the underlying s whenever you need it. See programs/FormDemo.hs for a complete working example.

Also note that, by default, forms and their field inputs are concatenated together in a vBox. This can be customized on a per-field basis and for the entire form by using the functions setFieldConcat and setFormConcat, respectively.

Bear in mind that for most uses, the FormField and FormFieldState types will not be used directly. Instead, the constructors for various field types (such as editTextField) will be used instead.

Synopsis

Data types

data Form s e n Source #

A form: a sequence of input fields that manipulate the fields of an underlying state that you choose. This value must be stored in the Brick application's state.

Type variables are as follows:

  • s - the data type of your choosing containing the values manipulated by the fields in this form.
  • e - your application's event type
  • n - your application's resource name type

data FormFieldState s e n where Source #

A form field state accompanied by the fields that manipulate that state. The idea is that some record field in your form state has one or more form fields that manipulate that value. This data type maps that state field (using a lens into your state) to the form input fields responsible for managing that state field, along with a current value for that state field and an optional function to control how the form inputs are rendered.

Most form fields will just have one input, such as text editors, but others, such as radio button collections, will have many, which is why this type supports more than one input corresponding to a state field.

Type variables are as follows:

  • s - the data type containing the value manipulated by these form fields.
  • e - your application's event type
  • n - your application's resource name type

Constructors

FormFieldState 

Fields

  • :: { formFieldState :: b

    The current state value associated with the field collection. Note that this type is existential. All form fields in the collection must validate to this type.

  •    , formFieldLens :: Lens' s a

    A lens to extract and store a successfully-validated form input back into your form state.

  •    , formFieldUpdate :: a -> b -> b

    Given a new form state value, update the form field state in place.

  •    , formFields :: [FormField a b e n]

    The form fields, in order, that the user will interact with to manipulate this state value.

  •    , formFieldRenderHelper :: Widget n -> Widget n

    A helper function to augment the rendered representation of this collection of form fields. It receives the default representation and can augment it, for example, by adding a label on the left.

  •    , formFieldConcat :: [Widget n] -> Widget n

    Concatenation function for this field's input renderings.

  •    } -> FormFieldState s e n
     

data FormField a b e n Source #

A form field. This represents an interactive input field in the form. Its user input is validated and thus converted into a type of your choosing.

Type variables are as follows:

  • a - the type of the field in your form state that this field manipulates
  • b - the form field's internal state type
  • e - your application's event type
  • n - your application's resource name type

Constructors

FormField 

Fields

  • formFieldName :: n

    The name identifying this form field.

  • formFieldValidate :: b -> Maybe a

    A validation function converting this field's state into a value of your choosing. Nothing indicates a validation failure. For example, this might validate an Editor state value by parsing its text contents s aan integer and return Maybe Int. This is for pure avalue validation; if additional validation is required a(e.g. via IO), use this field's state value in an aexternal validation routine and use setFieldValid to afeed the result back into the form.

  • formFieldExternallyValid :: Bool

    Whether the field is valid according to an external validation source. Defaults to always being True and can be set with setFieldValid. The value of this field also affects the behavior of allFieldsValid and getInvalidFields.

  • formFieldRender :: Bool -> b -> Widget n

    A function to render this form field. Parameters are whether the field is currently focused, followed by the field state.

  • formFieldHandleEvent :: BrickEvent n e -> b -> EventM n b

    An event handler for this field. This receives the event and the field state and returns a new field state.

Creating and using forms

newForm Source #

Arguments

:: [s -> FormFieldState s e n]

The form field constructors. This is intended to be populated using the various field constructors in this module.

-> s

The initial form state used to populate the fields.

-> Form s e n 

Create a new form with the specified input fields and an initial form state. The fields are initialized from the state using their state lenses and the first form input is focused initially.

formFocus :: Form s e n -> FocusRing n Source #

The focus ring for the form, indicating which form field has input focus.

formState :: Form s e n -> s Source #

The current state of the form. Forms guarantee that only valid inputs ever get stored in the state, and that after each input event on a form field, if that field contains a valid state value then the value is immediately saved to its corresponding field in this state value using the form field's lens over s.

handleFormEvent :: Eq n => BrickEvent n e -> Form s e n -> EventM n (Form s e n) Source #

Dispatch an event to the appropriate form field and return a new form. This handles the following events in this order:

  • On Tab keypresses, this changes the focus to the next field in the form.
  • On Shift-Tab keypresses, this changes the focus to the previous field in the form.
  • On mouse button presses (regardless of button or modifier), the focus is changed to the clicked form field and the event is forwarded to the event handler for the clicked form field.
  • On Left or Up, if the currently-focused field is part of a collection (e.g. radio buttons), the previous entry in the collection is focused.
  • On Right or Down, if the currently-focused field is part of a collection (e.g. radio buttons), the next entry in the collection is focused.
  • All other events are forwarded to the currently focused form field.

In all cases where an event is forwarded to a form field, validation of the field's input state is performed immediately after the event has been handled. If the form field's input state succeeds validation using the field's validator function, its value is immediately stored in the form state using the form field's state lens. The external validation flag is ignored during this step to ensure that external validators have a chance to get the intermediate validated value.

renderForm :: Eq n => Form s e n -> Widget n Source #

Render a form.

For each form field, each input for the field is rendered using the implementation provided by its FormField. The inputs are then concatenated with the field's concatenation function (see setFieldConcat) and are then augmented using the form field's rendering augmentation function (see @@=). Fields with invalid inputs (either due to built-in validator failure or due to external validation failure via setFieldValid) will be displayed using the invalidFormInputAttr attribute.

Finally, all of the resulting field renderings are concatenated with the form's concatenation function (see setFormConcat).

renderFormFieldState :: Eq n => FocusRing n -> FormFieldState s e n -> Widget n Source #

Render a single form field collection. This is called internally by renderForm but is exposed in cases where a form field state needs to be rendered outside of a Form, so renderForm is probably what you want.

(@@=) :: (Widget n -> Widget n) -> (s -> FormFieldState s e n) -> s -> FormFieldState s e n infixr 5 Source #

Compose a new rendering augmentation function with the one in the form field collection. For example, we might put a label on the left side of a form field:

(str "Please check: " <+>) @@= checkboxField alive AliveField "Alive?"

This can also be used to add multiple augmentations and associates right:

(withDefAttr someAttribute) @@=
(str "Please check: " <+>) @@=
  checkboxField alive AliveField "Alive?"

allFieldsValid :: Form s e n -> Bool Source #

Returns whether all form fields in the form currently have valid values according to the fields' validation functions. This is useful when we need to decide whether the form state is up to date with respect to the form input fields.

invalidFields :: Form s e n -> [n] Source #

Returns the resource names associated with all form input fields that currently have invalid inputs. This is useful when we need to force the user to repair invalid inputs before moving on from a form editing session.

setFieldValid Source #

Arguments

:: Eq n 
=> Bool

Whether the field is considered valid.

-> n

The name of the form field to set as (in)valid.

-> Form s e n

The form to modify.

-> Form s e n 

Manually indicate that a field has invalid contents. This can be useful in situations where validation beyond the form element's validator needs to be performed and the result of that validation needs to be fed back into the form state.

setFormConcat :: ([Widget n] -> Widget n) -> Form s e n -> Form s e n Source #

Set a form's concatenation function.

setFieldConcat :: ([Widget n] -> Widget n) -> FormFieldState s e n -> FormFieldState s e n Source #

Set a form field's concatenation function.

setFormFocus :: Eq n => n -> Form s e n -> Form s e n Source #

Set the focused field of a form.

updateFormState :: s -> Form s e n -> Form s e n Source #

Update the state contained in a form.

This updates all form fields to be consistent with the new form state. Where possible, this attempts to maintain other input state, such as text editor cursor position.

Note that since this updates the form fields, this means that any field values will be completely overwritten! This may or may not be what you want, since a user actively using the form could get confused if their edits go away. Use carefully.

Simple form field constructors

editTextField Source #

Arguments

:: (Ord n, Show n) 
=> Lens' s Text

The state lens for this value.

-> n

The resource name for the input field.

-> Maybe Int

The optional line limit for the editor (see editor).

-> s

The initial form state.

-> FormFieldState s e n 

A form field using an editor to edit a text value. Since the value is free-form text, it is always valid.

This field responds to all events handled by editor, including mouse events.

editShowableField Source #

Arguments

:: (Ord n, Show n, Read a, Show a) 
=> Lens' s a

The state lens for this value.

-> n

The resource name for the input field.

-> s

The initial form state.

-> FormFieldState s e n 

A form field using a single-line editor to edit the Show representation of a state field value of type a. This automatically uses its Read instance to validate the input. This field is mostly useful in cases where the user-facing representation of a value matches the Show representation exactly, such as with Int.

This field responds to all events handled by editor, including mouse events.

editShowableFieldWithValidate Source #

Arguments

:: (Ord n, Show n, Read a, Show a) 
=> Lens' s a

The state lens for this value.

-> n

The resource name for the input field.

-> (a -> Bool)

Additional validation step for input. True indicates that the value is valid.

-> s

The initial form state.

-> FormFieldState s e n 

A form field using a single-line editor to edit the Show representation of a state field value of type a. This automatically uses its Read instance to validate the input, and also accepts an additional user-defined pass for validation. This field is mostly useful in cases where the user-facing representation of a value matches the Show representation exactly, such as with Int, but you don't want to accept just any Int.

This field responds to all events handled by editor, including mouse events.

editPasswordField Source #

Arguments

:: (Ord n, Show n) 
=> Lens' s Text

The state lens for this value.

-> n

The resource name for the input field.

-> s

The initial form state.

-> FormFieldState s e n 

A form field using a single-line editor to edit a free-form text value represented as a password. The value is always considered valid and is always represented with one asterisk per password character.

This field responds to all events handled by editor, including mouse events.

radioField Source #

Arguments

:: (Ord n, Show n, Eq a) 
=> Lens' s a

The state lens for this value.

-> [(a, n, Text)]

The available choices, in order. Each choice has a value of type a, a resource name, and a text label.

-> s

The initial form state.

-> FormFieldState s e n 

A form field for selecting a single choice from a set of possible choices. Each choice has an associated value and text label.

This field responds to Space keypresses to select a radio button option and to mouse clicks.

checkboxField Source #

Arguments

:: (Ord n, Show n) 
=> Lens' s Bool

The state lens for this value.

-> n

The resource name for the input field.

-> Text

The label for the check box, to appear at its right.

-> s

The initial form state.

-> FormFieldState s e n 

A form field for manipulating a boolean value. This represents True as [X] label and False as [ ] label.

This field responds to Space keypresses to toggle the checkbox and to mouse clicks.

listField Source #

Arguments

:: forall s e n a. (Ord n, Show n, Eq a) 
=> (s -> Vector a)

Possible choices.

-> Lens' s (Maybe a)

The state lens for the initially/finally selected element.

-> (Bool -> a -> Widget n)

List item rendering function.

-> Int

List item height in rows.

-> n

The resource name for the input field.

-> s

The initial form state.

-> FormFieldState s e n 

A form field for selecting a single choice from a set of possible choices in a scrollable list. This uses a List internally.

This field responds to the same input events that a List does.

Advanced form field constructors

editField Source #

Arguments

:: (Ord n, Show n) 
=> Lens' s a

The state lens for this value.

-> n

The resource name for the input field.

-> Maybe Int

The optional line limit for the editor (see editor).

-> (a -> Text)

The initialization function that turns your value into the editor's initial contents. The resulting text may contain newlines.

-> ([Text] -> Maybe a)

The validation function that converts the editor's contents into a valid value of type a.

-> ([Text] -> Widget n)

The rendering function for the editor's contents (see renderEditor).

-> (Widget n -> Widget n)

A rendering augmentation function to adjust the representation of the rendered editor.

-> s

The initial form state.

-> FormFieldState s e n 

A form field for using an editor to edit the text representation of a value. The other editing fields in this module are special cases of this function.

This field responds to all events handled by editor, including mouse events.

radioCustomField Source #

Arguments

:: (Ord n, Show n, Eq a) 
=> Char

Left bracket character.

-> Char

Checkmark character.

-> Char

Right bracket character.

-> Lens' s a

The state lens for this value.

-> [(a, n, Text)]

The available choices, in order. Each choice has a value of type a, a resource name, and a text label.

-> s

The initial form state.

-> FormFieldState s e n 

A form field for selecting a single choice from a set of possible choices. Each choice has an associated value and text label. This function permits the customization of the [*] notation characters.

This field responds to Space keypresses to select a radio button option and to mouse clicks.

checkboxCustomField Source #

Arguments

:: (Ord n, Show n) 
=> Char

Left bracket character.

-> Char

Checkmark character.

-> Char

Right bracket character.

-> Lens' s Bool

The state lens for this value.

-> n

The resource name for the input field.

-> Text

The label for the check box, to appear at its right.

-> s

The initial form state.

-> FormFieldState s e n 

A form field for manipulating a boolean value. This represents True as [X] label and False as [ ] label. This function permits the customization of the [X] notation characters.

This field responds to Space keypresses to toggle the checkbox and to mouse clicks.

Attributes

formAttr :: AttrName Source #

The namespace for the other form attributes.

invalidFormInputAttr :: AttrName Source #

The attribute for form input fields with invalid values.

focusedFormInputAttr :: AttrName Source #

The attribute for form input fields that have the focus.