1 /* 2 * @(#)long1.c 1.2 01/03/85 3 * 4 * Routines to implement "long" commands in the SUN Gremlin picture editor. 5 * 6 * Mark Opperman (opcode@monet.BERKELEY) 7 * 8 */ 9 10 /* 11 * This file contains routines to implement the long text commands 12 * of the gremlin PICTURE editor. 13 */ 14 15 #include <sunwindow/rect.h> 16 #include "gremlin.h" 17 #include <ctype.h> 18 19 /* imports from graphics files */ 20 21 extern GRBlankPoints(); 22 extern GRDisplayPoint(); 23 extern GRErasePoint(); 24 extern GRfontfound(); 25 extern GROpenFont(); 26 extern GRSetTextPos(); 27 extern curve_set; /* TRUE if spline points pre-computed */ 28 29 /* imports from point.c */ 30 31 extern POINT *PTMakeTextPoints(); 32 33 /* imports from display.c */ 34 35 extern DISClearSetDisplay(); 36 extern DISScreenAdd(); 37 extern DISScreenErase(); 38 39 /* imports from database files */ 40 41 extern ELT *DBCreateElt(); 42 extern DBGravitate(); 43 extern DBChangeBrush(); 44 extern DBChangeFont(); 45 extern DBChangeSize(); 46 extern DBChangeStipple(); 47 extern DBChangeText(); 48 extern DBChangeJustify(); 49 extern DBAddSet(); 50 extern DBClearSet(); 51 extern POINT *PTMakePoint(); 52 extern PTDeletePoint(); 53 54 /* imports from undodb.c */ 55 56 extern UNRembMod(); 57 58 /* imports from short.c */ 59 60 extern SHUpdate(); 61 62 /* imports from menu.c */ 63 64 extern HiArtMode; 65 extern HiLineStyle; 66 extern HiBrush[]; 67 extern MNHighLt(); 68 extern MNUnHighLt(); 69 extern HiFont[]; 70 extern HiSize[]; 71 extern HiStipple[]; 72 73 /* imports from text.c */ 74 75 extern TxKillLine(); 76 extern TxMsgOK(); 77 extern text_getvalue(); 78 79 /* imports from C */ 80 81 extern char *malloc(); 82 extern char *strcpy(); 83 84 /* imports from main.c */ 85 86 extern ELT *PICTURE; /* current PICTURE database */ 87 extern ELT *cset; /* current set database */ 88 extern Artmode; /* indication of point display size */ 89 extern CBRUSH, CSIZE, CFONT; /* current brush, size, font */ 90 extern CJUST; /* current text justification */ 91 extern CSTIPPLE; /* current stipple pattern */ 92 extern Alignment; /* point alignment indicator */ 93 extern float PX, PY; /* cursor coordinates */ 94 extern float Lastx, Lasty; /* previous cursor coordinates */ 95 extern SEQ; /* point sequence number */ 96 extern POINT *POINTLIST, *BACKPOINT;/* accumulated point list */ 97 extern Adjustment; /* point adjustment mode */ 98 extern GravityOn; /* gravity mode flag */ 99 extern CHANGED; /* PICTURE changed flag */ 100 extern SymbolicLines; 101 extern Gridsize; 102 103 extern SUN_XORIGIN; 104 extern SUN_YORIGIN; 105 extern struct rect pix_size; 106 107 /* locals */ 108 109 int SHOWPOINTS; /* TRUE if current set reference points on */ 110 111 static char badarg[] = "bad args"; 112 static char noset[] = "no current set"; 113 static char delmsg[] = "can't delete any more points"; 114 115 #define BADNUM 0x7fffffff /* largest positive 32-bit integer */ 116 117 /* 118 * This routine trys to interpret the string starting at 119 * line+index as an integral numeric parameter. The function 120 * returns the numeric equivalent or the largest possible 121 * integer if there is some error in interpreting the string. 122 */ 123 GetNumParm(line, index) 124 register char *line; 125 register int *index; 126 { 127 char num[20]; 128 register sign = 1; 129 register i; 130 int result; 131 132 for (i=0; (*(line + *index) == ' '); ++i) /* skip blanks */ 133 ++(*index); 134 135 if (*(line + *index) == '-') { /* negative number */ 136 sign = -1; 137 ++(*index); 138 } 139 140 for (i=0; !Delimiter(*(line + *index)); ++i) { 141 num[i] = *(line + *index); 142 if (!isdigit(num[i])) 143 return(BADNUM); 144 ++(*index); 145 } 146 147 if (i == 0) 148 return(BADNUM); 149 150 num[i] = '\0'; 151 (void) sscanf(num, "%d", &result); 152 return(result * sign); 153 } /* end GetNumParm */ 154 155 156 /* 157 * This routine accepts coordinates from the text terminal 158 * and creates and displays a point from them by passing them 159 * along to LGPoint. 160 */ 161 LGOPoint() 162 { 163 int index, xcoord, ycoord; 164 char buf[TEXT_BUFMAX]; 165 166 text_getvalue(&buf[0]); 167 TxKillLine(); 168 index = 0; 169 xcoord = GetNumParm(buf, &index); 170 if (xcoord == BADNUM) { 171 error(badarg); 172 return; 173 } 174 175 ++index; 176 ycoord = GetNumParm(buf, &index); 177 if (ycoord == BADNUM) { 178 error(badarg); 179 return; 180 } 181 182 PX = xcoord; 183 PY = ycoord; 184 LGPoint(); 185 } /* end LGOPoint */ 186 187 188 /* 189 * This routine accepts cursor coordinates (global PX & PY) and then 190 * creates and displays points according to the current adjustment and 191 * alignment modes. Note that alignment and gravity are mutually exclusive 192 * and adjustment takes precedence over either. 193 */ 194 LGPoint() 195 { 196 ELT *temp; 197 POINT *p1; 198 float signx = 1.0; 199 float signy = 1.0; 200 201 temp = DBInit(); 202 if (GravityOn) 203 DBGravitate (PX, PY, &PX, &PY, &p1, &temp, PICTURE, FALSE); 204 205 if (DBNullelt(temp)) { /* no gravity in effect */ 206 /* Round to nearest alignment boundary */ 207 if (PX < 0) { 208 signx = -1.0; 209 PX = -PX; 210 } 211 if (PY < 0) { 212 signy = -1.0; 213 PY = -PY; 214 } 215 216 PX = (float) (((int) (PX / Alignment + 0.5)) * Alignment) * signx; 217 PY = (float) (((int) (PY / Alignment + 0.5)) * Alignment) * signy; 218 } 219 220 if (SEQ > 0) { /* this isn't the first point */ 221 switch (Adjustment) { 222 case HORZ: 223 PY = Lasty; 224 break; 225 case VERT: 226 PX = Lastx; 227 break; 228 case MAN: 229 if (fabs(PX - Lastx) > fabs(PY - Lasty)) 230 PY = Lasty; 231 else 232 PX = Lastx; 233 break; 234 } 235 } 236 237 if (SEQ >= MAXPOINTS) { 238 error("too many points"); 239 return; 240 } 241 242 GRDisplayPoint(PX, PY, SEQ); 243 (void) PTMakePoint(PX, PY, &POINTLIST); 244 Lastx = PX; 245 Lasty = PY; 246 247 ++SEQ; 248 } /* end LGPoint */ 249 250 251 /* 252 * Clear all points on from Showpoints command. 253 */ 254 CSP() 255 { 256 if (SHOWPOINTS) 257 LGShowPoints(); 258 } 259 260 261 /* 262 * This routine deletes all points from the POINTLIST and 263 * clears them from the display also. 264 */ 265 CP() 266 { 267 POINT *temp; 268 269 while (!Nullpoint(BACKPOINT)) { 270 temp = PTNextPoint(BACKPOINT); 271 free ((char *) BACKPOINT); 272 BACKPOINT = temp; 273 } 274 275 GRBlankPoints(POINTLIST); 276 BACKPOINT = POINTLIST; 277 POINTLIST = PTInit(); 278 SEQ = 0; 279 } /* end CP */ 280 281 282 /* 283 * Clear all displayed points. 284 */ 285 LGClearPoints() 286 { 287 CP(); 288 CSP(); 289 } /* end LGClearPoints */ 290 291 292 /* 293 * This routine removes the last point from the POINTLIST 294 * and erases it from the screen. 295 */ 296 LGDeletePoint() 297 { 298 POINT *pt1, *pt2, *pt3; 299 300 if (SEQ == 0) { 301 error("no point"); 302 return; 303 } 304 305 pt2 = pt3 = POINTLIST; 306 while (!Nullpoint(pt3)) { /* find last point and pointer to it */ 307 pt1 = pt2; 308 pt2 = pt3; 309 pt3 = PTNextPoint(pt3); 310 } 311 312 SEQ--; 313 GRErasePoint(pt2->x, pt2->y, SEQ); 314 PTDeletePoint(pt2, &POINTLIST); 315 if (SEQ > 0) { /* pt1 points to last one of them */ 316 Lastx = pt1->x; 317 Lasty = pt1->y; 318 } 319 } /* end LGDeletePoint */ 320 321 322 /* 323 * This routine causes the positioning points of the current set 324 * to be displayed. 325 */ 326 LGShowPoints() 327 { 328 register ELT *elt; 329 register POINT *p1; 330 register pno; 331 332 if (DBNullelt(cset)) { 333 error(noset); 334 return; 335 } 336 337 elt = cset; 338 while (!DBNullelt(elt)) { 339 p1 = elt->ptlist; 340 pno = 0; 341 342 while (!Nullpoint(p1)) { 343 GRDisplayPoint(p1->x, p1->y, pno); 344 p1 = PTNextPoint(p1); 345 pno++; 346 } 347 348 elt = DBNextofSet(elt); 349 } 350 SHOWPOINTS = !SHOWPOINTS; 351 } /* end LGShowPoints */ 352 353 354 /* 355 * This routine handles the two forms of the TEXT command. 356 * From the text subwindow, when a RETURN is pressed, the text 357 * buffer is copied to the LAST point layed down, the text is 358 * consumed, and that point is eaten. This provides a convenient 359 * method of entering several TEXT elements at many locations 360 * in the picture. 361 * From the menu subwindow, the traditional Gremlin TEXT command 362 * is implemented. One or two points may be specified, and all 363 * points are consumed at the end of the command. 364 */ 365 static 366 LGTextDisplay(oldway) 367 int oldway; 368 { 369 register ELT *elt; 370 char buf[TEXT_BUFMAX]; 371 POINT pos, ppnt, *p1; 372 char *text; 373 374 if (SEQ == 0) { 375 error("not enough points"); 376 return; 377 } 378 379 text_getvalue(&buf[0]); 380 381 if (*buf == '\0') { /* no text */ 382 error("empty string"); 383 return; 384 } 385 386 GROpenFont(CFONT, CSIZE); 387 if (!GRfontfound(CFONT, CSIZE)) { 388 error("can't open font file"); 389 return; 390 } 391 392 UNForget(); 393 text = malloc((unsigned) strlen(buf) + 1); 394 (void) strcpy(text, buf); 395 DISClearSetDisplay(); 396 DBClearSet(); 397 398 if (oldway == TRUE) { /* one or two points OK */ 399 ppnt.x = POINTLIST->x; 400 ppnt.y = POINTLIST->y; 401 if (SEQ > 1) { 402 p1 = PTNextPoint(POINTLIST); 403 ppnt.x = (ppnt.x + p1->x) / 2; 404 ppnt.y = (ppnt.y + p1->y) / 2; 405 } 406 } 407 else { /* find last point */ 408 p1 = POINTLIST; 409 while (!Nullpoint(PTNextPoint(p1))) 410 p1 = PTNextPoint(p1); 411 ppnt.x = p1->x; 412 ppnt.y = p1->y; 413 } 414 415 GRSetTextPos(text, CJUST, CFONT, CSIZE, &ppnt, &pos); 416 p1 = PTMakeTextPoints(text, CFONT, CSIZE, &ppnt, &pos); 417 elt = DBCreateElt(CJUST, p1, CFONT, CSIZE, text, &PICTURE); 418 419 DISScreenAdd(elt, pixmask | csetmask); 420 DBAddSet(elt); 421 422 if (oldway == TRUE) 423 CP(); 424 else 425 LGDeletePoint(); 426 427 TxKillLine(); 428 CHANGED = TRUE; 429 } /* end LGTextDisplay */ 430 431 432 /* 433 * This routine implements the TEXT command from the menu subwindow. 434 */ 435 LGText() 436 { 437 LGTextDisplay(TRUE); /* the old way of doing text entry */ 438 } /* end LGText */ 439 440 441 LGTextSW() 442 { 443 LGTextDisplay(FALSE); /* the new way of doing text entry */ 444 } /* end LGTextSW */ 445 446 447 /* 448 * This routine sets the current brush to that specified in the parameter. 449 */ 450 LGBrush(brush) 451 { 452 MNUnHighLt(HiBrush[CBRUSH-1]); 453 CBRUSH = brush; 454 MNHighLt(HiBrush[CBRUSH-1]); 455 } /* end LGBrush */ 456 457 458 LGBrush1() 459 { 460 LGBrush(1); 461 } 462 463 464 LGBrush2() 465 { 466 LGBrush(2); 467 } 468 469 470 LGBrush3() 471 { 472 LGBrush(3); 473 } 474 475 476 LGBrush4() 477 { 478 LGBrush(4); 479 } 480 481 482 LGBrush5() 483 { 484 LGBrush(5); 485 } 486 487 488 LGBrush6() 489 { 490 LGBrush(6); 491 } 492 493 494 /* 495 * This routine causes the elements in the current set 496 * to be redrawn using the new brush. 497 */ 498 LGMBrush(brush) 499 int brush; 500 { 501 register ELT *elt; 502 503 if (DBNullelt(cset)) { 504 error(noset); 505 return; 506 } 507 508 UNForget(); 509 CSP(); 510 511 elt = cset; 512 while (!DBNullelt(elt)) { 513 if (!TEXT(elt->type)) { 514 DISScreenErase(elt, pixmask | csetmask); 515 DBChangeBrush(elt, brush, &PICTURE); 516 curve_set = TRUE; /* no need to re-compute spline points */ 517 DISScreenAdd(elt, pixmask | csetmask); 518 } 519 elt = DBNextofSet(elt); 520 } 521 522 CP(); 523 CHANGED = TRUE; 524 } /* end LGMBrush */ 525 526 527 LGMBrush1() 528 { 529 LGMBrush(1); 530 } 531 532 533 LGMBrush2() 534 { 535 LGMBrush(2); 536 } 537 538 539 LGMBrush3() 540 { 541 LGMBrush(3); 542 } 543 544 545 LGMBrush4() 546 { 547 LGMBrush(4); 548 } 549 550 551 LGMBrush5() 552 { 553 LGMBrush(5); 554 } 555 556 557 LGMBrush6() 558 { 559 LGMBrush(6); 560 } 561 562 563 /* 564 * This routine causes text elements in the current set 565 * to be redrawn using the new justification mode. 566 * mode is 1 - 9 for tl, tc, tr, cl, cc, cl, bl, bc, br 567 */ 568 LGMJustify(just) 569 int just; 570 { 571 register ELT *elt; 572 573 if (DBNullelt(cset)) { 574 error(noset); 575 return; 576 } 577 578 UNForget(); 579 CSP(); 580 581 elt = cset; 582 while (!DBNullelt(elt)) { 583 if (TEXT(elt->type)) { 584 DISScreenErase(elt, pixmask | csetmask); 585 DBChangeJustify(elt, just, &PICTURE); 586 DISScreenAdd(elt, pixmask | csetmask); 587 } 588 elt = DBNextofSet(elt); 589 } 590 591 CP(); 592 CHANGED = TRUE; 593 } /* end LGMJustify */ 594 595 596 /* 597 * This routine causes the text elements in the current set 598 * to be redrawn using the new font. 599 */ 600 LGMFont(font) 601 int font; 602 { 603 register ELT *elt; 604 605 if (DBNullelt(cset)) { 606 error(noset); 607 return; 608 } 609 610 UNForget(); 611 CSP(); 612 613 elt = cset; 614 while (!DBNullelt(elt)) { 615 if (TEXT(elt->type)) { 616 GROpenFont(font, elt->size); 617 if (!GRfontfound(font, elt->size)) { 618 error("can't open font file"); 619 } 620 else { 621 DISScreenErase(elt, pixmask | csetmask); 622 TxMsgOK(); 623 DBChangeFont(elt, font, &PICTURE); 624 DISScreenAdd(elt, pixmask | csetmask); 625 } 626 } 627 elt = DBNextofSet(elt); 628 } 629 630 CP(); 631 CHANGED = TRUE; 632 } /* end LGMFont */ 633 634 635 LGMFont1() 636 { 637 LGMFont(1); 638 } 639 640 641 LGMFont2() 642 { 643 LGMFont(2); 644 } 645 646 647 LGMFont3() 648 { 649 LGMFont(3); 650 } 651 652 653 LGMFont4() 654 { 655 LGMFont(4); 656 } 657 658 659 /* 660 * This routine causes the text elements in the current set 661 * to be redrawn using the new size. 662 */ 663 LGMSize(size) 664 int size; 665 { 666 register ELT *elt; 667 668 if (DBNullelt(cset)) { 669 error(noset); 670 return; 671 } 672 673 UNForget(); 674 CSP(); 675 676 elt = cset; 677 while (!DBNullelt(elt)) { 678 if (TEXT(elt->type)) { 679 GROpenFont(elt->brushf, size); 680 if (!GRfontfound(elt->brushf, size)) { 681 error("can't open font file"); 682 } 683 else { 684 DISScreenErase(elt, pixmask | csetmask); 685 TxMsgOK(); 686 DBChangeSize(elt, size, &PICTURE); 687 DISScreenAdd(elt, pixmask | csetmask); 688 } 689 } 690 elt = DBNextofSet(elt); 691 } 692 693 CP(); 694 CHANGED = TRUE; 695 } /* end LGMFize */ 696 697 698 LGMSize1() 699 { 700 LGMSize(1); 701 } 702 703 704 LGMSize2() 705 { 706 LGMSize(2); 707 } 708 709 710 LGMSize3() 711 { 712 LGMSize(3); 713 } 714 715 716 LGMSize4() 717 { 718 LGMSize(4); 719 } 720 721 722 /* 723 * This routine causes the polygon elements in the current set 724 * to be redrawn using the new stipple. 725 */ 726 LGMStipple(stipple) 727 int stipple; 728 { 729 register ELT *elt; 730 731 if (DBNullelt(cset)) { 732 error(noset); 733 return; 734 } 735 736 UNForget(); 737 CSP(); 738 739 elt = cset; 740 while (!DBNullelt(elt)) { 741 if (elt->type == POLYGON) { 742 DISScreenErase(elt, pixmask | csetmask); 743 TxMsgOK(); 744 DBChangeStipple(elt, stipple, &PICTURE); 745 DISScreenAdd(elt, pixmask | csetmask); 746 } 747 elt = DBNextofSet(elt); 748 } 749 750 CP(); 751 CHANGED = TRUE; 752 } /* end LGMStipple */ 753 754 755 LGMStipple1() 756 { 757 LGMStipple(1); 758 } 759 760 761 LGMStipple2() 762 { 763 LGMStipple(2); 764 } 765 766 767 LGMStipple3() 768 { 769 LGMStipple(3); 770 } 771 772 773 LGMStipple4() 774 { 775 LGMStipple(4); 776 } 777 778 779 LGMStipple5() 780 { 781 LGMStipple(5); 782 } 783 784 785 LGMStipple6() 786 { 787 LGMStipple(6); 788 } 789 790 791 LGMStipple7() 792 { 793 LGMStipple(7); 794 } 795 796 797 LGMStipple8() 798 { 799 LGMStipple(8); 800 } 801 802 803 /* 804 * This routine allows modification of text by replacing 805 * an existing string with a new one, appropriately repositioned 806 */ 807 LGMText() 808 { 809 register ELT *elt; 810 char buf[TEXT_BUFMAX]; 811 812 if (DBNullelt(cset)) { 813 error(noset); 814 return; 815 } 816 817 text_getvalue(&buf[0]); 818 if (*buf == '\0') { /* no text */ 819 error("empty string"); 820 return; 821 } 822 823 UNForget(); 824 CSP(); 825 826 elt = cset; 827 while (!DBNullelt(elt)) { 828 if (TEXT(elt->type)) { 829 DISScreenErase(elt, pixmask | csetmask); 830 TxMsgOK(); 831 DBChangeText(elt, buf, &PICTURE); 832 DISScreenAdd(elt, pixmask | csetmask); 833 } 834 elt = DBNextofSet(elt); 835 } 836 837 CP(); 838 TxKillLine(); 839 CHANGED = TRUE; 840 } /* end LGMText */ 841 842 843 /* 844 * This routine modifies the element which contains the point 845 * closest to the first of two specified points so that that point 846 * coincides with the second of the points (if specified). 847 * 848 * Note: it implies knowledge of the database representation by modifying 849 * the element directly. 850 */ 851 LGMPoint() 852 { 853 ELT *elt; 854 POINT *p1, *p2, *p3, *p4; 855 float x1, y1; 856 int length; 857 858 if (SEQ < 1) { 859 error("no point specified"); 860 return; 861 } 862 863 /* find point */ 864 DBGravitate(POINTLIST->x, POINTLIST->y, &x1, &y1, &p1, &elt, cset, TRUE); 865 866 if (DBNullelt(elt) || TEXT(elt->type)) { 867 error("can't find a good element"); 868 return; 869 } 870 871 if (SEQ == 1) { /* wants to delete a point */ 872 length = PTListLength(elt); 873 if (((elt->type == POLYGON) && (length == 3)) || (length == 2)) { 874 error(delmsg); 875 return; 876 } 877 } 878 879 /* now OK to do whatever */ 880 UNForget(); 881 CSP(); 882 883 DBClearSet(); 884 GRClear(csetmask); 885 DISScreenErase(elt, pixmask); 886 UNRembMod(elt, &PICTURE); 887 if (SEQ > 1) { /* move a point, not delete */ 888 p2 = PTNextPoint(POINTLIST); 889 p1->x = p2->x; 890 p1->y = p2->y; 891 p2 = PTNextPoint(p2); 892 if (!Nullpoint(p2)) { 893 p3 = PTInit(); 894 while (!Nullpoint(p2)) { 895 p4 = PTMakePoint(p2->x, p2->y, &p3); 896 p2 = PTNextPoint(p2); 897 } 898 p4->nextpt = p1->nextpt; 899 p1->nextpt = p3; 900 } 901 } 902 else { 903 PTDeletePoint(p1, &(elt->ptlist)); 904 } 905 906 DISScreenAdd(elt, pixmask | csetmask); 907 DBAddSet(elt); 908 909 CP(); 910 CHANGED = TRUE; 911 } /* end LGMPoint */ 912 913 914 /* 915 * This routine allows users to leave gripe messages or report 916 * bugs to the maintainer. Mail is invoked via the defined constant GRIPE. 917 */ 918 LGGripe() 919 { 920 TxPutMsg("mail gripes to opcode@monet"); 921 } /* end LGGripe */ 922 923 924 /* 925 * This routine controls the size of the point that is displayed. 926 * The sizes available are Artmode in which a small (3 x 3) point is displayed 927 * with no number and regular (non-Artmode). 928 */ 929 LGLittlePoint() 930 { 931 register POINT *plist; 932 register sp; 933 register i = 0; 934 935 GRBlankPoints(POINTLIST); 936 if ((sp = SHOWPOINTS) != 0) /* turn off show points */ 937 CSP(); 938 Artmode = !Artmode; 939 940 plist = POINTLIST; 941 while (!Nullpoint(plist)) { 942 GRDisplayPoint(plist->x, plist->y, i++); 943 plist = PTNextPoint(plist); 944 } 945 946 if (sp != 0) /* turn on show points */ 947 LGShowPoints(); 948 949 if (Artmode) 950 MNUnHighLt(HiArtMode); 951 else 952 MNHighLt(HiArtMode); 953 } /* end LGLittlePoint */ 954 955 956 /* 957 * This routine looks at the command line for parameters to set 958 * the current Font. 959 */ 960 LGFont(font) 961 int font; 962 { 963 MNUnHighLt(HiFont[CFONT-1]); 964 CFONT = font; 965 MNHighLt(HiFont[CFONT-1]); 966 } /* end LGFont */ 967 968 969 LGFont1() 970 { 971 LGFont(1); 972 } 973 974 975 LGFont2() 976 { 977 LGFont(2); 978 } 979 980 981 LGFont3() 982 { 983 LGFont(3); 984 } 985 986 987 LGFont4() 988 { 989 LGFont(4); 990 } 991 992 993 /* 994 * This routine changes the current character size. 995 */ 996 LGSize(size) 997 int size; 998 { 999 MNUnHighLt(HiSize[CSIZE-1]); 1000 CSIZE = size; 1001 MNHighLt(HiSize[CSIZE-1]); 1002 } /* end LGSize */ 1003 1004 1005 LGSize1() 1006 { 1007 LGSize(1); 1008 } 1009 1010 1011 LGSize2() 1012 { 1013 LGSize(2); 1014 } 1015 1016 1017 LGSize3() 1018 { 1019 LGSize(3); 1020 } 1021 1022 1023 LGSize4() 1024 { 1025 LGSize(4); 1026 } 1027 1028 1029 /* 1030 * This routine changes the current stipple pattern. 1031 */ 1032 LGStipple(stipple) 1033 int stipple; 1034 { 1035 MNUnHighLt(HiStipple[CSTIPPLE-1]); 1036 CSTIPPLE = stipple; 1037 MNHighLt(HiStipple[CSTIPPLE-1]); 1038 } /* end LGStipple */ 1039 1040 1041 LGStipple1() 1042 { 1043 LGStipple(1); 1044 } 1045 1046 1047 LGStipple2() 1048 { 1049 LGStipple(2); 1050 } 1051 1052 1053 LGStipple3() 1054 { 1055 LGStipple(3); 1056 } 1057 1058 1059 LGStipple4() 1060 { 1061 LGStipple(4); 1062 } 1063 1064 1065 LGStipple5() 1066 { 1067 LGStipple(5); 1068 } 1069 1070 1071 LGStipple6() 1072 { 1073 LGStipple(6); 1074 } 1075 1076 1077 LGStipple7() 1078 { 1079 LGStipple(7); 1080 } 1081 1082 1083 LGStipple8() 1084 { 1085 LGStipple(8); 1086 } 1087 1088 1089 /* 1090 * Toggle line style 1091 */ 1092 LGLineStyle() 1093 { 1094 if (SymbolicLines = !SymbolicLines) 1095 MNUnHighLt(HiLineStyle); 1096 else 1097 MNHighLt(HiLineStyle); 1098 1099 SHUpdate(); 1100 } /* end LGLineStyle */ 1101 1102 1103 LGPan() 1104 { 1105 if (SEQ < 1) { 1106 error("need one point"); 1107 return; 1108 } 1109 1110 LGdopan(POINTLIST->x, POINTLIST->y); 1111 } 1112 1113 1114 /* 1115 * Make (wx, wy) center of Gremlin window. 1116 */ 1117 LGdopan(wx, wy) 1118 float wx, wy; 1119 { 1120 float cx, cy; 1121 register tx, ty; 1122 1123 CP(); /* eat points first */ 1124 1125 cx = SUN_XORIGIN + (pix_size.r_width >> 1); /* window x center */ 1126 cy = SUN_YORIGIN - (pix_size.r_height >> 1); /* window y center */ 1127 1128 tx = (int) (wx - cx); /* x translation */ 1129 ty = (int) (wy - cy); /* y translation */ 1130 1131 tx += (tx < 0) ? -1 : 1; /* fudge factor */ 1132 ty += (ty < 0) ? -1 : 1; 1133 1134 SUN_XORIGIN += (tx / Gridsize) * Gridsize; 1135 SUN_YORIGIN += (ty / Gridsize) * Gridsize; 1136 1137 SHUpdate(); 1138 } /* end LGPan */ 1139 1140 1141 /* 1142 * Pan to absolute center of picture. 1143 * Invoked by the middle button on the PAN icon. 1144 */ 1145 LGMPan() 1146 { 1147 register ELT *elt; 1148 register POINT *point; 1149 float minx, miny, maxx, maxy; 1150 1151 if (DBNullelt(PICTURE)) { 1152 error("empty picture"); 1153 return; 1154 } 1155 1156 elt = PICTURE; 1157 minx = maxx = elt->ptlist->x; 1158 miny = maxy = elt->ptlist->y; 1159 1160 while (!DBNullelt(elt)) { 1161 point = elt->ptlist; 1162 1163 while (!Nullpoint(point)) { 1164 MINMAX(minx, maxx, point->x); 1165 MINMAX(miny, maxy, point->y); 1166 point = PTNextPoint(point); 1167 } 1168 1169 elt = DBNextElt(elt); 1170 } 1171 1172 LGdopan(maxx - ((maxx - minx) / 2.0), maxy - ((maxy - miny) / 2.0)); 1173 } 1174