1 /*
2 * @(#)long2.c 1.2 01/03/85
3 *
4 * More routines to implement "long" commands for the SUN Gremlin
5 * picture editor.
6 *
7 * Mark Opperman (opcode@monet.BERKELEY)
8 *
9 */
10
11 #include <suntool/tool_hs.h>
12 #include <suntool/menu.h>
13 #include <sys/file.h>
14 #include "gremlin.h"
15 #include <ctype.h>
16
17 /* imports from graphics files */
18
19 extern GRBlankPoints();
20 extern GRDisplayPoint();
21 extern GRSetTextPos();
22
23 /* imports from path.c */
24
25 extern PSetPath();
26 extern PConvertTilde();
27 extern char *PGetPath();
28
29 /* imports from display.c */
30
31 extern DISClearSetDisplay();
32 extern DISScreenAdd();
33 extern DISScreenErase();
34
35 /* imports from database files */
36
37 extern ELT *DBCopy();
38 extern ELT *DBRead();
39 extern ELT *DBCreateElt();
40
41 extern POINT *PTMakeTextPoints();
42 extern POINT *PTMakePoint();
43
44 extern DBAddSet();
45 extern DBChangeBrush();
46 extern DBChangeType();
47 extern DBChangeTypeStipple();
48 extern DBClearElt();
49 extern DBClearSet();
50 extern DBDelete();
51 extern DBGravitate();
52 extern DBXform();
53
54 /* imports from undodb.c */
55
56 extern UNELT *unlist;
57 extern UNELT *unback;
58 extern UNForget();
59
60 /* imports from short.c */
61
62 extern SHUpdate();
63 extern int adj[];
64
65 /* imports from text.c */
66
67 extern TxKillLine();
68 extern TxMsgOK();
69 extern TxPutMsg();
70
71 /* imports from menu.c */
72
73 extern MNHighLt();
74 extern MNUnHighLt();
75 extern HiMode[];
76
77 /* imports from C */
78
79 extern char *strcpy();
80 extern char *sprintf();
81 extern char *malloc();
82 extern FILE *fopen();
83
84 /* imports from sun.c */
85
86 extern flush_window_input();
87 extern prompt_ok();
88
89 /* imports from main.c */
90
91 extern char namestripe[];
92 extern char version[];
93 extern struct tool *tool;
94 extern struct pixfont *text_pf;
95
96 extern tool_fd;
97 extern menu_fd;
98
99 extern ELT *PICTURE; /* current PICTURE database */
100 extern ELT *cset; /* current set database */
101 extern Orientation; /* orientation of workspace */
102 extern SEARCH; /* flag for path search */
103 extern Alignment; /* point alignment indicator */
104 extern CBRUSH; /* current brush */
105 extern CSTIPPLE; /* current stipple */
106 extern float PX, PY; /* cursor coordinates */
107 extern float Lastx, Lasty; /* previous cursor coordinates */
108 extern SEQ; /* point sequence number */
109 extern POINT *POINTLIST, *BACKPOINT;/* accumulated point list */
110 extern Gridsize; /* grid spacing */
111 extern Adjustment; /* point adjustment mode */
112 extern CHANGED; /* PICTURE changed flag */
113 extern ELT *MEN[]; /* pointers for user symbols */
114 extern POINT MENPOINT[]; /* pointers used fo user symbols */
115 extern newfileformat; /* TRUE if using SUN file format */
116
117 /* imports from long1.c */
118
119 extern CSP();
120 extern CP();
121
122 char *Editfile;
123 char *eltnames[] = {
124 "BOTLEFT", "BOTRIGHT", "CENTCENT", "VECTOR", "ARC", "CURVE", "POLYGON",
125 "", "", "",
126 "TOPLEFT", "TOPCENT", "TOPRIGHT", "CENTLEFT", "CENTRIGHT", "BOTCENT"
127 };
128
129 char nowrite_msg[] = "NO WRITE SINCE LAST CHANGE! Press left button to \
130 edit new file, middle or right button to cancel.";
131 char filexists_msg[] = "FILE EXISTS! Press left button to overwrite, middle \
132 or right button to cancel.";
133 static char quit_msg[] = "NO WRITE SINCE LAST CHANGE! Press left button \
134 to confirm quit, middle or right button to cancel.";
135 static char quit2_msg[] = "Press left button to confirm quit, middle or right \
136 button to cancel.";
137
138 #define BADNUM -1
139 #define NONUM -2
140
141 static char badarg[] = "bad args";
142
143
144 /*
145 * This routine creates and displays a POLYGON element from the
146 * points previously specified.
147 */
148 static
LGDrawPolygon(bordered)149 LGDrawPolygon(bordered)
150 int bordered;
151 {
152 register POINT *p1, *p2;
153 POINT *p0, *plist;
154 ELT *e1;
155 char *txt;
156
157 if (SEQ < 3) { /* not enough points */
158 error("need at least 3 points");
159 return;
160 }
161
162 UNForget();
163
164 DISClearSetDisplay();
165 DBClearSet();
166
167 plist = PTInit();
168 p0 = p1 = POINTLIST;
169 (void) PTMakePoint(p1->x, p1->y, &plist);
170 p2 = PTNextPoint(p1);
171
172 while (!Nullpoint(p2)) {
173 (void) PTMakePoint(p2->x, p2->y, &plist);
174 p1 = p2;
175 p2 = PTNextPoint(p1);
176 }
177
178 txt = malloc(1);
179 *txt = '\0';
180 e1 = DBCreateElt(POLYGON, plist, bordered ? CBRUSH : 0, CSTIPPLE,
181 txt, &PICTURE);
182 DISScreenAdd(e1, pixmask | csetmask);
183 DBAddSet(e1);
184
185 CP();
186 CHANGED = TRUE;
187 } /* end LGDrawPolygon */
188
189
LGBPolygon()190 LGBPolygon()
191 {
192 LGDrawPolygon(TRUE);
193 }
194
195
LGPolygon()196 LGPolygon()
197 {
198 LGDrawPolygon(FALSE);
199 }
200
201
202 /*
203 * Modify elements in current set to POLYGON type with the indicated
204 * brush. POLYGONs, CURVEs and VECTORs can be modified to either
205 * bordered or unbordered POLYGONs.
206 */
LGModifyPolygon(brush)207 LGModifyPolygon(brush)
208 int brush; /* zero for unbordered */
209 {
210 register ELT *elt;
211
212 if (DBNullelt(cset)) {
213 error("no current set");
214 return;
215 }
216
217 UNForget();
218 CSP();
219
220 elt = cset;
221 while (!DBNullelt(elt)) {
222 if (elt->type == POLYGON) {
223 DISScreenErase(elt, pixmask | csetmask);
224 DBChangeBrush(elt, brush, &PICTURE);
225 DISScreenAdd(elt, pixmask | csetmask);
226 }
227 else if ((elt->type == VECTOR) || (elt->type == CURVE)) {
228 DISScreenErase(elt, pixmask | csetmask);
229 if (brush != 0) /* bordered polygon */
230 DBChangeTypeStipple(elt, POLYGON, CSTIPPLE, &PICTURE);
231 else /* unbordered polygon */
232 DBChangeTypeBrushStipple(elt, POLYGON, 0, CSTIPPLE, &PICTURE);
233 DISScreenAdd(elt, pixmask | csetmask);
234 }
235
236 elt = DBNextofSet(elt);
237 }
238
239 CP();
240 CHANGED = TRUE;
241 } /* end LGModifyPolygon */
242
243
244 /*
245 * Modify curves, vectors and polygons in the current set
246 * to bordered polygons.
247 */
LGMBPolygon()248 LGMBPolygon()
249 {
250 LGModifyPolygon(CBRUSH);
251 }
252
253
254 /*
255 * Modify curves, vectors and polygons in the current set
256 * to unbordered polygons.
257 */
LGMPolygon()258 LGMPolygon()
259 {
260 LGModifyPolygon(0);
261 }
262
263
264 /*
265 * Modify curves and polygons in the current set to vectors.
266 */
LGMVector()267 LGMVector()
268 {
269 register ELT *elt;
270
271 if (DBNullelt(cset)) {
272 error("no current set");
273 return;
274 }
275
276 UNForget();
277 CSP();
278
279 elt = cset;
280 while (!DBNullelt(elt)) {
281 if (elt->type == POLYGON) {
282 DISScreenErase(elt, pixmask | csetmask);
283 if (elt->brushf != 0)
284 DBChangeTypeStipple(elt, VECTOR, 0, &PICTURE);
285 else
286 DBChangeTypeBrushStipple(elt, VECTOR, CBRUSH, 0, &PICTURE);
287 DISScreenAdd(elt, pixmask | csetmask);
288 }
289 else if (elt->type == CURVE) {
290 DISScreenErase(elt, pixmask | csetmask);
291 DBChangeType(elt, VECTOR, &PICTURE);
292 DISScreenAdd(elt, pixmask | csetmask);
293 }
294 elt = DBNextofSet(elt);
295 }
296
297 CP();
298 CHANGED = TRUE;
299 }
300
301
302 /*
303 * Modify vectors and polygons in the current set to curves.
304 */
LGMCurve()305 LGMCurve()
306 {
307 register ELT *elt;
308
309 if (DBNullelt(cset)) {
310 error("no current set");
311 return;
312 }
313
314 UNForget();
315 CSP();
316
317 elt = cset;
318 while (!DBNullelt(elt)) {
319 if (elt->type == VECTOR) {
320 DISScreenErase(elt, pixmask | csetmask);
321 DBChangeType(elt, CURVE, &PICTURE);
322 DISScreenAdd(elt, pixmask | csetmask);
323 }
324 else if (elt->type == POLYGON) {
325 DISScreenErase(elt, pixmask | csetmask);
326 if (elt->brushf != 0) /* bordered polygon */
327 DBChangeTypeStipple(elt, CURVE, 0, &PICTURE);
328 else /* unbordered polygon */
329 DBChangeTypeBrushStipple(elt, CURVE, CBRUSH, 0, &PICTURE);
330 DISScreenAdd(elt, pixmask | csetmask);
331 }
332 elt = DBNextofSet(elt);
333 }
334
335 CP();
336 CHANGED = TRUE;
337 }
338
339
LGIncludeSet()340 LGIncludeSet()
341 /*
342 * This routine adds all elements selected by points in POINTLIST
343 * to the current set. It does not remove previously selected elements.
344 */
345 {
346 POINT *p1, *p2;
347 ELT *e1;
348 float n1, n2;
349
350 if (DBNullelt(PICTURE))
351 return;
352
353 if (SEQ == 0) { /* no points: entire picture becomes current set */
354 e1 = PICTURE;
355 while (!DBNullelt(e1)) {
356 if (!DBInCset(e1)) { /* not now in current set */
357 DBAddSet(e1); /* add it to current set */
358 DISScreenAdd(e1, csetmask); /* and display it */
359 }
360 e1 = DBNextElt(e1);
361 }
362 }
363 else {
364 p1 = POINTLIST;
365
366 /* for each user point */
367 while (!Nullpoint(p1)) {
368
369 /* find closest element */
370 DBGravitate(p1->x, p1->y, &n1, &n2, &p2, &e1, PICTURE, FALSE);
371
372 /* if something's close and its not already in the current set */
373 if (!DBNullelt(e1) && !DBInCset(e1)) {
374 DBAddSet(e1); /* add it */
375 DISScreenAdd(e1, csetmask); /* and display it */
376 }
377 p1 = PTNextPoint(p1);
378 }
379 }
380
381 CP();
382 } /* end LGIncludeSet */
383
384
385 /*
386 * This routine implements the menu command. The contents of
387 * the specified user menu item is copied into the PICTURE transformed
388 * to the positioning point.
389 */
LGGet(buffer)390 LGGet(buffer)
391 int buffer;
392 {
393
394 ELT *elist, *e1;
395 POINT *plist;
396 int symbol, index;
397 float xmat[3][2];
398
399 if (SEQ < 1) {
400 error("no positioning point");
401 return;
402 }
403
404 UNForget();
405 buffer--; /* users inputs number between 1 and N, actual
406 buffer number is between 0 and N-1 */
407
408 xmat[0][0] = xmat[1][1] = 1; /* create transformation matrix */
409 xmat[0][1] = xmat[1][0] = 0; /* for copy into PICTURE */
410 plist = POINTLIST;
411
412 while (!Nullpoint(plist)) {
413 DISClearSetDisplay();
414 DBClearSet();
415 xmat[2][0] = plist->x - (MENPOINT[buffer]).x;
416 xmat[2][1] = plist->y - (MENPOINT[buffer]).y;
417 elist = MEN[buffer];
418
419 while (!DBNullelt(elist)) { /* copy buffer to picture */
420 e1 = DBCopy(elist, xmat, &PICTURE);
421 DISScreenAdd(e1, pixmask | csetmask);
422 DBAddSet(e1);
423 elist = DBNextElt(elist);
424 }
425
426 plist = PTNextPoint(plist);
427 }
428
429 CP();
430 CHANGED = TRUE;
431 } /* end LGGet */
432
433
LGGet1()434 LGGet1()
435 {
436 LGGet(1);
437 }
438
439
LGGet2()440 LGGet2()
441 {
442 LGGet(2);
443 }
444
445
LGGet3()446 LGGet3()
447 {
448 LGGet(3);
449 }
450
451
LGGet4()452 LGGet4()
453 {
454 LGGet(4);
455 }
456
457
458 /*
459 * This routine reads in the specified filename (command line) to the
460 * selected user symbol or current set if no user symbol is selected. If
461 * no filename is specified, the current set is copied to the user symbol;
462 */
LGRead()463 LGRead()
464 {
465 POINT pos, ppos;
466 ELT *elist, *e1;
467 char tname[TEXT_BUFMAX];
468 float xmat[3][2];
469 int orient;
470
471 text_getvalue(&tname[0]);
472 if (*tname == '\0') {
473 error("read from where?");
474 return;
475 }
476
477 elist = DBRead(tname, &orient, &pos); /* read file */
478 if (elist == (ELT *) NULL)
479 return;
480
481 UNForget(); /* forget changes registered */
482 /* by DBRead */
483 if (SEQ < 1) { /* no positioning point */
484 ppos.x = pos.x;
485 ppos.y = pos.y;
486 }
487 else {
488 ppos.x = POINTLIST->x;
489 ppos.y = POINTLIST->y;
490 }
491
492 xmat[0][0] = xmat[1][1] = 1; /* set up matrix to copy to */
493 xmat[0][1] = xmat[1][0] = 0; /* appropriate place in */
494 xmat[2][0] = ppos.x - pos.x; /* picture as current set */
495 xmat[2][1] = ppos.y - pos.y;
496 DISClearSetDisplay();
497 DBClearSet();
498
499 while (!DBNullelt(elist)) {
500 e1 = DBCopy(elist, xmat, &PICTURE);
501 DISScreenAdd(e1, pixmask | csetmask);
502 DBAddSet(e1);
503 e1 = DBNextElt(elist);
504 DBClearElt(elist);
505 elist = e1;
506 }
507
508 CHANGED = TRUE;
509 TxKillLine();
510 CP();
511 } /* end LGRead */
512
513
514 /*
515 * This routine reads in a new PICTURE for editing
516 */
LGEdit()517 LGEdit()
518 {
519 FILE *fp, *POpen();
520 POINT pos;
521 ELT *e1;
522 char *prealname, *tn, tname[TEXT_BUFMAX];
523 int fd;
524
525 text_getvalue(&tname[0]);
526
527 if (CHANGED) {
528 if (!prompt_ok(menu_fd, nowrite_msg)) {
529 return;
530 }
531 }
532
533 DISClearSetDisplay();
534 DBClearSet();
535
536 while (!DBNullelt(PICTURE)) { /* clear current PICTURE */
537 e1 = DBNextElt(PICTURE);
538 DBClearElt(PICTURE);
539 PICTURE = e1;
540 }
541
542 tn = tname;
543
544 POINTLIST = PTInit(); /* initialize globals */
545 SEQ = 0;
546 CHANGED = FALSE;
547 (void) strcpy(namestripe, version);
548
549 if (*tname != '\0') { /* filename present */
550 fp = POpen(tname, &prealname, SEARCH);
551
552 if (fp == NULL) {
553 PICTURE = DBInit();
554 strcpy(Editfile, tname);
555 strcat(namestripe, tname);
556 error("creating new file");
557 }
558 else {
559 fclose(fp);
560 strcpy(Editfile, prealname);
561 strcat(namestripe, prealname);
562 PICTURE = DBRead(tname, &Orientation, &pos);
563 if ((fd = open(prealname, O_WRONLY | O_APPEND)) < 0)
564 strcat(namestripe, " (read only)");
565 else
566 close(fd);
567 }
568 }
569 else { /* create new file */
570 PICTURE = DBInit();
571 (void) strcat(namestripe, "new file");
572 (void) strcpy(Editfile, "");
573 }
574
575 tool_display(tool);
576
577 unlist = unback = NULL;
578 CP();
579 SHUpdate(); /* display new picture */
580 TxKillLine();
581 } /* end LGEdit */
582
583
584 /*
585 * This routine (re) displays the points in the back-up pointlist
586 */
587 static
restorepoints()588 restorepoints()
589 {
590
591 register POINT *plist, *pl1;
592 register i;
593
594 GRBlankPoints(POINTLIST);
595 plist = BACKPOINT;
596
597 for (i=0; !Nullpoint(plist); ++i) {
598 Lastx = plist->x;
599 Lasty = plist->y;
600 GRDisplayPoint(plist->x, plist->y, i);
601 plist = PTNextPoint(plist);
602 }
603
604 pl1 = POINTLIST;
605 POINTLIST = BACKPOINT;
606 SEQ = i;
607 BACKPOINT = pl1;
608 } /* end restorepoints */
609
610
611 /*
612 * This routine uses the information in the undo database to reconstruct
613 * the PICTURE as it was before the last command. The undo database is set
614 * so that the next undo would nullify this one.
615 * An undo of an Add is to delete the new element.
616 * Add the old element back to undo a delete.
617 * Modified elements are undone by copying the old element into the database
618 * in place of the modified element.
619 */
LGUndo()620 LGUndo()
621 {
622 UNELT *fix, *temp;
623 ELT *(*e1);
624
625 fix = unlist; /* initialize unlist so that undo-ing can */
626 unlist = NULL; /* add items to properly undo the undo */
627
628 if (fix == NULL) {
629 fix = unback;
630 unback = NULL;
631 }
632
633 DISClearSetDisplay();
634 DBClearSet();
635
636 while (fix != NULL) {
637 switch (fix->action) {
638 case ADD:
639 DISScreenErase(fix->newelt, pixmask);
640 TxMsgOK();
641 restorepoints();
642 DBDelete(fix->newelt, fix->dbase);
643 temp = fix->nextun;
644 free((char *) fix);
645 fix = temp;
646 break;
647 case DELETE:
648 fix->action = ADD; /* create undo unelt */
649 fix->newelt = fix->oldelt;
650 fix->oldelt = NULL;
651 fix->newelt->nextelt = PICTURE;
652 restorepoints();
653 DISScreenAdd(fix->newelt, pixmask | csetmask);
654 DBAddSet(fix->newelt);
655 PICTURE = fix->newelt; /* put in database */
656 temp = fix->nextun;
657 fix->nextun = unlist; /* link into unlist */
658 unlist = fix;
659 fix = temp;
660 break;
661 case MOD:
662 DISScreenErase(fix->newelt, pixmask);
663 TxMsgOK();
664 restorepoints();
665 DISScreenAdd(fix->oldelt, pixmask | csetmask);
666 DBAddSet(fix->oldelt);
667 e1 = fix->dbase;
668
669 while (*e1 != fix->newelt) { /* find elt to replace */
670 e1 = &(DBNextElt((*e1)));
671 }
672
673 fix->oldelt->nextelt = DBNextElt((*e1));
674 *e1 = fix->oldelt;
675 fix->oldelt = fix->newelt;
676 fix->newelt = *e1; /* create undo unelt */
677 temp = fix->nextun;
678 fix->nextun = unlist;
679 unlist = fix; /* link into unlist */
680 fix = temp;
681 break;
682 }
683 }
684 } /* end LGUndo */
685
686
687 /*
688 * Write elements from elist to filename.
689 * If setonly is true, elements are taken from the "setnext"
690 * pointer; otherwise, elements are taken from "nextelt".
691 * Ie., the current set is written with setonly = TRUE and
692 * the complete picture is written with setonly = FALSE.
693 */
694 static
LGWriteSet(elist,filename,setonly)695 LGWriteSet(elist, filename, setonly)
696 ELT *elist;
697 char *filename;
698 int setonly;
699 {
700 FILE *fp;
701 POINT *plist, pos;
702 char string[256];
703
704 fp = fopen(filename, "w");
705 if (fp == NULL) {
706 (void) sprintf(string, "can't open %s", filename);
707 error(string);
708 return;
709 }
710
711 TxPutMsg("writing file...");
712 UNForget();
713 CHANGED = FALSE;
714
715 if (SEQ > 0) { /* specified a positioning point */
716 pos.x = POINTLIST->x;
717 pos.y = POINTLIST->y;
718 }
719 else {
720 if (!DBNullelt(elist)) {
721 pos.x = elist->ptlist->x;
722 pos.y = elist->ptlist->y;
723 }
724 else {
725 pos.x = pos.y = 0.0;
726 }
727 }
728
729 if (newfileformat)
730 fprintf(fp, "sungremlinfile\n"); /* write header */
731 else
732 fprintf(fp, "gremlinfile\n"); /* write header */
733 fprintf(fp, "%d %1.2f %1.2f\n", Orientation, pos.x, pos.y);
734
735 while (!DBNullelt(elist)) { /* write each element */
736 if (newfileformat)
737 fprintf(fp, "%s\n", eltnames[elist->type]);
738 else
739 fprintf(fp, "%d\n", elist->type);
740
741 plist = elist->ptlist;
742
743 while (!Nullpoint(plist)) { /* write each point */
744 fprintf(fp, "%1.2f %1.2f\n", plist->x, plist->y);
745 plist = PTNextPoint(plist);
746 }
747
748 if (newfileformat)
749 fprintf(fp, "*\n"); /* end pointlist */
750 else
751 fprintf(fp, "-1.00 -1.00\n"); /* end pointlist */
752
753 fprintf(fp, "%d %d\n", elist->brushf, elist->size);
754 fprintf(fp,"%d %s\n", strlen(elist->textpt), elist->textpt);
755 elist = setonly ? DBNextofSet(elist) : DBNextElt(elist);
756 }
757 fprintf(fp, "-1\n");
758
759 (void) fclose(fp);
760 TxMsgOK();
761 TxKillLine();
762 CP();
763 } /* end LGWriteSet */
764
765
766 /*
767 * This routine writes the current set into the specified filename
768 */
LGSave()769 LGSave()
770 {
771 FILE *fp;
772 char tname[TEXT_BUFMAX], filename[TEXT_BUFMAX], *tn, *fn;
773 int space, stat;
774
775 space = TEXT_BUFMAX;
776 text_getvalue(&tname[0]);
777 tn = tname;
778 fn = filename;
779
780 if (*tname == '\0') {
781 error("write to where?");
782 return;
783 }
784
785 stat = PConvertTilde(&tn, &fn, &space);
786 *fn = '\0';
787
788 if (stat == FALSE) {
789 sprintf(filename, "unknown path %s", tname);
790 error(filename);
791 return;
792 }
793
794 fp = fopen(filename, "r");
795 if (fp != NULL) {
796 if (!prompt_ok(menu_fd, filexists_msg)) {
797 fclose(fp);
798 return;
799 }
800 else
801 fclose(fp);
802 }
803
804 LGWriteSet(cset, filename, TRUE);
805 } /* end LGSave */;
806
807
808 /*
809 * This routine writes the current PICTURE into the specified filename
810 * or to the current Editfile
811 */
LGWrite()812 LGWrite()
813 {
814 FILE *fp;
815 char tname[TEXT_BUFMAX], filename[TEXT_BUFMAX], *tn, *fn;
816 int space, stat;
817
818 space = TEXT_BUFMAX;
819 text_getvalue(&tname[0]);
820 tn = tname;
821 fn = filename;
822
823 if (tname[0] == '\0') {
824 if (Editfile[0] == '\0') {
825 error("write to where?");
826 return;
827 }
828 strcpy(filename, Editfile);
829 }
830 else {
831 stat = PConvertTilde(&tn, &fn, &space);
832 *fn = '\0';
833 if (stat == FALSE) {
834 sprintf(filename, "unknown path %s", tname);
835 error(filename);
836 return;
837 }
838 fp = fopen(filename, "r");
839 if (fp != NULL) {
840 if (!prompt_ok(menu_fd, filexists_msg)) {
841 fclose(fp);
842 return;
843 }
844 else
845 fclose(fp);
846 }
847 }
848
849 LGWriteSet(PICTURE, filename, FALSE);
850 } /* end LGWrite */;
851
852
853 /*
854 * This routine terminates the editor. The terminal states for the text
855 * terminal and the graphics display are restored and an EXIT is performed.
856 */
LGQuit()857 LGQuit()
858 {
859 if (prompt_ok(tool_fd, CHANGED ? quit_msg : quit2_msg))
860 exit(0);
861 } /* end LGQuit */
862
863
864 /*
865 * Horizontal Adjust -
866 * This routine toggles the adjustment mode.
867 */
LGHAdjust()868 LGHAdjust()
869 {
870 if (Adjustment == HORZ) {
871 MNUnHighLt(HiMode[adj[HORZ]]);
872 Adjustment = NOADJ;
873 }
874 else {
875 if (Adjustment != NOADJ)
876 MNUnHighLt(HiMode[adj[Adjustment]]);
877 MNHighLt(HiMode[adj[HORZ]]);
878 Adjustment = HORZ;
879 }
880 } /* end LGHAdjust */
881
882
883 /*
884 * Vertical Adjust -
885 * This routine toggles the adjustment mode.
886 */
LGVAdjust()887 LGVAdjust()
888 {
889 if (Adjustment == VERT) {
890 MNUnHighLt(HiMode[adj[VERT]]);
891 Adjustment = NOADJ;
892 }
893 else {
894 if (Adjustment != NOADJ)
895 MNUnHighLt(HiMode[adj[Adjustment]]);
896 MNHighLt(HiMode[adj[VERT]]);
897 Adjustment = VERT;
898 }
899 } /* end LGVAdjust */
900
901
902 /*
903 * This local routine returns 1 if x >= 0
904 * otherwise returns -1
905 */
906 static
sign(x)907 sign(x)
908 float x;
909 {
910 return((x >= 0) ? 1 : -1);
911 }
912
913
914 /*
915 * This routine is called by all mirroring routines to effect the
916 * transformation specified by xmat.
917 */
918 static
mirror(xmat)919 mirror(xmat)
920 float xmat[3][2];
921 {
922 register ELT *elt;
923 POINT pt, pos, *p1, *p2;
924 int i, j;
925
926 UNForget();
927 elt = cset;
928 CSP();
929
930 while (!DBNullelt(elt)) {
931 DISScreenErase(elt, pixmask | csetmask);
932 TxMsgOK();
933 DBXform(elt, xmat, &PICTURE);
934 if (TEXT(elt->type)) {
935 GRSetTextPos(elt->textpt, elt->type, elt->brushf, elt->size,
936 elt->ptlist, &pos);
937 elt->ptlist = PTMakeTextPoints(elt->textpt, elt->brushf, elt->size,
938 elt->ptlist, &pos);
939 DISScreenAdd(elt, pixmask | csetmask);
940 }
941 else {
942 if ((elt->type == ARC) && (elt->size > 0) &&
943 (xmat[0][0] * xmat[1][1] < 0)) {
944 /* arcs require special handling */
945 /* but, circles OK and mirror in both directions OK */
946 /* otherwise, swap starting and ending points of arc */
947 p1 = PTNextPoint(elt->ptlist);
948 p2 = PTNextPoint(p1);
949 pt.x = p1->x;
950 pt.y = p1->y;
951 p1->x = p2->x;
952 p1->y = p2->y;
953 p2->x = pt.x;
954 p2->y = pt.y;
955 }
956 DISScreenAdd(elt, pixmask | csetmask);
957 }
958 elt = DBNextofSet(elt);
959 }
960 CP();
961 } /* end mirror */
962
963
964 /*
965 * This routine mirrors the elements in the current set VERTICALLY
966 * The mirroring is accomplished by defining a transformation
967 * matrix and calling DBXform.
968 */
LGVMirror()969 LGVMirror()
970 {
971 float xmat[3][2];
972
973 if (SEQ < 1) { /* not enough points */
974 error("not enough points");
975 return;
976 }
977
978 if (DBNullelt(cset)) {
979 error("no current set");
980 return;
981 }
982
983 /* create transformation matrix to translate set to origin,
984 perform the mirroring and translate back */
985
986 xmat[0][0] = -1.0;
987 xmat[1][1] = 1.0;
988 xmat[1][0] = xmat[0][1] = xmat[2][1] = 0.0;
989 xmat[2][0] = 2.0 * POINTLIST->x;
990
991 mirror(xmat);
992 CHANGED = TRUE;
993 } /* end LGVMirror */
994
995
996 /*
997 * This routine mirrors the elements in the current set HORIZONTALLY
998 * The mirroring is accomplished by defining a transformation
999 * matrix and calling DBXform.
1000 */
LGHMirror()1001 LGHMirror()
1002 {
1003 float xmat[3][2];
1004
1005 if (SEQ < 1) { /* not enough points */
1006 error("not enough points");
1007 return;
1008 }
1009
1010 if (DBNullelt(cset)) {
1011 error("no current set");
1012 return;
1013 }
1014
1015 /* create transformation matrix to translate set to origin,
1016 perform the mirroring and translate back */
1017
1018 xmat[0][0] = 1.0;
1019 xmat[1][1] = -1.0;
1020 xmat[1][0] = xmat[0][1] = xmat[2][0] = 0.0;
1021 xmat[2][1] = 2.0 * POINTLIST->y;
1022
1023 mirror(xmat);
1024 CHANGED = TRUE;
1025 } /* end LGHMirror */
1026
1027
1028 /*
1029 * This routine looks at the command line for parameters to set
1030 * the current search path.
1031 */
LGPath()1032 LGPath()
1033 {
1034 char buf[TEXT_BUFMAX];
1035 char buf2[TEXT_BUFMAX];
1036 register i, i2;
1037
1038 i = i2 = -1;
1039 text_getvalue(&buf[0]);
1040 while (buf[++i]) {
1041 if (buf[i] != ' ')
1042 buf2[++i2] = buf[i];
1043 }
1044 buf2[++i2] = '\0';
1045
1046 if (*buf2 == '\0')
1047 TxPutMsg(PGetPath()); /* no arguments */
1048 else {
1049 SEARCH = TRUE;
1050 PSetPath(buf2);
1051 }
1052
1053 TxKillLine();
1054 } /* end LGPath */
1055
1056
1057 /*
1058 * Sometimes it's important to do nothing.
1059 */
nop()1060 nop()
1061 {
1062 }
1063