use crate::{global_context::current_scope_id, Runtime, ScopeId};
use generational_box::GenerationalBox;
use std::{
cell::{Cell, RefCell},
rc::Rc,
};
pub struct Event<T: 'static + ?Sized> {
pub data: Rc<T>,
pub(crate) propagates: Rc<Cell<bool>>,
}
impl<T: ?Sized + 'static> Event<T> {
pub(crate) fn new(data: Rc<T>, bubbles: bool) -> Self {
Self {
data,
propagates: Rc::new(Cell::new(bubbles)),
}
}
}
impl<T> Event<T> {
pub fn map<U: 'static, F: FnOnce(&T) -> U>(&self, f: F) -> Event<U> {
Event {
data: Rc::new(f(&self.data)),
propagates: self.propagates.clone(),
}
}
#[deprecated = "use stop_propagation instead"]
pub fn cancel_bubble(&self) {
self.propagates.set(false);
}
pub fn stop_propagation(&self) {
self.propagates.set(false);
}
pub fn data(&self) -> Rc<T> {
self.data.clone()
}
}
impl<T: ?Sized> Clone for Event<T> {
fn clone(&self) -> Self {
Self {
propagates: self.propagates.clone(),
data: self.data.clone(),
}
}
}
impl<T> std::ops::Deref for Event<T> {
type Target = Rc<T>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UiEvent")
.field("bubble_state", &self.propagates)
.field("data", &self.data)
.finish()
}
}
pub struct EventHandler<T = ()> {
pub(crate) origin: ScopeId,
pub(super) callback: GenerationalBox<Option<ExternalListenerCallback<T>>>,
}
impl<T> std::fmt::Debug for EventHandler<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EventHandler")
.field("origin", &self.origin)
.field("callback", &self.callback)
.finish()
}
}
impl<T: 'static> Default for EventHandler<T> {
fn default() -> Self {
EventHandler::new(|_| {})
}
}
impl<F: FnMut(T) + 'static, T: 'static> From<F> for EventHandler<T> {
fn from(f: F) -> Self {
EventHandler::new(f)
}
}
impl<T> Copy for EventHandler<T> {}
impl<T> Clone for EventHandler<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: 'static> PartialEq for EventHandler<T> {
fn eq(&self, _: &Self) -> bool {
true
}
}
type ExternalListenerCallback<T> = Rc<RefCell<dyn FnMut(T)>>;
impl<T: 'static> EventHandler<T> {
#[track_caller]
pub fn new(mut f: impl FnMut(T) + 'static) -> EventHandler<T> {
let owner = crate::innerlude::current_owner::<generational_box::UnsyncStorage>();
let callback = owner.insert(Some(Rc::new(RefCell::new(move |event: T| {
f(event);
})) as Rc<RefCell<dyn FnMut(T)>>));
EventHandler {
callback,
origin: current_scope_id().expect("to be in a dioxus runtime"),
}
}
#[track_caller]
pub fn leak(mut f: impl FnMut(T) + 'static) -> EventHandler<T> {
let callback = GenerationalBox::leak(Some(Rc::new(RefCell::new(move |event: T| {
f(event);
})) as Rc<RefCell<dyn FnMut(T)>>));
EventHandler {
callback,
origin: current_scope_id().expect("to be in a dioxus runtime"),
}
}
pub fn call(&self, event: T) {
if let Some(callback) = self.callback.read().as_ref() {
Runtime::with(|rt| rt.scope_stack.borrow_mut().push(self.origin));
{
let mut callback = callback.borrow_mut();
callback(event);
}
Runtime::with(|rt| rt.scope_stack.borrow_mut().pop());
}
}
pub fn release(&self) {
self.callback.set(None);
}
#[doc(hidden)]
pub fn __set(&mut self, value: ExternalListenerCallback<T>) {
self.callback.set(Some(value));
}
#[doc(hidden)]
pub fn __take(&self) -> ExternalListenerCallback<T> {
self.callback
.read()
.clone()
.expect("EventHandler was manually dropped")
}
}
impl<T: 'static> std::ops::Deref for EventHandler<T> {
type Target = dyn Fn(T) + 'static;
fn deref(&self) -> &Self::Target {
let uninit_callable = std::mem::MaybeUninit::<Self>::uninit();
let uninit_closure = move |t| Self::call(unsafe { &*uninit_callable.as_ptr() }, t);
let size_of_closure = std::mem::size_of_val(&uninit_closure);
assert_eq!(size_of_closure, std::mem::size_of::<Self>());
fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
b
}
let reference_to_closure = cast_lifetime(
{
&uninit_closure
},
unsafe { std::mem::transmute(self) },
);
reference_to_closure as &_
}
}