1use crate::file_dialogs::FileDialog;
2
3use {
4 crate::{
5 area::Area,
6 cursor::MouseCursor,
7 cx::{Cx, CxRef, OsType, XrCapabilities},
8 draw_list::DrawListId,
9 event::{DragItem, HttpRequest, NextFrame, Timer, Trigger, VideoSource},
10 gpu_info::GpuInfo,
11 macos_menu::MacosMenu,
12 makepad_futures::executor::Spawner,
13 makepad_live_id::*,
14 event::xr::XrAnchor,
15 makepad_math::{DVec2, Rect},
16 pass::{CxPassParent, CxPassRect, PassId},
17 texture::Texture,
18 window::WindowId,
19 dvec2,
20 },
21 std::{
22 any::{Any, TypeId},
23 rc::Rc,
24 },
25};
26pub enum OpenUrlInPlace{
27 Yes,
28 No
29}
30pub trait CxOsApi {
31 fn init_cx_os(&mut self);
32
33 fn spawn_thread<F>(&mut self, f: F)
34 where
35 F: FnOnce() + Send + 'static;
36
37 fn start_stdin_service(&mut self) {}
38 fn pre_start() -> bool {
39 false
40 }
41
42 fn open_url(&mut self, url:&str, in_place:OpenUrlInPlace);
43
44 fn seconds_since_app_start(&self)->f64;
45
46 fn default_window_size(&self)->DVec2{dvec2(800.,600.)}
47
48 fn max_texture_width()->usize{4096}
49
50 fn in_xr_mode(&self)->bool{false}
51
52 fn micro_zbias_step(&self)->f32{0.00001}
53
54 }
58
59#[derive(PartialEq)]
60pub enum CxOsOp {
61 CreateWindow(WindowId),
62 ResizeWindow(WindowId, DVec2),
63 RepositionWindow(WindowId, DVec2),
64 CloseWindow(WindowId),
65 MinimizeWindow(WindowId),
66 Deminiaturize(WindowId),
67 MaximizeWindow(WindowId),
68 FullscreenWindow(WindowId),
69 NormalizeWindow(WindowId),
70 RestoreWindow(WindowId),
71 HideWindow(WindowId),
72 SetTopmost(WindowId, bool),
73 ShowInDock(bool),
74
75 ShowTextIME(Area, DVec2),
76 HideTextIME,
77 SetCursor(MouseCursor),
78 StartTimer {
79 timer_id: u64,
80 interval: f64,
81 repeats: bool,
82 },
83 StopTimer(u64),
84 Quit,
85
86 StartDragging(Vec<DragItem>),
87 UpdateMacosMenu(MacosMenu),
88 ShowClipboardActions(String),
89 CopyToClipboard(String),
90
91 HttpRequest {
92 request_id: LiveId,
93 request: HttpRequest,
94 },
95 CancelHttpRequest{
96 request_id: LiveId,
97 },
98
99 PrepareVideoPlayback(LiveId, VideoSource, u32, bool, bool),
100 BeginVideoPlayback(LiveId),
101 PauseVideoPlayback(LiveId),
102 ResumeVideoPlayback(LiveId),
103 MuteVideoPlayback(LiveId),
104 UnmuteVideoPlayback(LiveId),
105 CleanupVideoPlaybackResources(LiveId),
106 UpdateVideoSurfaceTexture(LiveId),
107
108 CreateWebView{
109 id: LiveId,
110 area: Area,
111 texture: Texture,
112 url: String
113 },
114 UpdateWebView{
115 id: LiveId,
116 area: Area
117 },
118 CloseWebView{
119 id:LiveId
120 },
121 SaveFileDialog(FileDialog),
122 SelectFileDialog(FileDialog),
123 SaveFolderDialog(FileDialog),
124 SelectFolderDialog(FileDialog),
125
126 XrStartPresenting,
127 XrSetLocalAnchor(XrAnchor),
128 XrAdvertiseAnchor(XrAnchor),
129 XrDiscoverAnchor(u8),
130 XrStopPresenting,
131
132}
133
134impl std::fmt::Debug for CxOsOp {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 match self{
137 Self::CreateWindow(..)=>write!(f, "CreateWindow"),
138 Self::CloseWindow(..)=>write!(f, "CloseWindow"),
139 Self::MinimizeWindow(..)=>write!(f, "MinimizeWindow"),
140 Self::Deminiaturize(..)=>write!(f, "Deminiaturize"),
141 Self::MaximizeWindow(..)=>write!(f, "MaximizeWindow"),
142 Self::FullscreenWindow(..)=>write!(f, "FullscreenWindow"),
143 Self::NormalizeWindow(..)=>write!(f, "NormalizeWindow"),
144 Self::RestoreWindow(..)=>write!(f, "RestoreWindow"),
145 Self::HideWindow(..)=>write!(f, "HideWindow"),
146 Self::SetTopmost(..)=>write!(f, "SetTopmost"),
147 Self::ShowInDock(..)=>write!(f, "ShowInDock"),
148
149 Self::ShowTextIME(..)=>write!(f, "ShowTextIME"),
150 Self::HideTextIME=>write!(f, "HideTextIME"),
151 Self::SetCursor(..)=>write!(f, "SetCursor"),
152 Self::StartTimer{..}=>write!(f, "StartTimer"),
153 Self::StopTimer(..)=>write!(f, "StopTimer"),
154 Self::Quit=>write!(f, "Quit"),
155
156 Self::StartDragging(..)=>write!(f, "StartDragging"),
157 Self::UpdateMacosMenu(..)=>write!(f, "UpdateMacosMenu"),
158 Self::ShowClipboardActions(..)=>write!(f, "ShowClipboardActions"),
159 Self::CopyToClipboard(..)=>write!(f, "CopyToClipboard"),
160
161 Self::HttpRequest{..}=>write!(f, "HttpRequest"),
162 Self::CancelHttpRequest{..}=>write!(f, "CancelHttpRequest"),
163
164 Self::PrepareVideoPlayback(..)=>write!(f, "PrepareVideoPlayback"),
165 Self::BeginVideoPlayback(..)=>write!(f, "BeginVideoPlayback"),
166 Self::PauseVideoPlayback(..)=>write!(f, "PauseVideoPlayback"),
167 Self::ResumeVideoPlayback(..)=>write!(f, "ResumeVideoPlayback"),
168 Self::MuteVideoPlayback(..)=>write!(f, "MuteVideoPlayback"),
169 Self::UnmuteVideoPlayback(..)=>write!(f, "UnmuteVideoPlayback"),
170 Self::CleanupVideoPlaybackResources(..)=>write!(f, "CleanupVideoPlaybackResources"),
171 Self::UpdateVideoSurfaceTexture(..)=>write!(f, "UpdateVideoSurfaceTexture"),
172 Self::CreateWebView{..}=>write!(f, "CreateWebView"),
173 Self::UpdateWebView{..}=>write!(f, "UpdateWebView"),
174 Self::CloseWebView{..}=>write!(f, "CloseWebView"),
175 Self::SaveFileDialog(..)=>write!(f, "SaveFileDialog"),
176 Self::SelectFileDialog(..)=>write!(f, "SelectFileDialog"),
177 Self::SaveFolderDialog(..)=>write!(f, "SaveFolderDialog"),
178 Self::SelectFolderDialog(..)=>write!(f, "SelectFolderDialog"),
179 Self::ResizeWindow(..)=>write!(f, "ResizeWindow"),
180 Self::RepositionWindow(..)=>write!(f, "RepositionWindow"),
181
182 Self::XrStartPresenting=>write!(f, "XrStartPresenting"),
183 Self::XrStopPresenting=>write!(f, "XrStopPresenting"),
184 Self::XrAdvertiseAnchor(_)=>write!(f, "XrAdvertiseAnchor"),
185 Self::XrSetLocalAnchor(_)=>write!(f, "XrSetLocalAnchor"),
186 Self::XrDiscoverAnchor(_)=>write!(f, "XrDiscoverAnchor"),
187 }
188 }
189}
190impl Cx {
191 pub fn in_draw_event(&self)->bool{
192 self.in_draw_event
193 }
194
195 pub fn xr_capabilities(&self) -> &XrCapabilities {
196 &self.xr_capabilities
197 }
198
199 pub fn get_ref(&self) -> CxRef {
200 CxRef(self.self_ref.clone().unwrap())
201 }
202
203 pub fn take_dependency(&mut self, path: &str) -> Result<Rc<Vec<u8>>, String> {
204 if let Some(data) = self.dependencies.get_mut(path) {
205 if let Some(data) = data.data.take() {
206 return match data {
207 Ok(data) => Ok(data),
208 Err(s) => Err(s.clone()),
209 };
210 }
211 }
212 Err(format!("Dependency not loaded {}", path))
213 }
214
215 pub fn get_dependency(&self, path: &str) -> Result<Rc<Vec<u8>>, String> {
216 if let Some(data) = self.dependencies.get(path) {
217 if let Some(data) = &data.data {
218 return match data {
219 Ok(data) => Ok(data.clone()),
220 Err(s) => Err(s.clone()),
221 };
222 }
223 }
224 Err(format!("Dependency not loaded {}", path))
225 }
226 pub fn null_texture(&self) -> Texture {
227 self.null_texture.clone()
228 }
229 pub fn redraw_id(&self) -> u64 {
230 self.redraw_id
231 }
232
233 pub fn os_type(&self) -> &OsType {
234 &self.os_type
235 }
236 pub fn in_makepad_studio(&self) -> bool {
237 self.in_makepad_studio
238 }
239
240 pub fn cpu_cores(&self) -> usize {
241 self.cpu_cores
242 }
243 pub fn gpu_info(&self) -> &GpuInfo {
244 &self.gpu_info
245 }
246
247 pub fn update_macos_menu(&mut self, menu: MacosMenu) {
248 self.platform_ops.push(CxOsOp::UpdateMacosMenu(menu));
249 }
250
251 pub fn xr_start_presenting(&mut self) {
252 self.platform_ops.push(CxOsOp::XrStartPresenting);
253 }
254
255 pub fn xr_advertise_anchor(&mut self, anchor:XrAnchor) {
256 self.platform_ops.push(CxOsOp::XrAdvertiseAnchor(anchor));
257 }
258
259 pub fn xr_set_local_anchor(&mut self, anchor:XrAnchor) {
260 self.platform_ops.push(CxOsOp::XrSetLocalAnchor(anchor));
261 }
262
263 pub fn xr_discover_anchor(&mut self, id: u8) {
264 self.platform_ops.push(CxOsOp::XrDiscoverAnchor(id));
265 }
266
267
268 pub fn quit(&mut self) {
269 self.platform_ops.push(CxOsOp::Quit);
270 }
271 pub fn show_in_dock(&mut self, show: bool) {
274 self.platform_ops.push(CxOsOp::ShowInDock(show));
275 }
276 pub fn push_unique_platform_op(&mut self, op: CxOsOp) {
277 if self.platform_ops.iter().find(|o| **o == op).is_none() {
278 self.platform_ops.push(op);
279 }
280 }
281
282 pub fn show_text_ime(&mut self, area: Area, pos: DVec2) {
283 if !self.keyboard.text_ime_dismissed {
284 self.ime_area = area;
285 self.platform_ops.push(CxOsOp::ShowTextIME(area, pos));
286 }
287 }
288
289 pub fn hide_text_ime(&mut self) {
290 self.keyboard.reset_text_ime_dismissed();
291 self.platform_ops.push(CxOsOp::HideTextIME);
292 }
293
294 pub fn text_ime_was_dismissed(&mut self) {
295 self.keyboard.set_text_ime_dismissed();
296 self.platform_ops.push(CxOsOp::HideTextIME);
297 }
298
299 pub fn show_clipboard_actions(&mut self, selected: String) {
300 self.platform_ops
301 .push(CxOsOp::ShowClipboardActions(selected));
302 }
303
304 pub fn copy_to_clipboard(&mut self, content: &str) {
308 self.platform_ops.push(CxOsOp::CopyToClipboard(content.to_owned()));
309 }
310
311 pub fn start_dragging(&mut self, items: Vec<DragItem>) {
312 self.platform_ops.iter().for_each(|p| {
313 if let CxOsOp::StartDragging { .. } = p {
314 panic!("start drag twice");
315 }
316 });
317 self.platform_ops.push(CxOsOp::StartDragging(items));
318 }
319
320 pub fn set_cursor(&mut self, cursor: MouseCursor) {
321 if let Some(p) = self.platform_ops.iter_mut().find(|p| match p {
323 CxOsOp::SetCursor(_) => true,
324 _ => false,
325 }) {
326 *p = CxOsOp::SetCursor(cursor)
327 } else {
328 self.platform_ops.push(CxOsOp::SetCursor(cursor))
329 }
330 }
331
332 pub fn sweep_lock(&mut self, value: Area) {
333 self.fingers.sweep_lock(value);
334 }
335
336 pub fn sweep_unlock(&mut self, value: Area) {
337 self.fingers.sweep_unlock(value);
338 }
339
340 pub fn start_timeout(&mut self, interval: f64) -> Timer {
341 self.timer_id += 1;
342 self.platform_ops.push(CxOsOp::StartTimer {
343 timer_id: self.timer_id,
344 interval,
345 repeats: false,
346 });
347 Timer(self.timer_id)
348 }
349
350 pub fn start_interval(&mut self, interval: f64) -> Timer {
351 self.timer_id += 1;
352 self.platform_ops.push(CxOsOp::StartTimer {
353 timer_id: self.timer_id,
354 interval,
355 repeats: true,
356 });
357 Timer(self.timer_id)
358 }
359
360 pub fn stop_timer(&mut self, timer: Timer) {
361 if timer.0 != 0 {
362 self.platform_ops.push(CxOsOp::StopTimer(timer.0));
363 }
364 }
365
366
367 pub fn get_dpi_factor_of(&mut self, area: &Area) -> f64 {
368 if let Some(draw_list_id) = area.draw_list_id() {
369 let pass_id = self.draw_lists[draw_list_id].pass_id.unwrap();
370 return self.get_delegated_dpi_factor(pass_id);
371 }
372 return 1.0;
373 }
374
375 pub fn get_pass_window_id(&self, pass_id: PassId) -> Option<WindowId> {
376 let mut pass_id_walk = pass_id;
377 for _ in 0..25 {
378 match self.passes[pass_id_walk].parent {
379 CxPassParent::Window(window_id) => {
380 return Some(window_id)
381 }
382 CxPassParent::Pass(next_pass_id) => {
383 pass_id_walk = next_pass_id;
384 }
385 _ => {
386 break;
387 }
388 }
389 }
390 None
391 }
392
393 pub fn get_delegated_dpi_factor(&mut self, pass_id: PassId) -> f64 {
394 let mut pass_id_walk = pass_id;
395 for _ in 0..25 {
396 match self.passes[pass_id_walk].parent {
397 CxPassParent::Window(window_id) => {
398 if !self.windows[window_id].is_created {
399 return 1.0;
400 }
401 return self.windows[window_id].window_geom.dpi_factor;
402 }
403 CxPassParent::Pass(next_pass_id) => {
404 pass_id_walk = next_pass_id;
405 }
406 _ => {
407 break;
408 }
409 }
410 }
411 1.0
412 }
413
414 pub fn redraw_pass_and_parent_passes(&mut self, pass_id: PassId) {
415 let mut walk_pass_id = pass_id;
416 loop {
417 if let Some(main_list_id) = self.passes[walk_pass_id].main_draw_list_id {
418 self.redraw_list_and_children(main_list_id);
419 }
420 match self.passes[walk_pass_id].parent.clone() {
421 CxPassParent::Pass(next_pass_id) => {
422 walk_pass_id = next_pass_id;
423 }
424 _ => {
425 break;
426 }
427 }
428 }
429 }
430
431 pub fn get_pass_rect(&self, pass_id: PassId, dpi: f64) -> Option<Rect> {
432 match self.passes[pass_id].pass_rect {
433 Some(CxPassRect::Area(area)) => {
434 let rect = area.rect(self);
435 Some(Rect {
436 pos: (rect.pos * dpi).floor() / dpi,
437 size: (rect.size * dpi).ceil() / dpi,
438 })
439 }
440 Some(CxPassRect::AreaOrigin(area, origin)) => {
441 let rect = area.rect(self);
442 Some(Rect {
443 pos: origin,
444 size: (rect.size * dpi).ceil() / dpi,
445 })
446 }
447 Some(CxPassRect::Size(size)) => Some(Rect {
455 pos: DVec2::default(),
456 size: (size * dpi).ceil() / dpi,
457 }),
458 None => None,
459 }
460 }
461
462 pub fn get_pass_name(&self, pass_id: PassId) -> &str {
463 &self.passes[pass_id].debug_name
464 }
465
466 pub fn repaint_pass(&mut self, pass_id: PassId) {
467 let cxpass = &mut self.passes[pass_id];
468 cxpass.paint_dirty = true;
469 }
470
471 pub fn repaint_pass_and_child_passes(&mut self, pass_id: PassId) {
472 let cxpass = &mut self.passes[pass_id];
473 cxpass.paint_dirty = true;
474 for sub_pass_id in self.passes.id_iter() {
475 if let CxPassParent::Pass(dep_pass_id) = self.passes[sub_pass_id].parent.clone() {
476 if dep_pass_id == pass_id {
477 self.repaint_pass_and_child_passes(sub_pass_id);
478 }
479 }
480 }
481 }
482
483 pub fn redraw_pass_and_child_passes(&mut self, pass_id: PassId) {
484 let cxpass = &self.passes[pass_id];
485 if let Some(main_list_id) = cxpass.main_draw_list_id {
486 self.redraw_list_and_children(main_list_id);
487 }
488 for sub_pass_id in self.passes.id_iter() {
490 if let CxPassParent::Pass(dep_pass_id) = self.passes[sub_pass_id].parent.clone() {
491 if dep_pass_id == pass_id {
492 self.redraw_pass_and_child_passes(sub_pass_id);
493 }
494 }
495 }
496 }
497
498 pub fn redraw_all(&mut self) {
499 self.new_draw_event.redraw_all = true;
500 }
501
502 pub fn redraw_area(&mut self, area: Area) {
503 if let Some(draw_list_id) = area.draw_list_id() {
504 self.redraw_list(draw_list_id);
505 }
506 }
507
508 pub fn redraw_area_in_draw(&mut self, area: Area) {
509 if let Some(draw_list_id) = area.draw_list_id() {
510 self.redraw_list_in_draw(draw_list_id);
511 }
512 }
513
514 pub fn redraw_area_and_children(&mut self, area: Area) {
515 if let Some(draw_list_id) = area.draw_list_id() {
516 self.redraw_list_and_children(draw_list_id);
517 }
518 }
519
520 pub fn redraw_list(&mut self, draw_list_id: DrawListId) {
521 if self.in_draw_event{
522 return
523 }
524 self.redraw_list_in_draw(draw_list_id);
525 }
526
527 pub fn redraw_list_in_draw(&mut self, draw_list_id: DrawListId) {
528 if self
529 .new_draw_event
530 .draw_lists
531 .iter()
532 .position(|v| *v == draw_list_id)
533 .is_some()
534 {
535 return;
536 }
537 self.new_draw_event.draw_lists.push(draw_list_id);
538 }
539
540 pub fn redraw_list_and_children(&mut self, draw_list_id: DrawListId) {
541 if self.in_draw_event{
542 return
543 }
544 if self
545 .new_draw_event
546 .draw_lists_and_children
547 .iter()
548 .position(|v| *v == draw_list_id)
549 .is_some()
550 {
551 return;
552 }
553 self.new_draw_event
554 .draw_lists_and_children
555 .push(draw_list_id);
556 }
557
558 pub fn get_ime_area_rect(&self) -> Rect {
559 self.ime_area.rect(self)
560 }
561
562 pub fn update_area_refs(&mut self, old_area: Area, new_area: Area) -> Area {
563 if old_area == Area::Empty {
564 return new_area;
565 }
566 if self.ime_area == old_area {
567 self.ime_area = new_area;
568 }
569 self.fingers.update_area(old_area, new_area);
570 self.drag_drop.update_area(old_area, new_area);
571 self.keyboard.update_area(old_area, new_area);
572
573 new_area
574 }
575
576 pub fn set_key_focus(&mut self, focus_area: Area) {
577 self.keyboard.set_key_focus(focus_area);
578 }
579
580 pub fn revert_key_focus(&mut self) {
581 self.keyboard.revert_key_focus();
582 }
583
584 pub fn has_key_focus(&self, focus_area: Area) -> bool {
585 self.keyboard.has_key_focus(focus_area)
586 }
587
588 pub fn new_next_frame(&mut self) -> NextFrame {
589 let res = NextFrame(self.next_frame_id);
590 self.next_frame_id += 1;
591 self.new_next_frames.insert(res);
592 res
593 }
594
595 pub fn send_trigger(&mut self, area: Area, trigger: Trigger) {
596 if let Some(triggers) = self.triggers.get_mut(&area) {
597 triggers.push(trigger);
598 } else {
599 let mut new_set = Vec::new();
600 new_set.push(trigger);
601 self.triggers.insert(area, new_set);
602 }
603 }
604
605 pub fn set_global<T: 'static + Any + Sized>(&mut self, value: T) {
606 if !self.globals.iter().any(|v| v.0 == TypeId::of::<T>()) {
607 self.globals.push((TypeId::of::<T>(), Box::new(value)));
608 }
609 }
610
611 pub fn get_global<T: 'static + Any>(&mut self) -> &mut T {
612 let item = self
613 .globals
614 .iter_mut()
615 .find(|v| v.0 == TypeId::of::<T>())
616 .unwrap();
617 item.1.downcast_mut().unwrap()
618 }
619
620 pub fn has_global<T: 'static + Any>(&mut self) -> bool {
621 self.globals
622 .iter_mut()
623 .find(|v| v.0 == TypeId::of::<T>())
624 .is_some()
625 }
626
627 pub fn global<T: 'static + Any + Default>(&mut self) -> &mut T {
628 if !self.has_global::<T>() {
629 self.set_global(T::default());
630 }
631 self.get_global::<T>()
632 }
633
634 pub fn spawner(&self) -> &Spawner {
635 &self.spawner
636 }
637
638 pub fn http_request(&mut self, request_id: LiveId, request: HttpRequest) {
639 self.platform_ops.push(CxOsOp::HttpRequest {
640 request_id,
641 request,
642 });
643 }
644
645 pub fn cancel_http_request(&mut self, request_id: LiveId) {
646 self.platform_ops.push(CxOsOp::CancelHttpRequest {
647 request_id,
648 });
649 }
650 pub fn prepare_video_playback(
666 &mut self,
667 video_id: LiveId,
668 source: VideoSource,
669 external_texture_id: u32,
670 autoplay: bool,
671 should_loop: bool,
672 ) {
673 self.platform_ops.push(CxOsOp::PrepareVideoPlayback(
674 video_id,
675 source,
676 external_texture_id,
677 autoplay,
678 should_loop,
679 ));
680 }
681
682 pub fn begin_video_playback(&mut self, video_id: LiveId) {
683 self.platform_ops.push(CxOsOp::BeginVideoPlayback(video_id));
684 }
685
686 pub fn pause_video_playback(&mut self, video_id: LiveId) {
687 self.platform_ops.push(CxOsOp::PauseVideoPlayback(video_id));
688 }
689
690 pub fn resume_video_playback(&mut self, video_id: LiveId) {
691 self.platform_ops
692 .push(CxOsOp::ResumeVideoPlayback(video_id));
693 }
694
695 pub fn mute_video_playback(&mut self, video_id: LiveId) {
696 self.platform_ops.push(CxOsOp::MuteVideoPlayback(video_id));
697 }
698
699 pub fn unmute_video_playback(&mut self, video_id: LiveId) {
700 self.platform_ops
701 .push(CxOsOp::UnmuteVideoPlayback(video_id));
702 }
703
704 pub fn cleanup_video_playback_resources(&mut self, video_id: LiveId) {
705 self.platform_ops
706 .push(CxOsOp::CleanupVideoPlaybackResources(video_id));
707 }
708
709 pub fn println_resources(&self) {
710 println!("Num textures: {}", self.textures.0.pool.len());
711 }
712
713 pub fn open_system_savefile_dialog(&mut self) {
714 self.platform_ops.push(CxOsOp::SaveFileDialog(FileDialog::new()));
715 }
716
717 pub fn open_system_openfile_dialog(&mut self) {
718 self.platform_ops.push(CxOsOp::SelectFileDialog(FileDialog::new()));
719 }
720
721 pub fn open_system_savefolder_dialog(&mut self) {
722 self.platform_ops.push(CxOsOp::SaveFolderDialog(FileDialog::new()));
723
724 }
725
726 pub fn open_system_openfolder_dialog(&mut self) {
727 self.platform_ops.push(CxOsOp::SelectFolderDialog(FileDialog::new()));
728
729 }
730
731 pub fn event_id(&self) -> u64 {
732 self.event_id
733 }
734}
735
736#[macro_export]
737macro_rules! register_component_factory {
738 ( $ cx: ident, $ registry: ident, $ ty: ty, $ factory: ident) => {
739 let module_id = LiveModuleId::from_str(&module_path!()).unwrap();
740 if let Some((reg, _)) = $cx
741 .live_registry
742 .borrow()
743 .components
744 .get_or_create::<$registry>()
745 .map
746 .get(&LiveType::of::<$ty>())
747 {
748 if reg.module_id != module_id {
749 panic!(
750 "Component already registered {} {}",
751 stringify!($ty),
752 reg.module_id
753 );
754 }
755 }
756 $cx.live_registry
757 .borrow()
758 .components
759 .get_or_create::<$registry>()
760 .map
761 .insert(
762 LiveType::of::<$ty>(),
763 (
764 LiveComponentInfo {
765 name: LiveId::from_str_with_lut(stringify!($ty)).unwrap(),
766 module_id,
767 },
768 Box::new($factory()),
769 ),
770 );
771 };
772}