NAME

Term::Fabulous::Widget - Abstract base class of the Term::Fabulous container widgets

SYNOPSIS

# Term::Fabulous::Widget is abstract; you use its subclasses:
use Term::Fabulous::Widget::Box;
use Term::Fabulous::Enum::BorderStyle;
use Clay::XS qw(sizing_grow sizing_fit CLAY_TOP_TO_BOTTOM);

my $panel = Term::Fabulous::Widget::Box->new(
	id               => 'panel',
	layout           => {
		layout_direction => CLAY_TOP_TO_BOTTOM,
		sizing           => { width => sizing_grow(), height => sizing_fit() },
		padding          => { left => 1, right => 1 },
		child_gap        => 1,
	},
	background_color => [ 30, 35, 50, 255 ],
	bordered         => 1,
	border_color     => [ 120, 160, 220, 255 ],
	border_style     => Term::Fabulous::Enum::BorderStyle->Round,
	classes          => ['sidebar'],
);

# Writing a widget class of your own:
use Object::Pad;
class My::Panel :isa(Term::Fabulous::Widget) :strict(params) { }

DESCRIPTION

Term::Fabulous::Widget is the common base of every Term::Fabulous widget that is a rectangle on the screen and can hold other widgets: Term::Fabulous::Widget::Box and everything built on it (Term::Fabulous::Widget::Button, Term::Fabulous::Widget::ScrollBox, Term::Fabulous::Widget::Canvas, the input widgets, ...). Term::Fabulous::Widget::Text is not one of them: text is a leaf that always lives inside such a widget.

The class is abstract: Term::Fabulous::Widget->new dies. Create a Term::Fabulous::Widget::Box when you need a plain container, or subclass this class (or Box) for a widget of your own.

This page is the reference for everything these widgets have in common: the constructor parameters for layout, background, border and ids, and the methods for children, events and states. Most of it comes from Clay::UI, the widget layer on top of the Clay layout engine, through the roles this class inherits from Term::Fabulous::Widget::Element and the one it composes itself:

The sections below summarize what you need for everyday use; the role pages have the full details.

CONSTRUCTOR

new

my $box = Term::Fabulous::Widget::Box->new(%parameters);

new is called on a concrete subclass. All parameters are optional. The concrete classes reject unknown parameters: a typo dies with Unrecognised parameters for ... constructor. Widgets are created empty; add children afterwards with "add_child".

id

A non-empty string. Default: none. Names the widget: "remove_child_with_id" removes children by id, listeners can tell widgets apart with $event->target->id, and Clay keeps state (such as a scroll position) for it between frames. "find_by_id" finds a widget in a tree by its id. Ids must be unique in a widget tree: two widgets with the same id make drawing die with a Clay error. Ids starting with anon: are reserved and die. Widgets without an id get one generated from their position in the tree. Term::Fabulous::Widget::ScrollBox requires an id.

layout

A hash reference of layout options. Default: {}, which sizes the widget to fit its content and stacks children from left to right. The keys are:

sizing

{ width => $sizing, height => $sizing }, each built with a function from Clay::XS: sizing_fit($min, $max) (as big as the content, the default), sizing_grow($min, $max) (take the space left over in the parent), sizing_fixed($cells) and sizing_percent($fraction) (a share of the parent, a number from 0 to 1; 0.5 is half). A fraction above 1 is accepted by new but makes drawing die with a Clay error. $min and $max are optional limits in cells. Either axis may be left out.

padding

{ left => $n, right => $n, top => $n, bottom => $n }, any subset, in cells; padding_all($n) from Clay::XS builds one with all four sides. The padding lies inside the border (see "Border space" in Term::Fabulous::Role::HasBorderStyle).

child_gap

The number of empty cells between two neighboring children.

layout_direction

CLAY_LEFT_TO_RIGHT (the default), CLAY_TOP_TO_BOTTOM, CLAY_LEFT_TO_RIGHT_WRAP (left to right, wrapping onto new lines; see "Flow layout" in Term::Fabulous::Manual::Layout) or CLAY_BACK_TO_FRONT (on top of each other; see "Stack layout" in Term::Fabulous::Manual::Layout), constants exported by Clay::XS.

line_gap

