diff --git a/examples/expressions/main.rs b/examples/expressions/main.rs index 7c137eb223b2..49410c48e38e 100644 --- a/examples/expressions/main.rs +++ b/examples/expressions/main.rs @@ -1,6 +1,8 @@ mod metadata; mod note; +use glib::closure; + use gtk::gio; use gtk::glib; use gtk::prelude::*; @@ -40,7 +42,7 @@ fn build_ui(app: >k::Application) { metadata_expression .chain_property::("title") - .chain_closure(|args| { + .chain_closure_with_callback(|args| { let title: String = args[1].get().unwrap(); format!("Title: {}", title) }) @@ -48,11 +50,12 @@ fn build_ui(app: >k::Application) { metadata_expression .chain_property::("last-modified") - .chain_closure(|args| { - let last_modified: glib::DateTime = args[1].get().unwrap(); - format!("Last Modified: {}", last_modified.format_iso8601().unwrap()) - }) - .bind(&last_modified_label, "label", gtk::Widget::NONE); + .chain_closure::(closure!( + |_: gtk::ListItem, last_modified: glib::DateTime| { + format!("Last Modified: {}", last_modified.format_iso8601().unwrap()) + } + )) + .bind(&last_modified_label, "label", Some(list_item)); list_item.set_child(Some(&hbox)); }); diff --git a/gtk4/src/closure_expression.rs b/gtk4/src/closure_expression.rs index e4755dbf9643..4ab32bf1eb71 100644 --- a/gtk4/src/closure_expression.rs +++ b/gtk4/src/closure_expression.rs @@ -23,16 +23,13 @@ define_expression!( impl ClosureExpression { #[doc(alias = "gtk_closure_expression_new")] - pub fn new(params: impl IntoIterator>, callback: F) -> Self + pub fn new(params: I, closure: glib::RustClosure) -> Self where - F: Fn(&[Value]) -> R + 'static, R: ValueType, + I: IntoIterator, + E: AsRef, { assert_initialized_main_thread!(); - let closure = glib::Closure::new_local(move |values| { - let ret = callback(values); - Some(ret.to_value()) - }); let params = params .into_iter() @@ -42,7 +39,7 @@ impl ClosureExpression { unsafe { from_glib_full(ffi::gtk_closure_expression_new( R::Type::static_type().into_glib(), - closure.to_glib_none().0, + closure.as_ref().to_glib_none().0, params.len() as u32, params.to_glib_full(), )) @@ -50,14 +47,19 @@ impl ClosureExpression { } #[doc(alias = "gtk_closure_expression_new")] - pub fn with_closure( + pub fn with_callback( params: impl IntoIterator>, - closure: glib::Closure, + callback: F, ) -> Self where + F: Fn(&[Value]) -> R + 'static, R: ValueType, { assert_initialized_main_thread!(); + let closure = glib::Closure::new_local(move |values| { + let ret = callback(values); + Some(ret.to_value()) + }); let params = params .into_iter() diff --git a/gtk4/src/expression.rs b/gtk4/src/expression.rs index 72b67cec131a..952a8f75d455 100644 --- a/gtk4/src/expression.rs +++ b/gtk4/src/expression.rs @@ -161,8 +161,9 @@ impl Expression { } // rustdoc-stripper-ignore-next - /// Create a [`gtk::PropertyExpression`] that looks up for `property_name` - /// with self as parameter. This is useful in long chains of [`gtk::Expression`]s. + /// Create a [`PropertyExpression`](crate::PropertyExpression) that looks up for + /// `property_name` with self as parameter. This is useful in long chains of + /// [`Expression`](crate::Expression)s. pub fn chain_property>( &self, property_name: &str, @@ -171,14 +172,47 @@ impl Expression { } // rustdoc-stripper-ignore-next - /// Create a [`gtk::ClosureExpression`] with self as a parameter. This is useful in long - /// chains of [`gtk::Expression`]s. - pub fn chain_closure(&self, f: F) -> crate::ClosureExpression + /// Create a [`ClosureExpression`](crate::ClosureExpression) from a [`glib::Closure`] with self + /// as the second parameter and `R` as the return type. The return type is checked at run-time + /// and must always be specified. This is useful in long chains of + /// [`Expression`](crate::Expression)s when using the [`glib::closure!`] macro. + /// + /// Note that the first parameter will always be the `this` object bound to the expression. If + /// `None` is passed as `this` then the type of the first parameter must be + /// `Option` otherwise type checking will panic. + /// + /// ```no_run + /// # use gtk4 as gtk; + /// use gtk::prelude::*; + /// use gtk::glib; + /// use glib::{closure, Object}; + /// + /// let button = gtk::Button::new(); + /// button.set_label("Hello"); + /// let label = button + /// .property_expression("label") + /// .chain_closure::(closure!(|_: Option, label: &str| { + /// format!("{} World", label) + /// })) + /// .evaluate_as::(gtk::Widget::NONE); + /// assert_eq!(label.unwrap(), "Hello World"); + /// ``` + pub fn chain_closure(&self, closure: glib::RustClosure) -> crate::ClosureExpression + where + R: glib::value::ValueType, + { + crate::ClosureExpression::new::(&[self], closure) + } + + // rustdoc-stripper-ignore-next + /// Create a [`ClosureExpression`](crate::ClosureExpression) with self as the second parameter. + /// This is useful in long chains of [`Expression`](crate::Expression)s. + pub fn chain_closure_with_callback(&self, f: F) -> crate::ClosureExpression where F: Fn(&[glib::Value]) -> R + 'static, R: glib::value::ValueType, { - crate::ClosureExpression::new(&[self], f) + crate::ClosureExpression::with_callback(&[self], f) } } @@ -217,12 +251,13 @@ impl glib::value::ToValueOptional for Expression { } // rustdoc-stripper-ignore-next -/// Trait containing convenience methods in creating [`gtk::PropertyExpression`] that +/// Trait containing convenience methods in creating +/// [`PropertyExpression`](crate::PropertyExpression) that /// looks up a property of a [`glib::Object`]. /// /// # Example /// -/// `label_expression` is a [`gtk::Expression`] that looks up at Button's `label` +/// `label_expression` is an [`Expression`](crate::Expression) that looks up at Button's `label` /// property. /// /// ```no_run