200 lines
6.0 KiB
Rust
200 lines
6.0 KiB
Rust
#[macro_export]
|
|
macro_rules! event {
|
|
($name:ident) => {
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name;
|
|
|
|
impl $crate::extensions::Event for $name {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
};
|
|
|
|
($name:ident {$($inner:tt)*}) => {
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name {
|
|
$($inner)*
|
|
}
|
|
|
|
impl $crate::extensions::Event for $name {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
};
|
|
|
|
($name:ident ($($inner:tt)*)) => {
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name ($($inner)*);
|
|
|
|
impl $crate::extensions::Event for $name {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! component {
|
|
($name:ident) => {
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name;
|
|
|
|
impl $crate::widget::Component for $name {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
|
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
};
|
|
|
|
($name:ident {$($inner:tt)*}) => {
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name {
|
|
$($inner)*
|
|
}
|
|
|
|
impl $crate::widget::Component for $name {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
|
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
};
|
|
|
|
($name:ident ($($inner:tt)*)) => {
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name ($($inner)*);
|
|
|
|
impl $crate::widget::Component for $name {
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
|
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/// Macro to create an event handler closure that calls a method on `self`
|
|
///
|
|
/// This macro automates the pattern of capturing `self` as a raw pointer,
|
|
/// then passing an event to a method on `self` inside an unsafe closure.
|
|
///
|
|
/// # Parameters
|
|
/// - `$self_ty`: The self type.
|
|
/// - `$self`: The instance variable (usually `self`) to call the method on.
|
|
/// - `$events`: The event source which has an `.on` method to register the handler.
|
|
/// - `$method`: The method name on `self` to call when an event occurs.
|
|
///
|
|
/// # Usage
|
|
/// ```rust
|
|
/// event_handler!(self, events, on_keypress);
|
|
/// ```
|
|
///
|
|
/// This expands roughly to:
|
|
/// ```rust
|
|
/// let self_ref = self as *mut Self;
|
|
/// events.on(move |event| unsafe { (*self_ref).on_keypress(event) });
|
|
/// ```
|
|
///
|
|
/// # Safety
|
|
/// This macro uses `unsafe` code because it dereferences a raw pointer inside the closure.
|
|
/// Ensure that the `self` reference lives at least as long as the closure to avoid undefined behavior.
|
|
///
|
|
/// # Why use raw pointers here?
|
|
/// Often, event handlers require `'static` closures, but `self` is a stack reference.
|
|
/// Capturing `self` directly is not possible, so this workaround uses a raw pointer.
|
|
#[macro_export]
|
|
macro_rules! event_handler {
|
|
($self_ty:ty, $self:ident, $events:ident, $method:ident) => {{
|
|
let self_ref = $self as *mut $self_ty;
|
|
$events.on(move |es, e| unsafe { (*self_ref).$method(es, e) });
|
|
}};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! transform {
|
|
($($f:ident: $v:expr),* $(,)?) => {{
|
|
let mut t = Transform::new();
|
|
$(t.$f = $v.into();)*
|
|
t
|
|
}};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! rsx {
|
|
($($inner:tt)*) => {{
|
|
let mut r = $crate::frontend::Rsx(Vec::new());
|
|
|
|
$crate::rsx_inner! { r, $($inner)* };
|
|
|
|
r
|
|
}};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! rsx_inner {
|
|
// static
|
|
($r:expr, $(@$comp:expr;)* static $s:literal $($rest:tt)*) => {
|
|
let w = $crate::widget::StaticWidget::new(Box::new(format!($s)));
|
|
$(w.component($comp);)*
|
|
$r.create_element_static(w, $crate::frontend::Rsx(Vec::new()));
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
($r:expr, $(@$comp:expr;)* $(%$dep:ident)* $s:literal $($rest:tt)*) => {
|
|
$r.create_element({ $(let $dep = $dep.clone();)* move || {
|
|
$crate::widget::WidgetLoad::new(format!($s)) $(.component($comp))*
|
|
} }, vec![$(Box::new($dep.clone())),*], $crate::frontend::Rsx(Vec::new()));
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
// static
|
|
($r:expr, $(@$comp:expr;)* static $name:path { $($inner:tt)* } ($($e:expr),*) $($rest:tt)*) => {
|
|
let w = $crate::widget::StaticWidget::new(Box::new(<$name>::new($($e),*)));
|
|
$(w.component($comp);)*
|
|
$r.create_element_static(w, $crate::frontend::Rsx(Vec::new()));
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
// static
|
|
($r:expr, $(@$comp:expr;)* static $name:path { $($inner:tt)* } $($rest:tt)*) => {
|
|
let w = $crate::widget::StaticWidget::new(Box::new(<$name>::new()));
|
|
$(w.component($comp);)*
|
|
$r.create_element_static(w, $crate::frontend::Rsx(Vec::new()));
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
($r:expr, $(@$comp:expr;)* $(%$dep:ident)* $name:path { $($inner:tt)* } ($($e:expr),*) $($rest:tt)*) => {
|
|
$r.create_element({ $(let $dep = $dep.clone();)* move || {
|
|
$crate::widget::WidgetLoad::new(<$name>::new($($e),*)) $(.component($comp))*
|
|
} }, vec![$(Box::new($dep.clone())),*], $crate::rsx!{ $($inner)* });
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
($r:expr, $(@$comp:expr;)* $(%$dep:ident)* $name:path { $($inner:tt)* } $($rest:tt)*) => {
|
|
$r.create_element({ $(let $dep = $dep.clone();)* move || {
|
|
$crate::widget::WidgetLoad::new(<$name>::new()) $(.component($comp))*
|
|
} }, vec![$(Box::new($dep.clone())),*], $crate::rsx!{ $($inner)* });
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
($r:expr, $expand:ident => ($($inner:tt)*) $($rest:tt)*) => {
|
|
$r.expand(&mut $expand($($inner)*));
|
|
$crate::rsx_inner! { $r, $($rest)* };
|
|
};
|
|
|
|
($r:expr,) => {};
|
|
}
|