NAME

Term::Fabulous::Widget::Input - Common base class of the input widgets

SYNOPSIS

use Term::Fabulous::Widget::TextField;

# Every input widget accepts these parameters:
my $field = Term::Fabulous::Widget::TextField->new(
	id                     => 'name',
	disabled               => 0,
	required               => 1,
	validator              => 'email',
	text_color             => '#dcdfe4',
	accent_color           => [ 97, 175, 239, 255 ],
	disabled_color         => 0x6c7078,
	invalid_color          => 'Tomato',
	focus_background_color => 'rgb(52, 58, 72)',
);

$field->disabled(1);                   # gray, ignores input, loses the focus
$field->accent_color('#ff8800');      # shows in the next frame
my $message = $field->error;           # what is wrong with the value, or undef
$field->on( ValidityChange => sub ($event) { $hint->text( $event->error // '' ); return } );

# A widget of your own (see SUBCLASS INTERFACE):
use Object::Pad;
use Term::Fabulous::Widget::Input;

class My::Toggle :isa(Term::Fabulous::Widget::Input) :strict(params) {
	field $on = 0;

	method value () { return $on }

	method natural_size () { return ( 5, 1 ) }    # columns, rows

	method paint () {
		my $bg = $self->paint_focus_background;
		$self->paint_text( 0, 0, $on ? '[ON]' : '[OFF]', $self->accent_attr, $bg );
		return;
	}

	method activate () {                       # a click
		$on = $on ? 0 : 1;
		$self->mark_changed;                    # the next frame paints it
		$self->fire_change($on);
		return;
	}

	method handle_key ($event) {
		return 0 unless ( $event->main_key_name // '' ) eq 'Space';
		$self->activate;
		return 1;                               # used: stops bubbling
	}
}

DESCRIPTION

Term::Fabulous::Widget::Input is the abstract base class of all input widgets:

You do not create an Input directly (the class is abstract and new dies); this page describes what all input widgets have in common, and how to write an input widget of your own.

What every input widget does:

  • It takes the keyboard focus. Under Term::Fabulous, Tab and BackTab (Shift+Tab) move the focus from input to input, and a click on an input focuses it. The focused input shows its content on focus_background_color. A radio button is the exception: its radio group takes the focus for all its buttons.

  • It receives the key presses while it has the focus. Keys it uses (for example letters in a text field) stop there; keys it does not use (for example Escape, Tab or F1) bubble on to its ancestors, so application shortcuts on an outer box keep working while the user types. Each widget's KEYS section lists the keys it uses. See "KEYBOARD" in Term::Fabulous::Manual::Events.

  • It works with the mouse: clicks, drags and the mouse wheel, as described in each widget's MOUSE section. Term::Fabulous asks the terminal to report the pointer as it moves, too, so the hover state of an input (is_hovered, the OnHoverStart and OnHoverStopped events) follows the pointer. A terminal that does not report plain movement changes the hover state only when a button is pressed or released, while it is dragged and when the wheel turns.

  • It fires a Term::Fabulous::Event::Change when the user changes its value (see "EVENTS").

  • It can check its value: required rejects an empty value, validator a wrong one. An invalid value is drawn in the invalid look and reported by "error", "is_valid" and the ValidityChange event (see "Invalid values").

  • It sizes itself to its content unless the layout says otherwise (see "SIZE").

  • It can be disabled (see "disabled").

  • It has the derived states focused, hovered, pressed and disabled, which $input->has_state('focused') and $input->states report (see "has_state" in Term::Fabulous::Widget). Whether the value is valid is not one of these states; ask "is_valid".

  • It can be built from a KDL layout file (see "KDL PROPERTIES").

Technically, an input is a Term::Fabulous::Widget::Display, a canvas that paints itself when a frame is drawn (see "Painting"): setters only record the new state, and the frame paints whatever changed since the last one, so only cells that really changed are sent to the terminal. Anything you draw into an input with the canvas methods (put, put_text, ...) is lost the next time it paints.

Painting

Every setter of an input records the new value and calls mark_changed ("mark_changed" in Clay::UI::Role::Core::Element), so a frame becomes due; nothing is painted at once. When the frame is drawn, the renderer calls the input's refresh ("refresh" in Term::Fabulous::Widget::Canvas), which compares the input's paint key (see "paint_key") with the one it last painted for: the size of its buffer, how often the input was marked changed, whether it has the focus, whether it is enabled, whether its value is valid, and what a subclass adds, such as the state of its radio group. Only when the key differs does it clear the buffer and call "paint". So the cells always show the state of the frame they are drawn in, also when the state was changed by another widget, and a frame that changes nothing about an input paints nothing of it. The cells read with cell show the state of the last frame. This is how every Term::Fabulous::Widget::Display paints; see "Painting" in Term::Fabulous::Widget::Display.

Invalid values

An input's value is invalid while it is empty and the input is required, or while its validator rejects it (see "required" and "validator"). An invalid input looks different as soon as its value is invalid, without waiting for the user to leave it:

Eleven inputs: a focused e-mail field with ada@exa in red, a valid address in white, ada@ in red without and with a red border, an empty required field that looks normal and one whose border is red, a red unchecked check box, a dropdown showing its gray placeholder, ada@ in purple, ada@ in yellow with a yellow border, and a disabled field in gray

The picture shows examples/widgets/input-validation.pl in the dark theme. From the top:

  • Typing, focused: an e-mail field after typing ada@exa. The look changes with every key, so the text stays red until the address is complete. The cursor takes the color of the text.

  • Valid, invalid: the text of an invalid value is drawn in invalid_color, by default the theme's danger red.

  • Invalid, border: an input with a border (bordered => 1) also draws its border in the danger red, unless it was given a border_color of its own.

  • Required, empty: an empty text field shows its placeholder in the usual gray, required or not. So a required field without a border does not look invalid while it is empty, only when the user types something wrong. With a border, the border is red.

  • Required check box: an unchecked required box draws its box and its label in invalid_color.

  • Required dropdown: a dropdown without a choice shows its placeholder in gray, like an empty text field.

  • invalid_color: the color of an invalid value set for one input, here '#c678dd', a purple.

  • Theme variant: a theme can draw invalid values in other colors, for every input or only for the inputs with a class. The program's theme draws the text inputs of the class calm in the warning color:

    my $theme = Term::Fabulous::Theme->new(
    	name     => 'calm-invalid',
    	extends  => 'dark',
    	variants => { 'text_input.calm' => { 'text.invalid' => 'warning', 'border.color.invalid' => 'warning' } },
    );
    my $field = Term::Fabulous::Widget::TextField->new( validator => 'email', classes => ['calm'] );

    The slots are text and border.color in the state invalid. They belong to the family input, which the families text_input (text fields and text areas) and dropdown extend; a variant names the family of the widget, as text_input.calm does. To change every input, set the slots input.text.invalid and input.border.color.invalid instead. See Term::Fabulous::Theme.

  • Disabled: a disabled input shows the disabled look, valid or not.

The input does not draw the message that says what is wrong. Read it from "error" or from the ValidityChange event, and show it where it suits your program; the recipes "Check the values of a form (required, validator)" in Term::Fabulous::Cookbook::Forms and "Write your own checks and restrict typing (accept, pattern, code)" in Term::Fabulous::Cookbook::Forms show two ways.

CONSTRUCTOR

new

my $input = Term::Fabulous::Widget::TextField->new(%parameters);    # or any other input

Every input widget's new accepts the parameters below, in addition to its own. Unknown parameters die. Term::Fabulous::Widget::Input itself is abstract: calling Term::Fabulous::Widget::Input->new dies.

id

A string. Optional. Identifies the widget for Clay, which needs a unique id per widget; it is also handy for telling inputs apart in a form-wide Change listener ($event->target->id). Ids must be unique in a widget tree.

layout

A hash reference of layout options, as for every widget: sizing, padding, child_gap, child_alignment, layout_direction. See "LAYOUT" in Term::Fabulous::Manual::Layout. A sizing you give here overrides the natural size of the input on that axis (see "SIZE").

background_color

The widget's background, in any format Term::Fabulous::Color accepts (see "Color formats" in Term::Fabulous::Manual::Looks); it is stored as an [r, g, b, a] array reference. Text inputs and the dropdown default to a dark gray ([36, 40, 48, 255]); the other inputs have no background of their own and show the background of their parent.

bordered
border_color
border_style

A border around the input, exactly as for Term::Fabulous::Widget::Box; see "BORDERS" in Term::Fabulous::Manual::Looks. Without bordered, the theme's border.enabled for the input's family decides (input, text_input or dropdown; false in the built-in themes, so inputs have no border). The border takes cells inside the widget's box; the natural size is grown accordingly.

disabled

A boolean, stored as 1 or 0. Default: 0. A disabled input is painted in disabled_color, ignores keys, clicks and the mouse wheel, and cannot take the focus; since the user cannot change it, it fires no Change or Submit of its own accord. See "disabled".

can_focus

A boolean. Default: 1. Whether the input may take the keyboard focus (see Clay::UI::Role::Interaction::Focusable). It counts while the input is enabled: a disabled input cannot take the focus, whatever this says (see "can_focus"). A Term::Fabulous::Widget::RadioButton never takes the focus (it does not accept it, see "accepts_focus"), so for it the parameter has no effect.

required

A boolean, stored as 1 or 0. Default: 0. Whether an empty value is invalid: empty text, a dropdown without a selection, an unchecked checkbox (see "value_is_empty"). See "required".

required_message

A string. Default: 'Please fill in this field.'. What "error" reports for an empty required value.

validator

What checks a non-empty value: the name of a named validator ('email', 'integer', 'number', 'url', 'hostname', 'ip', 'date', 'time'), a regular expression the whole value must match, a code reference that returns what is wrong with the value (or false), a list of those, or a Term::Fabulous::Validator for one with options. Default: undef, any value is fine. See "validator".

text_color

The color of the input's text. Default: the theme's input.text, [220, 223, 228, 255] in the dark theme, a light gray.

disabled_color

The color of all text while the input is disabled, and of inactive parts such as scrollbar tracks. Default: the theme's input.text in the disabled state, [108, 112, 120, 255] in the dark theme, a medium gray.

invalid_color

The color of the text while the value is invalid (see "is_valid"). Default: the theme's input.text in the invalid state, the danger token, [224, 108, 117, 255] in the dark theme, a red. The border of an invalid input takes input.border.color in the invalid state, the same red, unless the input has a border_color of its own.

accent_color

The color of highlights: check marks, the selected radio button's mark, the filled part of a slider, the dropdown's arrow and the border of its open list. Default: the theme's input.accent, [97, 175, 239, 255] in the dark theme, a light blue.

focus_background_color

The background of the input's content while it has the focus. Default: the theme's input.background in the focused state, [52, 58, 72, 255] in the dark theme, a dark blue-gray.

The five colors return to the theme with "reset_look" in Term::Fabulous::Widget; the input's own background_color, border_color and border style come from the theme's input family too when they are not given. See "THEMES" in Term::Fabulous::Manual::Looks.

The five colors accept every color format of the canvas: a packed 0xRRGGBB integer, an [r, g, b] or [r, g, b, a] array reference, a { r, g, b } hash reference, a string such as '#ff8800', 'rgb(255, 136, 0)' or 'hsl(32, 100%, 50%)', or a Term::Fabulous::Color object (see "Colors" in Term::Fabulous::Widget::Canvas). undef and invalid colors die. A color with alpha 0 means "no color": the terminal's default color is used.

An input is a Term::Fabulous::Widget::Box, so it also takes the other parameters of a Box, described in "new" in Term::Fabulous::Widget: floating, width_group and height_group (to line up the inputs of a form), classes, glyphs_show_through, the per-side border styles (border_style_top and so on), border_corners and outer_border_sides.

METHODS

disabled

my $is_disabled = $input->disabled;
$input->disabled(1);
$input->disabled(0);

Accessor, from Clay::UI::Role::Interaction::Disableable. Returns 1 or 0; any plain true or false value may be written, also through new; a reference dies (Clay::UI: 'disabled' must be a plain boolean value).

Writing a true value disables the input: it is painted in disabled_color, ignores keys, clicks and the mouse wheel (so the user causes no Change or Submit), cannot take the focus (can_focus reads 0) and, if it has the focus, gives the focus up at once (no widget is focused afterwards, unless the input is inside an open Term::Fabulous::Widget::Dialog, whose backdrop takes it). Clay::UI never presses a disabled widget: a click on it fires no OnPress or OnRelease. KeyPress and Mouse events fired on a disabled input still bubble on to its ancestors, and it is still hovered (OnHoverStart, OnHoverStopped), so listeners you add yourself for these still run. It has the derived state disabled ("DERIVED STATES" in Clay::UI::Role::Style::HasStates).

Writing a false value enables the input again: it can take the focus when can_focus was last set to a true value, through new, a layout file or the accessor, also while the input was disabled. A Term::Fabulous::Widget::RadioButton, which never takes the focus, keeps 0. Writing the value the input already has changes nothing. Returns the new value (1 or 0).

A radio button also counts as disabled while its radio group is disabled: its is_enabled is then false, while its own disabled stays 0.

is_enabled

if ( $input->is_enabled ) { ... }

True when the input accepts input, the opposite of disabled.

text_color

my $color = $input->text_color;
$input->text_color('#ffffff');

Accessor for the text_color parameter. The reader returns the color as [r, g, b, a], whatever form it was given in (see "cell_color" in Term::Fabulous::Check). Writing marks the input changed and returns the new color. An invalid color, or undef, dies and leaves the old color.

disabled_color

$input->disabled_color([ 90, 90, 90 ]);

Accessor for the disabled_color parameter; works like "text_color".

invalid_color

$input->invalid_color('#ff5555');

Accessor for the invalid_color parameter; works like "text_color".

required

my $is_required = $input->required;
$input->required(1);

Accessor for the required parameter. Returns 1 or 0; a reference dies. Writing runs "validate", so a ValidityChange is fired when the message changed with it.

required_message

$input->required_message('Please enter your name.');

Accessor for the required_message parameter. A value that is not a string dies. Writing runs "validate".

validator

my $validator = $input->validator;    # a Term::Fabulous::Validator, or undef
$input->validator('email');
$input->validator( qr/\A[A-Z]{3}\z/ );
$input->validator( sub ($value) { $value % 2 ? 'Please enter an even number.' : undef } );
$input->validator( [ 'hostname', qr/\.example\.com\z/ ] );
$input->validator( Term::Fabulous::Validator->integer( min => 1, max => 65535 ) );
$input->validator(undef);             # any value is fine

Accessor for the validator. The reader returns the Term::Fabulous::Validator object, whatever form it was given in, or undef. Writing takes everything "coerce" in Term::Fabulous::Validator does; an unknown name or an unsuitable value dies and leaves the validator as it was. Writing runs "validate". A text input also takes the accept spec the validator suggests, as long as it was not given one of its own (see "accept" in Term::Fabulous::Widget::TextInput).

error

my $message = $input->error;

What is wrong with the value right now, or undef when it is fine: required_message for an empty required value, else what the validator says about a non-empty value. An empty value that is not required is fine, and the validator never sees it. The value is checked every time you ask; nothing is cached.

is_valid

if ( $input->is_valid ) { ... }

True when "error" is undef. While it is false, the input shows the invalid look: its text in invalid_color and its border, when it has one, in the theme's input.border.color of the invalid state; "look_state" in Term::Fabulous::Role::Themed is invalid. A disabled input shows the disabled look instead.

validate

my $message = $input->validate;

Checks the value and returns the message, or undef when the value is fine. When the message differs from the one the input reported last, it also fires Term::Fabulous::Event::ValidityChange on the input.

The input calls it after every Change and when required, required_message or validator is written. Call it yourself after setting the value from the program, which fires no events.

Before its first ValidityChange, an input counts as having reported a valid value. An input that is invalid from the start, such as an empty required field, therefore reports nothing until the user changes it or something calls validate. To show the messages of such inputs, call validate on them: once after building the form ($_->validate foreach $form->invalid_inputs), or when the user sends the form. "invalid_inputs" in Term::Fabulous::Widget lists the inputs below a widget that are not valid, reported or not.

accent_color

$input->accent_color(0xFF8800);

Accessor for the accent_color parameter; works like "text_color".

focus_background_color

$input->focus_background_color('rgb(40, 44, 60)');

Accessor for the focus_background_color parameter; works like "text_color".

mark_changed

$input->mark_changed;

Marks the input changed: a frame becomes due (see "mark_changed" in Clay::UI::Role::Core::Element), and that frame paints the input again from its current state and sizes it again, also when the change was made from a timer. The setters call it, so you only need it after changing state behind the widget's back, for example through "editor" in Term::Fabulous::Widget::TextInput. Returns the input.

can_focus

$input->can_focus(0);
if ( $input->can_focus ) { ... }

Whether the input can take the focus now: 1 when it may (the last value written, through new, a layout file or this accessor, was true), it is enabled and it accepts the focus at all (a radio button does not); 0 otherwise. Writing records whether the input may take the focus and returns what reading returns now: can_focus(1) on a disabled input returns 0, and the input takes the focus once it is enabled. The order of can_focus and disabled does not matter. Writing a false value to the focused input takes the focus away at once. From Clay::UI::Role::Interaction::Focusable.

is_focused

if ( $input->is_focused ) { ... }

True while the input has the keyboard focus. Inherited from Clay::UI::Role::Interaction::Focusable. Give an input the focus with $ui->interaction->set_focused_widget($input).

SIZE

Every input has a natural content size: for example one row and as many columns as its label needs (a checkbox), or preferred_columns by one row (a text field). When the layout gives no sizing for an axis, the input is given a fixed size on that axis: its natural size plus its padding and its border (see "Size" in Term::Fabulous::Widget::Display). A sizing in the layout always wins:

# 20 columns wide (the default preferred_columns), one row high:
Term::Fabulous::Widget::TextField->new;

# As wide as the parent allows, still one row high:
Term::Fabulous::Widget::TextField->new( layout => { sizing => { width => sizing_grow() } } );

The natural size is a fixed sizing, and a width_group or height_group ("new" in Term::Fabulous::Widget) lines up fit and grow sizings only. An input has no content Clay could fit, so a plain fit sizing gives it no columns at all; to line up inputs, give each a fit sizing with its natural size as the minimum:

# Both 30 columns wide, the width of the wider one:
Term::Fabulous::Widget::TextField->new( width_group => 1, layout => { sizing => { width => sizing_fit(20) } } );
Term::Fabulous::Widget::TextField->new( width_group => 1, layout => { sizing => { width => sizing_fit(30) } } );

EVENTS

Change

Term::Fabulous::Event::Change, fired on the input when the user changes its value. Setting the value from the program never fires it. It bubbles to the input's ancestors unless a listener on the way returns something other than Clay::UI::Enum::Result->CONTINUE.

ValidityChange

Term::Fabulous::Event::ValidityChange, fired by "validate" right after a Change when the message about the value changed with it: the value became invalid, valid, or invalid for another reason. It bubbles like Change. The event carries is_valid and error.

OnFocus, OnBlur

Clay::UI::Events::OnFocus and Clay::UI::Events::OnBlur, fired by Clay::UI when the input gains or loses the focus.

OnHoverStart, OnHoverStopped, OnPress, OnRelease

The pointer events of Clay::UI; see "MOUSE" in Term::Fabulous::Manual::Events. A completed click (OnRelease after a press on the same input) is what toggles a checkbox or selects a radio button.

CanvasResize

Term::Fabulous::Event::CanvasResize, fired when the layout gives the input a new size. The input paints itself for the new size in the same frame.

The input registers its own listeners for KeyPress, Mouse, OnFocus, OnBlur and OnRelease when it is constructed. Listeners you add with on run after them, on the same widget, and see every event, including keys the input used. Keep in mind that your listener's return value also decides whether the event bubbles further.

KDL PROPERTIES

In a layout file (see Term::Fabulous::Layout), every input accepts the properties of "KDL PROPERTIES" in Term::Fabulous::Widget::Box (layout, sizing, padding, border, background_color, border_color, bordered, width_group, height_group) and the following ones. The string after the widget name is its id (TextField "name" is the id name).

disabled

Takes #true or #false, like the disabled parameter.

can_focus

Takes #true or #false, like the can_focus parameter; with disabled #true in the same block the order does not matter.

required

Takes #true or #false, like the required parameter.

required_message

A string, like the required_message parameter.

validator

The name of a named validator (validator "email"); a layout cannot give a regular expression, code or options, set those from the program. A text input applies it before its value, wherever it stands.

text_color, disabled_color, invalid_color, accent_color, focus_background_color

Any Term::Fabulous::Color string, such as "#ff8800" or "rgb(255, 136, 0)".

A complete layout with one disabled text field:

use Term::Fabulous::Widget::Box as Box
use Term::Fabulous::Widget::TextField as TextField

Box "form" {
	TextField "name" {
		disabled #true
		accent_color "#ff8800"
		sizing width=grow
	}
	TextField "email" {
		required #true
		validator "email"
	}
}

Properties are applied after the widget was constructed, with the same checks as the accessors of the same name. Values that depend on each other are applied together, so their order in the layout does not matter: a dropdown's options come before its value, a slider's min, max and step are one range set before its value, and a text input's max_length, accept and validator come before its value. Everything else is applied in the order of the layout.

SUBCLASS INTERFACE

To write an input widget of your own, subclass Term::Fabulous::Widget::Input with Object::Pad (see the "SYNOPSIS"). You must implement natural_size and paint; override the other methods as needed, value as soon as the input holds a value. Paint with put_attrs ("put_attrs" in Term::Fabulous::Widget::Canvas) and the helpers below and those of "SUBCLASS INTERFACE" in Term::Fabulous::Widget::Display (color_attr, paint_text, fill_attrs), which take termbox2 attributes (the integers returned by foreground_attr, color_attr and friends) instead of colors.

Term::Fabulous draws a frame only when something changed, and the frame paints the input (see "Painting"). Whenever your widget changes state that paint or natural_size uses, call $self->mark_changed and do not paint: the next frame calls paint. When paint also reads state of other objects that change without telling your widget, add that state to "paint_key". Without either, the change shows only when something else makes the input paint.

natural_size

method natural_size () { return ( $columns, $rows ) }

Required. The content size the input wants when the layout does not size it (see "SIZE"): a number of cells per axis, or a sizing hash of Clay::XS, as described in "natural_size" in Term::Fabulous::Widget::Display. Called for every frame.

paint

method paint () { ... }

Required. Draws the input into its buffer. It is called while a frame is drawn, when the "paint_key" changed, with a cleared buffer that has at least one cell; use $self->columns and $self->rows for its size. Cell writes made here belong to the frame being drawn and make no further frame due.

paint_key

method paint_key :override () {
	my $group = $self->group;
	return ( $self->SUPER::paint_key, $group->value, $group->is_focused );
}

The list of values "paint" depends on; the input paints again when any of them changed since it last painted. The default holds what "paint_key" in Term::Fabulous::Widget::Display holds (the size of the buffer and a count of the input's mark_changed calls), whether the input has the focus and whether it is enabled. Extend it with what paint reads from other objects, which do not mark this input changed: Term::Fabulous::Widget::RadioButton adds its group's value, focus and cursor button, Term::Fabulous::Widget::TextInput its editor's revision. The values are compared as strings; keep them cheap to compute, since the key is computed for every frame.

handle_key

method handle_key ($event) { return $used }

Receives every Term::Fabulous::Event::KeyPress fired on the input (or bubbling up to it) while it is enabled. Return true when you used the key: the event then stops. Return false to let it bubble on. The default uses nothing.

handle_mouse

method handle_mouse ($event) { return $used }

Receives every Term::Fabulous::Event::Mouse fired on the input (or bubbling up to it) while it is enabled. Return value as for handle_key. The default uses nothing.

The event carries terminal coordinates. Use "cell_at" in Term::Fabulous::Widget::Canvas to turn them into a cell of the input's buffer; it returns the empty list when the pointer is outside the buffer (on the border or padding):

method handle_mouse ($event) {
	my ( $column, $row ) = $self->cell_at($event) or return 0;
	...
}

activate

method activate () { ... }

Called when the input is clicked (the left button pressed and released over it) while it is enabled. The default does nothing.

focus_changed

method focus_changed ($is_focused) { ... }

Called after the input gained ($is_focused true) or lost the focus, for what a widget does then besides painting (a dropdown closes its list). The default does nothing; the focus is part of the "paint_key".

layout_properties

method layout_properties :common () {
	return ( $class->SUPER::layout_properties, on_label => 'scalar', off_label => 'scalar', on_color => 'color' );
}

The table of the properties a KDL layout may set and how each is read (see "layout_properties" in Term::Fabulous::Role::CanParseLayout). To make parameters of your widget settable from a layout file, declare it as a class method (:common), keep the inherited table through $class->SUPER::layout_properties and add an accessor (reader and writer) of the same name for each new property. Every input inherits can_focus and disabled (booleans) and its four colors.

accepts_focus

method accepts_focus :override () { return 0 }

Whether the input can ever take the focus. Default: 1 (from Clay::UI::Role::Interaction::Focusable). An input that returns 0 (like Term::Fabulous::Widget::RadioButton) gets can_focus 0 even when enabled.

fire_change

$self->fire_change($new_value);

Fires a Term::Fabulous::Event::Change with that value on the input, then runs "validate", which fires a ValidityChange when the message about the value changed. Call it after the user changed the value, never when the program did.

value

method value () { return $on }

The value the input holds, read by validation ("required", "validator", "is_valid") whenever it is asked. Optional: the default returns undef, so an input without a value of its own, such as a list that only moves the reader somewhere, counts as empty and is valid unless it is required. Every input of Term::Fabulous overrides it.

value_is_empty

method value_is_empty :override () { return $checked ? 0 : 1 }

Whether the value counts as not filled in, which required rejects and the validator never sees. Default: value is undef or the empty string. Term::Fabulous::Widget::Checkbox overrides it: an unchecked box is empty. From Term::Fabulous::Role::Validatable, which also has validator_changed, the hook a text input uses to take the validator's suggested accept.

foreground_attr

my $fg = $self->foreground_attr;

The termbox2 attribute of text_color, or of disabled_color while the input is disabled, or of invalid_color while its value is invalid.

accent_attr

my $fg = $self->accent_attr;

The termbox2 attribute of accent_color, or of disabled_color while the input is disabled.

reverse_attr

my $cursor_fg = $self->reverse_attr($fg);

An attribute in reverse video (foreground and background swapped), as used for the text cursor. undef counts as the terminal default.

rgba_of

my $rgba = $self->rgba_of($color);

Any color the canvas accepts, as the [r, g, b, a] array reference that background_color and border_color take. A packed integer is opaque.

focus_background_attr

my $bg = $self->focus_background_attr;

The attribute of focus_background_color while the input has the focus, undef otherwise. Override it to change when the focus background is shown (Term::Fabulous::Widget::RadioButton shows it only on the button the keyboard is on).

paint_focus_background

my $bg = $self->paint_focus_background;

Fills the whole buffer with focus_background_attr when it is defined, and returns it (undef when the input shows no focus background). Pass the result on as the background of everything you paint after it.

CAVEATS

  • A disabled input does not use the mouse wheel; inside a Term::Fabulous::Widget::ScrollBox the wheel over it scrolls the scroll box. So does the wheel over a text area, a slider or an open dropdown list that cannot move any further.

SEE ALSO

"FORMS AND INPUT WIDGETS" in Term::Fabulous::Manual::Forms, Term::Fabulous::Event::Change, Term::Fabulous::Event::ValidityChange, Term::Fabulous::Validator, Term::Fabulous::Widget::Display, Term::Fabulous::Widget::Canvas, Term::Fabulous::Widget::TextInput.