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}