1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
/// Defines a state and setter.
///
/// `use_state!` can be used to define a local (for a single gstore component) state variable and a
/// setter to update this value  
///
/// # Example
/// ```rust,no_run
/// #[macro_use]
/// extern crate gstore;
/// use gtk::prelude::*;
///
/// use_state! {
///     [count: u32, set_count] = 0
/// }
///
/// # pub fn main() {}
///
/// pub fn counter() -> gtk::ApplicationWindow {
///     glib::timeout_add_local(1000, move || {
///         // update the local state value each second...
///         set_count(count() + 1);
///         glib::Continue(true)
///     });
///     return application_window! {
///         children [
///             label! {
///                 properties {
///                     // The value of the local state can be read with a getter function
///                     label: format!("Count: {}", count())
///                     expand: true
///                 }
///             }
///         ]
///     }
/// }
/// ```
#[macro_export]
macro_rules! use_state {
    (
        $([$field:ident: $t:ty, $setter:ident] = $init:expr),*
    ) => {
        use std::ops::Deref;

        // --- render handling ---
        static mut _RENDER_CALLBACKS: gstore::once_cell::sync::Lazy<Vec<Box<dyn Fn()>>> =
            gstore::once_cell::sync::Lazy::new(|| vec![]);

        fn _register_rerender<F>(callback: F)
        where
            F: Fn() + 'static,
        {
            unsafe { _RENDER_CALLBACKS.push(Box::new(callback)) }
        }

        fn _rerender() {
            unsafe {
                for callback in _RENDER_CALLBACKS.deref() {
                    callback()
                }
            }
        }

        fn stateful<F>(callback: F)
        where
            F: Fn() + 'static,
        {
            _register_rerender(callback)
        }

        // --- state definition ---
        #[derive(Debug, Clone)]
        struct LocalState {$(
            $field: $t
        ),*}

        impl Default for LocalState {
            fn default() -> Self {
               LocalState {$(
                  $field: $init
               ),*}
            }
        }

        static mut _STATE: gstore::once_cell::sync::Lazy<LocalState> =
            gstore::once_cell::sync::Lazy::new(|| LocalState::default());

        // --- getters and setters ---
        $(
        fn $setter(v: $t) {
            unsafe {
                _STATE.$field = v;
            }
            _rerender()
        }
        fn $field() -> $t {
            unsafe {
                _STATE.$field.clone()
            }
        }
        )*

    };
}