pub mod annotations;
pub mod components;
pub mod handlers;
pub mod props;
pub mod styles;
pub use components::*;
pub use grx_macros::component;
pub use grx_macros::props;
pub use styles::Style;
pub use serde_json;
#[cfg(feature = "gstore")]
pub mod gstore_debug;
#[cfg(feature = "gtk")]
pub mod gtk_components;
mod grx {
pub use super::*;
}
pub mod prelude {
pub use super::component;
pub use super::components::*;
pub use super::grx;
pub use super::props;
pub use super::Component;
pub use super::ComponentExt;
pub use std::rc::Rc;
}
#[macro_export]
macro_rules! grx {
(
$text:literal
) => {{
{
$crate::text::Text::new($text)
}
}};
(
$component_name:ident
// args
$( ($($args:tt)*) )?
$([$($body:tt)+])?
) => {{
#[allow(unused_mut)]
let mut props = $component_name::Props::default();
$(
$crate::grx_args!{props, $($args)*}
)?
$(
props.children = $crate::grx_body!{$($body)+};
)?
let styles = props.styles.clone();
let c = $component_name::$component_name(props);
$(
$crate::grx_id!{c, $($args)*};
)?
let root: $crate::Component = c;
for s in styles {
$crate::styles::apply(&s, &root);
}
root
}};
}
#[macro_export]
macro_rules! grx_args {
($props:ident, $styles:ident=[$($st:tt)*] $(,$($rest:tt)*)?) => {
#[allow(unused_mut)]
let mut st = vec![];
$crate::grx_styles!{st, $($st)*}
$props.$styles = st;
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, id=$id:ident $(,$($rest:tt)*)?) => {
$props.id = stringify!($id).into();
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, $handler:ident=|| {$($handle:stmt);*$(;)?} $(,$($rest:tt)*)?) => {
$props.$handler = Some(Rc::new(|_| {
$($handle)*
}));
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, $handler:ident=|$i:ident| $handle:expr $(,$($rest:tt)*)?) => {
$props.$handler = Some(Rc::new(|$i| $handle));
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, $handler:ident=move |$i:ident| {$($handle:stmt);*$(;)?} $(,$($rest:tt)*)?) => {
$props.$handler = Some(Rc::new(move |$i| {
$($handle)*
}));
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, $handler:ident=move || $handle:stmt $(,$($rest:tt)*)?) => {
$props.$handler = Some(Rc::new(move |_| {
$handle
}));
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, $handler:ident=|$($args:ident),+| {$($handle:stmt)*} $(,$($rest:tt)*)?) => {
$props.$handler = Some(Rc::new(|_| {
$($handle)*
}));
$(
$crate::grx_args!{$props, $($rest)*}
)?
};
($props:ident, $prop_key:ident=$val:expr $(,$($rest:tt)*)?) => {
#[allow(unused_braces)]
{
$props.$prop_key = $val;
}
$(
$crate::grx_args!{$props, $($rest)*}
)?
}
}
#[macro_export]
macro_rules! grx_styles {
($styles:ident, $st:ident $(( $($st_arg:expr),+ ))? $(, $($rest:tt)*)?) => {{
#[allow(unused_imports)]
use $crate::styles::Align::*;
#[allow(unused_imports)]
use $crate::styles::Overflow::*;
#[allow(unused_imports)]
use $crate::styles::Wrap::*;
#[allow(unused_imports)]
use $crate::styles::Justify::*;
$styles.push(
$crate::styles::Style::$st(
$crate::styles::Modifier::none
$(,
$($st_arg),+)?
)
);
$(
$crate::grx_styles!{$styles, $($rest)*}
)?
}};
($styles:ident, {$st:ident} $(, $($rest:tt)*)?) => {{
use $crate::styles::Align::*;
use $crate::styles::Overflow::*;
use $crate::styles::Wrap::*;
use $crate::styles::Justify::*;
$styles.push($st);
$(
$crate::grx_styles!{$styles, $($rest)*}
)?
}};
($styles:ident, $modi:ident:$st:ident $(( $($st_arg:expr),+ ))? $(, $($rest:tt)*)?) => {{
$styles.push(
$crate::styles::Style::$st(
$crate::styles::Modifier::$modi
$(,
$($st_arg),+)?
)
);
$(
$crate::grx_styles!{$styles, $($rest)*}
)?
}};
}
#[macro_export]
macro_rules! grx_body {
(
$text:literal
$(,$($rest:tt)*)?
) => {{
{
#[allow(unused_mut)]
let mut body: Vec<$crate::Component> = vec![
$crate::text::Text::new($text)
];
$(
body.append(&mut $crate::grx_body!{$($rest)*});
)?
body
}
}};
(
$(#[$($anno:ident=$value:expr),+])?
icon($name:literal)
$([$($body:tt)+])?
$(,$($rest:tt)*)?
) => {$crate::grx_body!{ $(#[$($anno=$value),+])? icon( name=$name ) $([$($body)+])? $(,$($rest)*)? }};
(
$(#[$($anno:ident=$value:expr),+])?
$component_name:ident
$( ($($args:tt)*) )?
$([$($body:tt)+])?
$(,$($rest:tt)*)?
) => {{
#[allow(unused_mut)]
let mut annotations: std::collections::HashMap<String, $crate::serde_json::Value> = std::collections::HashMap::new();
$(
$(
annotations.insert(stringify!($anno).into(), $value.into());
)+
)?
#[allow(unused_mut)]
let mut props = $component_name::Props::default();
$(
$crate::grx_args!{props, $($args)*}
)?
$(
props.children = $crate::grx_body!{$($body)+};
)?
{
let styles = props.styles.clone();
#[allow(unused_mut)]
let mut c = $component_name::$component_name(props);
let component: $crate::Component = c.clone();
*component.annotations_mut() = annotations;
for style in styles {
$crate::styles::apply(&style, &c);
}
$(
$crate::grx_id!{c, $($args)*};
)?
#[allow(unused_mut)]
let mut body: Vec<$crate::Component> = vec![c];
$(
body.append(&mut $crate::grx_body!{$($rest)*});
)?
body
}
}};
}
#[macro_export]
macro_rules! grx_id {
($variable:ident, id=$id:ident $($rest:tt)*) => {
$id = $variable.clone();
};
($variable:ident, $($rest:tt)*) => {
();
};
}
#[macro_export]
macro_rules! state {
($( [$getter:ident, $setter:ident]: $typ:ty );* $(;)?) => {
$(
mod $getter {
use super::*;
use std::sync::Mutex;
use once_cell::sync::Lazy;
type Callback = dyn Fn(&$typ) + Send + 'static;
#[allow(non_upper_case_globals)]
static _state: Lazy<Mutex<($typ, Vec<Box<Callback>>)>> =
Lazy::new(|| Mutex::new((Default::default(), Vec::new())));
pub(super) fn $getter<T>(cb: T)
where
T: Fn(&$typ) + Send + 'static,
{
if let Ok(mut lock) = _state.lock() {
cb(&lock.0);
lock.1.push(Box::new(cb));
}
}
pub(super) fn $setter<T>(setter: T)
where
T: (Fn(&$typ) -> $typ) + Send + 'static,
{
if let Ok(mut lock) = _state.lock() {
let value = setter(&lock.0);
lock.1.iter().for_each(|cb| cb(&value));
lock.0 = value;
}
}
}
use $getter::$getter;
use $getter::$setter;
)*
};
}
#[macro_export]
macro_rules! new_gc {
($name:ident {
$widget:ident,
$props:ident
$(,
$($field:ident: $init:expr),*$(,)?
)?
}) => {{
let children = $props.children.drain(0..).collect();
Rc::new($name {
widget: $widget,
props: $props,
children: std::cell::RefCell::new(children),
annotations: Default::default(),
$(
$(
$field: $init,
)*
)?
})
}};
}
#[macro_export]
macro_rules! default_on_click {
() => {
fn on_click(self: &Rc<Self>, handler: impl Fn(&Rc<Self>) + 'static) {
let gesture_click = gtk::GestureClick::builder().build();
let s = self.clone();
gesture_click.connect_released(move |_, _, _, _| handler(&s));
gtk::traits::WidgetExt::add_controller(&self.widget, gesture_click);
}
};
}
#[macro_export]
macro_rules! default_on_swipe {
() => {
fn on_swipe(self: &Rc<Self>, handler: impl Fn(&Rc<Self>, f64, f64) + 'static) {
let swipe = gtk::GestureSwipe::builder().build();
let s = self.clone();
swipe.connect_swipe(move |_gs, x, y| handler(&s, x, y));
gtk::traits::WidgetExt::add_controller(&self.widget, swipe);
}
};
}
#[macro_export]
macro_rules! default_interactable {
($name:ident) => {
impl $crate::Interactable for $name {
$crate::default_on_click! {}
$crate::default_on_swipe! {}
}
};
}
#[macro_export]
macro_rules! default_clear {
() => {
fn clear(self: &Rc<Self>) {
use gtk::prelude::WidgetExt;
let widget = &self.widget;
let mut child = widget.first_child();
while let Some(c) = child {
child = c.next_sibling();
widget.remove(&c);
}
}
};
}
#[macro_export]
macro_rules! default_remove {
() => {
fn remove<W>(self: &Rc<Self>, child: std::rc::Rc<W>)
where
W: $crate::ComponentExt + ?Sized,
{
let inner = child.inner();
let w: >k::Widget = inner.downcast_ref().unwrap();
self.widget.remove(w);
}
};
}
#[macro_export]
macro_rules! container_ext {
($comp:ident) => {
impl $crate::ContainerExt for $comp {
fn append<W>(self: &Rc<Self>, child: std::rc::Rc<W>)
where
W: $crate::ComponentExt + ?Sized,
{
let inner = child.inner();
let w: >k::Widget = inner.downcast_ref().unwrap();
self.widget.append(w);
}
$crate::default_clear! {}
$crate::default_remove! {}
}
};
}