gtk4/
expression.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{translate::*, value::FromValue, Object, Type, Value};
4
5use crate::{ffi, prelude::*, Expression};
6
7#[doc(hidden)]
8impl AsRef<Expression> for Expression {
9    #[inline]
10    fn as_ref(&self) -> &Expression {
11        self
12    }
13}
14
15// rustdoc-stripper-ignore-next
16/// A common trait implemented by the various [`Expression`](crate::Expression)
17/// types.
18///
19/// # Safety
20///
21/// The user is not supposed to implement this trait.
22pub unsafe trait IsExpression:
23    StaticType + FromGlibPtrFull<*mut ffi::GtkExpression> + 'static
24{
25}
26
27impl Expression {
28    #[inline]
29    pub fn upcast(self) -> Self {
30        self
31    }
32
33    #[inline]
34    pub fn upcast_ref(&self) -> &Self {
35        self
36    }
37
38    #[inline]
39    pub fn is<E: IsExpression>(&self) -> bool {
40        self.type_().is_a(E::static_type())
41    }
42
43    #[inline]
44    pub fn downcast<E: IsExpression>(self) -> Result<E, Expression> {
45        unsafe {
46            if self.is::<E>() {
47                Ok(from_glib_full(self.into_glib_ptr()))
48            } else {
49                Err(self)
50            }
51        }
52    }
53
54    #[inline]
55    pub fn downcast_ref<E: IsExpression>(&self) -> Option<&E> {
56        unsafe {
57            if self.is::<E>() {
58                Some(&*(self as *const Expression as *const E))
59            } else {
60                None
61            }
62        }
63    }
64
65    #[inline]
66    pub fn type_(&self) -> Type {
67        unsafe {
68            let ptr = self.as_ptr();
69            from_glib((*(*(ptr as *mut glib::gobject_ffi::GTypeInstance)).g_class).g_type)
70        }
71    }
72
73    #[doc(alias = "gtk_expression_evaluate")]
74    pub fn evaluate(&self, this: Option<&impl IsA<Object>>) -> Option<Value> {
75        assert_initialized_main_thread!();
76        unsafe {
77            let mut value = Value::uninitialized();
78            let ret = ffi::gtk_expression_evaluate(
79                self.to_glib_none().0,
80                this.map(|t| t.as_ref()).to_glib_none().0,
81                value.to_glib_none_mut().0,
82            );
83            if from_glib(ret) {
84                Some(value)
85            } else {
86                None
87            }
88        }
89    }
90
91    // rustdoc-stripper-ignore-next
92    /// Similar to [`Self::evaluate`] but panics if the value is of a different
93    /// type.
94    #[doc(alias = "gtk_expression_evaluate")]
95    pub fn evaluate_as<V: for<'b> FromValue<'b> + 'static, T: IsA<Object>>(
96        &self,
97        this: Option<&T>,
98    ) -> Option<V> {
99        self.evaluate(this).map(|v| {
100            v.get_owned::<V>()
101                .expect("Failed to evaluate to this value type")
102        })
103    }
104
105    // rustdoc-stripper-ignore-next
106    /// Create a [`PropertyExpression`](crate::PropertyExpression) that looks up
107    /// for `property_name` with self as parameter. This is useful in long
108    /// chains of [`Expression`](crate::Expression)s.
109    pub fn chain_property<T: IsA<glib::Object>>(
110        &self,
111        property_name: &str,
112    ) -> crate::PropertyExpression {
113        crate::PropertyExpression::new(T::static_type(), Some(self), property_name)
114    }
115
116    // rustdoc-stripper-ignore-next
117    /// Create a [`ClosureExpression`](crate::ClosureExpression) from a
118    /// [`glib::Closure`] with self as the second parameter and `R` as the
119    /// return type. The return type is checked at run-time and must always
120    /// be specified. This is useful in long chains of
121    /// [`Expression`](crate::Expression)s when using the [`glib::closure!`]
122    /// macro.
123    ///
124    /// Note that the first parameter will always be the `this` object bound to
125    /// the expression. If `None` is passed as `this` then the type of the
126    /// first parameter must be `Option<glib::Object>` otherwise type
127    /// checking will panic.
128    ///
129    /// ```no_run
130    /// # use gtk4 as gtk;
131    /// use glib::{closure, Object};
132    /// use gtk::{glib, prelude::*};
133    ///
134    /// let button = gtk::Button::new();
135    /// button.set_label("Hello");
136    /// let label = button
137    ///     .property_expression("label")
138    ///     .chain_closure::<String>(closure!(|_: Option<Object>, label: &str| {
139    ///         format!("{} World", label)
140    ///     }))
141    ///     .evaluate_as::<String, _>(gtk::Widget::NONE);
142    /// assert_eq!(label.unwrap(), "Hello World");
143    /// ```
144    pub fn chain_closure<R>(&self, closure: glib::RustClosure) -> crate::ClosureExpression
145    where
146        R: glib::value::ValueType,
147    {
148        crate::ClosureExpression::new::<R>([self], closure)
149    }
150
151    // rustdoc-stripper-ignore-next
152    /// Create a [`ClosureExpression`](crate::ClosureExpression) with self as
153    /// the second parameter. This is useful in long chains of
154    /// [`Expression`](crate::Expression)s.
155    pub fn chain_closure_with_callback<F, R>(&self, f: F) -> crate::ClosureExpression
156    where
157        F: Fn(&[glib::Value]) -> R + 'static,
158        R: glib::value::ValueType,
159    {
160        crate::ClosureExpression::with_callback([self], f)
161    }
162}
163
164impl std::fmt::Debug for Expression {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        f.debug_struct("Expression")
167            .field("value_type", &self.value_type())
168            .field("is_static", &self.is_static())
169            .finish()
170    }
171}
172
173impl glib::value::ValueType for Expression {
174    type Type = Self;
175}
176
177unsafe impl<'a> glib::value::FromValue<'a> for Expression {
178    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
179
180    #[inline]
181    unsafe fn from_value(value: &'a glib::Value) -> Self {
182        skip_assert_initialized!();
183        from_glib_full(crate::ffi::gtk_value_dup_expression(value.to_glib_none().0))
184    }
185}
186
187impl glib::value::ToValue for Expression {
188    #[inline]
189    fn to_value(&self) -> glib::Value {
190        let mut value = glib::Value::for_value_type::<Self>();
191        unsafe {
192            crate::ffi::gtk_value_set_expression(value.to_glib_none_mut().0, self.to_glib_none().0)
193        }
194        value
195    }
196
197    #[inline]
198    fn value_type(&self) -> glib::Type {
199        Self::static_type()
200    }
201}
202
203impl glib::value::ToValueOptional for Expression {
204    fn to_value_optional(s: Option<&Self>) -> glib::Value {
205        skip_assert_initialized!();
206        let mut value = glib::Value::for_value_type::<Self>();
207        unsafe {
208            crate::ffi::gtk_value_set_expression(value.to_glib_none_mut().0, s.to_glib_none().0)
209        }
210        value
211    }
212}
213
214impl From<Expression> for glib::Value {
215    fn from(e: Expression) -> Self {
216        skip_assert_initialized!();
217        let mut value = glib::Value::for_value_type::<Expression>();
218        unsafe {
219            crate::ffi::gtk_value_take_expression(value.to_glib_none_mut().0, e.into_glib_ptr())
220        }
221        value
222    }
223}
224
225// rustdoc-stripper-ignore-next
226/// Trait containing convenience methods in creating
227/// [`PropertyExpression`](crate::PropertyExpression) that
228/// looks up a property of a [`glib::Object`].
229///
230/// # Example
231///
232/// `label_expression` is an [`Expression`](crate::Expression) that looks up at
233/// Button's `label` property.
234///
235/// ```no_run
236/// # use gtk4 as gtk;
237/// use gtk::prelude::*;
238///
239/// let button = gtk::Button::new();
240/// button.set_label("Label property");
241///
242/// let label_expression = button.property_expression("label");
243/// ```
244pub trait GObjectPropertyExpressionExt: IsA<glib::Object> {
245    // rustdoc-stripper-ignore-next
246    /// Create an expression looking up an object's property.
247    fn property_expression(&self, property_name: &str) -> crate::PropertyExpression {
248        let obj_expr = crate::ConstantExpression::new(self);
249        crate::PropertyExpression::new(Self::static_type(), Some(&obj_expr), property_name)
250    }
251
252    // rustdoc-stripper-ignore-next
253    /// Create an expression looking up an object's property with a weak
254    /// reference.
255    fn property_expression_weak(&self, property_name: &str) -> crate::PropertyExpression {
256        let obj_expr = crate::ObjectExpression::new(self);
257        crate::PropertyExpression::new(Self::static_type(), Some(&obj_expr), property_name)
258    }
259
260    // rustdoc-stripper-ignore-next
261    /// Create an expression looking up a property in the bound `this` object.
262    fn this_expression(property_name: &str) -> crate::PropertyExpression {
263        skip_assert_initialized!();
264        crate::PropertyExpression::new(Self::static_type(), Expression::NONE, property_name)
265    }
266}
267
268impl<O: IsA<glib::Object>> GObjectPropertyExpressionExt for O {}
269
270macro_rules! define_expression {
271    ($rust_type:ident, $ffi_type:path) => {
272        impl std::ops::Deref for $rust_type {
273            type Target = crate::Expression;
274
275            #[inline]
276            fn deref(&self) -> &Self::Target {
277                unsafe { &*(self as *const $rust_type as *const crate::Expression) }
278            }
279        }
280
281        impl AsRef<crate::Expression> for $rust_type {
282            #[inline]
283            fn as_ref(&self) -> &crate::Expression {
284                self.upcast_ref()
285            }
286        }
287
288        impl $rust_type {
289            #[inline]
290            pub fn upcast(self) -> crate::Expression {
291                unsafe { std::mem::transmute(self) }
292            }
293
294            #[inline]
295            pub fn upcast_ref(&self) -> &crate::Expression {
296                self
297            }
298        }
299
300        #[doc(hidden)]
301        impl<'a> ToGlibPtr<'a, *const crate::ffi::GtkExpression> for $rust_type {
302            type Storage =
303                ::std::marker::PhantomData<&'a $crate::glib::shared::Shared<$ffi_type, $rust_type>>;
304
305            #[inline]
306            fn to_glib_none(
307                &'a self,
308            ) -> $crate::glib::translate::Stash<'a, *const crate::ffi::GtkExpression, Self> {
309                let stash =
310                    $crate::glib::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self);
311                $crate::glib::translate::Stash(stash.0 as *const _, stash.1)
312            }
313
314            #[inline]
315            fn to_glib_full(&self) -> *const crate::ffi::GtkExpression {
316                $crate::glib::translate::ToGlibPtr::<*const $ffi_type>::to_glib_full(self)
317                    as *const _
318            }
319        }
320
321        #[doc(hidden)]
322        impl<'a> ToGlibPtr<'a, *mut crate::ffi::GtkExpression> for $rust_type {
323            type Storage =
324                ::std::marker::PhantomData<&'a $crate::glib::shared::Shared<$ffi_type, $rust_type>>;
325
326            #[inline]
327            fn to_glib_none(
328                &'a self,
329            ) -> $crate::glib::translate::Stash<'a, *mut crate::ffi::GtkExpression, Self> {
330                let stash =
331                    $crate::glib::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_none(self);
332                $crate::glib::translate::Stash(stash.0 as *mut _, stash.1)
333            }
334
335            #[inline]
336            fn to_glib_full(&self) -> *mut crate::ffi::GtkExpression {
337                $crate::glib::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_full(self) as *mut _
338            }
339        }
340
341        #[doc(hidden)]
342        impl IntoGlibPtr<*mut crate::ffi::GtkExpression> for $rust_type {
343            #[inline]
344            unsafe fn into_glib_ptr(self) -> *mut crate::ffi::GtkExpression {
345                let s = std::mem::ManuallyDrop::new(self);
346                s.to_glib_none().0
347            }
348        }
349
350        #[doc(hidden)]
351        impl IntoGlibPtr<*const crate::ffi::GtkExpression> for $rust_type {
352            #[inline]
353            unsafe fn into_glib_ptr(self) -> *const crate::ffi::GtkExpression {
354                let s = std::mem::ManuallyDrop::new(self);
355                s.to_glib_none().0
356            }
357        }
358
359        #[doc(hidden)]
360        impl FromGlibPtrFull<*mut crate::ffi::GtkExpression> for $rust_type {
361            #[inline]
362            unsafe fn from_glib_full(ptr: *mut crate::ffi::GtkExpression) -> Self {
363                from_glib_full(ptr as *mut $ffi_type)
364            }
365        }
366
367        unsafe impl crate::expression::IsExpression for $rust_type {}
368
369        impl glib::value::ValueType for $rust_type {
370            type Type = Self;
371        }
372
373        unsafe impl<'a> glib::value::FromValue<'a> for $rust_type {
374            type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
375
376            #[inline]
377            unsafe fn from_value(value: &'a glib::Value) -> Self {
378                skip_assert_initialized!();
379                from_glib_full(crate::ffi::gtk_value_dup_expression(value.to_glib_none().0))
380            }
381        }
382
383        impl glib::value::ToValue for $rust_type {
384            #[inline]
385            fn to_value(&self) -> glib::Value {
386                let mut value = glib::Value::for_value_type::<Self>();
387                unsafe {
388                    crate::ffi::gtk_value_set_expression(
389                        value.to_glib_none_mut().0,
390                        self.as_ptr() as *mut _,
391                    )
392                }
393                value
394            }
395
396            #[inline]
397            fn value_type(&self) -> glib::Type {
398                use glib::prelude::StaticType;
399                Self::static_type()
400            }
401        }
402
403        impl glib::value::ToValueOptional for $rust_type {
404            #[inline]
405            fn to_value_optional(s: Option<&Self>) -> glib::Value {
406                skip_assert_initialized!();
407                let mut value = glib::Value::for_value_type::<Self>();
408                unsafe {
409                    crate::ffi::gtk_value_set_expression(
410                        value.to_glib_none_mut().0,
411                        s.map(|s| s.as_ptr()).unwrap_or(std::ptr::null_mut()) as *mut _,
412                    )
413                }
414                value
415            }
416        }
417
418        impl From<$rust_type> for glib::Value {
419            fn from(e: $rust_type) -> Self {
420                skip_assert_initialized!();
421                let mut value = glib::Value::for_value_type::<$rust_type>();
422                unsafe {
423                    crate::ffi::gtk_value_take_expression(
424                        value.to_glib_none_mut().0,
425                        e.into_glib_ptr(),
426                    )
427                }
428                value
429            }
430        }
431
432        impl glib::HasParamSpec for $rust_type {
433            type ParamSpec = crate::ParamSpecExpression;
434
435            type SetValue = $rust_type;
436
437            type BuilderFn = for<'a> fn(&'a str) -> crate::builders::ParamSpecExpressionBuilder<'a>;
438
439            fn param_spec_builder() -> Self::BuilderFn {
440                Self::ParamSpec::builder
441            }
442        }
443    };
444}