pax_runtime_api/events.rs
1//! Event payloads and cancellation wrappers passed to Pax event handlers.
2
3use super::*;
4
5// Unified events
6
7/// One settled viewport-proximity sample in logical window coordinates.
8///
9/// Bounds are transformed layout AABBs, not padded paint coverage. Rectangular
10/// clips are intersected; curved/rotated clips use their bounding envelopes.
11/// Opacity, alpha coverage, sibling occlusion and external windows are ignored.
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct ViewportProximitySnapshot {
14 /// Whether the target intersects the proximity region with positive area.
15 pub in_proximity: bool,
16 /// Presented layout bounds relative to the global visual viewport's origin.
17 pub bounds: kurbo::Rect,
18 /// Positive-area intersection with the global viewport and ancestor clips.
19 pub viewport_intersection: Option<kurbo::Rect>,
20}
21
22impl ViewportProximitySnapshot {
23 /// Whether any positive-area viewport intersection exists.
24 pub fn is_in_viewport(&self) -> bool {
25 self.viewport_intersection.is_some()
26 }
27
28 /// Fraction of the layout AABB inside the effective viewport, from zero to one.
29 pub fn intersection_ratio(&self) -> f64 {
30 let area = self.bounds.area();
31 if area.is_finite() && area > 0.0 {
32 self.viewport_intersection
33 .map_or(0.0, |r| (r.area() / area).clamp(0.0, 1.0))
34 } else {
35 0.0
36 }
37 }
38}
39
40/// Entry into global viewport proximity, including initially nearby targets.
41/// Delivered before the initial change event. This local event does not bubble.
42#[derive(Clone, Debug)]
43pub struct ViewportProximityEnter {
44 /// Frozen sample shared with the initial change notification.
45 pub current: ViewportProximitySnapshot,
46}
47
48/// A settled geometry change during a continuous proximity visit.
49///
50/// First admission/re-entry has no previous sample. Departure sends one final
51/// change outside proximity before exit. Unchanged frames emit nothing.
52#[derive(Clone, Debug)]
53pub struct ViewportProximityChange {
54 /// Last delivered sample in this visit; `None` on admission/re-entry.
55 pub previous: Option<ViewportProximitySnapshot>,
56 /// Current frozen geometry, including the terminal outside sample.
57 pub current: ViewportProximitySnapshot,
58}
59
60/// Departure from global viewport proximity, after the terminal change event.
61/// Unmount cancels observation without synthesizing a geometric exit.
62#[derive(Clone, Debug)]
63pub struct ViewportProximityExit {
64 /// Last sample inside proximity.
65 pub previous: ViewportProximitySnapshot,
66 /// Terminal outside sample shared with the final change notification.
67 pub current: ViewportProximitySnapshot,
68}
69
70/// Event wrapper passed to Pax event handlers.
71///
72/// `Event<T>` carries the typed event payload and shared cancellation state,
73/// allowing handlers to call `prevent_default` where the active chassis supports it.
74#[derive(Clone)]
75pub struct Event<T> {
76 /// The event-specific payload, for example `Click` or `KeyDown`.
77 pub args: T,
78 // Shared cancellation state, so cloned event wrappers preserve `prevent_default`.
79 cancelled: Rc<Cell<bool>>,
80}
81
82impl<T: Clone + 'static> ImplToFromPaxAny for Event<T> {}
83
84impl<T> Event<T> {
85 /// Constructs an event wrapper around a raw payload.
86 pub fn new(args: T) -> Self {
87 Self {
88 args,
89 cancelled: Default::default(),
90 }
91 }
92
93 /// Cancels the platform default for this event, when the chassis supports cancellation.
94 pub fn prevent_default(&self) {
95 self.cancelled.set(true);
96 }
97
98 // Whether `prevent_default` has been called.
99 pub fn cancelled(&self) -> bool {
100 self.cancelled.get()
101 }
102}
103
104impl<T> Deref for Event<T> {
105 type Target = T;
106
107 fn deref(&self) -> &Self::Target {
108 &self.args
109 }
110}
111
112/// Scroll is the shared delta-based path for wheel scrolling, touch swipe gestures, and
113/// read-only native scroller position changes.
114/// Use `Wheel` or `TouchMove` when you need platform-specific details instead of the normalized
115/// delta stream.
116#[derive(Clone)]
117pub struct Scroll {
118 /// Horizontal scroll delta.
119 pub delta_x: f64,
120 /// Vertical scroll delta.
121 pub delta_y: f64,
122}
123
124// Touch Events
125
126/// Represents a single touch event.
127#[derive(Clone)]
128pub struct Touch {
129 /// The window-space x-coordinate of this touch point.
130 /// Use `NodeContext::local_point` to convert it into coordinates relative to a handler's node.
131 pub x: f64,
132 /// The window-space y-coordinate of this touch point.
133 /// Use `NodeContext::local_point` to convert it into coordinates relative to a handler's node.
134 pub y: f64,
135 /// Stable identifier for this touch across a touch sequence.
136 pub identifier: i64,
137 /// Horizontal delta since the previous touch update.
138 pub delta_x: f64,
139 /// Vertical delta since the previous touch update.
140 pub delta_y: f64,
141}
142
143impl From<&TouchMessage> for Touch {
144 fn from(value: &TouchMessage) -> Self {
145 Touch {
146 x: value.x,
147 y: value.y,
148 identifier: value.identifier,
149 delta_x: value.delta_x,
150 delta_y: value.delta_y,
151 }
152 }
153}
154
155/// A TouchStart occurs when the user touches an element.
156/// The contained `touches` represent a list of touch points. The hit node is captured for the
157/// touch identifier so subsequent move and end events keep routing to the same subtree.
158#[derive(Clone)]
159pub struct TouchStart {
160 /// Active touch points at the start of this touch sequence.
161 pub touches: Vec<Touch>,
162}
163
164/// A TouchMove occurs when the user moves while touching an element.
165/// The contained `touches` represent a list of touch points and the event targets the node captured
166/// at touch start, even when the point has moved outside its bounds.
167#[derive(Clone)]
168pub struct TouchMove {
169 /// Active touch points after this touch movement.
170 pub touches: Vec<Touch>,
171}
172
173/// A TouchEnd occurs when the user stops touching an element.
174/// The contained `touches` represent a list of touch points and the event targets, then releases,
175/// the node captured at touch start.
176#[derive(Clone)]
177pub struct TouchEnd {
178 /// Touch points that ended.
179 pub touches: Vec<Touch>,
180}
181
182/// A TouchCancel occurs when the platform aborts an active touch sequence before normal release,
183/// such as during a system interruption or host-level gesture cancellation.
184///
185/// The contained `touches` represent the cancelled touch points and the event targets, then
186/// releases, the node captured at touch start. Cancelled touches must not produce activation.
187/// A native Scroller that can observe its pan simultaneously with child touches keeps delivering
188/// move events and finishes the child sequence with `TouchEnd`; winning scroll arbitration alone
189/// does not cancel the touch.
190#[derive(Clone)]
191pub struct TouchCancel {
192 /// Touch points whose active sequence was cancelled.
193 pub touches: Vec<Touch>,
194}
195
196// Keyboard Events
197
198/// Common properties in keyboard events.
199#[derive(Clone)]
200pub struct KeyboardEventArgs {
201 /// Platform-normalized key string.
202 pub key: String,
203 /// Modifier keys active during the event.
204 pub modifiers: Vec<ModifierKey>,
205 /// Whether this event was generated by key-repeat.
206 pub is_repeat: bool,
207}
208
209/// User is pressing a key.
210#[derive(Clone)]
211pub struct KeyDown {
212 /// Common keyboard event data.
213 pub keyboard: KeyboardEventArgs,
214}
215
216/// A native text selection is beginning.
217#[derive(Clone)]
218pub struct SelectStart {}
219
220/// User has released a key.
221#[derive(Clone)]
222pub struct KeyUp {
223 /// Common keyboard event data.
224 pub keyboard: KeyboardEventArgs,
225}
226
227/// User presses a key that displays a character (alphanumeric or symbol).
228#[derive(Clone)]
229pub struct KeyPress {
230 /// Common keyboard event data.
231 pub keyboard: KeyboardEventArgs,
232}
233
234/// Window or component focused.
235#[derive(Clone)]
236pub struct Focus {}
237
238// Mouse Events
239
240/// Common properties in mouse-backed events and normalized activation events.
241#[derive(Clone)]
242pub struct MouseEventArgs {
243 /// The window-space x-coordinate of the event.
244 /// Use `NodeContext::local_point` to convert it into coordinates relative to a handler's node.
245 pub x: f64,
246 /// The window-space y-coordinate of the event.
247 /// Use `NodeContext::local_point` to convert it into coordinates relative to a handler's node.
248 pub y: f64,
249 /// Mouse button associated with the event.
250 pub button: MouseButton,
251 /// Modifier keys active during the event.
252 pub modifiers: Vec<ModifierKey>,
253}
254
255/// The variants of mouse buttons available on mouse-supporting platforms.
256#[derive(Clone, PartialEq)]
257pub enum MouseButton {
258 /// Primary mouse button.
259 Left,
260 /// Secondary mouse button.
261 Right,
262 /// Middle mouse button.
263 Middle,
264 /// Button not identified by the chassis.
265 Unknown,
266}
267
268impl From<MouseButtonMessage> for MouseButton {
269 fn from(value: MouseButtonMessage) -> Self {
270 match value {
271 MouseButtonMessage::Left => MouseButton::Left,
272 MouseButtonMessage::Right => MouseButton::Right,
273 MouseButtonMessage::Middle => MouseButton::Middle,
274 MouseButtonMessage::Unknown => MouseButton::Unknown,
275 }
276 }
277}
278
279/// The variants of modifier keys available on keyboard-supporting platforms.
280#[derive(Clone)]
281pub enum ModifierKey {
282 /// Shift key.
283 Shift,
284 /// Control key.
285 Control,
286 /// Alt or Option key.
287 Alt,
288 /// Command, Meta, or Windows key.
289 Command,
290}
291
292impl From<&ModifierKeyMessage> for ModifierKey {
293 fn from(value: &ModifierKeyMessage) -> Self {
294 match value {
295 ModifierKeyMessage::Shift => ModifierKey::Shift,
296 ModifierKeyMessage::Control => ModifierKey::Control,
297 ModifierKeyMessage::Alt => ModifierKey::Alt,
298 ModifierKeyMessage::Command => ModifierKey::Command,
299 }
300 }
301}
302
303/// User activates an element with a mouse click or single-touch tap.
304///
305/// `@click` and `@tap` handlers both receive `Event<Click>`. A touch tap is
306/// emitted after touch end and normalized with `button` set to
307/// `MouseButton::Left` and no modifiers.
308#[derive(Clone)]
309pub struct Click {
310 /// Common mouse event data.
311 pub mouse: MouseEventArgs,
312}
313
314/// User drops a file-like payload over an element.
315#[derive(Clone)]
316pub struct Drop {
317 /// The x-coordinate of the drop in the receiving node's local coordinate space.
318 pub x: f64,
319 /// The y-coordinate of the drop in the receiving node's local coordinate space.
320 pub y: f64,
321 /// File or payload name supplied by the platform.
322 pub name: String,
323 /// MIME type supplied by the platform.
324 pub mime_type: String,
325 /// Raw dropped payload bytes.
326 pub data: Vec<u8>,
327}
328
329/// User double-clicks a mouse button over an element.
330#[derive(Clone)]
331pub struct DoubleClick {
332 /// Common mouse event data.
333 pub mouse: MouseEventArgs,
334}
335
336/// User moves the mouse while it is over an element.
337#[derive(Clone)]
338pub struct MouseMove {
339 /// Common mouse event data.
340 pub mouse: MouseEventArgs,
341}
342
343/// User scrolls the mouse wheel over an element.
344#[derive(Clone)]
345pub struct Wheel {
346 /// The x-coordinate of the wheel event in the receiving node's local coordinate space.
347 pub x: f64,
348 /// The y-coordinate of the wheel event in the receiving node's local coordinate space.
349 pub y: f64,
350 /// Horizontal wheel delta.
351 pub delta_x: f64,
352 /// Vertical wheel delta.
353 pub delta_y: f64,
354 /// Modifier keys active during the event.
355 pub modifiers: Vec<ModifierKey>,
356}
357
358/// User checks or unchecks a checkbox.
359#[derive(Clone)]
360pub struct CheckboxChange {
361 /// The new checked state.
362 pub checked: bool,
363}
364
365/// User changes a slider's value.
366#[derive(Clone)]
367pub struct SliderChange {
368 /// The new slider value.
369 pub value: f64,
370}
371
372/// User types into a text input field.
373#[derive(Clone)]
374pub struct TextInput {
375 /// Text committed by the input event.
376 pub text: String,
377}
378
379/// User changes the text in a text input field.
380#[derive(Clone)]
381pub struct TextboxChange {
382 /// Current text after the change.
383 pub text: String,
384}
385
386/// Text input reported while the user edits a textbox.
387///
388/// On web, this follows the DOM `input` event. `TextboxChange` follows the
389/// DOM `change` event instead; commit timing depends on the platform control.
390#[derive(Clone)]
391pub struct TextboxInput {
392 /// Current text reported by the input event.
393 pub text: String,
394}
395
396/// User activates a native button by click or tap.
397#[derive(Clone)]
398pub struct ButtonClick {}
399
400/// Completion status for a native photo picker request.
401#[derive(Clone, PartialEq)]
402pub enum PhotoPickerStatus {
403 /// One or more photos were selected.
404 Selected,
405 /// The platform picker was dismissed without a selection.
406 Cancelled,
407 /// Camera or picker permission was denied or restricted.
408 PermissionDenied,
409 /// The requested source is not available on this platform/device.
410 Unavailable,
411 /// One or more candidate photos exceeded the configured byte limit.
412 SizeLimitExceeded,
413 /// The platform picker failed for another reason.
414 Failed,
415}
416
417impl From<&str> for PhotoPickerStatus {
418 fn from(value: &str) -> Self {
419 match value {
420 "selected" => Self::Selected,
421 "cancelled" => Self::Cancelled,
422 "permission_denied" => Self::PermissionDenied,
423 "unavailable" => Self::Unavailable,
424 "size_limit_exceeded" => Self::SizeLimitExceeded,
425 _ => Self::Failed,
426 }
427 }
428}
429
430/// Platform source used to produce a selected photo.
431#[derive(Clone, PartialEq)]
432pub enum PhotoPickerSourceKind {
433 /// Existing image from a photo library.
434 Library,
435 /// Existing image from the filesystem.
436 File,
437 /// Newly captured camera image.
438 Camera,
439 /// Source not recognized by this runtime version.
440 Other(String),
441}
442
443impl From<&str> for PhotoPickerSourceKind {
444 fn from(value: &str) -> Self {
445 match value {
446 "library" => Self::Library,
447 "file" => Self::File,
448 "camera" => Self::Camera,
449 other => Self::Other(other.to_string()),
450 }
451 }
452}
453
454/// One selected image returned by a native photo picker.
455#[derive(Clone)]
456pub struct PhotoPickerPhoto {
457 /// Stable temporary identifier for this selection.
458 pub temp_id: String,
459 /// File name supplied by the platform, when available.
460 pub file_name: Option<String>,
461 /// MIME type supplied or inferred by the platform.
462 pub mime_type: String,
463 /// Byte size of the selected asset.
464 pub byte_size: u64,
465 /// Image width in pixels, when available.
466 pub width: Option<u32>,
467 /// Image height in pixels, when available.
468 pub height: Option<u32>,
469 /// Source used for this image.
470 pub source_kind: PhotoPickerSourceKind,
471 /// Platform preview/read handle, such as an object URL or file URL.
472 pub handle: Option<String>,
473 /// Copied asset bytes when the chassis can provide them within configured limits.
474 pub data: Option<Vec<u8>>,
475}
476
477impl From<&PhotoPickerAssetArgs> for PhotoPickerPhoto {
478 fn from(value: &PhotoPickerAssetArgs) -> Self {
479 Self {
480 temp_id: value.temp_id.clone(),
481 file_name: value.file_name.clone(),
482 mime_type: value.mime_type.clone(),
483 byte_size: value.byte_size,
484 width: value.width,
485 height: value.height,
486 source_kind: PhotoPickerSourceKind::from(value.source_kind.as_str()),
487 handle: value.handle.clone(),
488 data: if value.data.is_empty() {
489 None
490 } else {
491 Some(value.data.clone())
492 },
493 }
494 }
495}
496
497/// Native photo picker completion event.
498#[derive(Clone)]
499pub struct PhotoPickerChange {
500 /// Picker node id that produced the result.
501 pub id: u32,
502 /// App-controlled request id, usually copied from the picker trigger value.
503 pub request_id: u64,
504 /// Completion status.
505 pub status: PhotoPickerStatus,
506 /// Human-readable platform message for errors or partial results.
507 pub message: Option<String>,
508 /// Selected photos, empty for cancellation, permission denial, or unavailable sources.
509 pub photos: Vec<PhotoPickerPhoto>,
510}
511
512impl From<&PhotoPickerInterruptArgs> for PhotoPickerChange {
513 fn from(value: &PhotoPickerInterruptArgs) -> Self {
514 Self {
515 id: value.id,
516 request_id: value.request_id,
517 status: PhotoPickerStatus::from(value.status.as_str()),
518 message: value.message.clone(),
519 photos: value.photos.iter().map(PhotoPickerPhoto::from).collect(),
520 }
521 }
522}
523
524/// User presses a mouse button over an element.
525#[derive(Clone)]
526pub struct MouseDown {
527 /// Common mouse event data.
528 pub mouse: MouseEventArgs,
529}
530
531/// User releases a mouse button over an element.
532#[derive(Clone)]
533pub struct MouseUp {
534 /// Common mouse event data.
535 pub mouse: MouseEventArgs,
536}
537
538/// User moves the mouse onto an element.
539#[derive(Clone)]
540pub struct MouseOver {}
541
542/// User moves the mouse away from an element.
543#[derive(Clone)]
544pub struct MouseOut {}
545
546/// User right-clicks an element to open the context menu.
547#[derive(Clone)]
548pub struct ContextMenu {
549 /// Common mouse event data.
550 pub mouse: MouseEventArgs,
551}