makepad_platform/event/event.rs
1use {
2 std::{
3 rc::Rc,
4 cell::Cell,
5 collections::{HashSet, HashMap}
6 },
7 crate::{
8 //makepad_live_compiler::LiveEditEvent,
9 makepad_live_id::LiveId,
10 cx::Cx,
11 area::Area,
12 //midi::{Midi1InputData, MidiInputInfo},
13 event::{
14 finger::*,
15 keyboard::*,
16 window::*,
17 xr::*,
18 drag_drop::*,
19 designer::*,
20 network::*,
21 video_playback::*,
22 },
23 action::ActionsBuf,
24 animator::Ease,
25 audio::AudioDevicesEvent,
26 midi::MidiPortsEvent,
27 video::VideoInputsEvent,
28 draw_list::DrawListId,
29 },
30};
31
32/// Events that can be sent between the Makepad framework and the application.
33#[derive(Debug)]
34pub enum Event {
35 /// The application has just been created.
36 ///
37 /// * This event is always sent exactly once (before any other event)
38 /// at the very beginning of the application lifecycle.
39 /// * This is a good point for one-time initialization of application state, resources, tasks, etc.
40 ///
41 /// | Platform | Lifecycle Function/Callback |
42 /// |----------|-----------------------------|
43 /// | Android | [`onCreate`] |
44 /// | others | coming soon... |
45 ///
46 /// [`onCreate`]: https://developer.android.com/reference/android/app/Activity#onCreate(android.os.Bundle)
47 Startup,
48 /// The application is being shut down is about to close and be destroyed.
49 ///
50 /// * This event may not be sent at all, so you should not rely on it.
51 /// * For example, some mobile platforms do not always send this event when closing the app.
52 /// * Desktop platforms do typically send this event when the user closes the application.
53 /// * If it is sent, it will be sent only once at the end of the application lifecycle.
54 ///
55 /// | Platform | Lifecycle Function/Callback |
56 /// |----------|-----------------------------|
57 /// | Android | [`onDestroy`] |
58 /// | others | coming soon... |
59 ///
60 /// [`onDestroy`]: https://developer.android.com/reference/android/app/Activity#onDestroy()
61 Shutdown,
62
63 /// The application has been started in the foreground and is now visible to the user,
64 /// but is not yet actively receiving user input.
65 ///
66 /// * This event can be sent multiple times over the course of the application's lifecycle.
67 /// * For example, it will be sent right after `Startup` has been sent
68 /// at the beginning of the application.
69 /// * It can also be sent after `Stop` if the user starts the application again
70 /// by navigating back to the application.
71 /// * It will be sent when the application was re-opened and shown again
72 /// after being previously hidden in the background.
73 ///
74 /// | Platform | Lifecycle Function/Callback |
75 /// |----------|-----------------------------|
76 /// | Android | [`onStart`] |
77 /// | others | coming soon... |
78 ///
79 /// [`onStart`]: https://developer.android.com/reference/android/app/Activity#onStart(
80 #[doc(alias("start, restart, show"))]
81 Foreground,
82 /// The application has been hidden in the background and is no longer visible to the user.
83 ///
84 /// * This event may be sent multiple times over the course of the application's lifecycle.
85 /// * For example, it can be sent after `Pause` has been sent, i.e., when the user
86 /// navigates away from the application, causing it to be no longer visible.
87 /// * This is a good point to stop updating the UI/animations and other visual elements.
88 ///
89 /// | Platform | Lifecycle Function/Callback |
90 /// |----------|-----------------------------|
91 /// | Android | [`onStop`] |
92 /// | others | coming soon... |
93 ///
94 /// [`onStop`]: https://developer.android.com/reference/android/app/Activity#onStop()
95 #[doc(alias("stop, hide")) ]
96 Background,
97
98 /// The application is now in the foreground and being actively used,
99 /// i.e., it is receiving input from the user.
100 ///
101 /// * This event may be sent multiple times over the course of the application's lifecycle.
102 /// * For example, it will be sent after `Start` once the application is fully in the foreground.
103 /// It can also be sent after `Pause`, once the user navigates back to the application.
104 ///
105 /// | Platform | Lifecycle Function/Callback |
106 /// |----------|-----------------------------|
107 /// | Android | [`onResume`] |
108 /// | others | coming soon... |
109 ///
110 /// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume()
111 Resume,
112 /// The application has been temporarily paused and is still visible in the foregound,
113 /// but is not actively receiving input from the user.
114 ///
115 /// * This event may be sent multiple times over the course of the application's lifecycle.
116 /// * This is a good point to save temporary application states in case the application
117 /// is about to be stopped or destroyed.
118 ///
119 /// | Platform | Lifecycle Function/Callback |
120 /// |----------|-----------------------------|
121 /// | Android | [`onPause`] |
122 /// | others | coming soon... |
123 ///
124 /// [`onPause`]: https://developer.android.com/reference/android/app/Activity#onPause()
125 Pause,
126
127 Draw(DrawEvent),
128 LiveEdit,
129 /// The application has gained focus and is now the active window receiving user input.
130 AppGotFocus,
131 /// The application has lost focus and is no longer the active window receiving user input.
132 AppLostFocus,
133 NextFrame(NextFrameEvent),
134 XrUpdate(XrUpdateEvent),
135 XrLocal(XrLocalEvent),
136
137 WindowDragQuery(WindowDragQueryEvent),
138 WindowCloseRequested(WindowCloseRequestedEvent),
139 WindowClosed(WindowClosedEvent),
140 WindowGeomChange(WindowGeomChangeEvent),
141 VirtualKeyboard(VirtualKeyboardEvent),
142 ClearAtlasses,
143
144 /// The raw event that occurs when the user presses a mouse button down.
145 ///
146 /// Do not match upon or handle this event directly; instead, use the family of
147 /// `hit`` functions ([`Event::hits()`]) and handle the returned [`Hit::FingerDown`].
148 MouseDown(MouseDownEvent),
149 /// The raw event that occurs when the user moves the mouse.
150 ///
151 /// Do not match upon or handle this event directly; instead, use the family of
152 /// `hit` functions ([`Event::hits()`]) and handle the returned [`Hit`].
153 MouseMove(MouseMoveEvent),
154 /// The raw event that occurs when the user releases a previously-pressed mouse button.
155 ///
156 /// Do not match upon or handle this event directly; instead, use the family of
157 /// `hit` functions ([`Event::hits()`]) and handle the returned [`Hit::FingerUp`].
158 MouseUp(MouseUpEvent),
159 /// The raw event that occurs when the user moves the mouse outside of the window.
160 ///
161 /// Do not match upon or handle this event directly; instead, use the family of
162 /// `hit` functions ([`Event::hits()`]) and handle the returned [`Hit::FingerOverOut`].
163 MouseLeave(MouseLeaveEvent),
164 /// The raw event that occurs when the user touches the screen.
165 ///
166 /// Do not match upon or handle this event directly; instead, use the family of
167 /// `hit` functions ([`Event::hits()`]) and handle the returned [`Hit`].
168 TouchUpdate(TouchUpdateEvent),
169 /// The raw event that occurs when the user finishes a long press touch/click.
170 ///
171 /// Do not match upon or handle this event directly; instead, use the family of
172 /// `hit` functions ([`Event::hits()`]) and handle the returned [`Hit::FingerLongPress`].
173 LongPress(LongPressEvent),
174 /// The raw event that occurs when the user scrolls, e.g.,
175 /// by using the mouse wheel or a touch flick.
176 ///
177 /// Do not match upon or handle this event directly; instead use the family of
178 /// `hit` functions ([`Event::hits()`]) and handle the returned [`Hit::FingerScroll`].
179 Scroll(ScrollEvent), // this is the MouseWheel / touch scroll event sent by the OS
180
181 Timer(TimerEvent),
182
183 Signal,
184 Trigger(TriggerEvent),
185 MacosMenuCommand(LiveId),
186 KeyFocus(KeyFocusEvent),
187 KeyFocusLost(KeyFocusEvent),
188 KeyDown(KeyEvent),
189 KeyUp(KeyEvent),
190 TextInput(TextInputEvent),
191 TextCopy(TextClipboardEvent),
192 TextCut(TextClipboardEvent),
193
194 Drag(DragEvent),
195 Drop(DropEvent),
196 DragEnd,
197
198 Actions(ActionsBuf),
199 AudioDevices(AudioDevicesEvent),
200 MidiPorts(MidiPortsEvent),
201 VideoInputs(VideoInputsEvent),
202 NetworkResponses(NetworkResponsesEvent),
203
204 VideoPlaybackPrepared(VideoPlaybackPreparedEvent),
205 VideoTextureUpdated(VideoTextureUpdatedEvent),
206 VideoPlaybackCompleted(VideoPlaybackCompletedEvent),
207 VideoPlaybackResourcesReleased(VideoPlaybackResourcesReleasedEvent),
208 VideoDecodingError(VideoDecodingErrorEvent),
209 TextureHandleReady(TextureHandleReadyEvent),
210
211 /// The "go back" navigational button or gesture was performed.
212 ///
213 /// Tip: use the [`Event::consume_back_pressed()`] method to handle this event
214 /// instead of matching on it directly.
215 ///
216 /// Once a widget has handled this event, it should set the `handled` flag to `true`
217 /// to ensure that a single "go back" action is not handled multiple times.
218 BackPressed {
219 handled: Cell<bool>,
220 },
221 #[cfg(target_arch = "wasm32")]
222 ToWasmMsg(ToWasmMsgEvent),
223
224 DesignerPick(DesignerPickEvent),
225}
226
227impl Event{
228 pub fn name(&self)->&'static str{
229 Self::name_from_u32(self.to_u32())
230 }
231
232 pub fn name_from_u32(v:u32)->&'static str{
233 match v{
234 1=>"Startup",
235 2=>"Shutdown",
236
237 3=>"Foreground",
238 4=>"Background",
239
240 5=>"Resume",
241 6=>"Pause",
242
243 7=>"Draw",
244 8=>"LiveEdit",
245 9=>"AppGotFocus",
246 10=>"AppLostFocus",
247 11=>"NextFrame",
248 12=>"XRUpdate",
249
250 13=>"WindowDragQuery",
251 14=>"WindowCloseRequested",
252 15=>"WindowClosed",
253 16=>"WindowGeomChange",
254 17=>"VirtualKeyboard",
255 18=>"ClearAtlasses",
256
257 19=>"MouseDown",
258 20=>"MouseMove",
259 21=>"MouseUp",
260 22=>"TouchUpdate",
261 23=>"LongPress",
262 24=>"Scroll",
263
264 25=>"Timer",
265
266 26=>"Signal",
267 27=>"Trigger",
268 28=>"MacosMenuCommand",
269 29=>"KeyFocus",
270 30=>"KeyFocusLost",
271 31=>"KeyDown",
272 32=>"KeyUp",
273 33=>"TextInput",
274 34=>"TextCopy",
275 35=>"TextCut",
276
277 36=>"Drag",
278 37=>"Drop",
279 38=>"DragEnd",
280
281 39=>"AudioDevices",
282 40=>"MidiPorts",
283 41=>"VideoInputs",
284 42=>"NetworkResponses",
285
286 43=>"VideoPlaybackPrepared",
287 44=>"VideoTextureUpdated",
288 45=>"VideoPlaybackCompleted",
289 46=>"VideoDecodingError",
290 47=>"VideoPlaybackResourcesReleased",
291 48=>"TextureHandleReady",
292 49=>"MouseLeave",
293 50=>"Actions",
294 51=>"BackPressed",
295
296 #[cfg(target_arch = "wasm32")]
297 52=>"ToWasmMsg",
298
299 53=>"DesignerPick",
300 54=>"XrLocal",
301 _=>panic!()
302 }
303 }
304
305 pub fn to_u32(&self)->u32{
306 match self{
307 Self::Startup=>1,
308 Self::Shutdown=>2,
309
310 Self::Foreground=>3,
311 Self::Background=>4,
312
313 Self::Resume=>5,
314 Self::Pause=>6,
315
316 Self::Draw(_)=>7,
317 Self::LiveEdit=>8,
318 Self::AppGotFocus=>9,
319 Self::AppLostFocus=>10,
320 Self::NextFrame(_)=>11,
321 Self::XrUpdate(_)=>12,
322
323 Self::WindowDragQuery(_)=>13,
324 Self::WindowCloseRequested(_)=>14,
325 Self::WindowClosed(_)=>15,
326 Self::WindowGeomChange(_)=>16,
327 Self::VirtualKeyboard(_)=>17,
328 Self::ClearAtlasses=>18,
329
330 Self::MouseDown(_)=>19,
331 Self::MouseMove(_)=>20,
332 Self::MouseUp(_)=>21,
333 Self::TouchUpdate(_)=>22,
334 Self::LongPress(_)=>23,
335 Self::Scroll(_)=>24,
336
337 Self::Timer(_)=>25,
338
339 Self::Signal=>26,
340 Self::Trigger(_)=>27,
341 Self::MacosMenuCommand(_)=>28,
342 Self::KeyFocus(_)=>29,
343 Self::KeyFocusLost(_)=>30,
344 Self::KeyDown(_)=>31,
345 Self::KeyUp(_)=>32,
346 Self::TextInput(_)=>33,
347 Self::TextCopy(_)=>34,
348 Self::TextCut(_)=>35,
349
350 Self::Drag(_)=>36,
351 Self::Drop(_)=>37,
352 Self::DragEnd=>38,
353
354 Self::AudioDevices(_)=>39,
355 Self::MidiPorts(_)=>40,
356 Self::VideoInputs(_)=>41,
357 Self::NetworkResponses(_)=>42,
358
359 Self::VideoPlaybackPrepared(_)=>43,
360 Self::VideoTextureUpdated(_)=>44,
361 Self::VideoPlaybackCompleted(_)=>45,
362 Self::VideoDecodingError(_)=>46,
363 Self::VideoPlaybackResourcesReleased(_)=>47,
364 Self::TextureHandleReady(_)=>48,
365 Self::MouseLeave(_)=>49,
366 Self::Actions(_)=>50,
367 Self::BackPressed{..}=>51,
368
369 #[cfg(target_arch = "wasm32")]
370 Self::ToWasmMsg(_)=>52,
371
372 Self::DesignerPick(_) =>53,
373 Self::XrLocal(_)=>54
374 }
375 }
376
377 /// A convenience function to check if the event is a [`BackPressed`] event
378 /// that has not yet been handled, and then mark it as handled.
379 ///
380 /// Returns `true` if the event was a [`BackPressed`] event that wasn't already handled.
381 pub fn back_pressed(&self) -> bool {
382 if let Self::BackPressed { handled } = self {
383 if !handled.get() {
384 handled.set(true);
385 return true;
386 }
387 }
388 false
389 }
390}
391
392
393#[derive(Debug)]
394pub enum Hit{
395 KeyFocus(KeyFocusEvent),
396 KeyFocusLost(KeyFocusEvent),
397 KeyDown(KeyEvent),
398 KeyUp(KeyEvent),
399 Trigger(TriggerHitEvent),
400 TextInput(TextInputEvent),
401 TextCopy(TextClipboardEvent),
402 TextCut(TextClipboardEvent),
403
404 FingerScroll(FingerScrollEvent),
405 FingerDown(FingerDownEvent),
406 FingerMove(FingerMoveEvent),
407 FingerHoverIn(FingerHoverEvent),
408 FingerHoverOver(FingerHoverEvent),
409 FingerHoverOut(FingerHoverEvent),
410 FingerUp(FingerUpEvent),
411 FingerLongPress(FingerLongPressEvent),
412
413 DesignerPick(DesignerPickEvent),
414
415 Nothing
416}
417
418#[derive(Clone)]
419pub enum DragHit{
420 Drag(DragHitEvent),
421 Drop(DropHitEvent),
422 DragEnd,
423 NoHit
424}
425
426impl Event{
427 pub fn requires_visibility(&self) -> bool{
428 match self{
429 Self::MouseDown(_)|
430 Self::MouseMove(_)|
431 Self::TouchUpdate(_)|
432 Self::Scroll(_)=>true,
433 _=>false
434 }
435 }
436}
437
438#[derive(Clone, Debug)]
439pub struct TriggerEvent {
440 pub triggers: HashMap<Area, Vec<Trigger>>
441}
442
443/*
444#[derive(Clone, Debug)]
445pub struct MidiInputListEvent {
446 pub inputs: Vec<MidiInputInfo>,
447}*/
448
449#[derive(Clone, Debug, Default)]
450pub struct DrawEvent {
451 pub draw_lists: Vec<DrawListId>,
452 pub draw_lists_and_children: Vec<DrawListId>,
453 pub redraw_all: bool,
454 pub xr_state: Option<Rc<XrState>>
455}
456
457impl DrawEvent{
458 pub fn will_redraw(&self) -> bool {
459 self.redraw_all
460 || self.draw_lists.len() != 0
461 || self.draw_lists_and_children.len() != 0
462 }
463
464 pub fn draw_list_will_redraw(&self, cx:&Cx, draw_list_id:DrawListId)->bool{
465 if self.redraw_all {
466 return true;
467 }
468 // figure out if areas are in some way a child of view_id, then we need to redraw
469 for check_draw_list_id in &self.draw_lists {
470 let mut next = Some(*check_draw_list_id);
471 while let Some(vw) = next{
472 if vw == draw_list_id {
473 return true
474 }
475 if let Some(n) = cx.draw_lists.checked_index(vw){
476 next = n.codeflow_parent_id;
477 }
478 else{ // a drawlist in our redraw lists was reused
479 break;
480 }
481 }
482 }
483 // figure out if areas are in some way a parent of view_id, then redraw
484 for check_draw_list_id in &self.draw_lists_and_children {
485 let mut next = Some(draw_list_id);
486 while let Some(vw) = next{
487 if vw == *check_draw_list_id {
488 return true
489 }
490 if let Some(n) = cx.draw_lists.checked_index(vw){
491 next = n.codeflow_parent_id;
492 }
493 else{ // a drawlist in our redraw lists was reused
494 break;
495 }
496 }
497 }
498 false
499 }
500}
501
502
503#[derive(Clone, Debug)]
504pub enum VirtualKeyboardEvent{
505 WillShow{time:f64, height:f64, duration:f64, ease:Ease},
506 WillHide{time:f64, height:f64, duration:f64, ease:Ease},
507 DidShow{time:f64, height:f64},
508 DidHide{time:f64},
509}
510
511#[derive(Clone, Default, Debug)]
512pub struct NextFrameEvent {
513 pub frame: u64,
514 pub time: f64,
515 pub set: HashSet<NextFrame>
516}
517
518#[derive(Clone, Debug)]
519pub struct TimerEvent {
520 pub time: Option<f64>,
521 pub timer_id: u64
522}
523
524#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq)]
525pub struct Trigger{
526 pub id:LiveId,
527 pub from:Area
528}
529
530#[derive(Clone, Debug, PartialEq)]
531pub struct TriggerHitEvent(pub Vec<Trigger>);
532
533#[derive(Clone, Debug)]
534pub struct WebSocketErrorEvent {
535 pub socket_id: LiveId,
536 pub error: String
537}
538
539#[derive(Clone, Debug)]
540pub struct WebSocketMessageEvent {
541 pub socket_id: LiveId,
542 pub data: Vec<u8>
543}
544
545#[derive(Clone, Debug, Default, Eq, PartialEq, Copy, Hash)]
546pub struct NextFrame(pub u64);
547
548impl NextFrame{
549 pub fn is_event(&self, event:&Event)->Option<NextFrameEvent>{
550 if let Event::NextFrame(ne) = event{
551 if ne.set.contains(&self){
552 return Some(ne.clone())
553 }
554 }
555 None
556 }
557}
558
559#[derive(Copy, Clone, Debug, Default)]
560pub struct Timer(pub u64);
561
562impl Timer {
563 pub fn is_event(&self, event:&Event)->Option<TimerEvent>{
564 if let Event::Timer(te) = event{
565 if te.timer_id == self.0{
566 return Some(te.clone())
567 }
568 }
569 None
570 }
571
572 pub fn is_timer(&self, event:&TimerEvent)->Option<TimerEvent>{
573 if event.timer_id == self.0{
574 return Some(event.clone())
575 }
576 None
577 }
578
579 pub fn empty() -> Timer {
580 Timer(0)
581 }
582
583 pub fn is_empty(&self) -> bool {
584 self.0 == 0
585 }
586}
587
588#[cfg(target_arch = "wasm32")]
589use crate::makepad_wasm_bridge::ToWasmMsg;
590
591#[cfg(target_arch = "wasm32")]
592use crate::makepad_wasm_bridge::ToWasmMsgRef;
593
594#[cfg(target_arch = "wasm32")]
595#[derive(Clone, Debug)]
596pub struct ToWasmMsgEvent{
597 pub id: LiveId,
598 pub msg: ToWasmMsg,
599 pub offset: usize
600}
601
602#[cfg(target_arch = "wasm32")]
603impl ToWasmMsgEvent{
604 pub fn as_ref(&self)->ToWasmMsgRef{self.msg.as_ref_at(self.offset)}
605}