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}