1 /*
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This is a plug-in for GIMP.
5 *
6 * Generates images containing vector type drawings.
7 *
8 * Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #include "config.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <libgimp/gimp.h>
30 #include <libgimp/gimpui.h>
31
32 #include "gfig.h"
33 #include "gfig-dialog.h"
34 #include "gfig-style.h"
35 #include "gfig-arc.h"
36 #include "gfig-bezier.h"
37 #include "gfig-circle.h"
38 #include "gfig-dobject.h"
39 #include "gfig-ellipse.h"
40 #include "gfig-line.h"
41 #include "gfig-poly.h"
42 #include "gfig-rectangle.h"
43 #include "gfig-spiral.h"
44 #include "gfig-star.h"
45
46 #include "libgimp/stdplugins-intl.h"
47
48 static GfigObject *operation_obj = NULL;
49 static GdkPoint *move_all_pnt; /* Point moving all from */
50
51
52 static void draw_one_obj (GfigObject *obj,
53 cairo_t *cr);
54 static void do_move_obj (GfigObject *obj,
55 GdkPoint *to_pnt);
56 static void do_move_all_obj (GdkPoint *to_pnt);
57 static void do_move_obj_pnt (GfigObject *obj,
58 GdkPoint *to_pnt);
59 static void remove_obj_from_list (GFigObj *obj,
60 GfigObject *del_obj);
61 static gint scan_obj_points (DobjPoints *opnt,
62 GdkPoint *pnt);
63
64 void
d_save_object(GfigObject * obj,GString * string)65 d_save_object (GfigObject *obj,
66 GString *string)
67 {
68 do_save_obj (obj, string);
69
70 switch (obj->type)
71 {
72 case BEZIER:
73 case POLY:
74 case SPIRAL:
75 case STAR:
76 g_string_append_printf (string, "<EXTRA>\n");
77 g_string_append_printf (string, "%d\n</EXTRA>\n", obj->type_data);
78 break;
79 default:
80 break;
81 }
82 }
83
84 static DobjType
gfig_read_object_type(gchar * desc)85 gfig_read_object_type (gchar *desc)
86 {
87 gchar *ptr = desc;
88 DobjType type;
89
90 if (*ptr != '<')
91 return OBJ_TYPE_NONE;
92
93 ptr++;
94
95 for (type = LINE; type < NUM_OBJ_TYPES; type++)
96 {
97 if (ptr == strstr (ptr, dobj_class[type].name))
98 return type;
99 }
100
101 return OBJ_TYPE_NONE;
102 }
103
104 GfigObject *
d_load_object(gchar * desc,FILE * fp)105 d_load_object (gchar *desc,
106 FILE *fp)
107 {
108 GfigObject *new_obj = NULL;
109 gint xpnt;
110 gint ypnt;
111 gchar buf[MAX_LOAD_LINE];
112 DobjType type;
113
114 type = gfig_read_object_type (desc);
115 if (type == OBJ_TYPE_NONE)
116 {
117 g_message ("Error loading object: type not recognized.");
118 return NULL;
119 }
120
121 while (get_line (buf, MAX_LOAD_LINE, fp, 0))
122 {
123 if (sscanf (buf, "%d %d", &xpnt, &ypnt) != 2)
124 {
125 /* Read <EXTRA> block if there is one */
126 if (!strcmp ("<EXTRA>", buf))
127 {
128 if ( !new_obj)
129 {
130 g_message ("Error while loading object (no points)");
131 return NULL;
132 }
133
134 get_line (buf, MAX_LOAD_LINE, fp, 0);
135
136 if (sscanf (buf, "%d", &new_obj->type_data) != 1)
137 {
138 g_message ("Error while loading object (no type data)");
139 g_free (new_obj);
140 return NULL;
141 }
142
143 get_line (buf, MAX_LOAD_LINE, fp, 0);
144 if (strcmp ("</EXTRA>", buf))
145 {
146 g_message ("Syntax error while loading object");
147 g_free (new_obj);
148 return NULL;
149 }
150 /* Go around and read the last line */
151 continue;
152 }
153 else
154 return new_obj;
155 }
156
157 if (!new_obj)
158 new_obj = d_new_object (type, xpnt, ypnt);
159 else
160 d_pnt_add_line (new_obj, xpnt, ypnt, -1);
161 }
162
163 return new_obj;
164 }
165
166 GfigObject *
d_new_object(DobjType type,gint x,gint y)167 d_new_object (DobjType type,
168 gint x,
169 gint y)
170 {
171 GfigObject *nobj = g_new0 (GfigObject, 1);
172
173 nobj->type = type;
174 nobj->class = &dobj_class[type];
175 nobj->points = new_dobjpoint (x, y);
176
177 nobj->type_data = 0;
178
179 if (type == BEZIER)
180 {
181 nobj->type_data = 4;
182 }
183 else if (type == POLY)
184 {
185 nobj->type_data = 3; /* default to 3 sides */
186 }
187 else if (type == SPIRAL)
188 {
189 nobj->type_data = 4; /* default to 4 turns */
190 }
191 else if (type == STAR)
192 {
193 nobj->type_data = 3; /* default to 3 sides 6 points */
194 }
195
196 return nobj;
197 }
198
199 void
gfig_init_object_classes(void)200 gfig_init_object_classes (void)
201 {
202 d_arc_object_class_init ();
203 d_line_object_class_init ();
204 d_rectangle_object_class_init ();
205 d_circle_object_class_init ();
206 d_ellipse_object_class_init ();
207 d_poly_object_class_init ();
208 d_spiral_object_class_init ();
209 d_star_object_class_init ();
210 d_bezier_object_class_init ();
211 }
212
213 /* Delete a list of points */
214 void
d_delete_dobjpoints(DobjPoints * pnts)215 d_delete_dobjpoints (DobjPoints * pnts)
216 {
217 DobjPoints *next;
218 DobjPoints *pnt2del = pnts;
219
220 while (pnt2del)
221 {
222 next = pnt2del->next;
223 g_free (pnt2del);
224 pnt2del = next;
225 }
226 }
227
228 DobjPoints *
new_dobjpoint(gint x,gint y)229 new_dobjpoint (gint x, gint y)
230 {
231 DobjPoints *npnt = g_new0 (DobjPoints, 1);
232
233 npnt->pnt.x = x;
234 npnt->pnt.y = y;
235
236 return npnt;
237 }
238
239 DobjPoints *
d_copy_dobjpoints(DobjPoints * pnts)240 d_copy_dobjpoints (DobjPoints *pnts)
241 {
242 DobjPoints *ret = NULL;
243 DobjPoints *head = NULL;
244 DobjPoints *newpnt;
245 DobjPoints *pnt2copy;
246
247 for (pnt2copy = pnts; pnt2copy; pnt2copy = pnt2copy->next)
248 {
249 newpnt = new_dobjpoint (pnt2copy->pnt.x, pnt2copy->pnt.y);
250
251 if (!ret)
252 {
253 head = ret = newpnt;
254 }
255 else
256 {
257 head->next = newpnt;
258 head = newpnt;
259 }
260 }
261
262 return ret;
263 }
264
265 static DobjPoints *
get_diffs(GfigObject * obj,gint * xdiff,gint * ydiff,GdkPoint * to_pnt)266 get_diffs (GfigObject *obj,
267 gint *xdiff,
268 gint *ydiff,
269 GdkPoint *to_pnt)
270 {
271 DobjPoints *spnt;
272
273 g_assert (obj != NULL);
274
275 for (spnt = obj->points; spnt; spnt = spnt->next)
276 {
277 if (spnt->found_me)
278 {
279 *xdiff = spnt->pnt.x - to_pnt->x;
280 *ydiff = spnt->pnt.y - to_pnt->y;
281 return spnt;
282 }
283 }
284 return NULL;
285 }
286
287 static gboolean
inside_sqr(GdkPoint * cpnt,GdkPoint * testpnt)288 inside_sqr (GdkPoint *cpnt,
289 GdkPoint *testpnt)
290 {
291 /* Return TRUE if testpnt is near cpnt */
292 gint x = cpnt->x;
293 gint y = cpnt->y;
294 gint tx = testpnt->x;
295 gint ty = testpnt->y;
296
297 return (abs (x - tx) <= SQ_SIZE && abs (y - ty) < SQ_SIZE);
298 }
299
300 static gboolean
scan_obj_points(DobjPoints * opnt,GdkPoint * pnt)301 scan_obj_points (DobjPoints *opnt,
302 GdkPoint *pnt)
303 {
304 while (opnt)
305 {
306 if (inside_sqr (&opnt->pnt, pnt))
307 {
308 opnt->found_me = TRUE;
309 return TRUE;
310 }
311 opnt->found_me = FALSE;
312 opnt = opnt->next;
313 }
314 return FALSE;
315 }
316
317 static GfigObject *
get_nearest_objs(GFigObj * obj,GdkPoint * pnt)318 get_nearest_objs (GFigObj *obj,
319 GdkPoint *pnt)
320 {
321 /* Nearest object to given point or NULL */
322 GList *all;
323 GfigObject *test_obj;
324 gint count = 0;
325
326 if (!obj)
327 return NULL;
328
329 for (all = obj->obj_list; all; all = g_list_next (all))
330 {
331 test_obj = all->data;
332
333 if (count == obj_show_single || obj_show_single == -1)
334 if (scan_obj_points (test_obj->points, pnt))
335 {
336 return test_obj;
337 }
338 count++;
339 }
340 return NULL;
341 }
342
343 void
object_operation_start(GdkPoint * pnt,gboolean shift_down)344 object_operation_start (GdkPoint *pnt,
345 gboolean shift_down)
346 {
347 GfigObject *new_obj;
348
349 /* Find point in given object list */
350 operation_obj = get_nearest_objs (gfig_context->current_obj, pnt);
351
352 /* Special case if shift down && move obj then moving all objs */
353
354 if (shift_down && selvals.otype == MOVE_OBJ)
355 {
356 move_all_pnt = g_new (GdkPoint, 1);
357 *move_all_pnt = *pnt; /* Structure copy */
358 setup_undo ();
359 return;
360 }
361
362 if (!operation_obj)
363 return;/* None to work on */
364
365 gfig_context->selected_obj = operation_obj;
366
367 setup_undo ();
368
369 switch (selvals.otype)
370 {
371 case MOVE_OBJ:
372 if (operation_obj->type == BEZIER)
373 {
374 tmp_bezier = operation_obj;
375 }
376 break;
377
378 case MOVE_POINT:
379 if (operation_obj->type == BEZIER)
380 {
381 tmp_bezier = operation_obj;
382 }
383 /* If shift is down the break into sep lines */
384 if ((operation_obj->type == POLY
385 || operation_obj->type == STAR)
386 && shift_down)
387 {
388 switch (operation_obj->type)
389 {
390 case POLY:
391 d_poly2lines (operation_obj);
392 break;
393 case STAR:
394 d_star2lines (operation_obj);
395 break;
396 default:
397 break;
398 }
399 /* Re calc which object point we are looking at */
400 scan_obj_points (operation_obj->points, pnt);
401 gtk_widget_queue_draw (gfig_context->preview);
402 }
403 break;
404
405 case COPY_OBJ:
406 /* Copy the "operation object" */
407 /* Then bung us into "copy/move" mode */
408
409 new_obj = (GfigObject*) operation_obj->class->copyfunc (operation_obj);
410 if (new_obj)
411 {
412 gfig_style_copy (&new_obj->style, &operation_obj->style, "Object");
413 scan_obj_points (new_obj->points, pnt);
414 add_to_all_obj (gfig_context->current_obj, new_obj);
415 operation_obj = new_obj;
416 selvals.otype = MOVE_COPY_OBJ;
417 gtk_widget_queue_draw (gfig_context->preview);
418 }
419 break;
420
421 case DEL_OBJ:
422 remove_obj_from_list (gfig_context->current_obj, operation_obj);
423 break;
424
425 case SELECT_OBJ:
426 /* don't need to do anything */
427 break;
428
429 case MOVE_COPY_OBJ: /* Never when button down */
430 default:
431 g_warning ("Internal error selvals.otype object operation start");
432 break;
433 }
434
435 }
436
437 void
object_operation_end(GdkPoint * pnt,gboolean shift_down)438 object_operation_end (GdkPoint *pnt,
439 gboolean shift_down)
440 {
441 if (selvals.otype != DEL_OBJ && operation_obj &&
442 operation_obj->type == BEZIER)
443 {
444 tmp_bezier = NULL; /* use as switch */
445 }
446
447 if (operation_obj && selvals.otype != DEL_OBJ)
448 gfig_style_set_context_from_style (&operation_obj->style);
449
450 operation_obj = NULL;
451
452 if (move_all_pnt)
453 {
454 g_free (move_all_pnt);
455 move_all_pnt = NULL;
456 }
457
458 /* Special case - if copying mode MUST be copy when button up received */
459 if (selvals.otype == MOVE_COPY_OBJ)
460 selvals.otype = COPY_OBJ;
461 }
462
463 /* Move object around */
464 void
object_operation(GdkPoint * to_pnt,gboolean shift_down)465 object_operation (GdkPoint *to_pnt,
466 gboolean shift_down)
467 {
468 /* Must do different things depending on object type */
469 /* but must have object to operate on! */
470
471 /* Special case - if shift own and move_obj then move ALL objects */
472 if (move_all_pnt && shift_down && selvals.otype == MOVE_OBJ)
473 {
474 do_move_all_obj (to_pnt);
475 return;
476 }
477
478 if (!operation_obj)
479 return;
480
481 switch (selvals.otype)
482 {
483 case MOVE_OBJ:
484 case MOVE_COPY_OBJ:
485 switch (operation_obj->type)
486 {
487 case LINE:
488 case RECTANGLE:
489 case CIRCLE:
490 case ELLIPSE:
491 case POLY:
492 case ARC:
493 case STAR:
494 case SPIRAL:
495 case BEZIER:
496 do_move_obj (operation_obj, to_pnt);
497 break;
498 default:
499 /* Internal error */
500 g_warning ("Internal error in operation_obj->type");
501 break;
502 }
503 break;
504 case MOVE_POINT:
505 switch (operation_obj->type)
506 {
507 case LINE:
508 case RECTANGLE:
509 case CIRCLE:
510 case ELLIPSE:
511 case POLY:
512 case ARC:
513 case STAR:
514 case SPIRAL:
515 case BEZIER:
516 do_move_obj_pnt (operation_obj, to_pnt);
517 break;
518 default:
519 /* Internal error */
520 g_warning ("Internal error in operation_obj->type");
521 break;
522 }
523 break;
524 case DEL_OBJ:
525 case SELECT_OBJ:
526 break;
527 case COPY_OBJ: /* Should have been changed to MOVE_COPY_OBJ */
528 default:
529 g_warning ("Internal error selvals.otype");
530 break;
531 }
532 }
533
534 static void
update_pnts(GfigObject * obj,gint xdiff,gint ydiff)535 update_pnts (GfigObject *obj,
536 gint xdiff,
537 gint ydiff)
538 {
539 DobjPoints *spnt;
540
541 g_assert (obj != NULL);
542
543 /* Update all pnts */
544 for (spnt = obj->points; spnt; spnt = spnt->next)
545 {
546 spnt->pnt.x -= xdiff;
547 spnt->pnt.y -= ydiff;
548 }
549 }
550
551 static void
remove_obj_from_list(GFigObj * obj,GfigObject * del_obj)552 remove_obj_from_list (GFigObj *obj,
553 GfigObject *del_obj)
554 {
555 /* Nearest object to given point or NULL */
556
557 g_assert (del_obj != NULL);
558
559 if (g_list_find (obj->obj_list, del_obj))
560 {
561 obj->obj_list = g_list_remove (obj->obj_list, del_obj);
562
563 free_one_obj (del_obj);
564
565 if (obj->obj_list)
566 gfig_context->selected_obj = obj->obj_list->data;
567 else
568 gfig_context->selected_obj = NULL;
569
570 if (obj_show_single != -1)
571 {
572 /* We've just deleted the only visible one */
573 draw_grid_clear ();
574 obj_show_single = -1; /* Show entry again */
575 }
576
577 gtk_widget_queue_draw (gfig_context->preview);
578 }
579 else
580 g_warning (_("Hey, where has the object gone?"));
581 }
582
583 static void
do_move_all_obj(GdkPoint * to_pnt)584 do_move_all_obj (GdkPoint *to_pnt)
585 {
586 /* Move all objects in one go */
587 /* Undraw/then draw in new pos */
588 gint xdiff = move_all_pnt->x - to_pnt->x;
589 gint ydiff = move_all_pnt->y - to_pnt->y;
590
591 if (xdiff || ydiff)
592 {
593 GList *all;
594
595 for (all = gfig_context->current_obj->obj_list; all; all = all->next)
596 {
597 GfigObject *obj = all->data;
598
599 update_pnts (obj, xdiff, ydiff);
600 }
601
602 *move_all_pnt = *to_pnt;
603
604 gtk_widget_queue_draw (gfig_context->preview);
605 }
606 }
607
608 void
do_save_obj(GfigObject * obj,GString * string)609 do_save_obj (GfigObject *obj,
610 GString *string)
611 {
612 DobjPoints *spnt;
613
614 for (spnt = obj->points; spnt; spnt = spnt->next)
615 {
616 g_string_append_printf (string, "%d %d\n", spnt->pnt.x, spnt->pnt.y);
617 }
618 }
619
620 static void
do_move_obj(GfigObject * obj,GdkPoint * to_pnt)621 do_move_obj (GfigObject *obj,
622 GdkPoint *to_pnt)
623 {
624 /* Move the whole line - undraw the line to start with */
625 /* Then draw in new pos */
626 gint xdiff = 0;
627 gint ydiff = 0;
628
629 get_diffs (obj, &xdiff, &ydiff, to_pnt);
630
631 if (xdiff || ydiff)
632 {
633 update_pnts (obj, xdiff, ydiff);
634
635 gtk_widget_queue_draw (gfig_context->preview);
636 }
637 }
638
639 static void
do_move_obj_pnt(GfigObject * obj,GdkPoint * to_pnt)640 do_move_obj_pnt (GfigObject *obj,
641 GdkPoint *to_pnt)
642 {
643 /* Move the whole line - undraw the line to start with */
644 /* Then draw in new pos */
645 DobjPoints *spnt;
646 gint xdiff = 0;
647 gint ydiff = 0;
648
649 spnt = get_diffs (obj, &xdiff, &ydiff, to_pnt);
650
651 if ((!xdiff && !ydiff) || !spnt)
652 return;
653
654 spnt->pnt.x = spnt->pnt.x - xdiff;
655 spnt->pnt.y = spnt->pnt.y - ydiff;
656
657 /* Draw in new pos */
658 gtk_widget_queue_draw (gfig_context->preview);
659 }
660
661 /* copy objs */
662 GList *
copy_all_objs(GList * objs)663 copy_all_objs (GList *objs)
664 {
665 GList *new_all_objs = NULL;
666
667 while (objs)
668 {
669 GfigObject *object = objs->data;
670 GfigObject *new_object = (GfigObject *) object->class->copyfunc (object);
671 gfig_style_copy (&new_object->style, &object->style, "Object");
672
673 new_all_objs = g_list_prepend (new_all_objs, new_object);
674
675 objs = objs->next;
676 }
677
678 new_all_objs = g_list_reverse (new_all_objs);
679
680 return new_all_objs;
681 }
682
683 /* Screen refresh */
684 static void
draw_one_obj(GfigObject * obj,cairo_t * cr)685 draw_one_obj (GfigObject *obj,
686 cairo_t *cr)
687 {
688 obj->class->drawfunc (obj, cr);
689 }
690
691 void
draw_objects(GList * objs,gboolean show_single,cairo_t * cr)692 draw_objects (GList *objs,
693 gboolean show_single,
694 cairo_t *cr)
695 {
696 /* Show_single - only one object to draw Unless shift
697 * is down in which case show all.
698 */
699
700 gint count = 0;
701
702 while (objs)
703 {
704 if (!show_single || count == obj_show_single || obj_show_single == -1)
705 draw_one_obj (objs->data, cr);
706
707 objs = g_list_next (objs);
708 count++;
709 }
710 }
711
712 void
prepend_to_all_obj(GFigObj * fobj,GList * nobj)713 prepend_to_all_obj (GFigObj *fobj,
714 GList *nobj)
715 {
716 setup_undo (); /* Remember ME */
717
718 fobj->obj_list = g_list_concat (fobj->obj_list, nobj);
719 }
720
721 static void
scale_obj_points(DobjPoints * opnt,gdouble scale_x,gdouble scale_y)722 scale_obj_points (DobjPoints *opnt,
723 gdouble scale_x,
724 gdouble scale_y)
725 {
726 while (opnt)
727 {
728 opnt->pnt.x = (gint) (opnt->pnt.x * scale_x);
729 opnt->pnt.y = (gint) (opnt->pnt.y * scale_y);
730 opnt = opnt->next;
731 }
732 }
733
734 void
add_to_all_obj(GFigObj * fobj,GfigObject * obj)735 add_to_all_obj (GFigObj *fobj,
736 GfigObject *obj)
737 {
738 GList *nobj = NULL;
739
740 nobj = g_list_append (nobj, obj);
741
742 if (need_to_scale)
743 scale_obj_points (obj->points, scale_x_factor, scale_y_factor);
744
745 prepend_to_all_obj (fobj, nobj);
746
747 /* initialize style when we add the object */
748 gfig_context->selected_obj = obj;
749 }
750
751 /* First button press -- start drawing object */
752 /*
753 * object_start() creates a new object of the type specified in the
754 * button panel. It is activated by a button press, and causes
755 * a small square to be drawn at the initial point. The style of
756 * the new object is set to values taken from the style control
757 * widgets.
758 */
759 void
object_start(GdkPoint * pnt,gboolean shift_down)760 object_start (GdkPoint *pnt,
761 gboolean shift_down)
762 {
763 /* start for the current object */
764 if (!selvals.scaletoimage)
765 {
766 need_to_scale = 1;
767 selvals.scaletoimage = 1;
768 }
769 else
770 {
771 need_to_scale = 0;
772 }
773
774 switch (selvals.otype)
775 {
776 case LINE:
777 /* Shift means we are still drawing */
778 d_line_start (pnt, shift_down);
779 break;
780 case RECTANGLE:
781 d_rectangle_start (pnt, shift_down);
782 break;
783 case CIRCLE:
784 d_circle_start (pnt, shift_down);
785 break;
786 case ELLIPSE:
787 d_ellipse_start (pnt, shift_down);
788 break;
789 case POLY:
790 d_poly_start (pnt, shift_down);
791 break;
792 case ARC:
793 d_arc_start (pnt, shift_down);
794 break;
795 case STAR:
796 d_star_start (pnt, shift_down);
797 break;
798 case SPIRAL:
799 d_spiral_start (pnt, shift_down);
800 break;
801 case BEZIER:
802 d_bezier_start (pnt, shift_down);
803 break;
804 default:
805 /* Internal error */
806 break;
807 }
808
809 if (obj_creating)
810 {
811 if (gfig_context->debug_styles)
812 g_printerr ("Creating object, setting style from context\n");
813 gfig_style_set_style_from_context (&obj_creating->style);
814 }
815
816 }
817
818 void
object_end(GdkPoint * pnt,gboolean shift_down)819 object_end (GdkPoint *pnt,
820 gboolean shift_down)
821 {
822 /* end for the current object */
823 /* Add onto global object list */
824
825 /* If shift is down may carry on drawing */
826 switch (selvals.otype)
827 {
828 case LINE:
829 d_line_end (pnt, shift_down);
830 break;
831 case RECTANGLE:
832 d_rectangle_end (pnt, shift_down);
833 break;
834 case CIRCLE:
835 d_circle_end (pnt, shift_down);
836 break;
837 case ELLIPSE:
838 d_ellipse_end (pnt, shift_down);
839 break;
840 case POLY:
841 d_poly_end (pnt, shift_down);
842 break;
843 case STAR:
844 d_star_end (pnt, shift_down);
845 break;
846 case ARC:
847 d_arc_end (pnt, shift_down);
848 break;
849 case SPIRAL:
850 d_spiral_end (pnt, shift_down);
851 break;
852 case BEZIER:
853 d_bezier_end (pnt, shift_down);
854 break;
855 default:
856 /* Internal error */
857 break;
858 }
859
860 if (need_to_scale)
861 {
862 need_to_scale = 0;
863 selvals.scaletoimage = 0;
864 }
865 }
866
867 /* Stuff for the generation/deletion of objects. */
868
869 /* Objects are easy one they are created - you just go down the object
870 * list calling the draw function for each object but... when they
871 * are been created we have to be a little more careful. When
872 * the first point is placed on the canvas we create the object,
873 * the mouse position then defines the next point that can move around.
874 * careful how we draw this position.
875 */
876
877 void
free_one_obj(GfigObject * obj)878 free_one_obj (GfigObject *obj)
879 {
880 d_delete_dobjpoints (obj->points);
881 g_free (obj);
882 }
883
884 void
free_all_objs(GList * objs)885 free_all_objs (GList *objs)
886 {
887 g_list_free_full (objs, (GDestroyNotify) free_one_obj);
888 }
889
890 gchar *
get_line(gchar * buf,gint s,FILE * from,gint init)891 get_line (gchar *buf,
892 gint s,
893 FILE *from,
894 gint init)
895 {
896 gint slen;
897 char *ret;
898
899 if (init)
900 line_no = 1;
901 else
902 line_no++;
903
904 do
905 {
906 ret = fgets (buf, s, from);
907 }
908 while (!ferror (from) && buf[0] == '#');
909
910 slen = strlen (buf);
911
912 /* The last newline is a pain */
913 if (slen > 0)
914 buf[slen - 1] = '\0';
915
916 /* Check and remove an '\r' too from Windows */
917 if ((slen > 1) && (buf[slen - 2] == '\r'))
918 buf[slen - 2] = '\0';
919
920 if (ferror (from))
921 {
922 g_warning (_("Error reading file"));
923 return NULL;
924 }
925
926 #ifdef DEBUG
927 printf ("Processing line '%s'\n", buf);
928 #endif /* DEBUG */
929
930 return ret;
931 }
932
933 void
clear_undo(void)934 clear_undo (void)
935 {
936 int lv;
937
938 for (lv = undo_level; lv >= 0; lv--)
939 {
940 free_all_objs (undo_table[lv]);
941 undo_table[lv] = NULL;
942 }
943
944 undo_level = -1;
945
946 gfig_dialog_action_set_sensitive ("undo", FALSE);
947 }
948
949 void
setup_undo(void)950 setup_undo (void)
951 {
952 /* Copy object list to undo buffer */
953 #if DEBUG
954 printf ("setup undo level [%d]\n", undo_level);
955 #endif /*DEBUG*/
956
957 if (!gfig_context->current_obj)
958 {
959 /* If no current_obj must be loading -> no undo */
960 return;
961 }
962
963 if (undo_level >= selvals.maxundo - 1)
964 {
965 int loop;
966 /* the little one in the bed said "roll over".. */
967 if (undo_table[0])
968 free_one_obj (undo_table[0]->data);
969 for (loop = 0; loop < undo_level; loop++)
970 {
971 undo_table[loop] = undo_table[loop + 1];
972 }
973 }
974 else
975 {
976 undo_level++;
977 }
978 undo_table[undo_level] =
979 copy_all_objs (gfig_context->current_obj->obj_list);
980
981 gfig_dialog_action_set_sensitive ("undo", TRUE);
982
983 gfig_context->current_obj->obj_status |= GFIG_MODIFIED;
984 }
985
986 void
new_obj_2edit(GFigObj * obj)987 new_obj_2edit (GFigObj *obj)
988 {
989 GFigObj *old_current = gfig_context->current_obj;
990
991 /* Clear undo levels */
992 /* redraw the preview */
993 /* Set up options as define in the selected object */
994
995 clear_undo ();
996
997 /* Point at this one */
998 gfig_context->current_obj = obj;
999
1000 /* Show all objects to start with */
1001 obj_show_single = -1;
1002
1003 /* Change options */
1004 options_update (old_current);
1005
1006 /* redraw with new */
1007 gtk_widget_queue_draw (gfig_context->preview);
1008
1009 if (obj->obj_status & GFIG_READONLY)
1010 {
1011 g_message (_("Editing read-only object - "
1012 "you will not be able to save it"));
1013
1014 gfig_dialog_action_set_sensitive ("save", FALSE);
1015 }
1016 else
1017 {
1018 gfig_dialog_action_set_sensitive ("save", TRUE);
1019 }
1020 }
1021
1022 /* Add a point to a line (given x, y)
1023 * pos = 0 = head
1024 * pos = -1 = tail
1025 * 0 < pos = nth position
1026 */
1027
1028 void
d_pnt_add_line(GfigObject * obj,gint x,gint y,gint pos)1029 d_pnt_add_line (GfigObject *obj,
1030 gint x,
1031 gint y,
1032 gint pos)
1033 {
1034 DobjPoints *npnts = new_dobjpoint (x, y);
1035
1036 g_assert (obj != NULL);
1037
1038 if (!pos)
1039 {
1040 /* Add to head */
1041 npnts->next = obj->points;
1042 obj->points = npnts;
1043 }
1044 else
1045 {
1046 DobjPoints *pnt = obj->points;
1047
1048 /* Go down chain until the end if pos */
1049 while (pos < 0 || pos-- > 0)
1050 {
1051 if (!(pnt->next) || !pos)
1052 {
1053 npnts->next = pnt->next;
1054 pnt->next = npnts;
1055 break;
1056 }
1057 else
1058 {
1059 pnt = pnt->next;
1060 }
1061 }
1062 }
1063 }
1064