NAME
Clay::UI::Role::Interaction::Hoverable - role for widgets that track the pointer hovering over them
SYNOPSIS
use v5.22;
use warnings;
use feature 'signatures';
no warnings 'experimental::signatures';
use Object::Pad;
use Clay::XS qw(sizing_grow);
use Clay::UI;
use Clay::UI::Box;
use Clay::UI::Role::Interaction::Hoverable;
class My::Tile :strict(params)
:does(Clay::UI::Box)
:does(Clay::UI::Role::Interaction::Hoverable)
{}
my $tile = My::Tile->new(
id => 'tile',
layout => { sizing => { width => sizing_grow(), height => sizing_grow() } },
);
$tile->on('OnHoverStart', sub ($event) { say 'entered'; return });
$tile->on('OnHoverStopped', sub ($event) { say 'left'; return });
my $ui = Clay::UI->new(width => 100, height => 100, root => $tile);
$ui->render;
$ui->render(pointer_state => { x => 50, y => 50, down => 0 }); # entered
say $tile->is_hovered; # 1
$ui->render(pointer_state => { x => 500, y => 500, down => 0 }); # left
DESCRIPTION
A widget that composes this role is hovered while the pointer is over it, and receives:
Clay::UI::Events::OnHoverStart in the frame the pointer comes over it;
Clay::UI::Events::OnHoverStopped in the frame the pointer leaves it, or at once when it is removed from the tree while hovered.
Neither event bubbles: every hovered widget, nested ones included, gets its own. Widgets that do not compose Hoverable are never hovered and get no hover events, although "under_pointer" in Clay::UI::Interaction lists them.
No wiring is needed: "render" in Clay::UI finds the widgets under the pointer and fires the events before it lays out the frame (see "HOW A FRAME WORKS" in Clay::UI), so listeners may change the tree. The pointer is tested against the previous frame's layout, so a widget can be hovered from the frame after the one that first lays it out.
Hovering needs an element: composing Hoverable (or Clay::UI::Role::Interaction::Pressable) into a text widget dies at construction with Clay::UI: <class> composes Clay::UI::Role::Interaction::Hoverable on a text node; Clay cannot report the pointer over text elements - wrap the text in an Element. Make the element around the text hoverable instead.
The role composes Clay::UI::Role::Layout::HasParent, Clay::UI::Role::Events::Emitter and Clay::UI::Role::Style::HasStates, which provides the derived state hovered.
METHODS
is_hovered
my $over = $widget->is_hovered;
Returns 1 while the pointer is over the widget, as of the last "render" in Clay::UI (or synthetic "update" in Clay::UI::Interaction), and 0 otherwise. Returns 0 for a widget that does not belong to a Clay::UI. A disabled widget (Clay::UI::Role::Interaction::Disableable) is still hovered.
SEE ALSO
Clay::UI::Events::OnHoverStart, Clay::UI::Events::OnHoverStopped, Clay::UI::Role::Interaction::Pressable, Clay::UI::Interaction.