Safe Haskell | None |
---|---|
Language | Haskell2010 |
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
FormField
s 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 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
- updateFormState :: s -> 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
- editShowableFieldWithValidate :: (Ord n, Show n, Read a, Show a) => Lens' s a -> n -> (a -> Bool) -> 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
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 typen
- 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 typen
- your application's resource name type
FormFieldState | |
|
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 manipulatesb
- the form field's internal state typee
- your application's event typen
- your application's resource name type
FormField | |
|
Creating and using forms
:: [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
orUp
, if the currently-focused field is part of a collection (e.g. radio buttons), the previous entry in the collection is focused. - On
Right
orDown
, 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.
:: 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.
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
:: (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 |
-> 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.
:: (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 #
:: (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.
|
-> 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.
:: (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.
:: (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 |
-> 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.
:: 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 |
Advanced form field constructors
:: (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 |
-> (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 |
-> ([Text] -> Widget n) | The rendering function for the editor's contents (see
|
-> (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.
:: (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 |
-> 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.
:: (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 |
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.