gsk4/
transform.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4
5use crate::{ffi, Transform};
6
7impl Transform {
8    /// Parses a given into a transform.
9    ///
10    /// Strings printed via [`to_str()`][Self::to_str()]
11    /// can be read in again successfully using this function.
12    ///
13    /// If @string does not describe a valid transform, false
14    /// is returned and `NULL` is put in @out_transform.
15    /// ## `string`
16    /// the string to parse
17    ///
18    /// # Returns
19    ///
20    /// true if @string described a valid transform
21    ///
22    /// ## `out_transform`
23    /// return location for the transform
24    #[doc(alias = "gsk_transform_parse")]
25    pub fn parse(string: impl IntoGStr) -> Result<Self, glib::BoolError> {
26        assert_initialized_main_thread!();
27        unsafe {
28            string.run_with_gstr(|string| {
29                let mut out_transform = std::ptr::null_mut();
30                let ret = from_glib(ffi::gsk_transform_parse(
31                    string.as_ptr(),
32                    &mut out_transform,
33                ));
34                if ret {
35                    Ok(from_glib_full(out_transform))
36                } else {
37                    Err(glib::bool_error!("Can't parse Transform"))
38                }
39            })
40        }
41    }
42
43    /// Inverts the given transform.
44    ///
45    /// If @self is not invertible, `NULL` is returned.
46    /// Note that inverting `NULL` also returns `NULL`, which is
47    /// the correct inverse of `NULL`. If you need to differentiate
48    /// between those cases, you should check @self is not `NULL`
49    /// before calling this function.
50    ///
51    /// This function consumes @self. Use `Gsk::Transform::ref()` first
52    /// if you want to keep it around.
53    ///
54    /// # Returns
55    ///
56    /// The inverted transform
57    #[doc(alias = "gsk_transform_invert")]
58    pub fn invert(self) -> Result<Self, glib::BoolError> {
59        unsafe {
60            let matrix = self.to_matrix();
61            if matrix == graphene::Matrix::new_identity() {
62                return Ok(self);
63            }
64
65            let res: Option<Self> = from_glib_full(ffi::gsk_transform_invert(self.into_glib_ptr()));
66            res.ok_or_else(|| glib::bool_error!("Failed to invert the transform"))
67        }
68    }
69
70    /// Rotates @self by an angle around the Z axis.
71    ///
72    /// The rotation happens around the origin point of (0, 0).
73    ///
74    /// This function consumes @self. Use `Gsk::Transform::ref()` first
75    /// if you want to keep it around.
76    /// ## `angle`
77    /// the rotation angle, in degrees (clockwise)
78    ///
79    /// # Returns
80    ///
81    /// The new transform
82    #[doc(alias = "gsk_transform_rotate")]
83    #[must_use]
84    pub fn rotate(self, angle: f32) -> Self {
85        unsafe {
86            let res: Option<Self> =
87                from_glib_full(ffi::gsk_transform_rotate(self.into_glib_ptr(), angle));
88            res.unwrap_or_default()
89        }
90    }
91
92    /// Rotates @self @angle degrees around @axis.
93    ///
94    /// For a rotation in 2D space, use [`rotate()`][Self::rotate()]
95    ///
96    /// This function consumes @self. Use `Gsk::Transform::ref()` first
97    /// if you want to keep it around.
98    /// ## `angle`
99    /// the rotation angle, in degrees (clockwise)
100    /// ## `axis`
101    /// The rotation axis
102    ///
103    /// # Returns
104    ///
105    /// The new transform
106    #[doc(alias = "gsk_transform_rotate_3d")]
107    #[must_use]
108    pub fn rotate_3d(self, angle: f32, axis: &graphene::Vec3) -> Self {
109        unsafe {
110            let res: Option<Self> = from_glib_full(ffi::gsk_transform_rotate_3d(
111                self.into_glib_ptr(),
112                angle,
113                axis.to_glib_none().0,
114            ));
115            res.unwrap_or_default()
116        }
117    }
118
119    /// Scales @self in 2-dimensional space by the given factors.
120    ///
121    /// Use [`scale_3d()`][Self::scale_3d()] to scale in all 3 dimensions.
122    ///
123    /// This function consumes @self. Use `Gsk::Transform::ref()` first
124    /// if you want to keep it around.
125    /// ## `factor_x`
126    /// scaling factor on the X axis
127    /// ## `factor_y`
128    /// scaling factor on the Y axis
129    ///
130    /// # Returns
131    ///
132    /// The new transform
133    #[doc(alias = "gsk_transform_scale")]
134    #[must_use]
135    pub fn scale(self, factor_x: f32, factor_y: f32) -> Self {
136        unsafe {
137            let res: Option<Self> = from_glib_full(ffi::gsk_transform_scale(
138                self.into_glib_ptr(),
139                factor_x,
140                factor_y,
141            ));
142            res.unwrap_or_default()
143        }
144    }
145
146    /// Scales @self by the given factors.
147    ///
148    /// This function consumes @self. Use `Gsk::Transform::ref()` first
149    /// if you want to keep it around.
150    /// ## `factor_x`
151    /// scaling factor on the X axis
152    /// ## `factor_y`
153    /// scaling factor on the Y axis
154    /// ## `factor_z`
155    /// scaling factor on the Z axis
156    ///
157    /// # Returns
158    ///
159    /// The new transform
160    #[doc(alias = "gsk_transform_scale_3d")]
161    #[must_use]
162    pub fn scale_3d(self, factor_x: f32, factor_y: f32, factor_z: f32) -> Self {
163        unsafe {
164            let res: Option<Self> = from_glib_full(ffi::gsk_transform_scale_3d(
165                self.into_glib_ptr(),
166                factor_x,
167                factor_y,
168                factor_z,
169            ));
170            res.unwrap_or_default()
171        }
172    }
173
174    /// Applies a skew transform.
175    ///
176    /// This function consumes @self. Use `Gsk::Transform::ref()` first
177    /// if you want to keep it around.
178    /// ## `skew_x`
179    /// skew factor, in degrees, on the X axis
180    /// ## `skew_y`
181    /// skew factor, in degrees, on the Y axis
182    ///
183    /// # Returns
184    ///
185    /// The new transform
186    #[cfg(feature = "v4_6")]
187    #[cfg_attr(docsrs, doc(cfg(feature = "v4_6")))]
188    #[doc(alias = "gsk_transform_skew")]
189    #[must_use]
190    pub fn skew(self, skew_x: f32, skew_y: f32) -> Self {
191        unsafe {
192            let res: Option<Self> = from_glib_full(ffi::gsk_transform_skew(
193                self.into_glib_ptr(),
194                skew_x,
195                skew_y,
196            ));
197            res.unwrap_or_default()
198        }
199    }
200
201    /// Applies all the operations from @other to @self.
202    ///
203    /// This function consumes @self. Use `Gsk::Transform::ref()` first
204    /// if you want to keep it around.
205    /// ## `other`
206    /// transform to apply
207    ///
208    /// # Returns
209    ///
210    /// The new transform
211    #[doc(alias = "gsk_transform_transform")]
212    #[must_use]
213    pub fn transform(self, other: Option<&Self>) -> Self {
214        unsafe {
215            let res: Option<Self> = from_glib_full(ffi::gsk_transform_transform(
216                self.into_glib_ptr(),
217                other.to_glib_none().0,
218            ));
219            res.unwrap_or_default()
220        }
221    }
222
223    /// Translates @self in 2-dimensional space by @point.
224    ///
225    /// This function consumes @self. Use `Gsk::Transform::ref()` first
226    /// if you want to keep it around.
227    /// ## `point`
228    /// the point to translate the transform by
229    ///
230    /// # Returns
231    ///
232    /// The new transform
233    #[doc(alias = "gsk_transform_translate")]
234    #[must_use]
235    pub fn translate(self, point: &graphene::Point) -> Self {
236        unsafe {
237            let res: Option<Self> = from_glib_full(ffi::gsk_transform_translate(
238                self.into_glib_ptr(),
239                point.to_glib_none().0,
240            ));
241            res.unwrap_or_default()
242        }
243    }
244
245    /// Translates @self by @point.
246    ///
247    /// This function consumes @self. Use `Gsk::Transform::ref()` first
248    /// if you want to keep it around.
249    /// ## `point`
250    /// the point to translate the transform by
251    ///
252    /// # Returns
253    ///
254    /// The new transform
255    #[doc(alias = "gsk_transform_translate_3d")]
256    #[must_use]
257    pub fn translate_3d(self, point: &graphene::Point3D) -> Self {
258        unsafe {
259            let res: Option<Self> = from_glib_full(ffi::gsk_transform_translate_3d(
260                self.into_glib_ptr(),
261                point.to_glib_none().0,
262            ));
263            res.unwrap_or_default()
264        }
265    }
266}
267
268impl std::str::FromStr for Transform {
269    type Err = glib::BoolError;
270    fn from_str(s: &str) -> Result<Self, Self::Err> {
271        skip_assert_initialized!();
272        Self::parse(s)
273    }
274}
275
276#[test]
277fn invert_identity_is_identity() {
278    let transform = Transform::new();
279    let output = transform.clone().invert();
280    assert_eq!(output.unwrap(), transform);
281}