Skip to main content

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::{FillRule, PathPoint, Stroke, ffi};
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 { Some(bounds) } else { None }
83        }
84    }
85
86    /// Computes the closest point on the path to the given point.
87    ///
88    /// If there is no point closer than the given threshold,
89    /// false is returned.
90    /// ## `point`
91    /// the point
92    /// ## `threshold`
93    /// maximum allowed distance
94    ///
95    /// # Returns
96    ///
97    /// true if @point was set to the closest point
98    ///   on @self, false if no point is closer than @threshold
99    ///
100    /// ## `result`
101    /// return location for the closest point
102    ///
103    /// ## `distance`
104    /// return location for the distance
105    #[doc(alias = "gsk_path_get_closest_point")]
106    #[doc(alias = "get_closest_point")]
107    pub fn closest_point(
108        &self,
109        point: &graphene::Point,
110        threshold: f32,
111    ) -> Option<(PathPoint, f32)> {
112        unsafe {
113            let mut result = PathPoint::uninitialized();
114            let mut distance = std::mem::MaybeUninit::uninit();
115            let ret = from_glib(ffi::gsk_path_get_closest_point(
116                self.to_glib_none().0,
117                point.to_glib_none().0,
118                threshold,
119                result.to_glib_none_mut().0,
120                distance.as_mut_ptr(),
121            ));
122            if ret {
123                Some((result, distance.assume_init()))
124            } else {
125                None
126            }
127        }
128    }
129
130    /// Gets the end point of the path.
131    ///
132    /// An empty path has no points, so false
133    /// is returned in this case.
134    ///
135    /// # Returns
136    ///
137    /// true if @result was filled
138    ///
139    /// ## `result`
140    /// return location for point
141    #[doc(alias = "gsk_path_get_end_point")]
142    #[doc(alias = "get_end_point")]
143    pub fn end_point(&self) -> Option<PathPoint> {
144        unsafe {
145            let mut result = PathPoint::uninitialized();
146            let ret = from_glib(ffi::gsk_path_get_end_point(
147                self.to_glib_none().0,
148                result.to_glib_none_mut().0,
149            ));
150            if ret { Some(result) } else { None }
151        }
152    }
153
154    //#[cfg(feature = "v4_22")]
155    //#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
156    //#[doc(alias = "gsk_path_get_next")]
157    //#[doc(alias = "get_next")]
158    //pub fn is_next(&self, point: /*Unimplemented*/PathPoint) -> bool {
159    //    unsafe { TODO: call ffi:gsk_path_get_next() }
160    //}
161
162    //#[cfg(feature = "v4_22")]
163    //#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
164    //#[doc(alias = "gsk_path_get_previous")]
165    //#[doc(alias = "get_previous")]
166    //pub fn is_previous(&self, point: /*Unimplemented*/PathPoint) -> bool {
167    //    unsafe { TODO: call ffi:gsk_path_get_previous() }
168    //}
169
170    /// Gets the start point of the path.
171    ///
172    /// An empty path has no points, so false
173    /// is returned in this case.
174    ///
175    /// # Returns
176    ///
177    /// true if @result was filled
178    ///
179    /// ## `result`
180    /// return location for point
181    #[doc(alias = "gsk_path_get_start_point")]
182    #[doc(alias = "get_start_point")]
183    pub fn start_point(&self) -> Option<PathPoint> {
184        unsafe {
185            let mut result = PathPoint::uninitialized();
186            let ret = from_glib(ffi::gsk_path_get_start_point(
187                self.to_glib_none().0,
188                result.to_glib_none_mut().0,
189            ));
190            if ret { Some(result) } else { None }
191        }
192    }
193
194    /// Computes the bounds for stroking the given path with the
195    /// given parameters.
196    ///
197    /// The returned bounds may be larger than necessary, because this
198    /// function aims to be fast, not accurate. The bounds are guaranteed
199    /// to contain the area affected by the stroke, including protrusions
200    /// like miters.
201    /// ## `stroke`
202    /// stroke parameters
203    ///
204    /// # Returns
205    ///
206    /// true if the path has bounds, false if the path is known
207    ///   to be empty and have no bounds.
208    ///
209    /// ## `bounds`
210    /// the bounds to fill in
211    #[doc(alias = "gsk_path_get_stroke_bounds")]
212    #[doc(alias = "get_stroke_bounds")]
213    pub fn stroke_bounds(&self, stroke: &Stroke) -> Option<graphene::Rect> {
214        unsafe {
215            let mut bounds = graphene::Rect::uninitialized();
216            let ret = from_glib(ffi::gsk_path_get_stroke_bounds(
217                self.to_glib_none().0,
218                stroke.to_glib_none().0,
219                bounds.to_glib_none_mut().0,
220            ));
221            if ret { Some(bounds) } else { None }
222        }
223    }
224
225    /// Computes the tight bounds of the given path.
226    ///
227    /// This function works harder than [`bounds()`][Self::bounds()] to
228    /// produce the smallest possible bounds.
229    ///
230    /// # Returns
231    ///
232    /// true if the path has bounds, false if the path is known
233    ///   to be empty and have no bounds
234    ///
235    /// ## `bounds`
236    /// return location for the bounds
237    #[cfg(feature = "v4_22")]
238    #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
239    #[doc(alias = "gsk_path_get_tight_bounds")]
240    #[doc(alias = "get_tight_bounds")]
241    pub fn tight_bounds(&self) -> Option<graphene::Rect> {
242        unsafe {
243            let mut bounds = graphene::Rect::uninitialized();
244            let ret = from_glib(ffi::gsk_path_get_tight_bounds(
245                self.to_glib_none().0,
246                bounds.to_glib_none_mut().0,
247            ));
248            if ret { Some(bounds) } else { None }
249        }
250    }
251
252    #[cfg(feature = "v4_26")]
253    #[cfg_attr(docsrs, doc(cfg(feature = "v4_26")))]
254    #[doc(alias = "gsk_path_hash")]
255    fn hash(&self) -> u32 {
256        unsafe { ffi::gsk_path_hash(self.to_glib_none().0) }
257    }
258
259    /// Returns whether a point is inside the fill area of a path.
260    ///
261    /// Note that this function assumes that filling a contour
262    /// implicitly closes it.
263    /// ## `point`
264    /// the point to test
265    /// ## `fill_rule`
266    /// the fill rule to follow
267    ///
268    /// # Returns
269    ///
270    /// true if @point is inside
271    #[doc(alias = "gsk_path_in_fill")]
272    pub fn in_fill(&self, point: &graphene::Point, fill_rule: FillRule) -> bool {
273        unsafe {
274            from_glib(ffi::gsk_path_in_fill(
275                self.to_glib_none().0,
276                point.to_glib_none().0,
277                fill_rule.into_glib(),
278            ))
279        }
280    }
281
282    /// Returns if the path represents a single closed contour.
283    ///
284    /// # Returns
285    ///
286    /// true if the path is closed
287    #[doc(alias = "gsk_path_is_closed")]
288    pub fn is_closed(&self) -> bool {
289        unsafe { from_glib(ffi::gsk_path_is_closed(self.to_glib_none().0)) }
290    }
291
292    /// Checks if the path is empty, i.e. contains no lines or curves.
293    ///
294    /// # Returns
295    ///
296    /// true if the path is empty
297    #[doc(alias = "gsk_path_is_empty")]
298    pub fn is_empty(&self) -> bool {
299        unsafe { from_glib(ffi::gsk_path_is_empty(self.to_glib_none().0)) }
300    }
301
302    /// Appends the path to a cairo context for drawing with Cairo.
303    ///
304    /// This may cause some suboptimal conversions to be performed as
305    /// Cairo does not support all features of [`Path`][crate::Path].
306    ///
307    /// This function does not clear the existing Cairo path. Call
308    /// cairo_new_path() if you want this.
309    /// ## `cr`
310    /// a cairo context
311    #[doc(alias = "gsk_path_to_cairo")]
312    pub fn to_cairo(&self, cr: &cairo::Context) {
313        unsafe {
314            ffi::gsk_path_to_cairo(self.to_glib_none().0, mut_override(cr.to_glib_none().0));
315        }
316    }
317
318    /// Converts the path into a human-readable string.
319    ///
320    /// You can use this function in a debugger to get a quick overview
321    /// of the path.
322    ///
323    /// This is a wrapper around `Gsk::Path::print()`, see that function
324    /// for details.
325    ///
326    /// # Returns
327    ///
328    /// a new string for @self
329    #[doc(alias = "gsk_path_to_string")]
330    #[doc(alias = "to_string")]
331    pub fn to_str(&self) -> glib::GString {
332        unsafe { from_glib_full(ffi::gsk_path_to_string(self.to_glib_none().0)) }
333    }
334
335    /// Returns whether 2 paths only differ by an x/y translation and
336    /// compare `Gsk::Path::equal()` otherwise.
337    ///
338    /// If you want to know the translation, you can use
339    /// [`bounds()`][Self::bounds()] and compare the bounds.
340    ///
341    /// Note that this function may return false for otherwise translatable
342    /// paths due to floating point quantization.
343    /// ## `path2`
344    /// another path
345    ///
346    /// # Returns
347    ///
348    /// true if @self and @path2 are equal when applying a
349    ///     translation
350    #[cfg(feature = "v4_26")]
351    #[cfg_attr(docsrs, doc(cfg(feature = "v4_26")))]
352    #[doc(alias = "gsk_path_translatable")]
353    pub fn translatable(&self, path2: &Path) -> bool {
354        unsafe {
355            from_glib(ffi::gsk_path_translatable(
356                self.to_glib_none().0,
357                path2.to_glib_none().0,
358            ))
359        }
360    }
361
362    /// Constructs a path from a serialized form.
363    ///
364    /// The string is expected to be in (a superset of)
365    /// [SVG path syntax](https://www.w3.org/TR/SVG11/paths.html#PathData),
366    /// as e.g. produced by [`to_str()`][Self::to_str()].
367    ///
368    /// A high-level summary of the syntax:
369    ///
370    /// - `M x y` Move to `(x, y)`
371    /// - `L x y` Add a line from the current point to `(x, y)`
372    /// - `Q x1 y1 x2 y2` Add a quadratic Bézier from the current point to `(x2, y2)`, with control point `(x1, y1)`
373    /// - `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)`
374    /// - `Z` Close the contour by drawing a line back to the start point
375    /// - `H x` Add a horizontal line from the current point to the given x value
376    /// - `V y` Add a vertical line from the current point to the given y value
377    /// - `T x2 y2` Add a quadratic Bézier, using the reflection of the previous segments' control point as control point
378    /// - `S x2 y2 x3 y3` Add a cubic Bézier, using the reflection of the previous segments' second control point as first control point
379    /// - `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.
380    /// - `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`.
381    ///
382    /// All the commands have lowercase variants that interpret coordinates
383    /// relative to the current point.
384    ///
385    /// The `O` command is an extension that is not supported in SVG.
386    /// ## `string`
387    /// a string
388    ///
389    /// # Returns
390    ///
391    /// a new [`Path`][crate::Path], or `NULL` if @string could not be parsed
392    #[doc(alias = "gsk_path_parse")]
393    pub fn parse(string: &str) -> Result<Path, glib::BoolError> {
394        assert_initialized_main_thread!();
395        unsafe {
396            Option::<_>::from_glib_full(ffi::gsk_path_parse(string.to_glib_none().0))
397                .ok_or_else(|| glib::bool_error!("Can't parse Path"))
398        }
399    }
400}
401
402#[cfg(feature = "v4_22")]
403#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
404impl PartialEq for Path {
405    #[inline]
406    fn eq(&self, other: &Self) -> bool {
407        self.equal(other)
408    }
409}
410
411#[cfg(feature = "v4_22")]
412#[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
413impl Eq for Path {}
414
415impl std::fmt::Display for Path {
416    #[inline]
417    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
418        f.write_str(&self.to_str())
419    }
420}
421
422#[cfg(feature = "v4_26")]
423#[cfg_attr(docsrs, doc(cfg(feature = "v4_26")))]
424impl std::hash::Hash for Path {
425    #[inline]
426    fn hash<H>(&self, state: &mut H)
427    where
428        H: std::hash::Hasher,
429    {
430        std::hash::Hash::hash(&self.hash(), state)
431    }
432}