events.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. use bumpalo::boxed::Box as BumpBox;
  2. use std::{
  3. any::Any,
  4. cell::{Cell, RefCell},
  5. fmt::Debug,
  6. rc::Rc,
  7. };
  8. pub struct UiEvent<T: 'static + ?Sized> {
  9. pub(crate) bubbles: Rc<Cell<bool>>,
  10. pub(crate) data: Rc<T>,
  11. }
  12. impl UiEvent<dyn Any> {
  13. pub fn downcast<T: 'static + Sized>(self) -> Option<UiEvent<T>> {
  14. Some(UiEvent {
  15. bubbles: self.bubbles,
  16. data: self.data.downcast().ok()?,
  17. })
  18. }
  19. }
  20. impl<T: ?Sized> Clone for UiEvent<T> {
  21. fn clone(&self) -> Self {
  22. Self {
  23. bubbles: self.bubbles.clone(),
  24. data: self.data.clone(),
  25. }
  26. }
  27. }
  28. impl<T> UiEvent<T> {
  29. pub fn cancel_bubble(&self) {
  30. self.bubbles.set(false);
  31. }
  32. }
  33. impl<T> std::ops::Deref for UiEvent<T> {
  34. type Target = Rc<T>;
  35. fn deref(&self) -> &Self::Target {
  36. &self.data
  37. }
  38. }
  39. impl<T: Debug> std::fmt::Debug for UiEvent<T> {
  40. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  41. f.debug_struct("UiEvent")
  42. .field("bubble_state", &self.bubbles)
  43. .field("data", &self.data)
  44. .finish()
  45. }
  46. }
  47. type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
  48. /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
  49. ///
  50. /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
  51. ///
  52. ///
  53. /// # Example
  54. ///
  55. /// ```rust, ignore
  56. ///
  57. /// rsx!{
  58. /// MyComponent { onclick: move |evt| log::info!("clicked"), }
  59. /// }
  60. ///
  61. /// #[derive(Props)]
  62. /// struct MyProps<'a> {
  63. /// onclick: EventHandler<'a, MouseEvent>,
  64. /// }
  65. ///
  66. /// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element {
  67. /// cx.render(rsx!{
  68. /// button {
  69. /// onclick: move |evt| cx.props.onclick.call(evt),
  70. /// }
  71. /// })
  72. /// }
  73. ///
  74. /// ```
  75. pub struct EventHandler<'bump, T = ()> {
  76. /// The (optional) callback that the user specified
  77. /// Uses a `RefCell` to allow for interior mutability, and FnMut closures.
  78. pub callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
  79. }
  80. impl<'a, T> Default for EventHandler<'a, T> {
  81. fn default() -> Self {
  82. Self {
  83. callback: RefCell::new(None),
  84. }
  85. }
  86. }
  87. impl<T> EventHandler<'_, T> {
  88. /// Call this event handler with the appropriate event type
  89. pub fn call(&self, event: T) {
  90. if let Some(callback) = self.callback.borrow_mut().as_mut() {
  91. callback(event);
  92. }
  93. }
  94. /// Forcibly drop the internal handler callback, releasing memory
  95. pub fn release(&self) {
  96. self.callback.replace(None);
  97. }
  98. }