Skip to main content

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}