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}