The number of empty rows between two lines of a CLAY_LEFT_TO_RIGHT_WRAP layout. Default: 0.

line_sizing

CLAY_LINE_SIZING_GROW (the default) or CLAY_LINE_SIZING_FIT, constants exported by Clay::XS: whether the lines of a CLAY_LEFT_TO_RIGHT_WRAP layout share the rows left over below them or keep the height of their tallest child.

child_alignment

{ x => $x, y => $y } with CLAY_ALIGN_X_LEFT, CLAY_ALIGN_X_CENTER or CLAY_ALIGN_X_RIGHT and CLAY_ALIGN_Y_TOP, CLAY_ALIGN_Y_CENTER or CLAY_ALIGN_Y_BOTTOM. Default: left and top.

Any other key, or a value of the wrong shape, dies. See "LAYOUT" in Term::Fabulous::Manual::Layout for how these work together.

floating

A hash reference that takes the widget out of its parent's layout and draws it on top of the other widgets, positioned against its parent, the root or another widget. It takes no space in its parent. Default: undef, the widget is laid out normally. The keys, all optional, take constants exported by Clay::XS:

attach_to

What the widget is positioned against: CLAY_ATTACH_TO_PARENT, CLAY_ATTACH_TO_ROOT (the whole screen) or CLAY_ATTACH_TO_ELEMENT_WITH_ID (the widget named by parent_id). The default, CLAY_ATTACH_TO_NONE, does not make the widget float.

parent_id

With CLAY_ATTACH_TO_ELEMENT_WITH_ID, the Clay element id number of the widget to attach to: Clay::XS::Clay_GetElementId($id)->{id} for the widget with the id $id. That widget does not have to be an ancestor.

attach_points

{ element => $point, parent => $point }: the point of this widget that is placed on the point of the widget it is attached to, each one of CLAY_ATTACH_POINT_LEFT_TOP, ..._LEFT_CENTER, ..._LEFT_BOTTOM, ..._CENTER_TOP, ..._CENTER_CENTER, ..._CENTER_BOTTOM, ..._RIGHT_TOP, ..._RIGHT_CENTER and ..._RIGHT_BOTTOM. Default: both CLAY_ATTACH_POINT_LEFT_TOP.

offset

{ x => $columns, y => $rows }, added to the position; negative values move left and up.

expand

{ width => $columns, height => $rows }, enlarges the widget's area without changing the space its children get.

z_index

An integer from -32768 to 32767. Floating widgets with a higher value are drawn on top of those with a lower one.

pointer_capture_mode

CLAY_POINTER_CAPTURE_MODE_CAPTURE (the default) or CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH, Clay's pointer setting for the widget. Term::Fabulous delivers Mouse events to the topmost widget painted under the pointer either way.

clip_to

CLAY_CLIP_TO_NONE (the default) or CLAY_CLIP_TO_ATTACHED_PARENT, which cuts the widget off at the clipping area (such as a Term::Fabulous::Widget::ScrollBox) of the widget it is attached to.

Any other key, or a value of the wrong shape, dies. See Clay::UI::Role::Layout::HasFloating.

background_color

The color of the widget's area, in any format Term::Fabulous::Color accepts: an array reference [r, g, b, a] (or [r, g, b], alpha 255), a hash reference { r = ..., g => ..., b => ..., a => ... }>, a string such as '#ff0000' or 'rgb(255, 0, 0)', or a Term::Fabulous::Color object. The value is stored as [r, g, b, a], which is what the reader returns. Default: none, so the widget's area shows what is behind it. An alpha of 0 means no color, 255 is opaque, and 1 to 254 is translucent: the color is blended with whatever is below the widget (see glyphs_show_through). See "COLORS" in Term::Fabulous::Manual::Looks.

A widget with neither a background color nor a border paints nothing, so it is also invisible to the mouse: clicks on it go to the widget behind it. A widget with only a border receives clicks on its border cells.

glyphs_show_through

Only matters with a translucent background_color (alpha 1 to 254). False (the default): the widget's area is covered with spaces in the blended color, so text and borders below it disappear. True: they stay visible through the background, with their colors tinted by it, until the widget paints its own content over them. Where the color below is the terminal default, which cannot be blended, the background is drawn opaque and a glyph's default foreground stays as it is. Any true or false value; references die. See "Alpha and the terminal default color" in Term::Fabulous::Manual::Looks.

