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