NAME
Clay::UI::Role::Events::Emitter - role that lets a widget fire events
SYNOPSIS
use v5.22;
use warnings;
use feature 'signatures';
no warnings 'experimental::signatures';
use Object::Pad;
use Clay::UI::Box; # composes Clay::UI::Role::Events::Emitter
use Clay::UI::Events::Event;
use Clay::UI::Enum::Result;
class My::Panel :strict(params) :does(Clay::UI::Box) {}
my $toolbar = My::Panel->new(id => 'toolbar');
my $button = My::Panel->new(id => 'save');
$toolbar->add_child($button);
$toolbar->on('OnSave', sub ($event) {
say 'toolbar: ', $event->target->id, ' wants to save';
return;
});
my $event = Clay::UI::Events::Event->new(name => 'OnSave');
# no listener on the button: bubbles to the toolbar
my $result = $button->fire_event($event);
say 'handled by ', $event->handled_by->id if $result == Clay::UI::Enum::Result->HANDLED;
DESCRIPTION
This role is the sending half of the Clay::UI event system: it gives a widget the "fire_event" method. The receiving half, on, is Clay::UI::Role::Events::Listener, which every widget has.
Clay::UI::Box composes this role, and so do Clay::UI::Role::Interaction::Hoverable, Clay::UI::Role::Interaction::Pressable, Clay::UI::Role::Interaction::Focusable and Clay::UI::Role::Layout::HasScroll, whose events Clay::UI fires through it. Text widgets (Clay::UI::Text) can register listeners, but no event reaches a text widget: it cannot fire, nothing bubbles through it (it is a leaf, and events bubble from a widget to its ancestors), and Clay::UI fires events only at element widgets.
The role composes Clay::UI::Role::Layout::HasParent (for the walk up the parent chain) and Clay::UI::Role::Events::Listener.
METHODS
fire_event
my $result = $widget->fire_event($event);
Dispatches $event, a Clay::UI::Events::Event object, starting at this widget:
Records this widget as
$event->target.Sets
$event->current_targetto the current widget (this widget first) and calls each of its listeners for$event->name, in registration order, with the event as the only argument. All listeners of the widget always run; their return values only decide whether the event moves on to the parent (step 3). A listener stops the event when it returns anything butClay::UI::Enum::Result->CONTINUE; the first widget where that happens becomes$event->handled_by.Moves on to the parent and repeats step 2, as the event's bubble mode allows:
ALWAYSalways moves on,IF_CONTINUEmoves on only when no listener of the current widget stopped the event,NEVERnever does (see Clay::UI::Enum::Bubble). The walk ends at the root widget.
Returns Clay::UI::Enum::Result->HANDLED when some listener stopped the event, otherwise Clay::UI::Enum::Result->CONTINUE (no listener at all is CONTINUE too). The same value is available afterwards as $event->result.
Dies with Clay::UI::Role::Events::Emitter: fire_event needs a Clay::UI::Events::Event instance, and with Clay::UI::Events::Event: event already dispatched; build a fresh event to fire again for an event object that was fired before.
A listener that dies ends the dispatch at once: the remaining listeners and ancestors are skipped and fire_event dies with that error. (When Clay::UI fires events in "render" in Clay::UI or "update" in Clay::UI::Interaction, it catches the error, fires the remaining events of the frame and rethrows the first error afterwards.)
The widget does not need to belong to a Clay::UI; firing works on any widget tree.
SEE ALSO
Clay::UI::Role::Events::Listener, Clay::UI::Events::Event, Clay::UI::Enum::Bubble, Clay::UI::Enum::Result.