bordered

Which sides have a border: one true or false value for all four sides, or a hash reference with any of the keys top, right, bottom and left and true or false values, where a side the hash leaves out has no border ({ top => 1, bottom => 1 } draws a line above and below the widget). Default: the theme's border.enabled for the widget's family, on all four sides. The box family (plain boxes, scroll boxes, canvases, charts and every widget that names no family of its own) has no border.enabled, so its widgets have no border unless they are given one (see "Borders" in Term::Fabulous::Theme). Stored as a hash of all four sides, 1 or 0. Another reference, an unknown side or a reference as a side's value dies, and so does undef: "reset_look" returns the parameter to the theme.

A border is one cell thick and takes that cell from the inside of the widget: the padding and the content start after it, and a widget with fit sizing grows by it. Room between the border and the content is padding. A side whose style is Hidden draws nothing and takes no space. See "BORDERS" in Term::Fabulous::Manual::Looks.

Term::Fabulous widgets do not take the border_width of Clay::UI::Role::Style::HasBorder: giving it to the constructor, or calling border_width, dies with a hint to use bordered.

border_color

The color of the border glyphs, in the same formats as background_color. Default: the terminal's default foreground color.

border_style

A Term::Fabulous::Enum::BorderStyle item, such as Term::Fabulous::Enum::BorderStyle->Round, or its name ('Round'), used for every side that has no side parameter of its own. Default: the theme's border.style for the widget's family (Round in the built-in themes); a side with a border but no style from the program, the widget or the theme is drawn with the Blank style (spaces). See Term::Fabulous::Role::HasBorderStyle.

border_style_top
border_style_right
border_style_bottom
border_style_left

The style of one side, a Term::Fabulous::Enum::BorderStyle item or its name. It wins over border_style for that side; see Term::Fabulous::Role::HasBorderStyle.

border_corners

undef (the default) or a hash reference with any of the keys top_left, top_right, bottom_left and bottom_right, each a glyph drawn at that corner instead of the style's corner glyph, for example to join the box to lines around it. See "border_corners" in Term::Fabulous::Role::HasBorderStyle.

outer_border_sides

An array reference of side names (top, right, bottom, left) whose glyphs are drawn on the background outside the widget instead of the widget's own. Default: []. See "outer_border_sides" in Term::Fabulous::Role::HasBorderStyle.

width_group
height_group

An integer from 0 to 1048575. Default: 0 (no group). Widgets anywhere in the tree with the same non-zero group number get the same width (or height): the largest content size among them. Useful to line up form labels. Only fit and grow sizing take part. See Clay::UI::Role::Layout::HasSizingGroup.

classes

An array reference of strings. Default: []. Names of your own, returned by "get_classes" and "classes". The theme reads them: a widget whose classes name a variant of its family draws with that variant (see "Variants and classes" in Term::Fabulous::Manual::Looks). The array is copied; anything but an array of defined, non-reference names dies.

The background, the border color, the border style and whether there is a border at all come from the theme of the UI when they are not given, where the theme has them for the widget's family (a plain Box has no background in the built-in themes and never gets a border from a theme; a Dialog or a Toast has both); see "THEMES" in Term::Fabulous::Manual::Looks. Subclasses document the theme slot each of their colors reads.

METHODS

The methods fall into four groups: children (add_child to ui), events (on, fire_event, handlers_for), layout and style accessors (layout to height_group) and states (add_state to get_classes).

States: every widget has a set of state names. hovered, pressed, focused and disabled are derived states: they follow the widget's interaction (for example on a Term::Fabulous::Widget::Button) or its disabled flag and cannot be set by hand. You may add names of your own, for example selected. See Clay::UI::Role::Style::HasStates.

add_child

$box->add_child($widget);
$box->add_child( $header, $body, $footer );

Appends one or more widgets (or Term::Fabulous::Widget::Texts) as children, in order. Returns the widget, so calls chain: $root->add_child($a)->add_child($b).

