clutter/auto/
path.rs

1use crate::{Knot, PathNode};
2use glib::{
3    object as gobject,
4    object::{Cast, IsA},
5    signal::{connect_raw, SignalHandlerId},
6    translate::*,
7    GString,
8};
9use std::boxed::Box as Box_;
10use std::{fmt, mem::transmute};
11
12glib_wrapper! {
13    pub struct Path(Object<ffi::ClutterPath, ffi::ClutterPathClass, PathClass>) @extends gobject::InitiallyUnowned;
14
15    match fn {
16        get_type => || ffi::clutter_path_get_type(),
17    }
18}
19
20impl Path {
21    /// Creates a new `Path` instance with no nodes.
22    ///
23    /// The object has a floating reference so if you add it to a
24    /// `BehaviourPath` then you do not need to unref it.
25    ///
26    /// # Returns
27    ///
28    /// the newly created `Path`
29    pub fn new() -> Path {
30        unsafe { from_glib_none(ffi::clutter_path_new()) }
31    }
32
33    pub fn with_description(desc: &str) -> Path {
34        unsafe {
35            from_glib_none(ffi::clutter_path_new_with_description(
36                desc.to_glib_none().0,
37            ))
38        }
39    }
40}
41
42impl Default for Path {
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48pub const NONE_PATH: Option<&Path> = None;
49
50/// Trait containing all `Path` methods.
51///
52/// # Implementors
53///
54/// [`Path`](struct.Path.html)
55pub trait PathExt: 'static {
56    // /// Add the nodes of the Cairo path to the end of `self`.
57    // /// ## `cpath`
58    // /// a Cairo path
59    // fn add_cairo_path(&self, cpath: &cairo::Path);
60
61    /// Adds a `PathNodeType::Close` type node to the path. This creates a
62    /// straight line from the last node to the last `PathNodeType::MoveTo`
63    /// type node.
64    fn add_close(&self);
65
66    /// Adds a `PathNodeType::CurveTo` type node to the path. This causes
67    /// the actor to follow a bezier from the last node to (`x_3`, `y_3`) using
68    /// (`x_1`, `y_1`) and (`x_2`,`y_2`) as control points.
69    /// ## `x_1`
70    /// the x coordinate of the first control point
71    /// ## `y_1`
72    /// the y coordinate of the first control point
73    /// ## `x_2`
74    /// the x coordinate of the second control point
75    /// ## `y_2`
76    /// the y coordinate of the second control point
77    /// ## `x_3`
78    /// the x coordinate of the third control point
79    /// ## `y_3`
80    /// the y coordinate of the third control point
81    fn add_curve_to(&self, x_1: i32, y_1: i32, x_2: i32, y_2: i32, x_3: i32, y_3: i32);
82
83    /// Adds a `PathNodeType::LineTo` type node to the path. This causes the
84    /// actor to move to the new coordinates in a straight line.
85    /// ## `x`
86    /// the x coordinate
87    /// ## `y`
88    /// the y coordinate
89    fn add_line_to(&self, x: i32, y: i32);
90
91    /// Adds a `PathNodeType::MoveTo` type node to the path. This is usually
92    /// used as the first node in a path. It can also be used in the middle
93    /// of the path to cause the actor to jump to the new coordinate.
94    /// ## `x`
95    /// the x coordinate
96    /// ## `y`
97    /// the y coordinate
98    fn add_move_to(&self, x: i32, y: i32);
99
100    /// Adds `node` to the end of the path.
101    /// ## `node`
102    /// a `PathNode`
103    fn add_node(&self, node: &PathNode);
104
105    /// Same as `PathExt::add_curve_to` except the coordinates are
106    /// relative to the previous node.
107    /// ## `x_1`
108    /// the x coordinate of the first control point
109    /// ## `y_1`
110    /// the y coordinate of the first control point
111    /// ## `x_2`
112    /// the x coordinate of the second control point
113    /// ## `y_2`
114    /// the y coordinate of the second control point
115    /// ## `x_3`
116    /// the x coordinate of the third control point
117    /// ## `y_3`
118    /// the y coordinate of the third control point
119    fn add_rel_curve_to(&self, x_1: i32, y_1: i32, x_2: i32, y_2: i32, x_3: i32, y_3: i32);
120
121    /// Same as `PathExt::add_line_to` except the coordinates are
122    /// relative to the previous node.
123    /// ## `x`
124    /// the x coordinate
125    /// ## `y`
126    /// the y coordinate
127    fn add_rel_line_to(&self, x: i32, y: i32);
128
129    /// Same as `PathExt::add_move_to` except the coordinates are
130    /// relative to the previous node.
131    /// ## `x`
132    /// the x coordinate
133    /// ## `y`
134    /// the y coordinate
135    fn add_rel_move_to(&self, x: i32, y: i32);
136
137    /// Adds new nodes to the end of the path as described in `str`. The
138    /// format is a subset of the SVG path format. Each node is represented
139    /// by a letter and is followed by zero, one or three pairs of
140    /// coordinates. The coordinates can be separated by spaces or a
141    /// comma. The types are:
142    ///
143    ///  - `M`: Adds a `PathNodeType::MoveTo` node. Takes one pair of coordinates.
144    ///  - `L`: Adds a `PathNodeType::LineTo` node. Takes one pair of coordinates.
145    ///  - `C`: Adds a `PathNodeType::CurveTo` node. Takes three pairs of coordinates.
146    ///  - `z`: Adds a `PathNodeType::Close` node. No coordinates are needed.
147    ///
148    /// The M, L and C commands can also be specified in lower case which
149    /// means the coordinates are relative to the previous node.
150    ///
151    /// For example, to move an actor in a 100 by 100 pixel square centered
152    /// on the point 300,300 you could use the following path:
153    ///
154    ///
155    /// ```text
156    ///   M 250,350 l 0 -100 L 350,250 l 0 100 z
157    /// ```
158    ///
159    /// If the path description isn't valid `false` will be returned and no
160    /// nodes will be added.
161    /// ## `str`
162    /// a string describing the new nodes
163    ///
164    /// # Returns
165    ///
166    /// `true` is the path description was valid or `false`
167    /// otherwise.
168    fn add_string(&self, str: &str) -> bool;
169
170    /// Removes all nodes from the path.
171    fn clear(&self);
172
173    /// Calls a function for each node of the path.
174    /// ## `callback`
175    /// the function to call with each node
176    /// ## `user_data`
177    /// user data to pass to the function
178    fn foreach<P: FnMut(&PathNode)>(&self, callback: P);
179
180    /// Returns a newly allocated string describing the path in the same
181    /// format as used by `PathExt::add_string`.
182    ///
183    /// # Returns
184    ///
185    /// a string description of the path. Free with `g_free`.
186    fn get_description(&self) -> Option<GString>;
187
188    /// Retrieves an approximation of the total length of the path.
189    ///
190    /// # Returns
191    ///
192    /// the length of the path.
193    fn get_length(&self) -> u32;
194
195    /// Retrieves the number of nodes in the path.
196    ///
197    /// # Returns
198    ///
199    /// the number of nodes.
200    fn get_n_nodes(&self) -> u32;
201
202    /// Retrieves the node of the path indexed by `index`.
203    /// ## `index_`
204    /// the node number to retrieve
205    /// ## `node`
206    /// a location to store a copy of the node
207    fn get_node(&self, index_: u32) -> PathNode;
208
209    /// Returns a `glib::SList` of `PathNode`<!-- -->s. The list should be
210    /// freed with `glib::SList::free`. The nodes are owned by the path and
211    /// should not be freed. Altering the path may cause the nodes in the
212    /// list to become invalid so you should copy them if you want to keep
213    /// the list.
214    ///
215    /// # Returns
216    ///
217    /// a
218    ///  list of nodes in the path.
219    fn get_nodes(&self) -> Vec<PathNode>;
220
221    /// The value in `progress` represents a position along the path where
222    /// 0.0 is the beginning and 1.0 is the end of the path. An
223    /// interpolated position is then stored in `position`.
224    /// ## `progress`
225    /// a position along the path as a fraction of its length
226    /// ## `position`
227    /// location to store the position
228    ///
229    /// # Returns
230    ///
231    /// index of the node used to calculate the position.
232    fn get_position(&self, progress: f64) -> (u32, Knot);
233
234    /// Inserts `node` into the path before the node at the given offset. If
235    /// `index_` is negative it will append the node to the end of the path.
236    /// ## `index_`
237    /// offset of where to insert the node
238    /// ## `node`
239    /// the node to insert
240    fn insert_node(&self, index_: i32, node: &PathNode);
241
242    /// Removes the node at the given offset from the path.
243    /// ## `index_`
244    /// index of the node to remove
245    fn remove_node(&self, index_: u32);
246
247    /// Replaces the node at offset `index_` with `node`.
248    /// ## `index_`
249    /// index to the existing node
250    /// ## `node`
251    /// the replacement node
252    fn replace_node(&self, index_: u32, node: &PathNode);
253
254    /// Replaces all of the nodes in the path with nodes described by
255    /// `str`. See `PathExt::add_string` for details of the format.
256    ///
257    /// If the string is invalid then `false` is returned and the path is
258    /// unaltered.
259    /// ## `str`
260    /// a string describing the path
261    ///
262    /// # Returns
263    ///
264    /// `true` is the path was valid, `false` otherwise.
265    fn set_description(&self, str: &str) -> bool;
266
267    // /// Add the nodes of the ClutterPath to the path in the Cairo context.
268    // /// ## `cr`
269    // /// a Cairo context
270    // fn to_cairo_path(&self, cr: &mut cairo::Context);
271
272    fn connect_property_description_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId;
273
274    fn connect_property_length_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId;
275}
276
277impl<O: IsA<Path>> PathExt for O {
278    // fn add_cairo_path(&self, cpath: &cairo::Path) {
279    //     unsafe {
280    //         ffi::clutter_path_add_cairo_path(
281    //             self.as_ref().to_glib_none().0,
282    //             cpath.to_glib_none().0,
283    //         );
284    //     }
285    // }
286
287    fn add_close(&self) {
288        unsafe {
289            ffi::clutter_path_add_close(self.as_ref().to_glib_none().0);
290        }
291    }
292
293    fn add_curve_to(&self, x_1: i32, y_1: i32, x_2: i32, y_2: i32, x_3: i32, y_3: i32) {
294        unsafe {
295            ffi::clutter_path_add_curve_to(
296                self.as_ref().to_glib_none().0,
297                x_1,
298                y_1,
299                x_2,
300                y_2,
301                x_3,
302                y_3,
303            );
304        }
305    }
306
307    fn add_line_to(&self, x: i32, y: i32) {
308        unsafe {
309            ffi::clutter_path_add_line_to(self.as_ref().to_glib_none().0, x, y);
310        }
311    }
312
313    fn add_move_to(&self, x: i32, y: i32) {
314        unsafe {
315            ffi::clutter_path_add_move_to(self.as_ref().to_glib_none().0, x, y);
316        }
317    }
318
319    fn add_node(&self, node: &PathNode) {
320        unsafe {
321            ffi::clutter_path_add_node(self.as_ref().to_glib_none().0, node.to_glib_none().0);
322        }
323    }
324
325    fn add_rel_curve_to(&self, x_1: i32, y_1: i32, x_2: i32, y_2: i32, x_3: i32, y_3: i32) {
326        unsafe {
327            ffi::clutter_path_add_rel_curve_to(
328                self.as_ref().to_glib_none().0,
329                x_1,
330                y_1,
331                x_2,
332                y_2,
333                x_3,
334                y_3,
335            );
336        }
337    }
338
339    fn add_rel_line_to(&self, x: i32, y: i32) {
340        unsafe {
341            ffi::clutter_path_add_rel_line_to(self.as_ref().to_glib_none().0, x, y);
342        }
343    }
344
345    fn add_rel_move_to(&self, x: i32, y: i32) {
346        unsafe {
347            ffi::clutter_path_add_rel_move_to(self.as_ref().to_glib_none().0, x, y);
348        }
349    }
350
351    fn add_string(&self, str: &str) -> bool {
352        unsafe {
353            from_glib(ffi::clutter_path_add_string(
354                self.as_ref().to_glib_none().0,
355                str.to_glib_none().0,
356            ))
357        }
358    }
359
360    fn clear(&self) {
361        unsafe {
362            ffi::clutter_path_clear(self.as_ref().to_glib_none().0);
363        }
364    }
365
366    fn foreach<P: FnMut(&PathNode)>(&self, callback: P) {
367        let callback_data: P = callback;
368        unsafe extern "C" fn callback_func<P: FnMut(&PathNode)>(
369            node: *const ffi::ClutterPathNode,
370            data: glib_sys::gpointer,
371        ) {
372            let node = from_glib_borrow(node);
373            let callback: *mut P = data as *const _ as usize as *mut P;
374            (*callback)(&node);
375        }
376        let callback = Some(callback_func::<P> as _);
377        let super_callback0: &P = &callback_data;
378        unsafe {
379            ffi::clutter_path_foreach(
380                self.as_ref().to_glib_none().0,
381                callback,
382                super_callback0 as *const _ as usize as *mut _,
383            );
384        }
385    }
386
387    fn get_description(&self) -> Option<GString> {
388        unsafe {
389            from_glib_full(ffi::clutter_path_get_description(
390                self.as_ref().to_glib_none().0,
391            ))
392        }
393    }
394
395    fn get_length(&self) -> u32 {
396        unsafe { ffi::clutter_path_get_length(self.as_ref().to_glib_none().0) }
397    }
398
399    fn get_n_nodes(&self) -> u32 {
400        unsafe { ffi::clutter_path_get_n_nodes(self.as_ref().to_glib_none().0) }
401    }
402
403    fn get_node(&self, index_: u32) -> PathNode {
404        unsafe {
405            let mut node = PathNode::uninitialized();
406            ffi::clutter_path_get_node(
407                self.as_ref().to_glib_none().0,
408                index_,
409                node.to_glib_none_mut().0,
410            );
411            node
412        }
413    }
414
415    fn get_nodes(&self) -> Vec<PathNode> {
416        unsafe {
417            FromGlibPtrContainer::from_glib_container(ffi::clutter_path_get_nodes(
418                self.as_ref().to_glib_none().0,
419            ))
420        }
421    }
422
423    fn get_position(&self, progress: f64) -> (u32, Knot) {
424        unsafe {
425            let mut position = Knot::uninitialized();
426            let ret = ffi::clutter_path_get_position(
427                self.as_ref().to_glib_none().0,
428                progress,
429                position.to_glib_none_mut().0,
430            );
431            (ret, position)
432        }
433    }
434
435    fn insert_node(&self, index_: i32, node: &PathNode) {
436        unsafe {
437            ffi::clutter_path_insert_node(
438                self.as_ref().to_glib_none().0,
439                index_,
440                node.to_glib_none().0,
441            );
442        }
443    }
444
445    fn remove_node(&self, index_: u32) {
446        unsafe {
447            ffi::clutter_path_remove_node(self.as_ref().to_glib_none().0, index_);
448        }
449    }
450
451    fn replace_node(&self, index_: u32, node: &PathNode) {
452        unsafe {
453            ffi::clutter_path_replace_node(
454                self.as_ref().to_glib_none().0,
455                index_,
456                node.to_glib_none().0,
457            );
458        }
459    }
460
461    fn set_description(&self, str: &str) -> bool {
462        unsafe {
463            from_glib(ffi::clutter_path_set_description(
464                self.as_ref().to_glib_none().0,
465                str.to_glib_none().0,
466            ))
467        }
468    }
469
470    // fn to_cairo_path(&self, cr: &mut cairo::Context) {
471    //     unsafe {
472    //         ffi::clutter_path_to_cairo_path(
473    //             self.as_ref().to_glib_none().0,
474    //             cr.to_glib_none_mut().0,
475    //         );
476    //     }
477    // }
478
479    fn connect_property_description_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
480        unsafe extern "C" fn notify_description_trampoline<P, F: Fn(&P) + 'static>(
481            this: *mut ffi::ClutterPath,
482            _param_spec: glib_sys::gpointer,
483            f: glib_sys::gpointer,
484        ) where
485            P: IsA<Path>,
486        {
487            let f: &F = &*(f as *const F);
488            f(&Path::from_glib_borrow(this).unsafe_cast_ref())
489        }
490        unsafe {
491            let f: Box_<F> = Box_::new(f);
492            connect_raw(
493                self.as_ptr() as *mut _,
494                b"notify::description\0".as_ptr() as *const _,
495                Some(transmute::<_, unsafe extern "C" fn()>(
496                    notify_description_trampoline::<Self, F> as *const (),
497                )),
498                Box_::into_raw(f),
499            )
500        }
501    }
502
503    fn connect_property_length_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
504        unsafe extern "C" fn notify_length_trampoline<P, F: Fn(&P) + 'static>(
505            this: *mut ffi::ClutterPath,
506            _param_spec: glib_sys::gpointer,
507            f: glib_sys::gpointer,
508        ) where
509            P: IsA<Path>,
510        {
511            let f: &F = &*(f as *const F);
512            f(&Path::from_glib_borrow(this).unsafe_cast_ref())
513        }
514        unsafe {
515            let f: Box_<F> = Box_::new(f);
516            connect_raw(
517                self.as_ptr() as *mut _,
518                b"notify::length\0".as_ptr() as *const _,
519                Some(transmute::<_, unsafe extern "C" fn()>(
520                    notify_length_trampoline::<Self, F> as *const (),
521                )),
522                Box_::into_raw(f),
523            )
524        }
525    }
526}
527
528impl fmt::Display for Path {
529    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
530        write!(f, "Path")
531    }
532}