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}