A widget has at most one parent at a time. Adding a widget that still has a parent dies, and so does adding the root of a Term::Fabulous or a widget to itself or one of its descendants. To move a widget, remove it from its parent first. See "add_child" in Clay::UI::Role::Core::Container.

remove_child

$box->remove_child($status);
$box->remove_child( $spinner, $label );

Removes each given widget that is a direct child of this one (the very object; widgets without an id and Text widgets included). A widget that is not a direct child is ignored. Dies, removing nothing, for anything but a widget, an id included (use "remove_child_with_id"). A removed widget keeps its children and its state and can be added again. Returns the widget.

Removing a subtree that holds the focused widget or a hovered widget fires OnBlur or OnHoverStopped on it during the call; OnBlur still bubbles through the old parents. When an OnBlur listener dies, the removal is completed first and the error is rethrown afterwards.

remove_child_with_id

$box->remove_child_with_id('status');

Removes every direct child whose id equals the argument. Unknown ids are ignored. Text widgets are never removed this way, even when they have an id (use "remove_child" or "remove_children_with"). Returns the widget. Removal works as described in "remove_child".

remove_children_with

$box->remove_children_with( sub { $_->isa('Term::Fabulous::Widget::Text') } );

Removes every direct child for which the code reference returns true. The child is passed as the argument and in $_. Returns the widget. Removal works as described in "remove_child".

clear_children

$box->clear_children;

Removes all children. Returns the widget. Removal works as described in "remove_child".

id

my $id = $widget->id;

The id given to the constructor, or undef when none was given (the generated id is not returned). There is no writer.

invalid_inputs

if ( my @invalid = $form->invalid_inputs ) {
	$message->text( $invalid[0]->error );
	$ui->interaction->set_focused_widget( $invalid[0] );
	return;
}

The input widgets at or below this one, in the same order as "find_by_id" walks, whose value is not valid (see "is_valid" in Term::Fabulous::Widget::Input): empty while required, or rejected by their validator. The widget itself is included when it is such an input. Returns an empty list when every input is fine, also when there is none. The tree is walked on every call.

find_by_id

my $volume = $root->find_by_id('volume');

The first widget, in depth-first pre-order, whose id equals the argument: the widget itself, then its first child and that child's descendants, then the second child, and so on, the order in which the frame lays them out ("descendants" in Clay::UI::Role::Core::Element). Text widgets with an id are found too, and so are the widgets a widget keeps below an internal child, such as the items of a Term::Fabulous::Widget::VirtualList. Returns undef when there is none. Dies when the argument is undef. The tree is walked on every call; keep the result instead of searching in every event.

children

my @kids = @{ $box->children };

A new array reference with the direct children, in order. Changing the array does not change the widget.

has_child

$box->add_child($status) unless $box->has_child($status);

1 when the widget is a direct child of this one (the very object), else 0. Dies for anything but a widget.

get_children_with

my @buttons = $box->get_children_with( sub { $_->isa('Term::Fabulous::Widget::Button') } );

The direct children for which the code reference returns true (as a list). Does not look at grandchildren.

descendants

my @fields = grep { $_->isa('Term::Fabulous::Widget::TextField') } $form->descendants;

Every widget below this one, not the widget itself, as a list in the order the frame lays them out: each child followed by the widgets below it, including those a widget keeps below an internal child (the items of a Term::Fabulous::Widget::VirtualList). See "descendants" in Clay::UI::Role::Core::Element.

parent

my $owner = $widget->parent;

The widget that contains this one, or undef for the root and for widgets that were never added or were removed.

root

my $top = $widget->root;

The topmost widget above this one (the widget itself when it has no parent).

ui

my $ui = $widget->ui;

The Term::Fabulous (or Term::Fabulous::Static) object whose tree contains the widget, or undef when it is not part of one. Useful in listeners, for example $widget->ui->interaction->set_focused_widget(...).

contains

return if $popup->contains( $event->target );

1 when the argument is this widget or a widget below it, else 0. Dies for anything but a widget. To ask whether the focus is inside a widget, use $widget->ui->interaction->has_focus_within($widget). See "contains" in Clay::UI::Role::Layout::HasParent.

on

$widget->on( KeyPress => sub ($event) { ...; return } );

