NAME
Clay::UI::Events::Event - base class of Clay::UI events, and how to make your own
SYNOPSIS
use v5.22;
use warnings;
use feature 'signatures';
no warnings 'experimental::signatures';
use Object::Pad;
use Clay::UI::Box;
use Clay::UI::Events::Event;
use Clay::UI::Enum::Bubble;
use Clay::UI::Enum::Result;
class My::Panel :strict(params) :does(Clay::UI::Box) {}
# A custom event: a subclass with its own name, payload and bubble mode.
class My::Events::OnSubmit :isa(Clay::UI::Events::Event) :strict(params) {
field $value :param :reader;
method event_name :common { 'OnSubmit' }
method default_bubble_mode :common { Clay::UI::Enum::Bubble->ALWAYS }
}
my $form = My::Panel->new(id => 'form');
my $field = My::Panel->new(id => 'field');
$form->add_child($field);
$form->on('OnSubmit', sub ($event) {
say 'form got ', $event->value, ' from ', $event->target->id;
return Clay::UI::Enum::Result->HANDLED;
});
# Fire it at the widget it concerns; it bubbles up to the form.
my $event = My::Events::OnSubmit->new(value => 42);
my $result = $field->fire_event($event);
say 'handled by ', $event->handled_by->id
if $result == Clay::UI::Enum::Result->HANDLED;
# A one-off event needs no subclass:
$field->fire_event(Clay::UI::Events::Event->new(name => 'OnPing'));
DESCRIPTION
Every Clay::UI event is an object of this class or of a subclass. An event has a name, which listeners register for with $widget->on($name, sub ($event) { ... }) (Clay::UI::Role::Events::Listener), and a bubble mode, which says whether the event travels from the widget it was fired at (the target) up to its ancestors (Clay::UI::Enum::Bubble).
A widget that composes Clay::UI::Role::Events::Emitter fires an event with $widget->fire_event($event) ("fire_event" in Clay::UI::Role::Events::Emitter). While the event travels, its accessors tell each listener where it is.
The built-in events are subclasses: Clay::UI::Events::OnHoverStart, Clay::UI::Events::OnHoverStopped, Clay::UI::Events::OnPress, Clay::UI::Events::OnRelease, Clay::UI::Events::OnScroll, Clay::UI::Events::OnFocus and Clay::UI::Events::OnBlur.
CONSTRUCTOR
new
my $event = Clay::UI::Events::Event->new(%params);
Creates an event. Both parameters are optional; unknown parameters die (the class is :strict(params)).
- name
-
The event name, a non-empty string. Default: what the class method
event_namereturns ('Event'for this class). Dies withClay::UI::Events::Event: 'name' must be a non-empty string. - bubble_mode
-
A Clay::UI::Enum::Bubble value. Default: what the class method
default_bubble_modereturns (IF_CONTINUEfor this class). Dies withClay::UI::Events::Event: 'bubble_mode' must be a Clay::UI::Enum::Bubble value.
ACCESSORS
name
my $name = $event->name;
The event name listeners register for.
bubble_mode
my $mode = $event->bubble_mode;
The Clay::UI::Enum::Bubble value that decides how far the event travels.
target
my $widget = $event->target;
The widget fire_event was called on. It stays the same while the event bubbles. undef before the event is fired.
current_target
my $widget = $event->current_target;
The widget whose listeners are running right now: the target first, then each ancestor the event bubbles to. undef before the event is fired.
handled_by
my $widget = $event->handled_by;
The first widget at which a listener returned anything but Clay::UI::Enum::Result->CONTINUE, or undef when no listener did (or the event has not been fired). With IF_CONTINUE and NEVER it is the widget where the event stopped; with ALWAYS the event travels on and this names the first such widget.
target, current_target and handled_by are weak references: a fired event never keeps widgets alive.
result
my $result = $event->result;
The outcome of the dispatch so far, as a Clay::UI::Enum::Result value: HANDLED when handled_by is set, CONTINUE otherwise. fire_event returns this value.
CLASS METHODS
Subclasses override these :common methods to give new its defaults.
event_name
method event_name :common { 'OnSubmit' }
The default name. Returns 'Event' in this class.
default_bubble_mode
method default_bubble_mode :common { Clay::UI::Enum::Bubble->NEVER }
The default bubble_mode. Returns Clay::UI::Enum::Bubble->IF_CONTINUE in this class.
CUSTOM EVENTS
To give an event a payload, subclass this class:
Declare the class with
:isa(Clay::UI::Events::Event)and:strict(params).Add the payload as fields with
:param :reader(as Clay::UI::Events::OnPress does withx,yandbutton).Override
event_name(anddefault_bubble_modewhenIF_CONTINUEis not right) as:commonmethods.Fire a new object with
$widget->fire_event($event)on a widget that composes Clay::UI::Role::Events::Emitter, for example any Clay::UI::Box. Text widgets can listen but not fire.
For an event without payload, Clay::UI::Events::Event->new(name => 'OnPing') is enough. Clay::UI never fires custom events by itself; fire them from your own listeners or code, for example from an OnRelease listener of a widget that turns a click into an OnSubmit.
FIRING AN EVENT TWICE
An event object is single-use. The first fire_event records the target; firing the same object again dies with Clay::UI::Events::Event: event already dispatched; build a fresh event to fire again. Create a new event for every dispatch.
SEE ALSO
Clay::UI::Role::Events::Emitter, Clay::UI::Role::Events::Listener, Clay::UI::Enum::Bubble, Clay::UI::Enum::Result, "EVENTS" in Clay::UI.