Note - this API is designed to support a narrow (but common!) set
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 state 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.
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.
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.
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.
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.
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 as
an integer and return MaybeInt. This is for pure
value validation; if additional validation is required
(e.g. via IO), use this field's state value in an
external validation routine and use setFieldValid to
feed the result back into the form.
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.
Make all inputs in the focused field visible. For composite
fields this will bring all options into view as long as the
viewport is large enough to show them all.
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.
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.
Dispatch an event to the currently focused form field. 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.
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). A visibility
request is also issued for the currently-focused form field in case
the form is rendered within a viewport.
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.
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:
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.
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.
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.
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.
Set the visibility mode of the specified form field's collection
when the form is rendered in viewport. This is used to change how
focused fields are brought into view when they're outside of view
in a viewport and gain focus. In practice, this means this function
need only be called on one form field name in a collection in order
to affect the visibility behavior of that field's entire input
collection.
There are two visibility modes:
ShowFocusedFieldOnly - this is the default behavior. In this
mode, when a field receives focus, it is brought into view but
other inputs in the same field collection (e.g. a set of radio
buttons) will not be brought into view along with it.
ShowCompositeField - in this mode, when a field receives focus,
all of the inputs in its collection (e.g. a set of radio buttons)
are brought into view as long as the viewport is large enough to
show them all. If it isn't, the viewport will show as many as space
allows.
ShowAugmentedField - in this mode, when a field receives focus,
all of the inputs in its collection (e.g. a set of radio buttons)
and its rendering augmentations (as applied with @@=) are brought
into view as long as the viewport is large enough to show them all.
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's attributes are governed by those exported from
Brick.Widgets.Edit.
This field responds to all events handled by editor, including
mouse events.
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 anyInt.
This field's attributes are governed by those exported from
Brick.Widgets.Edit.
This field responds to all events handled by editor, including
mouse events.
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's attributes are governed by those exported from
Brick.Widgets.Edit.
This field responds to all events handled by editor, including
mouse events.
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's attributes are governed by those exported from
Brick.Widgets.Edit.
This field responds to all events handled by editor, including
mouse events.
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.
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.
The attribute for form input fields with invalid values. Note that
this attribute will affect any field considered invalid and will take
priority over any attributes that the field uses to render itself.
The attribute for form input fields that have the focus. Note that
this attribute only affects fields that do not already use their own
attributes when rendering, such as editor- and list-based fields.
Those need to be styled by setting the appropriate attributes; see
the documentation for field constructors to find out which attributes
need to be configured.