gsk4/auto/path.rs
1// This file was generated by gir (https://github.com/gtk-rs/gir)
2// from gir-files (https://github.com/gtk-rs/gir-files)
3// DO NOT EDIT
4
5use crate::{ffi, FillRule, PathPoint, Stroke};
6use glib::translate::*;
7
8glib::wrapper! {
9 /// Describes lines and curves that are more complex than simple rectangles.
10 ///
11 /// Paths can used for rendering (filling or stroking) and for animations
12 /// (e.g. as trajectories).
13 ///
14 /// [`Path`][crate::Path] is an immutable, opaque, reference-counted struct.
15 /// After creation, you cannot change the types it represents. Instead,
16 /// new [`Path`][crate::Path] objects have to be created. The [`PathBuilder`][crate::PathBuilder]
17 /// structure is meant to help in this endeavor.
18 ///
19 /// Conceptually, a path consists of zero or more contours (continuous, connected
20 /// curves), each of which may or may not be closed. Contours are typically
21 /// constructed from Bézier segments.
22 ///
23 /// <picture>
24 /// <source srcset="path-dark.png" media="(prefers-color-scheme: dark)">
25 /// <img alt="A Path" src="path-light.png">
26 /// </picture>
27 #[derive(Debug)]
28 pub struct Path(Shared<ffi::GskPath>);
29
30 match fn {
31 ref => |ptr| ffi::gsk_path_ref(ptr),
32 unref => |ptr| ffi::gsk_path_unref(ptr),
33 type_ => || ffi::gsk_path_get_type(),
34 }
35}
36
37impl Path {
38 #[cfg(feature = "v4_22")]
39 #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
40 #[doc(alias = "gsk_path_equal")]
41 fn equal(&self, path2: &Path) -> bool {
42 unsafe {
43 from_glib(ffi::gsk_path_equal(
44 self.to_glib_none().0,
45 path2.to_glib_none().0,
46 ))
47 }
48 }
49
50 /// Computes the bounds of the given path.
51 ///
52 /// The returned bounds may be larger than necessary, because this
53 /// function aims to be fast, not accurate. The bounds are guaranteed
54 /// to contain the path. For accurate bounds, use
55 /// [`tight_bounds()`][Self::tight_bounds()].
56 ///
57 /// It is possible that the returned rectangle has 0 width and/or height.
58 /// This can happen when the path only describes a point or an
59 /// axis-aligned line.
60 ///
61 /// If the path is empty, false is returned and @bounds are set to
62 /// graphene_rect_zero(). This is different from the case where the path
63 /// is a single point at the origin, where the @bounds will also be set to
64 /// the zero rectangle but true will be returned.
65 ///
66 /// # Returns
67 ///
68 /// true if the path has bounds, false if the path is known
69 /// to be empty and have no bounds
70 ///
71 /// ## `bounds`
72 /// return location for the bounds
73 #[doc(alias = "gsk_path_get_bounds")]
74 #[doc(alias = "get_bounds")]
75 pub fn bounds(&self) -> Option<graphene::Rect> {
76 unsafe {
77 let mut bounds = graphene::Rect::uninitialized();
78 let ret = from_glib(ffi::gsk_path_get_bounds(
79 self.to_glib_none().0,
80 bounds.to_glib_none_mut().0,
81 ));
82 if ret {
83 Some(bounds)
84 } else {
85 None
86 }
87 }
88 }
89
90 /// Computes the closest point on the path to the given point.
91 ///
92 /// If there is no point closer than the given threshold,
93 /// false is returned.
94 /// ## `point`
95 /// the point
96 /// ## `threshold`
97 /// maximum allowed distance
98 ///
99 /// # Returns
100 ///
101 /// true if @point was set to the closest point
102 /// on @self, false if no point is closer than @threshold
103 ///
104 /// ## `result`
105 /// return location for the closest point
106 ///
107 /// ## `distance`
108 /// return location for the distance
109 #[doc(alias = "gsk_path_get_closest_point")]
110 #[doc(alias = "get_closest_point")]
111 pub fn closest_point(
112 &self,
113 point: &graphene::Point,
114 threshold: f32,
115 ) -> Option<(PathPoint, f32)> {
116 unsafe {
117 let mut result = PathPoint::uninitialized();
118 let mut distance = std::mem::MaybeUninit::uninit();
119 let ret = from_glib(ffi::gsk_path_get_closest_point(
120 self.to_glib_none().0,
121 point.to_glib_none().0,
122 threshold,
123 result.to_glib_none_mut().0,
124 distance.as_mut_ptr(),
125 ));
126 if ret {
127 Some((result, distance.assume_init()))
128 } else {
129 None
130 }
131 }
132 }
133
134 /// Gets the end point of the path.
135 ///
136 /// An empty path has no points, so false
137 /// is returned in this case.
138 ///
139 /// # Returns
140 ///
141 /// true if @result was filled
142 ///
143 /// ## `result`
144 /// return location for point
145 #[doc(alias = "gsk_path_get_end_point")]
146 #[doc(alias = "get_end_point")]
147 pub fn end_point(&self) -> Option<PathPoint> {
148 unsafe {
149 let mut result = PathPoint::uninitialized();
150 let ret = from_glib(ffi::gsk_path_get_end_point(
151 self.to_glib_none().0,
152 result.to_glib_none_mut().0,
153 ));
154 if ret {
155 Some(result)
156 } else {
157 None
158 }
159 }
160 }
161
162 //#[cfg(feature = "v4_22")]
163 //#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
164 //#[doc(alias = "gsk_path_get_next")]
165 //#[doc(alias = "get_next")]
166 //pub fn next(&self, point: /*Unimplemented*/PathPoint) -> bool {
167 // unsafe { TODO: call ffi:gsk_path_get_next() }
168 //}
169
170 //#[cfg(feature = "v4_22")]
171 //#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
172 //#[doc(alias = "gsk_path_get_previous")]
173 //#[doc(alias = "get_previous")]
174 //pub fn previous(&self, point: /*Unimplemented*/PathPoint) -> bool {
175 // unsafe { TODO: call ffi:gsk_path_get_previous() }
176 //}
177
178 /// Gets the start point of the path.
179 ///
180 /// An empty path has no points, so false
181 /// is returned in this case.
182 ///
183 /// # Returns
184 ///
185 /// true if @result was filled
186 ///
187 /// ## `result`
188 /// return location for point
189 #[doc(alias = "gsk_path_get_start_point")]
190 #[doc(alias = "get_start_point")]
191 pub fn start_point(&self) -> Option<PathPoint> {
192 unsafe {
193 let mut result = PathPoint::uninitialized();
194 let ret = from_glib(ffi::gsk_path_get_start_point(
195 self.to_glib_none().0,
196 result.to_glib_none_mut().0,
197 ));
198 if ret {
199 Some(result)
200 } else {
201 None
202 }
203 }
204 }
205
206 /// Computes the bounds for stroking the given path with the
207 /// given parameters.
208 ///
209 /// The returned bounds may be larger than necessary, because this
210 /// function aims to be fast, not accurate. The bounds are guaranteed
211 /// to contain the area affected by the stroke, including protrusions
212 /// like miters.
213 /// ## `stroke`
214 /// stroke parameters
215 ///
216 /// # Returns
217 ///
218 /// true if the path has bounds, false if the path is known
219 /// to be empty and have no bounds.
220 ///
221 /// ## `bounds`
222 /// the bounds to fill in
223 #[doc(alias = "gsk_path_get_stroke_bounds")]
224 #[doc(alias = "get_stroke_bounds")]
225 pub fn stroke_bounds(&self, stroke: &Stroke) -> Option<graphene::Rect> {
226 unsafe {
227 let mut bounds = graphene::Rect::uninitialized();
228 let ret = from_glib(ffi::gsk_path_get_stroke_bounds(
229 self.to_glib_none().0,
230 stroke.to_glib_none().0,
231 bounds.to_glib_none_mut().0,
232 ));
233 if ret {
234 Some(bounds)
235 } else {
236 None
237 }
238 }
239 }
240
241 /// Computes the tight bounds of the given path.
242 ///
243 /// This function works harder than [`bounds()`][Self::bounds()] to
244 /// produce the smallest possible bounds.
245 ///
246 /// # Returns
247 ///
248 /// true if the path has bounds, false if the path is known
249 /// to be empty and have no bounds
250 ///
251 /// ## `bounds`
252 /// return location for the bounds
253 #[cfg(feature = "v4_22")]
254 #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
255 #[doc(alias = "gsk_path_get_tight_bounds")]
256 #[doc(alias = "get_tight_bounds")]
257 pub fn tight_bounds(&self) -> Option<graphene::Rect> {
258 unsafe {
259 let mut bounds = graphene::Rect::uninitialized();
260 let ret = from_glib(ffi::gsk_path_get_tight_bounds(
261 self.to_glib_none().0,
262 bounds.to_glib_none_mut().0,
263 ));
264 if ret {
265 Some(bounds)
266 } else {
267 None
268 }
269 }
270 }
271
272 /// Returns whether a point is inside the fill area of a path.
273 ///
274 /// Note that this function assumes that filling a contour
275 /// implicitly closes it.
276 /// ## `point`
277 /// the point to test
278 /// ## `fill_rule`
279 /// the fill rule to follow
280 ///
281 /// # Returns
282 ///
283 /// true if @point is inside
284 #[doc(alias = "gsk_path_in_fill")]
285 pub fn in_fill(&self, point: &graphene::Point, fill_rule: FillRule) -> bool {
286 unsafe {
287 from_glib(ffi::gsk_path_in_fill(
288 self.to_glib_none().0,
289 point.to_glib_none().0,
290 fill_rule.into_glib(),
291 ))
292 }
293 }
294
295 /// Returns if the path represents a single closed contour.
296 ///
297 /// # Returns
298 ///
299 /// true if the path is closed
300 #[doc(alias = "gsk_path_is_closed")]
301 pub fn is_closed(&self) -> bool {
302 unsafe { from_glib(ffi::gsk_path_is_closed(self.to_glib_none().0)) }
303 }
304
305 /// Checks if the path is empty, i.e. contains no lines or curves.
306 ///
307 /// # Returns
308 ///
309 /// true if the path is empty
310 #[doc(alias = "gsk_path_is_empty")]
311 pub fn is_empty(&self) -> bool {
312 unsafe { from_glib(ffi::gsk_path_is_empty(self.to_glib_none().0)) }
313 }
314
315 /// Appends the path to a cairo context for drawing with Cairo.
316 ///
317 /// This may cause some suboptimal conversions to be performed as
318 /// Cairo does not support all features of [`Path`][crate::Path].
319 ///
320 /// This function does not clear the existing Cairo path. Call
321 /// cairo_new_path() if you want this.
322 /// ## `cr`
323 /// a cairo context
324 #[doc(alias = "gsk_path_to_cairo")]
325 pub fn to_cairo(&self, cr: &cairo::Context) {
326 unsafe {
327 ffi::gsk_path_to_cairo(self.to_glib_none().0, mut_override(cr.to_glib_none().0));
328 }
329 }
330
331 /// Converts the path into a human-readable string.
332 ///
333 /// You can use this function in a debugger to get a quick overview
334 /// of the path.
335 ///
336 /// This is a wrapper around `Gsk::Path::print()`, see that function
337 /// for details.
338 ///
339 /// # Returns
340 ///
341 /// a new string for @self
342 #[doc(alias = "gsk_path_to_string")]
343 #[doc(alias = "to_string")]
344 pub fn to_str(&self) -> glib::GString {
345 unsafe { from_glib_full(ffi::gsk_path_to_string(self.to_glib_none().0)) }
346 }
347
348 /// Constructs a path from a serialized form.
349 ///
350 /// The string is expected to be in (a superset of)
351 /// [SVG path syntax](https://www.w3.org/TR/SVG11/paths.html#PathData),
352 /// as e.g. produced by [`to_str()`][Self::to_str()].
353 ///
354 /// A high-level summary of the syntax:
355 ///
356 /// - `M x y` Move to `(x, y)`
357 /// - `L x y` Add a line from the current point to `(x, y)`
358 /// - `Q x1 y1 x2 y2` Add a quadratic Bézier from the current point to `(x2, y2)`, with control point `(x1, y1)`
359 /// - `C x1 y1 x2 y2 x3 y3` Add a cubic Bézier from the current point to `(x3, y3)`, with control points `(x1, y1)` and `(x2, y2)`
360 /// - `Z` Close the contour by drawing a line back to the start point
361 /// - `H x` Add a horizontal line from the current point to the given x value
362 /// - `V y` Add a vertical line from the current point to the given y value
363 /// - `T x2 y2` Add a quadratic Bézier, using the reflection of the previous segments' control point as control point
364 /// - `S x2 y2 x3 y3` Add a cubic Bézier, using the reflection of the previous segments' second control point as first control point
365 /// - `A rx ry r l s x y` Add an elliptical arc from the current point to `(x, y)` with radii rx and ry. See the SVG documentation for how the other parameters influence the arc.
366 /// - `O x1 y1 x2 y2 w` Add a rational quadratic Bézier from the current point to `(x2, y2)` with control point `(x1, y1)` and weight `w`.
367 ///
368 /// All the commands have lowercase variants that interpret coordinates
369 /// relative to the current point.
370 ///
371 /// The `O` command is an extension that is not supported in SVG.
372 /// ## `string`
373 /// a string
374 ///
375 /// # Returns
376 ///
377 /// a new [`Path`][crate::Path], or `NULL` if @string could not be parsed
378 #[doc(alias = "gsk_path_parse")]
379 pub fn parse(string: &str) -> Result<Path, glib::BoolError> {
380 assert_initialized_main_thread!();
381 unsafe {
382 Option::<_>::from_glib_full(ffi::gsk_path_parse(string.to_glib_none().0))
383 .ok_or_else(|| glib::bool_error!("Can't parse Path"))
384 }
385 }
386}
387
388#[cfg(feature = "v4_22")]
389#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
390impl PartialEq for Path {
391 #[inline]
392 fn eq(&self, other: &Self) -> bool {
393 self.equal(other)
394 }
395}
396
397#[cfg(feature = "v4_22")]
398#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
399impl Eq for Path {}
400
401impl std::fmt::Display for Path {
402 #[inline]
403 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
404 f.write_str(&self.to_str())
405 }
406}