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
use std::fmt::{Debug, Error, Formatter}; use std::rc::Rc; /// A callback property for sub-[`Component`][Component]s. /// /// When a subcomponent needs to communicate with its parent, you can use a `Callback` /// to simulate a signal handler. /// /// This is how you would declare a callback property that receives a [`String`][String] when /// something happens inside the subcomponent. The property value should be a closure /// which receives the [`String`][String] and returns a message for the parent component, of the /// parent component's [`Component::Message`][Message] type. The framework will automatically take /// care of figuring out the callback's type signature when you mount the subcomponent. /// /// Note that you must always wrap the callback in an [`Option`][Option], because the properties /// object is constructed using [`Default::default()`][default] before filling in the property values, /// and it needs a safe and constructable default value for the callback. More crucially, /// for this reason the machinery which figures out the callback's type signature is /// implemented for `Option<Callback<_>>` but not for plain `Callback<_>`. /// /// ```rust,no_run /// # use vgtk::Callback; /// struct MyComponentProperties { /// on_message: Option<Callback<String>>, /// } /// ``` /// /// This is how you might provide a callback property to the above: /// /// ```rust,no_run /// # use vgtk::{gtk, VNode, Component, Callback}; /// # #[derive(Clone, Debug, Default)] /// # pub struct MyComponent { /// # pub on_message: Option<Callback<String>>, /// # } /// # impl Component for MyComponent { /// # type Message = (); /// # type Properties = Self; /// # fn view(&self) -> VNode<Self> { todo!() } /// # } /// # #[derive(Clone, Debug)] enum ParentMessage { StringReceived(String) } /// # #[derive(Default)] struct Parent; /// # impl Component for Parent { type Message = ParentMessage; type Properties = (); /// # fn view(&self) -> VNode<Self> { gtk! { /// <@MyComponent on_message=|string| ParentMessage::StringReceived(string) /> /// # }}} /// ``` /// /// [Component]: trait.Component.html /// [Message]: trait.Component.html#associatedtype.Message /// [default]: https://doc.rust-lang.org/std/default/trait.Default.html#tymethod.default /// [String]: https://doc.rust-lang.org/std/string/struct.String.html /// [Option]: https://doc.rust-lang.org/std/option/enum.Option.html pub struct Callback<A>(pub(crate) Rc<dyn Fn(A)>); impl<A: Debug> Callback<A> { /// Send a value to the callback. pub fn send(&self, value: A) { (self.0)(value) } } impl<A> Clone for Callback<A> { fn clone(&self) -> Self { Callback(self.0.clone()) } } impl<A> PartialEq for Callback<A> { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.0, &other.0) } } impl<A> Debug for Callback<A> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!(f, "Callback()") } } impl<A, F: Fn(A) + 'static> From<F> for Callback<A> { fn from(func: F) -> Self { Callback(Rc::new(func)) } }