brick-0.52.1: A declarative terminal user interface library

Safe Haskell | None
Language | Haskell2010

Brick.Forms

Contents

- Data types
- Creating and using forms
- Simple form field constructors
- Advanced form field constructors
- Attributes

Description

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 `FormField`s combined for a single `FormFieldState` (e.g. a radio button sequence).

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 Form s e n
- data FormFieldState s e n where
  - FormFieldState :: {..} -> FormFieldState s e n
- data FormField a b e n = FormField {
  - formFieldName :: n
  - formFieldValidate :: b -> Maybe a
  - formFieldExternallyValid :: Bool
  - formFieldRender :: Bool -> b -> Widget n
  - formFieldHandleEvent :: BrickEvent n e -> b -> EventM n b
  }
- newForm :: [s -> FormFieldState s e n] -> s -> Form s e n
- formFocus :: Form s e n -> FocusRing n
- formState :: Form s e n -> s
- handleFormEvent :: Eq n => BrickEvent n e -> Form s e n -> EventM n (Form s e n)
- renderForm :: Eq n => Form s e n -> Widget n
- renderFormFieldState :: Eq n => FocusRing n -> FormFieldState s e n -> Widget n
- (@@=) :: (Widget n -> Widget n) -> (s -> FormFieldState s e n) -> s -> FormFieldState s e n
- allFieldsValid :: Form s e n -> Bool
- invalidFields :: Form s e n -> [n]
- setFieldValid :: Eq n => Bool -> n -> Form s e n -> Form s e n
- setFormConcat :: ([Widget n] -> Widget n) -> Form s e n -> Form s e n
- setFieldConcat :: ([Widget n] -> Widget n) -> FormFieldState s e n -> FormFieldState s e n
- setFormFocus :: Eq n => n -> Form s e n -> Form s e n
- editTextField :: (Ord n, Show n) => Lens' s Text -> n -> Maybe Int -> s -> FormFieldState s e n
- editShowableField :: (Ord n, Show n, Read a, Show a) => Lens' s a -> n -> s -> FormFieldState s e n
- editPasswordField :: (Ord n, Show n) => Lens' s Text -> n -> s -> FormFieldState s e n
- radioField :: (Ord n, Show n, Eq a) => Lens' s a -> [(a, n, Text)] -> s -> FormFieldState s e n
- checkboxField :: (Ord n, Show n) => Lens' s Bool -> n -> Text -> s -> FormFieldState s e n
- listField :: forall s e n a. (Ord n, Show n, Eq a) => (s -> Vector a) -> Lens' s (Maybe a) -> (Bool -> a -> Widget n) -> Int -> n -> s -> FormFieldState s e n
- editField :: (Ord n, Show n) => Lens' s a -> n -> Maybe Int -> (a -> Text) -> ([Text] -> Maybe a) -> ([Text] -> Widget n) -> (Widget n -> Widget n) -> s -> FormFieldState s e n
- radioCustomField :: (Ord n, Show n, Eq a) => Char -> Char -> Char -> Lens' s a -> [(a, n, Text)] -> s -> FormFieldState s e n
- checkboxCustomField :: (Ord n, Show n) => Char -> Char -> Char -> Lens' s Bool -> n -> Text -> s -> FormFieldState s e n
- formAttr :: AttrName
- invalidFormInputAttr :: AttrName
- focusedFormInputAttr :: AttrName

# 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.

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.

- , 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.

# 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.

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 editors 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.