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