1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
//! # Events
//!
//! Events let your UI react to user input: a click, a key press, the cursor entering an
//! element, a scroll, a file drop, and so on.
//!
//! Events are attached to **elements** (`rect`, `label`, `paragraph`, ...), not to components.
//! Components are just a way to organize and reuse UI. The listeners are on the elements that
//! the component returns.
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! # fn app() -> impl IntoElement {
//! rect()
//! .width(Size::px(100.))
//! .height(Size::px(100.))
//! .background(Color::RED)
//! .on_press(|_| println!("Clicked!"))
//! # }
//! ```
//!
//! ## Event handlers
//!
//! Most events have a method named `on_<event>` (and global variants `on_global_<event>`).
//! See [`EventHandlersExt`](freya_core::prelude::EventHandlersExt) for the full list.
//!
//! Common ones:
//!
//! - Press: [`on_press`](freya_core::prelude::EventHandlersExt::on_press),
//! [`on_secondary_down`](freya_core::prelude::EventHandlersExt::on_secondary_down).
//! - Pointer: [`on_pointer_press`](freya_core::prelude::EventHandlersExt::on_pointer_press),
//! [`on_pointer_down`](freya_core::prelude::EventHandlersExt::on_pointer_down),
//! [`on_pointer_move`](freya_core::prelude::EventHandlersExt::on_pointer_move),
//! [`on_pointer_enter`](freya_core::prelude::EventHandlersExt::on_pointer_enter),
//! [`on_pointer_leave`](freya_core::prelude::EventHandlersExt::on_pointer_leave),
//! [`on_pointer_over`](freya_core::prelude::EventHandlersExt::on_pointer_over),
//! [`on_pointer_out`](freya_core::prelude::EventHandlersExt::on_pointer_out).
//! - Mouse: [`on_mouse_down`](freya_core::prelude::EventHandlersExt::on_mouse_down),
//! [`on_mouse_up`](freya_core::prelude::EventHandlersExt::on_mouse_up),
//! [`on_mouse_move`](freya_core::prelude::EventHandlersExt::on_mouse_move).
//! - Touch: [`on_touch_start`](freya_core::prelude::EventHandlersExt::on_touch_start),
//! [`on_touch_move`](freya_core::prelude::EventHandlersExt::on_touch_move),
//! [`on_touch_end`](freya_core::prelude::EventHandlersExt::on_touch_end),
//! [`on_touch_cancel`](freya_core::prelude::EventHandlersExt::on_touch_cancel).
//! - Keyboard: [`on_key_down`](freya_core::prelude::EventHandlersExt::on_key_down),
//! [`on_key_up`](freya_core::prelude::EventHandlersExt::on_key_up).
//! - Wheel: [`on_wheel`](freya_core::prelude::EventHandlersExt::on_wheel).
//! - Layout: [`on_sized`](freya_core::prelude::EventHandlersExt::on_sized),
//! [`on_visible`](freya_core::prelude::EventHandlersExt::on_visible),
//! [`on_hidden`](freya_core::prelude::EventHandlersExt::on_hidden).
//! - Files: [`on_file_drop`](freya_core::prelude::EventHandlersExt::on_file_drop).
//!
//! Each handler receives an [`Event<D>`](freya_core::prelude::Event) where `D` is the payload
//! (e.g [`PointerEventData`](freya_core::prelude::PointerEventData),
//! [`KeyboardEventData`](freya_core::prelude::KeyboardEventData), etc).
//!
//! ## Propagation (bubbling)
//!
//! When an event fires on a target element it then **bubbles** up through its ancestors,
//! invoking any matching handler along the way.
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! # fn app() -> impl IntoElement {
//! rect()
//! .on_press(|_| println!("outer"))
//! .child(rect().on_press(|_| println!("inner")))
//! # }
//! ```
//!
//! Pressing the inner rect prints `inner` and then `outer`.
//!
//! ### Stopping propagation
//!
//! Call [`stop_propagation`](freya_core::prelude::Event::stop_propagation) on the event to
//! prevent it from continuing to bubble up to ancestors. The current handler still runs to
//! completion. Only ancestor handlers for **this same event** are skipped.
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! # fn app() -> impl IntoElement {
//! rect()
//! .on_press(|_| println!("outer"))
//! .child(rect().on_press(|e: Event<PressEventData>| {
//! e.stop_propagation();
//! println!("inner only");
//! }))
//! # }
//! ```
//!
//! Note that not every event bubbles. Move/enter/leave events, capture events, and global
//! events do not bubble: they target specific elements directly.
//!
//! ## Default behavior and `prevent_default`
//!
//! Some events have a **default behavior**: side effects that Freya runs after the handler
//! unless you opt out. The most common case is that an element-level event (e.g
//! [`on_mouse_up`](freya_core::prelude::EventHandlersExt::on_mouse_up)) also dispatches a related
//! **global** event (e.g [`on_global_pointer_up`](freya_core::prelude::EventHandlersExt::on_global_pointer_up)),
//! and that some events (e.g [`on_mouse_down`](freya_core::prelude::EventHandlersExt::on_mouse_down))
//! get translated into the unified [pointer events](freya_core::prelude::PointerEventData)
//! (e.g [`on_pointer_down`](freya_core::prelude::EventHandlersExt::on_pointer_down)).
//!
//! Calling [`prevent_default`](freya_core::prelude::Event::prevent_default) cancels those
//! follow-up events for this dispatch. It is **not** the same as `stop_propagation`:
//!
//! - `stop_propagation`: stops **this same event** from bubbling to ancestors.
//! - `prevent_default`: cancels **other related events** that would otherwise fire as a
//! consequence of this one.
//!
//! Each event declares which other events it can cancel. For example an
//! [`on_mouse_up`](freya_core::prelude::EventHandlersExt::on_mouse_up) handler that calls
//! `prevent_default` will additionally cancel the
//! [`on_pointer_press`](freya_core::prelude::EventHandlersExt::on_pointer_press) and the
//! [`on_global_pointer_up`](freya_core::prelude::EventHandlersExt::on_global_pointer_up)
//! events that would have fired afterwards.
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! # fn app() -> impl IntoElement {
//! rect()
//! .on_global_pointer_up(|_| println!("Anywhere on screen"))
//! .child(rect().on_mouse_up(|e: Event<MouseEventData>| {
//! // Suppresses the global handler above for this click only.
//! e.prevent_default();
//! println!("Click handled here");
//! }))
//! # }
//! ```
//!
//! A typical use case is a draggable scrollbar: while dragging, the scrollbar handles the
//! pointer move events itself and calls `prevent_default` so that no other element behind the
//! cursor receives hover/move events for the duration of the drag.
//!
//! ## Event ordering and priority
//!
//! When several events would dispatch in the same frame, Freya processes them in a fixed
//! priority order:
//!
//! 1. **Capture** events (e.g
//! [`on_capture_global_pointer_up`](freya_core::prelude::EventHandlersExt::on_capture_global_pointer_up),
//! [`on_capture_global_pointer_move`](freya_core::prelude::EventHandlersExt::on_capture_global_pointer_move)).
//! 2. **Leave** events ([`on_pointer_leave`](freya_core::prelude::EventHandlersExt::on_pointer_leave),
//! [`on_pointer_out`](freya_core::prelude::EventHandlersExt::on_pointer_out)).
//! 3. **Enter / over** events ([`on_pointer_enter`](freya_core::prelude::EventHandlersExt::on_pointer_enter),
//! [`on_pointer_over`](freya_core::prelude::EventHandlersExt::on_pointer_over)).
//! 4. Everything else.
//!
//! Within the same priority class, events are sorted by layer and cursor position so that
//! the topmost element under the cursor is reached first. Because of this, a handler that
//! calls `prevent_default` on a higher-priority event can naturally cancel lower-priority
//! events that would otherwise have fired in the same frame.
//!
//! Capture events are the strongest tool here: they run before anything else, and a
//! `prevent_default` on a capture handler can cancel the regular pointer events for that
//! tick. They are useful when you need to intercept input globally before any element sees
//! it (for example, dismissing an overlay on the next click anywhere).
//!
//! ## Global events
//!
//! Global events fire **once per dispatch**, regardless of which element is under the cursor
//! or focused. They are useful when you want to react to input that is not necessarily aimed
//! at your element.
//!
//! - [`on_global_pointer_up`](freya_core::prelude::EventHandlersExt::on_global_pointer_up)
//! - [`on_global_pointer_down`](freya_core::prelude::EventHandlersExt::on_global_pointer_down)
//! - [`on_global_pointer_move`](freya_core::prelude::EventHandlersExt::on_global_pointer_move)
//! - [`on_global_key_down`](freya_core::prelude::EventHandlersExt::on_global_key_down)
//! - [`on_global_key_up`](freya_core::prelude::EventHandlersExt::on_global_key_up)
//! - [`on_global_file_hover`](freya_core::prelude::EventHandlersExt::on_global_file_hover)
//! - [`on_global_file_hover_cancelled`](freya_core::prelude::EventHandlersExt::on_global_file_hover_cancelled)
//!
//! Global events do **not** bubble (they are dispatched directly to every listener), so
//! `stop_propagation` has no effect on them. A non-global handler that calls
//! `prevent_default` will, however, suppress the matching global event for that dispatch.
//!
//! ## Multi press combos
//!
//! [`EventsCombos`](freya_core::prelude::EventsCombos) turns consecutive presses into a
//! [`PressEventType`](freya_core::prelude::PressEventType). Up to four presses in a row form a
//! combo while they happen within 500ms of each other and without moving the pointer away.
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! # fn app() -> impl IntoElement {
//! rect().on_pointer_down(|e: Event<PointerEventData>| {
//! match EventsCombos::<()>::pressed(e.global_location()) {
//! PressEventType::Single => println!("Move the cursor"),
//! PressEventType::Double => println!("Select the word"),
//! PressEventType::Triple => println!("Select the line"),
//! PressEventType::Quadruple => println!("Select everything"),
//! }
//! })
//! # }
//! ```
//!
//! The combo is shared by the whole app and every call advances it, so call `pressed` once per
//! press.
//!
//! ## Exposing events from components
//!
//! Components render elements that receive events. To expose a specific action such as a
//! "click" or "change", accept a callback as a field and forward it from the inner element.
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyButton {
//! on_press: EventHandler<Event<PressEventData>>,
//! }
//!
//! impl Component for MyButton {
//! fn render(&self) -> impl IntoElement {
//! rect()
//! .padding(8.)
//! .background(Color::BLUE)
//! .on_press(self.on_press.clone())
//! .child("Press me")
//! }
//! }
//! ```
//!
//! To expose the full set of element handlers on a component, implement
//! [`EventHandlersExt`](freya_core::prelude::EventHandlersExt) and forward the stored handlers
//! to the element returned by `render`. Press handlers also require
//! [`AccessibilityExt`](freya_core::prelude::AccessibilityExt) to advertise the Click action:
//!
//! ```rust, no_run
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct Clickable {
//! event_handlers: EventHandlers,
//! accessibility: AccessibilityData,
//! }
//!
//! impl EventHandlersExt for Clickable {
//! fn event_handlers_mut(&mut self) -> &mut EventHandlers {
//! &mut self.event_handlers
//! }
//! }
//!
//! impl AccessibilityExt for Clickable {
//! fn accessibility_data_mut(&mut self) -> &mut AccessibilityData {
//! &mut self.accessibility
//! }
//! }
//!
//! impl Component for Clickable {
//! fn render(&self) -> impl IntoElement {
//! rect()
//! .accessibility(self.accessibility.clone())
//! .event_handlers(self.event_handlers.clone())
//! .child("Press me")
//! }
//! }
//!
//! # fn app() -> impl IntoElement {
//! Clickable {
//! event_handlers: EventHandlers::default(),
//! accessibility: AccessibilityData::default(),
//! }
//! .on_press(|_| println!("Pressed!"))
//! # }
//! ```