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 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 190 LGBPolygon() 191 { 192 LGDrawPolygon(TRUE); 193 } 194 195 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 */ 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 */ 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 */ 258 LGMPolygon() 259 { 260 LGModifyPolygon(0); 261 } 262 263 264 /* 265 * Modify curves and polygons in the current set to vectors. 266 */ 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 */ 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 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 */ 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 434 LGGet1() 435 { 436 LGGet(1); 437 } 438 439 440 LGGet2() 441 { 442 LGGet(2); 443 } 444 445 446 LGGet3() 447 { 448 LGGet(3); 449 } 450 451 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 */ 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 */ 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 1060 nop() 1061 { 1062 } 1063