1 #define GNOME_CANVAS_PATH_DEF_C
2
3 /*
4 * GnomeCanvasPathDef
5 *
6 * (C) 1999-2000 Lauris Kaplinski <lauris@ximian.com>
7 * Released under LGPL
8 *
9 * Authors: Lauris Kaplinski <lauris@ximian.com>
10 * Rusty Conover <rconover@bangtail.net>
11 *
12 * Copyright 1999-2001 Ximian Inc. and authors.
13 */
14
15 #include <string.h>
16 #include <libart_lgpl/art_misc.h>
17 #include "gnome-canvas-path-def.h"
18
19 /* The number of points to allocate at once */
20 #define GNOME_CANVAS_PATH_DEF_LENSTEP 32
21
22 struct _GnomeCanvasPathDef {
23 gint refcount;
24 ArtBpath * bpath;
25 gint end; /* ART_END position */
26 gint length; /* Num allocated Bpaths */
27 gint substart; /* subpath start */
28 gdouble x, y; /* previous moveto position */
29 guint sbpath : 1; /* Bpath is static */
30 guint hascpt : 1; /* Currentpoint is defined */
31 guint posset : 1; /* Previous was moveto */
32 guint moving : 1; /* Bpath end is moving */
33 guint allclosed : 1; /* All subpaths are closed */
34 guint allopen : 1; /* All subpaths are open */
35 };
36
37 static gboolean sp_bpath_good (ArtBpath * bpath);
38 static ArtBpath * sp_bpath_check_subpath (ArtBpath * bpath);
39 static gint sp_bpath_length (const ArtBpath * bpath);
40 static gboolean sp_bpath_all_closed (const ArtBpath * bpath);
41 static gboolean sp_bpath_all_open (const ArtBpath * bpath);
42
43 /* Boxed Type Support */
44
45 static GnomeCanvasPathDef *
path_def_boxed_copy(GnomeCanvasPathDef * path_def)46 path_def_boxed_copy (GnomeCanvasPathDef * path_def)
47 {
48 if (path_def)
49 gnome_canvas_path_def_ref (path_def);
50 return path_def;
51 }
52
53 GType
gnome_canvas_path_def_get_type(void)54 gnome_canvas_path_def_get_type (void)
55 {
56 static GType t = 0;
57 if (t == 0)
58 t = g_boxed_type_register_static
59 ("GnomeCanvasPathDef",
60 (GBoxedCopyFunc)path_def_boxed_copy,
61 (GBoxedFreeFunc)gnome_canvas_path_def_unref);
62 return t;
63 }
64
65 /* Constructors */
66
67 /**
68 * gnome_canvas_path_def_new:
69 *
70 * This function creates a new empty #gnome_canvas_path_def.
71 *
72 * Returns: the new canvas path definition.
73 */
74 GnomeCanvasPathDef *
gnome_canvas_path_def_new(void)75 gnome_canvas_path_def_new (void)
76 {
77 GnomeCanvasPathDef * path;
78
79 path = gnome_canvas_path_def_new_sized (GNOME_CANVAS_PATH_DEF_LENSTEP);
80
81 return path;
82 }
83
84 /**
85 * gnome_canvas_path_def_new_sized:
86 * @length: number of points to allocate for the path
87 *
88 * This function creates a new #gnome_canvas_path_def with @length
89 * number of points allocated. It is useful, if you know the exact
90 * number of points in path, so you can avoid automatic point
91 * array reallocation.
92 *
93 * Returns: the new canvas path definition
94 */
95 GnomeCanvasPathDef *
gnome_canvas_path_def_new_sized(gint length)96 gnome_canvas_path_def_new_sized (gint length)
97 {
98 GnomeCanvasPathDef * path;
99
100 g_return_val_if_fail (length > 0, NULL);
101
102 path = g_new (GnomeCanvasPathDef, 1);
103
104 path->refcount = 1;
105 path->bpath = art_new (ArtBpath, length);
106 path->end = 0;
107 path->bpath[path->end].code = ART_END;
108 path->length = length;
109 path->sbpath = FALSE;
110 path->hascpt = FALSE;
111 path->posset = FALSE;
112 path->moving = FALSE;
113 path->allclosed = TRUE;
114 path->allopen = TRUE;
115
116 return path;
117 }
118
119 /**
120 * gnome_canvas_path_def_new_from_bpath:
121 * @bpath: libart bezier path
122 *
123 * This function constructs a new #gnome_canvas_path_def and uses the
124 * passed @bpath as the contents. The passed bpath should not be
125 * static as the path definition is editable when constructed with
126 * this function. Also, passed bpath will be freed with art_free, if
127 * path is destroyed, so use it with caution.
128 * For constructing a #gnome_canvas_path_def
129 * from (non-modifiable) bpath use
130 * #gnome_canvas_path_def_new_from_static_bpath.
131 *
132 * Returns: the new canvas path definition that is populated with the
133 * passed bezier path, if the @bpath is bad NULL is returned.
134 */
135 GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_bpath(ArtBpath * bpath)136 gnome_canvas_path_def_new_from_bpath (ArtBpath * bpath)
137 {
138 GnomeCanvasPathDef * path;
139
140 g_return_val_if_fail (sp_bpath_good (bpath), NULL);
141
142 path = g_new (GnomeCanvasPathDef, 1);
143
144 path->refcount = 1;
145 path->bpath = bpath;
146 path->length = sp_bpath_length (bpath);
147 path->end = path->length - 1;
148 path->sbpath = FALSE;
149 path->hascpt = FALSE;
150 path->posset = FALSE;
151 path->moving = FALSE;
152 path->allclosed = sp_bpath_all_closed (bpath);
153 path->allopen = sp_bpath_all_open (bpath);
154
155 return path;
156 }
157
158 /**
159 * gnome_canvas_path_def_new_from_static_bpath:
160 * @bpath: libart bezier path
161 *
162 * This function constructs a new #gnome_canvas_path_def and
163 * references the passed @bpath as its contents. The
164 * #gnome_canvas_path_def returned from this function is to be
165 * considered static and non-editable (meaning you cannot change the
166 * path from what you passed in @bpath). The bpath will not be freed,
167 * if path will be destroyed, so use it with caution.
168 *
169 * Returns: the new canvas path definition that references the passed
170 * @bpath, or if the path is bad NULL is returned.
171 */
172 GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_static_bpath(ArtBpath * bpath)173 gnome_canvas_path_def_new_from_static_bpath (ArtBpath * bpath)
174 {
175 GnomeCanvasPathDef * path;
176
177 g_return_val_if_fail (sp_bpath_good (bpath), NULL);
178
179 path = g_new (GnomeCanvasPathDef, 1);
180
181 path->refcount = 1;
182 path->bpath = bpath;
183 path->length = sp_bpath_length (bpath);
184 path->end = path->length - 1;
185 path->sbpath = TRUE;
186 path->hascpt = FALSE;
187 path->posset = FALSE;
188 path->moving = FALSE;
189 path->allclosed = sp_bpath_all_closed (bpath);
190 path->allopen = sp_bpath_all_open (bpath);
191
192 return path;
193 }
194
195 /**
196 * gnome_canvas_path_def_new_from_foreign_bpath:
197 * @bpath: libart bezier path
198 *
199 * This function constructs a new #gnome_canvas_path_def and
200 * duplicates the contents of the passed @bpath in the definition.
201 *
202 * Returns: the newly created #gnome_canvas_path_def or NULL if the
203 * path is invalid.
204 */
205 GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_foreign_bpath(ArtBpath * bpath)206 gnome_canvas_path_def_new_from_foreign_bpath (ArtBpath * bpath)
207 {
208 GnomeCanvasPathDef * path;
209 gint length;
210
211 g_return_val_if_fail (sp_bpath_good (bpath), NULL);
212
213 length = sp_bpath_length (bpath);
214
215 path = gnome_canvas_path_def_new_sized (length);
216 memcpy (path->bpath, bpath, sizeof (ArtBpath) * length);
217 path->end = length - 1;
218 path->allclosed = sp_bpath_all_closed (bpath);
219 path->allopen = sp_bpath_all_open (bpath);
220
221 return path;
222 }
223
224 /**
225 * gnome_canvas_path_def_ref:
226 * @path: a GnomeCanvasPathDef
227 *
228 * Increment the reference count of the GnomeCanvasPathDef.
229 */
230 void
gnome_canvas_path_def_ref(GnomeCanvasPathDef * path)231 gnome_canvas_path_def_ref (GnomeCanvasPathDef * path)
232 {
233 g_return_if_fail (path != NULL);
234
235 path->refcount++;
236 }
237
238 /**
239 * gnome_canvas_path_def_finish:
240 * @path: a GnomeCanvasPathDef
241 *
242 * Trims dynamic point array to exact length of path.
243 */
244 void
gnome_canvas_path_def_finish(GnomeCanvasPathDef * path)245 gnome_canvas_path_def_finish (GnomeCanvasPathDef * path)
246 {
247 g_return_if_fail (path != NULL);
248 g_return_if_fail (path->sbpath);
249
250 if ((path->end + 1) < path->length) {
251 path->bpath = art_renew (path->bpath, ArtBpath, path->end + 1);
252 path->length = path->end + 1;
253 }
254
255 path->hascpt = FALSE;
256 path->posset = FALSE;
257 path->moving = FALSE;
258 }
259 /**
260 * gnome_canvas_path_def_ensure_space:
261 * @path: a GnomeCanvasPathDef
262 * @space: number of points to guarantee are allocated at the end of
263 * the path.
264 *
265 * This function ensures that enough space for @space points is
266 * allocated at the end of the path.
267 */
268 void
gnome_canvas_path_def_ensure_space(GnomeCanvasPathDef * path,gint space)269 gnome_canvas_path_def_ensure_space (GnomeCanvasPathDef * path, gint space)
270 {
271 g_return_if_fail (path != NULL);
272 g_return_if_fail (space > 0);
273
274 if (path->end + space < path->length) return;
275
276 if (space < GNOME_CANVAS_PATH_DEF_LENSTEP) space = GNOME_CANVAS_PATH_DEF_LENSTEP;
277
278 path->bpath = art_renew (path->bpath, ArtBpath, path->length + space);
279
280 path->length += space;
281 }
282
283 /**
284 * gnome_canvas_path_def_copy:
285 * @dst: a GnomeCanvasPathDef where the contents of @src will be stored.
286 * @src: a GnomeCanvasPathDef whose contents will be copied it @src.
287 *
288 * This function copies the contents @src to @dest. The old @dest path
289 * array is freed and @dest is marked as non-static (editable),
290 * regardless of the status of @src.
291 */
292 void
gnome_canvas_path_def_copy(GnomeCanvasPathDef * dst,const GnomeCanvasPathDef * src)293 gnome_canvas_path_def_copy (GnomeCanvasPathDef * dst, const GnomeCanvasPathDef * src)
294 {
295 g_return_if_fail (dst != NULL);
296 g_return_if_fail (src != NULL);
297
298 if (!dst->sbpath) g_free (dst->bpath);
299
300 memcpy (dst, src, sizeof (GnomeCanvasPathDef));
301
302 dst->bpath = g_new (ArtBpath, src->end + 1);
303 memcpy (dst->bpath, src->bpath, (src->end + 1) * sizeof (ArtBpath));
304
305 dst->sbpath = FALSE;
306 }
307
308
309 /**
310 * gnome_canvas_path_def_duplicate:
311 * @path: a GnomeCanvasPathDef to duplicate
312 *
313 * This function duplicates the passed @path. The new path is
314 * marked as non-static regardless of the state of original.
315 *
316 * Returns: a GnomeCanvasPathDef which is a duplicate of @path.
317 */
318 GnomeCanvasPathDef *
gnome_canvas_path_def_duplicate(const GnomeCanvasPathDef * path)319 gnome_canvas_path_def_duplicate (const GnomeCanvasPathDef * path)
320 {
321 GnomeCanvasPathDef * new;
322
323 g_return_val_if_fail (path != NULL, NULL);
324
325 new = gnome_canvas_path_def_new_from_foreign_bpath (path->bpath);
326 new->x = path->x;
327 new->y = path->y;
328 new->hascpt = path->hascpt;
329 new->posset = path->posset;
330 new->moving = path->moving;
331 new->allclosed = path->allclosed;
332 new->allopen = path->allopen;
333
334 return new;
335 }
336
337 /**
338 * gnome_canvas_path_def_concat:
339 * @list: a GSList of GnomeCanvasPathDefs to concatenate into one new
340 * path.
341 *
342 * This function concatenates a list of GnomeCanvasPathDefs into one
343 * newly created GnomeCanvasPathDef.
344 *
345 * Returns: a new GnomeCanvasPathDef
346 */
347 GnomeCanvasPathDef *
gnome_canvas_path_def_concat(const GSList * list)348 gnome_canvas_path_def_concat (const GSList * list)
349 {
350 GnomeCanvasPathDef * c, * new;
351 ArtBpath * bp;
352 const GSList * l;
353 gint length;
354
355 g_return_val_if_fail (list != NULL, NULL);
356
357 length = 1;
358
359 for (l = list; l != NULL; l = l->next) {
360 c = (GnomeCanvasPathDef *) l->data;
361 length += c->end;
362 }
363
364 new = gnome_canvas_path_def_new_sized (length);
365
366 bp = new->bpath;
367
368 for (l = list; l != NULL; l = l->next) {
369 c = (GnomeCanvasPathDef *) l->data;
370 memcpy (bp, c->bpath, c->end * sizeof (ArtBpath));
371 bp += c->end;
372 }
373
374 bp->code = ART_END;
375
376 new->end = length - 1;
377
378 new->allclosed = sp_bpath_all_closed (new->bpath);
379 new->allopen = sp_bpath_all_open (new->bpath);
380
381 return new;
382 }
383
384 /**
385 * gnome_canvas_path_def_split:
386 * @path: a GnomeCanvasPathDef
387 *
388 * This function splits the passed @path into a list of
389 * GnomeCanvasPathDefs which represent each segment of the origional
390 * path. The path is split when ever an ART_MOVETO or ART_MOVETO_OPEN
391 * is encountered. The closedness of resulting paths is set accordingly
392 * to closedness of corresponding segment.
393 *
394 * Returns: a list of GnomeCanvasPathDef(s).
395 */
396 GSList *
gnome_canvas_path_def_split(const GnomeCanvasPathDef * path)397 gnome_canvas_path_def_split (const GnomeCanvasPathDef * path)
398 {
399 GnomeCanvasPathDef * new;
400 GSList * l;
401 gint p, i;
402
403 g_return_val_if_fail (path != NULL, NULL);
404
405 p = 0;
406 l = NULL;
407
408 while (p < path->end) {
409 i = 1;
410 while ((path->bpath[p + i].code == ART_LINETO) || (path->bpath[p + i].code == ART_CURVETO)) i++;
411 new = gnome_canvas_path_def_new_sized (i + 1);
412 memcpy (new->bpath, path->bpath + p, i * sizeof (ArtBpath));
413 new->end = i;
414 new->bpath[i].code = ART_END;
415 new->allclosed = (new->bpath->code == ART_MOVETO);
416 new->allopen = (new->bpath->code == ART_MOVETO_OPEN);
417 l = g_slist_append (l, new);
418 p += i;
419 }
420
421 return l;
422 }
423
424 /**
425 * gnome_canvas_path_def_open_parts:
426 * @path: a GnomeCanvasPathDef
427 *
428 * This function creates a new GnomeCanvasPathDef that contains all of
429 * the open segments on the passed @path.
430 *
431 * Returns: a new GnomeCanvasPathDef that contains all of the open segemtns in @path.
432 */
433 GnomeCanvasPathDef *
gnome_canvas_path_def_open_parts(const GnomeCanvasPathDef * path)434 gnome_canvas_path_def_open_parts (const GnomeCanvasPathDef * path)
435 {
436 GnomeCanvasPathDef * new;
437 ArtBpath * p, * d;
438 gint len;
439 gboolean closed;
440
441 g_return_val_if_fail (path != NULL, NULL);
442
443 closed = TRUE;
444 len = 0;
445
446 for (p = path->bpath; p->code != ART_END; p++) {
447 switch (p->code) {
448 case ART_MOVETO_OPEN:
449 closed = FALSE;
450 len++;
451 break;
452 case ART_MOVETO:
453 closed = TRUE;
454 break;
455 case ART_LINETO:
456 case ART_CURVETO:
457 if (!closed) len++;
458 break;
459 default:
460 g_assert_not_reached ();
461 }
462 }
463
464 new = gnome_canvas_path_def_new_sized (len + 1);
465
466 closed = TRUE;
467 d = new->bpath;
468
469 for (p = path->bpath; p->code != ART_END; p++) {
470 switch (p->code) {
471 case ART_MOVETO_OPEN:
472 closed = FALSE;
473 *d++ = *p;
474 break;
475 case ART_MOVETO:
476 closed = TRUE;
477 break;
478 case ART_LINETO:
479 case ART_CURVETO:
480 if (!closed) *d++ = *p;
481 break;
482 default:
483 g_assert_not_reached ();
484 }
485 }
486
487 d->code = ART_END;
488
489 new->end = len;
490 new->allclosed = FALSE;
491 new->allopen = TRUE;
492
493 return new;
494 }
495
496 /**
497 * gnome_canvas_path_def_closed_parts:
498 * @path: a GnomeCanvasPathDef
499 *
500 * This function returns a new GnomeCanvasPathDef that contains the
501 * all of close parts of passed @path.
502 *
503 * Returns: a new GnomeCanvasPathDef that contains all of the closed
504 * parts of passed @path.
505 */
506 GnomeCanvasPathDef *
gnome_canvas_path_def_closed_parts(const GnomeCanvasPathDef * path)507 gnome_canvas_path_def_closed_parts (const GnomeCanvasPathDef * path)
508 {
509 GnomeCanvasPathDef * new;
510 ArtBpath * p, * d;
511 gint len;
512 gboolean closed;
513
514 g_return_val_if_fail (path != NULL, NULL);
515
516 closed = FALSE;
517 len = 0;
518
519 for (p = path->bpath; p->code != ART_END; p++) {
520 switch (p->code) {
521 case ART_MOVETO_OPEN:
522 closed = FALSE;
523 break;
524 case ART_MOVETO:
525 closed = TRUE;
526 len++;
527 break;
528 case ART_LINETO:
529 case ART_CURVETO:
530 if (closed) len++;
531 break;
532 default:
533 g_assert_not_reached ();
534 }
535 }
536
537 new = gnome_canvas_path_def_new_sized (len + 1);
538
539 closed = FALSE;
540 d = new->bpath;
541
542 for (p = path->bpath; p->code != ART_END; p++) {
543 switch (p->code) {
544 case ART_MOVETO_OPEN:
545 closed = FALSE;
546 break;
547 case ART_MOVETO:
548 closed = TRUE;
549 *d++ = *p;
550 break;
551 case ART_LINETO:
552 case ART_CURVETO:
553 if (closed) *d++ = *p;
554 break;
555 default:
556 g_assert_not_reached ();
557 }
558 }
559
560 d->code = ART_END;
561
562 new->end = len;
563 new->allclosed = TRUE;
564 new->allopen = FALSE;
565
566 return new;
567 }
568
569 /**
570 * gnome_canvas_path_def_close_all:
571 * @path: a GnomeCanvasPathDef
572 *
573 * This function closes all of the open segments in the passed path
574 * and returns a new GnomeCanvasPathDef.
575 *
576 * Returns: a GnomeCanvasPathDef that contains the contents of @path
577 * but has modified the path is fully closed
578 */
579 GnomeCanvasPathDef *
gnome_canvas_path_def_close_all(const GnomeCanvasPathDef * path)580 gnome_canvas_path_def_close_all (const GnomeCanvasPathDef * path)
581 {
582 GnomeCanvasPathDef * new;
583 ArtBpath * p, * d, * start;
584 gint len;
585 gboolean closed;
586
587 g_return_val_if_fail (path != NULL, NULL);
588
589 if (path->allclosed) {
590 new = gnome_canvas_path_def_duplicate (path);
591 return new;
592 }
593
594 len = 1;
595
596 /* Count MOVETO_OPEN */
597
598 for (p = path->bpath; p->code != ART_END; p++) {
599 len += 1;
600 if (p->code == ART_MOVETO_OPEN) len += 2;
601 }
602
603 new = gnome_canvas_path_def_new_sized (len);
604
605 d = start = new->bpath;
606 closed = TRUE;
607
608 for (p = path->bpath; p->code != ART_END; p++) {
609 switch (p->code) {
610 case ART_MOVETO_OPEN:
611 start = p;
612 closed = FALSE;
613 case ART_MOVETO:
614 if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
615 d->code = ART_LINETO;
616 d->x3 = start->x3;
617 d->y3 = start->y3;
618 d++;
619 }
620 if (p->code == ART_MOVETO) closed = TRUE;
621 d->code = ART_MOVETO;
622 d->x3 = p->x3;
623 d->y3 = p->y3;
624 d++;
625 break;
626 case ART_LINETO:
627 case ART_CURVETO:
628 *d++ = *p;
629 break;
630 default:
631 g_assert_not_reached ();
632 }
633 }
634
635 if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
636 d->code = ART_LINETO;
637 d->x3 = start->x3;
638 d->y3 = start->y3;
639 d++;
640 }
641
642 d->code = ART_END;
643
644 new->end = d - new->bpath;
645 new->allclosed = TRUE;
646 new->allopen = FALSE;
647
648 return new;
649 }
650
651 /* Destructor */
652
653 /**
654 * gnome_canvas_path_def_unref:
655 * @path: a GnomeCanvasPathDef
656 *
657 * Decrease the reference count of the passed @path. If the reference
658 * count is < 1 the path is deallocated.
659 */
660 void
gnome_canvas_path_def_unref(GnomeCanvasPathDef * path)661 gnome_canvas_path_def_unref (GnomeCanvasPathDef * path)
662 {
663 g_return_if_fail (path != NULL);
664
665 if (--path->refcount < 1) {
666 if ((!path->sbpath) && (path->bpath)) art_free (path->bpath);
667 g_free (path);
668 }
669 }
670
671
672 /* Methods */
673 /**
674 * gnome_canvas_path_def_reset:
675 * @path: a GnomeCanvasPathDef
676 *
677 * This function clears the contents of the passed @path.
678 */
679 void
gnome_canvas_path_def_reset(GnomeCanvasPathDef * path)680 gnome_canvas_path_def_reset (GnomeCanvasPathDef * path)
681 {
682 g_return_if_fail (path != NULL);
683 g_return_if_fail (!path->sbpath);
684
685 path->bpath->code = ART_END;
686 path->end = 0;
687 path->hascpt = FALSE;
688 path->posset = FALSE;
689 path->moving = FALSE;
690 path->allclosed = TRUE;
691 path->allopen = TRUE;
692 }
693
694 /* Several consequtive movetos are ALLOWED */
695
696 /**
697 * gnome_canvas_path_def_moveto:
698 * @path: a GnomeCanvasPathDef
699 * @x: x coordinate
700 * @y: y coordinate
701 *
702 * This function adds starts new subpath on @path, and sets its
703 * starting point to @x and @y. If current subpath is empty, it
704 * simply changes its starting coordinates to new values.
705 */
706 void
gnome_canvas_path_def_moveto(GnomeCanvasPathDef * path,gdouble x,gdouble y)707 gnome_canvas_path_def_moveto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
708 {
709 g_return_if_fail (path != NULL);
710 g_return_if_fail (!path->sbpath);
711 g_return_if_fail (!path->moving);
712
713 path->substart = path->end;
714 path->hascpt = TRUE;
715 path->posset = TRUE;
716 path->x = x;
717 path->y = y;
718
719 path->allclosed = FALSE;
720 }
721
722 /**
723 * gnome_canvas_path_def_lineto:
724 * @path: a GnomeCanvasPathDef
725 * @x: x coordinate
726 * @y: y coordinate
727 *
728 * This function add a line segment to the passed @path with the
729 * specified @x and @y coordinates.
730 */
731 void
gnome_canvas_path_def_lineto(GnomeCanvasPathDef * path,gdouble x,gdouble y)732 gnome_canvas_path_def_lineto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
733 {
734 ArtBpath * bp;
735
736 g_return_if_fail (path != NULL);
737 g_return_if_fail (!path->sbpath);
738 g_return_if_fail (path->hascpt);
739
740 if (path->moving) {
741 /* simply fix endpoint */
742 g_return_if_fail (!path->posset);
743 g_return_if_fail (path->end > 1);
744 bp = path->bpath + path->end - 1;
745 g_return_if_fail (bp->code == ART_LINETO);
746 bp->x3 = x;
747 bp->y3 = y;
748 path->moving = FALSE;
749 return;
750 }
751
752 if (path->posset) {
753 /* start a new segment */
754 gnome_canvas_path_def_ensure_space (path, 2);
755 bp = path->bpath + path->end;
756 bp->code = ART_MOVETO_OPEN;
757 bp->x3 = path->x;
758 bp->y3 = path->y;
759 bp++;
760 bp->code = ART_LINETO;
761 bp->x3 = x;
762 bp->y3 = y;
763 bp++;
764 bp->code = ART_END;
765 path->end += 2;
766 path->posset = FALSE;
767 path->allclosed = FALSE;
768 return;
769 }
770
771 /* Simply add line */
772
773 g_return_if_fail (path->end > 1);
774 gnome_canvas_path_def_ensure_space (path, 1);
775 bp = path->bpath + path->end;
776 bp->code = ART_LINETO;
777 bp->x3 = x;
778 bp->y3 = y;
779 bp++;
780 bp->code = ART_END;
781 path->end++;
782 }
783
784
785 /**
786 * gnome_canvas_path_def_lineto_moving:
787 * @path: a GnomeCanvasPathDef
788 * @x: x coordinate
789 * @y: y coordinate
790 *
791 * This functions adds a new line segment with loose endpoint to the path, or
792 * if endpoint is already loose, changes its coordinates to @x, @y. You
793 * can change the coordinates of loose endpoint as many times as you want,
794 * the last ones set will be fixed, if you continue line. This is useful
795 * for handling drawing with mouse.
796 */
797 void
gnome_canvas_path_def_lineto_moving(GnomeCanvasPathDef * path,gdouble x,gdouble y)798 gnome_canvas_path_def_lineto_moving (GnomeCanvasPathDef * path, gdouble x, gdouble y)
799 {
800 ArtBpath * bp;
801
802 g_return_if_fail (path != NULL);
803 g_return_if_fail (!path->sbpath);
804 g_return_if_fail (path->hascpt);
805
806 if (path->moving) {
807 /* simply change endpoint */
808 g_return_if_fail (!path->posset);
809 g_return_if_fail (path->end > 1);
810 bp = path->bpath + path->end - 1;
811 g_return_if_fail (bp->code == ART_LINETO);
812 bp->x3 = x;
813 bp->y3 = y;
814 return;
815 }
816
817 if (path->posset) {
818 /* start a new segment */
819 gnome_canvas_path_def_ensure_space (path, 2);
820 bp = path->bpath + path->end;
821 bp->code = ART_MOVETO_OPEN;
822 bp->x3 = path->x;
823 bp->y3 = path->y;
824 bp++;
825 bp->code = ART_LINETO;
826 bp->x3 = x;
827 bp->y3 = y;
828 bp++;
829 bp->code = ART_END;
830 path->end += 2;
831 path->posset = FALSE;
832 path->moving = TRUE;
833 path->allclosed = FALSE;
834 return;
835 }
836
837 /* Simply add line */
838
839 g_return_if_fail (path->end > 1);
840 gnome_canvas_path_def_ensure_space (path, 1);
841 bp = path->bpath + path->end;
842 bp->code = ART_LINETO;
843 bp->x3 = x;
844 bp->y3 = y;
845 bp++;
846 bp->code = ART_END;
847 path->end++;
848 path->moving = TRUE;
849 }
850
851 /**
852 * gnome_canvas_path_def_curveto:
853 * @path: a GnomeCanvasPathDef
854 * @x0: first control point x coordinate
855 * @y0: first control point y coordinate
856 * @x1: second control point x coordinate
857 * @y1: second control point y coordinate
858 * @x2: end of curve x coordinate
859 * @y2: end of curve y coordinate
860 *
861 * This function adds a bezier curve segment to the path definition.
862 */
863
864 void
gnome_canvas_path_def_curveto(GnomeCanvasPathDef * path,gdouble x0,gdouble y0,gdouble x1,gdouble y1,gdouble x2,gdouble y2)865 gnome_canvas_path_def_curveto (GnomeCanvasPathDef * path, gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
866 {
867 ArtBpath * bp;
868
869 g_return_if_fail (path != NULL);
870 g_return_if_fail (!path->sbpath);
871 g_return_if_fail (path->hascpt);
872 g_return_if_fail (!path->moving);
873
874 if (path->posset) {
875 /* start a new segment */
876 gnome_canvas_path_def_ensure_space (path, 2);
877 bp = path->bpath + path->end;
878 bp->code = ART_MOVETO_OPEN;
879 bp->x3 = path->x;
880 bp->y3 = path->y;
881 bp++;
882 bp->code = ART_CURVETO;
883 bp->x1 = x0;
884 bp->y1 = y0;
885 bp->x2 = x1;
886 bp->y2 = y1;
887 bp->x3 = x2;
888 bp->y3 = y2;
889 bp++;
890 bp->code = ART_END;
891 path->end += 2;
892 path->posset = FALSE;
893 path->allclosed = FALSE;
894 return;
895 }
896
897 /* Simply add path */
898
899 g_return_if_fail (path->end > 1);
900 gnome_canvas_path_def_ensure_space (path, 1);
901 bp = path->bpath + path->end;
902 bp->code = ART_CURVETO;
903 bp->x1 = x0;
904 bp->y1 = y0;
905 bp->x2 = x1;
906 bp->y2 = y1;
907 bp->x3 = x2;
908 bp->y3 = y2;
909 bp++;
910 bp->code = ART_END;
911 path->end++;
912 }
913
914 /**
915 * gnome_canvas_path_def_closepath:
916 * @path: a GnomeCanvasPathDef
917 *
918 * This function closes the last subpath of @path, adding a ART_LINETO to
919 * subpath starting point, if needed and changing starting pathcode to
920 * ART_MOVETO
921 */
922 void
gnome_canvas_path_def_closepath(GnomeCanvasPathDef * path)923 gnome_canvas_path_def_closepath (GnomeCanvasPathDef * path)
924 {
925 ArtBpath * bs, * be;
926
927 g_return_if_fail (path != NULL);
928 g_return_if_fail (!path->sbpath);
929 g_return_if_fail (path->hascpt);
930 g_return_if_fail (!path->posset);
931 g_return_if_fail (!path->moving);
932 g_return_if_fail (!path->allclosed);
933 /* We need at last M + L + L + E */
934 g_return_if_fail (path->end - path->substart > 2);
935
936 bs = path->bpath + path->substart;
937 be = path->bpath + path->end - 1;
938
939 if ((bs->x3 != be->x3) || (bs->y3 != be->y3)) {
940 gnome_canvas_path_def_lineto (path, bs->x3, bs->y3);
941 }
942
943 bs = path->bpath + path->substart; /* NB. def_lineto can
944 realloc bpath */
945 bs->code = ART_MOVETO;
946
947 path->allclosed = sp_bpath_all_closed (path->bpath);
948 path->allopen = sp_bpath_all_open (path->bpath);
949
950 path->hascpt = FALSE;
951 }
952
953 /**
954 * gnome_canvas_path_def_closepath_current:
955 * @path: a GnomeCanvasPathDef
956 *
957 * This function closes the last subpath by setting the coordinates of
958 * the endpoint of the last segment (line or curve) to starting point.
959 */
960 void
gnome_canvas_path_def_closepath_current(GnomeCanvasPathDef * path)961 gnome_canvas_path_def_closepath_current (GnomeCanvasPathDef * path)
962 {
963 ArtBpath * bs, * be;
964
965 g_return_if_fail (path != NULL);
966 g_return_if_fail (!path->sbpath);
967 g_return_if_fail (path->hascpt);
968 g_return_if_fail (!path->posset);
969 g_return_if_fail (!path->allclosed);
970 /* We need at last M + L + L + E */
971 g_return_if_fail (path->end - path->substart > 2);
972
973 bs = path->bpath + path->substart;
974 be = path->bpath + path->end - 1;
975
976 be->x3 = bs->x3;
977 be->y3 = bs->y3;
978
979 bs->code = ART_MOVETO;
980
981 path->allclosed = sp_bpath_all_closed (path->bpath);
982 path->allopen = sp_bpath_all_open (path->bpath);
983
984 path->hascpt = FALSE;
985 path->moving = FALSE;
986 }
987
988 /**
989 * gnome_canvas_path_def_bpath:
990 * @path: a GnomeCanvasPathDef
991 *
992 * This function returns a ArtBpath that consists of the path
993 * definition.
994 *
995 * Returns: ArtBpath
996 */
gnome_canvas_path_def_bpath(const GnomeCanvasPathDef * path)997 ArtBpath * gnome_canvas_path_def_bpath (const GnomeCanvasPathDef * path)
998 {
999 g_return_val_if_fail (path != NULL, NULL);
1000
1001 return path->bpath;
1002 }
1003
1004 /**
1005 * gnome_canvas_path_def_length:
1006 * @path: a GnomeCanvasPathDef
1007 *
1008 * This function returns the length of the path definition. Not
1009 * Euclidian length of the path but rather the number of points on the
1010 * path.
1011 *
1012 * Returns: integer, number of points on the path.
1013 */
gnome_canvas_path_def_length(const GnomeCanvasPathDef * path)1014 gint gnome_canvas_path_def_length (const GnomeCanvasPathDef * path)
1015 {
1016 g_return_val_if_fail (path != NULL, -1);
1017
1018 return path->end + 1;
1019 }
1020
1021 /**
1022 * gnome_canvas_path_def_is_empty:
1023 * @path: a GnomeCanvasPathDef
1024 *
1025 * This function is a boolean test to see if the path is empty,
1026 * meaning containing no line segments.
1027 *
1028 * Returns: boolean, indicating if the path is empty.
1029 */
1030 gboolean
gnome_canvas_path_def_is_empty(const GnomeCanvasPathDef * path)1031 gnome_canvas_path_def_is_empty (const GnomeCanvasPathDef * path)
1032 {
1033 g_return_val_if_fail (path != NULL, TRUE);
1034
1035 return (path->bpath->code == ART_END);
1036 }
1037
1038 /**
1039 * gnome_canvas_path_def_has_currentpoint:
1040 * @path: a GnomeCanvasPathdef
1041 *
1042 * This function is a boolean test checking to see if the path has a
1043 * current point defined. Current point will be set by line operators,
1044 * and cleared by closing subpath.
1045 *
1046 * Returns: boolean, indicating if the path has a current point defined.
1047 */
1048 gboolean
gnome_canvas_path_def_has_currentpoint(const GnomeCanvasPathDef * path)1049 gnome_canvas_path_def_has_currentpoint (const GnomeCanvasPathDef * path)
1050 {
1051 g_return_val_if_fail (path != NULL, FALSE);
1052
1053 return (path->hascpt);
1054 }
1055
1056 /**
1057 * gnome_canvas_path_def_currentpoint:
1058 * @path: a GnomeCanvasPathDef
1059 * @p: a ArtPoint where to store the current point
1060 *
1061 * Stores the current point of the path definition in the passed ArtPoint @p.
1062 */
1063 void
gnome_canvas_path_def_currentpoint(const GnomeCanvasPathDef * path,ArtPoint * p)1064 gnome_canvas_path_def_currentpoint (const GnomeCanvasPathDef * path, ArtPoint * p)
1065 {
1066 g_return_if_fail (path != NULL);
1067 g_return_if_fail (p != NULL);
1068 g_return_if_fail (path->hascpt);
1069
1070 if (path->posset) {
1071 p->x = path->x;
1072 p->y = path->y;
1073 } else {
1074 p->x = (path->bpath + path->end - 1)->x3;
1075 p->y = (path->bpath + path->end - 1)->y3;
1076 }
1077 }
1078
1079 /**
1080 * gnome_canvas_path_def_last_bpath:
1081 * @path: a GnomeCanvasPathDef
1082 *
1083 * This function returns pointer to the last ArtBpath segment in the path
1084 * definition.
1085 *
1086 * Returns: ArtBpath, being the last segment in the path definition or
1087 * null if no line segments have been defined.
1088 */
1089 ArtBpath *
gnome_canvas_path_def_last_bpath(const GnomeCanvasPathDef * path)1090 gnome_canvas_path_def_last_bpath (const GnomeCanvasPathDef * path)
1091 {
1092 g_return_val_if_fail (path != NULL, NULL);
1093
1094 if (path->end == 0) return NULL;
1095
1096 return path->bpath + path->end - 1;
1097 }
1098
1099 /**
1100 * gnome_canvas_path_def_first_bpath:
1101 * @path: a GnomeCanvasPathDef
1102 *
1103 * This function returns the first ArtBpath point in the definition.
1104 *
1105 * Returns: ArtBpath being the first point in the path definition or
1106 * null if no points are defined
1107 */
1108 ArtBpath *
gnome_canvas_path_def_first_bpath(const GnomeCanvasPathDef * path)1109 gnome_canvas_path_def_first_bpath (const GnomeCanvasPathDef * path)
1110 {
1111 g_return_val_if_fail (path != NULL, NULL);
1112
1113 if (path->end == 0) return NULL;
1114
1115 return path->bpath;
1116 }
1117
1118 /**
1119 * gnome_canvas_path_def_any_open:
1120 * @path: a GnomeCanvasPathDef
1121 *
1122 * This function returns a boolean value indicating if the path has
1123 * any open segments.
1124 *
1125 * Returns: boolean, indicating if the path has any open segments.
1126 */
1127 gboolean
gnome_canvas_path_def_any_open(const GnomeCanvasPathDef * path)1128 gnome_canvas_path_def_any_open (const GnomeCanvasPathDef * path)
1129 {
1130 g_return_val_if_fail (path != NULL, FALSE);
1131
1132 return (!path->allclosed);
1133 }
1134
1135 /**
1136 * gnome_canvas_path_def_all_open:
1137 * @path: a GnomeCanvasPathDef
1138 *
1139 * This function returns a boolean value indicating if the path only
1140 * contains open segments.
1141 *
1142 * Returns: boolean, indicating if the path has all open segments.
1143 */
1144 gboolean
gnome_canvas_path_def_all_open(const GnomeCanvasPathDef * path)1145 gnome_canvas_path_def_all_open (const GnomeCanvasPathDef * path)
1146 {
1147 g_return_val_if_fail (path != NULL, FALSE);
1148
1149 return (path->allopen);
1150 }
1151
1152 /**
1153 * gnome_canvas_path_def_any_closed:
1154 * @path: a GnomeCanvasPathDef
1155 *
1156 * This function returns a boolean valid indicating if the path has
1157 * any closed segements.
1158 *
1159 * Returns: boolean, indicating if the path has any closed segments.
1160 */
1161 gboolean
gnome_canvas_path_def_any_closed(const GnomeCanvasPathDef * path)1162 gnome_canvas_path_def_any_closed (const GnomeCanvasPathDef * path)
1163 {
1164 g_return_val_if_fail (path != NULL, FALSE);
1165
1166 return (!path->allopen);
1167 }
1168
1169 /**
1170 * gnome_canvas_path_def_all_closed:
1171 * @path: a GnomeCanvasPathDef
1172 *
1173 * This function returns a boolean value indicating if the path only
1174 * contains closed segments.
1175 *
1176 * Returns: boolean, indicating if the path has all closed segments.
1177 */
1178 gboolean
gnome_canvas_path_def_all_closed(const GnomeCanvasPathDef * path)1179 gnome_canvas_path_def_all_closed (const GnomeCanvasPathDef * path)
1180 {
1181 g_return_val_if_fail (path != NULL, FALSE);
1182
1183 return (path->allclosed);
1184 }
1185
1186 /* Private methods */
1187
1188 static
sp_bpath_good(ArtBpath * bpath)1189 gboolean sp_bpath_good (ArtBpath * bpath)
1190 {
1191 ArtBpath * bp;
1192
1193 g_return_val_if_fail (bpath != NULL, FALSE);
1194
1195 if (bpath->code == ART_END)
1196 return TRUE;
1197
1198 bp = bpath;
1199
1200 while (bp->code != ART_END) {
1201 bp = sp_bpath_check_subpath (bp);
1202 if (bp == NULL) return FALSE;
1203 }
1204
1205 return TRUE;
1206 }
1207
1208 static ArtBpath *
sp_bpath_check_subpath(ArtBpath * bpath)1209 sp_bpath_check_subpath (ArtBpath * bpath)
1210 {
1211 gint i, len;
1212 gboolean closed;
1213
1214 g_return_val_if_fail (bpath != NULL, NULL);
1215
1216 if (bpath->code == ART_MOVETO) {
1217 closed = TRUE;
1218 } else if (bpath->code == ART_MOVETO_OPEN) {
1219 closed = FALSE;
1220 } else {
1221 return NULL;
1222 }
1223
1224 len = 0;
1225
1226 for (i = 1; (bpath[i].code != ART_END) && (bpath[i].code != ART_MOVETO) && (bpath[i].code != ART_MOVETO_OPEN); i++) {
1227 switch (bpath[i].code) {
1228 case ART_LINETO:
1229 case ART_CURVETO:
1230 len++;
1231 break;
1232 default:
1233 return NULL;
1234 }
1235 }
1236
1237 if (closed) {
1238 if (len < 2) return NULL;
1239 if ((bpath->x3 != bpath[i-1].x3) || (bpath->y3 != bpath[i-1].y3)) return NULL;
1240 } else {
1241 if (len < 1) return NULL;
1242 }
1243
1244 return bpath + i;
1245 }
1246
1247 static gint
sp_bpath_length(const ArtBpath * bpath)1248 sp_bpath_length (const ArtBpath * bpath)
1249 {
1250 gint l;
1251
1252 g_return_val_if_fail (bpath != NULL, FALSE);
1253
1254 for (l = 0; bpath[l].code != ART_END; l++) ;
1255
1256 l++;
1257
1258 return l;
1259 }
1260
1261 static gboolean
sp_bpath_all_closed(const ArtBpath * bpath)1262 sp_bpath_all_closed (const ArtBpath * bpath)
1263 {
1264 const ArtBpath * bp;
1265
1266 g_return_val_if_fail (bpath != NULL, FALSE);
1267
1268 for (bp = bpath; bp->code != ART_END; bp++)
1269 if (bp->code == ART_MOVETO_OPEN) return FALSE;
1270
1271 return TRUE;
1272 }
1273
1274 static gboolean
sp_bpath_all_open(const ArtBpath * bpath)1275 sp_bpath_all_open (const ArtBpath * bpath)
1276 {
1277 const ArtBpath * bp;
1278
1279 g_return_val_if_fail (bpath != NULL, FALSE);
1280
1281 for (bp = bpath; bp->code != ART_END; bp++)
1282 if (bp->code == ART_MOVETO) return FALSE;
1283
1284 return TRUE;
1285 }
1286
1287
1288