relm4/binding/mod.rs
1//! Easy data bindings between objects.
2//!
3//! Particularly, this module provides types and traits
4//! that simplify connecting with the primary property of an object.
5//! In this context, *primary* means that the property is the most important and
6//! most accessed value stored by the object.
7//! Usually, this is very easy to figure out, such as the *active* property for [`gtk::ToggleButton`].
8//! In any case, the primary property type are always documented.
9//!
10//! To find out which widgets are currently supported and which property is considered as primary,
11//! please look at the list implementers for [`ConnectBinding`].
12//! Contributions to add support for more widgets are always welcome.
13
14mod bindings;
15mod widgets;
16
17pub use bindings::*;
18
19use std::ops::{Deref, DerefMut};
20
21use gtk::{glib, prelude::IsA};
22
23/// A trait that allows type-safe bindings between to the primary properties of two objects.
24pub trait ConnectBinding {
25 /// The type of the primary property.
26 type Target;
27
28 /// Create a type-safe bidirectional between the primary property of an object
29 /// and a [`Binding`].
30 fn bind<B: Binding<Target = Self::Target>>(&self, binding: &B);
31}
32
33/// Extension for [`ConnectBinding`].
34/// This trait is not implemented manually, but through
35/// automatically implemented for all types that implement
36/// [`ConnectBinding`].
37pub trait ConnectBindingExt {
38 /// The type of the primary property.
39 /// Inherited from [`ConnectBinding::Target`].
40 type Target;
41
42 /// Create an object and immediately connect it with a [`Binding`].
43 fn with_binding<B: Binding<Target = Self::Target>>(binding: &B) -> Self;
44}
45
46impl<T> ConnectBindingExt for T
47where
48 T: Default + ConnectBinding,
49{
50 type Target = <T as ConnectBinding>::Target;
51
52 fn with_binding<B: Binding<Target = Self::Target>>(binding: &B) -> Self {
53 let obj = Self::default();
54 obj.bind(binding);
55 obj
56 }
57}
58
59#[derive(Debug)]
60/// A RAII-guard that stores a value to
61/// a [`Binding`].
62///
63/// Once dropped, it will automatically update
64/// the value of the primary property.
65pub struct BindingGuard<B: Binding> {
66 value: Option<B::Target>,
67 inner: B,
68}
69
70impl<B: Binding> Deref for BindingGuard<B> {
71 type Target = <B as Binding>::Target;
72
73 fn deref(&self) -> &Self::Target {
74 self.value.as_ref().unwrap()
75 }
76}
77
78impl<B: Binding> DerefMut for BindingGuard<B> {
79 fn deref_mut(&mut self) -> &mut Self::Target {
80 self.value.as_mut().unwrap()
81 }
82}
83
84impl<B: Binding> Drop for BindingGuard<B> {
85 fn drop(&mut self) {
86 self.inner.set(self.value.take().unwrap());
87 }
88}
89
90/// A [`glib::Object`] with one primary property.
91pub trait Binding: Clone + IsA<glib::Object> {
92 /// The type of the primary property.
93 type Target;
94
95 #[must_use]
96 /// The name of the primary property.
97 fn property_name() -> &'static str {
98 "value"
99 }
100
101 /// Get a new [`BindingGuard`] from the object.
102 ///
103 /// Once dropped, the [`BindingGuard`] will
104 /// automatically update the value of the
105 /// primary property.
106 fn guard(&self) -> BindingGuard<Self> {
107 BindingGuard {
108 value: Some(self.get()),
109 inner: self.clone(),
110 }
111 }
112
113 /// Get the value of the primary property.
114 fn get(&self) -> Self::Target;
115
116 /// Set the value of the primary property.
117 fn set(&self, value: Self::Target);
118}