Registers a listener: a code reference called with the event object whenever an event of that name is fired on this widget or bubbles up to it from a descendant. Several listeners per name are allowed; they run in the order they were added. Returns the widget. Dies when the name is empty or the listener is not a code reference.

What the listener returns decides whether the event continues to the parent: only Clay::UI::Enum::Result->CONTINUE lets it go on, any other value (including a plain return;) stops it after this widget. The other listeners on the same widget still run. A few event types never bubble, whatever the listeners return. See "EVENTS" in Term::Fabulous::Manual::Events for the event names and the rules.

fire_event

$widget->fire_event( Term::Fabulous::Event::Change->new( value => 42 ) );

Delivers an event object to this widget's listeners and then up the parent chain as described in "on". An event object can be fired only once. Term::Fabulous calls this for you; call it yourself for events of your own or in tests. See Clay::UI::Role::Events::Emitter.

handlers_for

my $listeners = $widget->handlers_for('KeyPress');
printf "%d KeyPress listeners\n", scalar @$listeners;

A new array reference with the listeners registered on this widget for an event name, in the order they were added (an empty array reference when there are none). Changing the array does not change the widget. Mostly useful in tests.

layout

my $layout = $box->layout;
$box->layout( { %{ $box->layout }, child_gap => 2 } );

Accessor for the layout hash (see "new"). Without an argument it returns a copy of the stored hash; with an argument it replaces the whole hash and returns a copy of the new one. Changing the returned hash does not change the widget; write it back. An invalid hash dies like the constructor parameter. The change shows in the next frame. Copy the old hash as above to change a single key.

floating

my $floating = $popup->floating;
$popup->floating( { %{ $popup->floating // {} }, offset => { x => 4, y => 2 } } );

Accessor for the floating hash (see "new"). Without an argument it returns a copy of the stored hash (undef when none is set); with an argument it replaces the whole hash and returns a copy of the new one. undef makes the widget part of its parent's layout again. An invalid hash dies like the constructor parameter. The change shows in the next frame.

background_color

$box->background_color( [ 60, 90, 140, 255 ] );
$box->background_color('#3c5a8c');

Accessor. Without an argument it returns the color in use as [r, g, b, a]: the given one, or the theme's background for the widget's family (undef for a widget whose family has none, such as a plain Box); with an argument it sets the value, in any format the constructor parameter accepts, and returns the stored [r, g, b, a]. undef removes the given background color ("reset_look" does the same). An invalid value dies like the constructor parameter of the same name. The change shows in the next frame.

background_below

my $rgba = $widget->background_below;                     # opaque backgrounds only
my $seen = $widget->background_below( translucent => 1 );

The color the widget lies on, as a new [r, g, b, a]: the "background_color" of the widget itself or of its nearest ancestor that has an opaque one, else the screen background of the Term::Fabulous object the widget is shown in (the theme's background token, returned with alpha 255 because it is painted opaque; see "SCREEN BACKGROUND" in Term::Fabulous::Render), else undef: for a widget that is in no UI, in a Term::Fabulous::Static (which paints no screen) or under a background token with alpha 0. Widgets that draw on what lies below them use it: a Term::Fabulous::Widget::Table paints the cells that have no color of their own in it, and a chart mixes its ink from it.

A translucent background (alpha from 1 to 254) lets the colors below show through, so it is skipped. With translucent => 1 it counts as well: that is the color a painter blends a widget's own cells over, which is how the unset cells of a Term::Fabulous::Widget::Canvas are painted. Other options die.

glyphs_show_through

$box->glyphs_show_through(1);

Accessor for the constructor parameter of the same name (0 or 1). Without an argument it returns the current value; with an argument it sets the value and returns the new one. The change shows in the next frame.

border_color

$box->border_color( [ 97, 175, 239, 255 ] );
$box->border_color( Term::Fabulous::Enum::WebColor->SteelBlue );

Accessor. Without an argument it returns the color in use as [r, g, b, a]: the given one, or the theme's border color for the widget's family (undef for the terminal's default color, as for a plain Box); with an argument it sets the value, in any format the constructor parameter accepts, and returns the stored [r, g, b, a]. undef removes the given color ("reset_look" does the same). An invalid value dies like the constructor parameter of the same name. The change shows in the next frame.

bordered

$box->bordered(1);                                # every side
$box->bordered( { top => 1, bottom => 1 } );      # two sides
$box->bordered(0);                                # none, whatever the theme says
my $sides = $box->bordered;                       # { top => 1, right => 0, ... }

Accessor for the bordered parameter. The writer takes the same values as the constructor and returns the sides; an invalid value dies like the constructor parameter. The reader returns the sides the widget has a border on, given or from the theme's border.enabled, as a new hash reference of all four sides, each 1 or 0; a side whose style is Hidden still counts ("drawn_border_sides" in Term::Fabulous::Role::HasBorderStyle leaves it out). reset_look('bordered') returns it to the theme (no border in a family without border.enabled). The change shows in the next frame and changes the layout, because a border takes space.

border_width

Dies: Term::Fabulous widgets use "bordered" instead.

border_style_top

$box->border_style_top( Term::Fabulous::Enum::BorderStyle->Heavy );

Accessor for the style of the top side. The writer takes undef (no style of its own), a Term::Fabulous::Enum::BorderStyle item or its name, returns the new value, and anything else dies. The reader returns the style the side is drawn in: its own, else the theme's (or one the widget derives), else Blank; see "border_style_of" in Term::Fabulous::Role::HasBorderStyle. The change shows in the next frame. There is no border_style accessor; set the sides one by one. See Term::Fabulous::Role::HasBorderStyle.

border_style_right

$box->border_style_right( Term::Fabulous::Enum::BorderStyle->Heavy );

Accessor for the style of the right side. The writer takes undef (no style of its own), a Term::Fabulous::Enum::BorderStyle item or its name, returns the new value, and anything else dies. The reader returns the style the side is drawn in: its own, else the theme's (or one the widget derives), else Blank; see "border_style_of" in Term::Fabulous::Role::HasBorderStyle. The change shows in the next frame. There is no border_style accessor; set the sides one by one. See Term::Fabulous::Role::HasBorderStyle.

border_style_bottom

$box->border_style_bottom( Term::Fabulous::Enum::BorderStyle->Heavy );

Accessor for the style of the bottom side. The writer takes undef (no style of its own), a Term::Fabulous::Enum::BorderStyle item or its name, returns the new value, and anything else dies. The reader returns the style the side is drawn in: its own, else the theme's (or one the widget derives), else Blank; see "border_style_of" in Term::Fabulous::Role::HasBorderStyle. The change shows in the next frame. There is no border_style accessor; set the sides one by one. See Term::Fabulous::Role::HasBorderStyle.

border_style_left

$box->border_style_left( Term::Fabulous::Enum::BorderStyle->Heavy );

Accessor for the style of the left side. The writer takes undef (no style of its own), a Term::Fabulous::Enum::BorderStyle item or its name, returns the new value, and anything else dies. The reader returns the style the side is drawn in: its own, else the theme's (or one the widget derives), else Blank; see "border_style_of" in Term::Fabulous::Role::HasBorderStyle. The change shows in the next frame. There is no border_style accessor; set the sides one by one. See Term::Fabulous::Role::HasBorderStyle.

border_corners

$box->border_corners( { top_left => "\x{251C}" } );

Accessor for the corner glyphs; the reader returns a new hash reference or undef. See "border_corners" in Term::Fabulous::Role::HasBorderStyle.

outer_border_sides

$box->outer_border_sides( [ 'left', 'right' ] );

Accessor for the sides drawn outside the widget; the reader returns a new array reference. See "outer_border_sides" in Term::Fabulous::Role::HasBorderStyle.

width_group

$label->width_group(1);

Accessor. Without an argument it returns the group number (0 when the widget is in no group); with an argument it sets it and returns the new value. An invalid value dies like the constructor parameter. The change shows in the next frame.

height_group

$row->height_group(2);

Accessor for the height group, used like "width_group".

add_state

$row->add_state('selected');

Adds a state name of your own. Returns the widget. Dies for the derived states hovered, pressed, focused and disabled.

remove_state

$row->remove_state('selected');

Removes a state name of your own. Returns the widget. Dies for the derived states hovered, pressed, focused and disabled.

toggle_state

$row->toggle_state('selected');

Adds the name when it is missing, removes it otherwise. Returns the widget. Dies for the derived states hovered, pressed, focused and disabled.

clear_states

$row->clear_states;

Removes all state names of your own. The derived states (hovered, pressed, focused, disabled) are not affected. Returns the widget.

has_state

if ( $row->has_state('selected') ) { ... }

True when the state is active, including the derived ones.

states

my @active = $row->states;

The active state names, in no particular order.

classes

my $names = $widget->classes;    # ['sidebar']
$widget->classes( [ 'sidebar', 'primary' ] );

Accessor for the classes parameter. Without an argument it returns a copy of the names; with an array reference it replaces them, makes the widget read its theme looks again and returns a copy of the new names. An invalid value dies like the constructor parameter. The change shows in the next frame.

get_classes

my @classes = $widget->get_classes;    # ('sidebar', 'state_focused')

The names from the classes parameter, followed by state_NAME for every active state (state_hovered, state_selected, ...). The theme reads the classes only, not the state names.

reset_look

$button->reset_look('border_color');
$button->reset_look( 'background_color', 'focus_border_color' );

Drops the colors, border styles or borders the program gave for the named parameters, so the theme supplies them again. Takes the names of the widget's themed parameters (background_color, border_color, bordered and the ones a subclass lists), including the looks a widget keeps on its parts (the colors of a Term::Fabulous::Widget::Tabs live on its bar, the scrollbar colors of a Term::Fabulous::Widget::ScrollBox on both scrollbars); an unknown name dies naming the known ones. Returns the widget. The change shows in the next frame. From Term::Fabulous::Role::Themed, which also has look and look_value for widget authors.

mark_changed

$widget->mark_changed;

For widget authors: tells Term::Fabulous that the widget has changed in a way its accessors do not know about (state of your own that the widget draws), so that the next frame is drawn. The built-in accessors call it themselves. Returns the widget. See "mark_changed" in Clay::UI::Role::Core::Element and Term::Fabulous::Manual::CustomWidgets.

tree_changed

class My::Counter :isa(Term::Fabulous::Widget::Box) {
	field $clicks = 0;

	method tree_changed :override () {
		$self->SUPER::tree_changed;
		$clicks = 0;    # counts again from its new place
		return;
	}
}

For widget authors: Clay::UI calls it on every widget of a subtree that joined a tree, left one or became the root of a UI, once the change is complete (see "tree_changed" in Clay::UI::Role::Layout::HasParent). Here the widget forgets the looks it fetched, since its new place may be in a UI with another theme, and when that place is in a UI, calls looks_changed with all its looks. An override calls $self->SUPER::tree_changed first, as Term::Fabulous::Widget::VirtualList does to rebuild its items for the new place.

reverse_video

my $swapped = $widget->reverse_video;    # 0

For widget authors: whether the renderer swaps the foreground and background colors of every cell the widget and its children paint. Always 0 here; Term::Fabulous::Widget::Button returns 1 while it is pressed with pressed_background_color => 'reverse'. Override it in a widget class of your own for the same effect.

EVENTS

The class fires no events of its own. Every widget receives the events fired on its descendants, because events bubble up the tree (see "on"), and Term::Fabulous fires these on any widget:

Mouse (Term::Fabulous::Event::Mouse)

On the topmost widget painted under the pointer, for clicks and wheel notches. A widget paints its whole area when it has a background color and only its border cells when it has a border but no background; a widget with neither is transparent to the mouse.

KeyPress (Term::Fabulous::Event::KeyPress)

On the root widget when no widget has the focus.

Subclasses add their own events, such as Activate on a Term::Fabulous::Widget::Button and OnScroll on a Term::Fabulous::Widget::ScrollBox. The event reference of the events guide lists them all.

SEE ALSO

Term::Fabulous::Widget::Box, "LAYOUT" in Term::Fabulous::Manual::Layout (the layout options with pictures), "EVENTS" in Term::Fabulous::Manual::Events, Term::Fabulous::Role::HasBorderStyle, Clay::UI, "Line up labels with equal widths (width_group)" in Term::Fabulous::Cookbook::Layout, "Use a different border style on each side" in Term::Fabulous::Cookbook::Layout, "Mark widgets with states and classes" in Term::Fabulous::Cookbook::Layout.