1 #ifndef lint 2 static char sccsid[] = "@(#)subr.c 4.2 (Berkeley) 08/11/83"; 3 #endif 4 5 /* 6 * subr.c: general subroutines for fed. 7 */ 8 9 #include "fed.h" 10 11 /* 12 * initialize: various one time initializations. 13 */ 14 initialize() 15 { 16 register int i, j; 17 register char *cp; 18 19 /* Initialize random variables */ 20 curwind = -1; 21 pencolor = 1; 22 penweight = 0; 23 24 /* 25 * Initialize value of sqrtmat. This is a constant table 26 * so we don't have to redo all these square roots when the pen 27 * changes every time. 28 */ 29 for (i=0; i<10; i++) { 30 for (j=0; j<10; j++) { 31 sqrtmat[i][j] = sqrt((float) i*i + j*j); 32 } 33 } 34 35 /* Initialize base locations on screen. These remain fixed. */ 36 for (i=0; i<NROW; i++) 37 for (j=0; j<NCOL; j++) { 38 base[NCOL*i+j].c = (GLCOL+GLPAD) * j + 1; 39 base[NCOL*i+j].r = SCRHI - (GLROW+GLPAD+10) * i - GLROW - 3; 40 } 41 42 setbuf(stdout, stoutbuf); 43 44 curzoom = 1; /* default is zoomed completely out */ 45 ttyinit(); 46 } 47 48 /* 49 * showfont: Wipe clean the screen, display the font 50 * in a properly spaced fashion, wait for a char to be typed, if it's 51 * p print the font, then clear the screen and ungetc the char. 52 */ 53 showfont() 54 { 55 register int i, cr, cc, nc; 56 int roff, coff; 57 char maxc, minc; 58 char nextcmd; 59 char tmpbuf[WINDSIZE]; 60 61 zoomout(); 62 message("Show font from <char>"); 63 minc = inchar(); 64 sprintf(msgbuf, "Show font from %s to <char>", rdchar(minc)); 65 message(msgbuf); 66 maxc = inchar(); 67 68 clearg(); 69 zermat(tmpbuf, GLROW, GLCOL); 70 cr = SCRHI-GLROW; cc = 3; 71 for (i=minc; i<=maxc; i++) { 72 if (disptable[i].nbytes) { 73 /* 74 * We really should try to find out how far to the 75 * left the glyph goes so we don't run off the left 76 * end of the screen, but this is hard, so we fake it. 77 * Usually glyphs don't run past the left so it's OK. 78 */ 79 if (cc - disptable[i].left < 0) 80 cc = disptable[i].left; 81 nc = cc + disptable[i].width; 82 if (nc >= SCRWID) { 83 cc = 0; 84 nc = disptable[i].width; 85 cr -= 85; /* Should be GLROW but 4*100>360 */ 86 if (cr < 0) 87 break; /* Screen full. Just stop. */ 88 } 89 dispmsg(rdchar(i), cc, cr, 2); 90 placechar(i, cr+BASELINE, cc, tmpbuf); 91 cc = nc; 92 } 93 } 94 for (;;) { 95 nextcmd = inchar(); 96 if (nextcmd != 'p') 97 break; 98 printg(); 99 } 100 if (nextcmd != 'Q' && nextcmd != 'E' && nextcmd != 'N') 101 redraw(); 102 else 103 clearg(); 104 ungetc(nextcmd, stdin); 105 } 106 107 /* 108 * typein: Like showfont but takes a line of text from the user 109 * and "typesets" it on the screen. 110 */ 111 typein() 112 { 113 register int i, cr, cc, nc; 114 char *p; 115 int roff, coff; 116 char maxc, minc; 117 char nextcmd; 118 char tmpbuf[WINDSIZE]; 119 char msgtype[100]; 120 121 zoomout(); 122 readline("Input line to be typeset: ", msgtype, sizeof msgtype); 123 124 clearg(); 125 zermat(tmpbuf, GLROW, GLCOL); 126 cr = SCRHI-GLROW; cc = 3; 127 for (p=msgtype; *p; p++) { 128 i = *p; 129 if (disptable[i].nbytes) { 130 if (cc - disptable[i].left < 0) 131 cc = disptable[i].left; 132 nc = cc + disptable[i].width; 133 if (nc >= SCRWID) { 134 cc = 0; 135 nc = disptable[i].width; 136 cr -= 85; /* Should be GLROW but 4*100>360 */ 137 if (cr < 0) 138 break; /* Screen full. Just stop. */ 139 } 140 dispmsg(rdchar(i), cc, cr, 2); 141 placechar(i, cr+BASELINE, cc, tmpbuf); 142 cc = nc; 143 } 144 } 145 for (;;) { 146 nextcmd = inchar(); 147 if (nextcmd != 'p') 148 break; 149 printg(); 150 } 151 if (nextcmd != 'Q' && nextcmd != 'E' && nextcmd != 'N') 152 redraw(); 153 else 154 clearg(); 155 ungetc(nextcmd, stdin); 156 } 157 158 /* 159 * placechar: draw the character ch at position (llr, llc) on the screen. 160 * Position means the logical center of the character. zero is a GLROW x GLCOL 161 * matrix of zeros which is needed for comparison, that is, we assume that 162 * the spot on the screen where this is going is blank, so the chars better 163 * not overlap. 164 */ 165 placechar(ch, llr, llc, zero) 166 int ch; 167 int llr, llc; 168 bitmat zero; 169 { 170 bitmat glbuf; 171 int roff, coff; 172 173 glbuf = findbits(ch, GLROW, GLCOL, 0, 0, &roff, &coff); 174 if (glbuf == NULL) 175 return; 176 if (trace) 177 fprintf(trace, "placechar('%s'), roff=%d, coff=%d, llr=%d, llc=%d, down=%d, left=%d, r=%d, c=%d\n", rdchar(ch), roff, coff, llr, llc, disptable[ch].down, disptable[ch].left, llr-disptable[ch].down, llc-disptable[ch].left); 178 179 update(zero, glbuf, GLROW, GLCOL, llr-GLROW+roff, llc-coff); 180 if (trace) 181 fprintf(trace, "placechar, free %x\n", glbuf); 182 free(glbuf); 183 } 184 185 /* 186 * redraw: The screen has gotten screwed up somehow. 187 * Assume nothing but make it look right. 188 */ 189 redraw() 190 { 191 register int i; 192 193 zoomout(); 194 clearg(); 195 turnofrb(); 196 for (i=0; i<NWIND; i++) 197 if (wind[i].onscreen != NULL) { 198 zermat(wind[i].onscreen, GLROW, GLCOL); 199 syncwind(i); 200 201 /* Print the char at the lower left of the window */ 202 sprintf(msgbuf, "%s", rdchar(wind[i].used)); 203 dispmsg(msgbuf, base[i].c, base[i].r-11, 2); 204 } 205 if (curwind >= 0) 206 drawbox(base[curwind].r-1, base[curwind].c-1, 1, GLROW+2, GLCOL+2); 207 } 208 209 /* 210 * findbits: find the data bits of glyph c, wherever they are, and make 211 * nr x nc bitmat and put them in it, shifted by horoff and vertoff. 212 */ 213 bitmat 214 findbits(c, nr, nc, horoff, vertoff, rcenter, ccenter) 215 int c; 216 int nr, nc; /* the size of the dest */ 217 int horoff, vertoff; 218 int *rcenter, *ccenter; 219 { 220 register int i, j; 221 register int r1, r2, c1, c2; 222 bitmat retval, source; 223 int tr, tc; /* the size of source */ 224 char tmp[WINDSIZE]; 225 226 if (trace) 227 fprintf(trace, "findbits(c=%s, nr=%d, nc=%d, horoff=%d, vertoff=%d\n", rdchar(c), nr, nc, horoff, vertoff); 228 if (disptable[c].nbytes == 0) 229 return (NULL); 230 switch (cht[c].wherewind) { 231 case -2: 232 if (trace) 233 fprintf(trace, "case -2, saved from prev place\n"); 234 /* Saved from previous place */ 235 source = cht[c].whereat; 236 237 /* Ignore horoff/vertoff assuming they are already right */ 238 *rcenter = cht[c].rcent; 239 *ccenter = cht[c].ccent; 240 /* 241 * Small but important optimization: if the desired result is 242 * a whole window and the source happens to be in a whole 243 * window, just return the source pointer. This saves 244 * lots of memory copies and happens quite often. 245 */ 246 if (nr == GLROW && nc == GLCOL) 247 return (source); 248 tr = GLROW; tc = GLCOL; 249 break; 250 case -1: 251 if (trace) 252 fprintf(trace, "case -1: first time\n"); 253 /* First time for this glyph: get it from font file */ 254 fseek(fontdes, (long) fbase+disptable[c].addr, 0); 255 tr = cht[c].nrow; tc = cht[c].ncol; 256 if (tr > GLROW || tc > GLCOL || disptable[c].nbytes > WINDSIZE) 257 error("glyph too large for window"); 258 *rcenter = vertoff + disptable[c].up; 259 *ccenter = horoff + disptable[c].left; 260 source = tmp; 261 fread(source, disptable[c].nbytes, 1, fontdes); 262 break; 263 default: 264 if (trace) 265 fprintf(trace, "case default, in window %d", cht[c].wherewind); 266 source = wind[cht[c].wherewind].val; 267 tr = GLROW; tc = GLCOL; 268 *rcenter = vertoff + cht[c].rcent; 269 *ccenter = horoff + cht[c].ccent; 270 break; 271 } 272 if (trace) 273 fprintf(trace, "curchar=%c=%d, tr=%d, tc=%d\n", curchar, curchar, tr, tc); 274 275 dumpmat("before copy, source", source, tr, tc); 276 /* Copy in the bits into a bitmat of the right size */ 277 retval = newmat(nr, nc); 278 r1 = max(0, -vertoff); 279 r2 = min(GLROW-vertoff-1, GLROW-1); 280 r2 = min(r2, tr-1); 281 c1 = max(0, -horoff); 282 c2 = min(GLCOL-horoff-1, GLCOL-1); 283 c2 = min(c2, tc-1); 284 if (trace) 285 fprintf(trace, "findbits copy: r1=%d, r2=%d, c1=%d, c2=%d, horoff=%d, vertoff=%d\n", r1, r2, c1, c2, horoff, vertoff); 286 for (i=r1; i<=r2; i++) { 287 for (j=c1; j<=c2; j++) 288 setmat(retval, nr, nc, i+vertoff, j+horoff, mat(source, tr, tc, i, j, 6)); 289 } 290 dumpmat("result of copy", retval, nr, nc); 291 return (retval); 292 } 293 294 /* 295 * bufmod: called just before a buffer modifying command. 296 * Makes a backup copy of the glyph so we can undo later. 297 */ 298 bufmod() 299 { 300 changes++; 301 if (curwind < 0) 302 return; 303 if (wind[curwind].undval == NULL) 304 wind[curwind].undval = newmat(GLROW, GLCOL); 305 bitcopy(wind[curwind].undval, wind[curwind].val, GLROW, GLCOL); 306 und_p_r = pen_r; und_p_c = pen_c; 307 und_c_r = curs_r; und_c_c = curs_c; 308 } 309 310 /* 311 * undo: restore the backup copy. We just swap pointers, which is 312 * the same as interchanging the two matrices. This way, undo is 313 * its own inverse. 314 */ 315 undo() 316 { 317 register bitmat tmp; 318 319 if (wind[curwind].undval == NULL) { 320 error("Nothing to undo"); 321 } 322 tmp = wind[curwind].val; 323 wind[curwind].val = wind[curwind].undval; 324 wind[curwind].undval = tmp; 325 pen_r = und_p_r; pen_c = und_p_c; 326 move(base[curwind].c+pen_c, base[curwind].r+GLROW-pen_r); 327 curs_r = und_c_r; curs_c = und_c_c; 328 syncwind(curwind); 329 changes++; 330 } 331 332 /* 333 * drawline: draw a line of current flavor between the named two points. 334 * All points are relative to current window. 335 * 336 * The algorithm is that of a simple DDA. This is similar to what the 337 * hardware of the HP 2648 does but the placing of the points will be 338 * different (because of thick pens and erasers). 339 */ 340 drawline(from_r, from_c, to_r, to_c) 341 { 342 int length, i; 343 float x, y, xinc, yinc; 344 345 if (trace) 346 fprintf(trace, "drawline from (%d, %d) to (%d, %d)\n", from_r, from_c, to_r, to_c); 347 length = max(abs(to_r-from_r), abs(to_c-from_c)); 348 if (length <= 0) { 349 /* 350 * The actual value doesn't matter, we're just avoiding 351 * division by zero here. 352 */ 353 xinc = yinc = 1.0; 354 } else { 355 xinc = ((float) (to_r-from_r))/length; 356 yinc = ((float) (to_c-from_c))/length; 357 } 358 drawpoint(from_r, from_c); 359 x = from_r + 0.5; y = from_c + 0.5; 360 361 for (i=0; i<length; i++) { 362 x += xinc; y += yinc; 363 drawpoint((int) x, (int) y); 364 } 365 } 366 367 /* 368 * drawpoint: make a point of the current flavor at (r, c). 369 */ 370 drawpoint(r, c) 371 register int r, c; 372 { 373 register int i, j; 374 375 if (penweight == 0) 376 setmat(wind[curwind].val, GLROW, GLCOL, r, c, pencolor); 377 else { 378 for (i=0; i<10; i++) 379 for (j=0; j<10; j++) 380 if (penmat[i][j]) 381 setmat(wind[curwind].val, GLROW, GLCOL, r+i-4, c+j-4, pencolor); 382 } 383 } 384 385 /* 386 * setcmd: handle the s command. Format: s <what> <where>. 387 */ 388 setcmd() 389 { 390 char what, where; 391 392 message("set <what>"); 393 what = inchar(); 394 switch (what) { 395 396 case 'p': /* set pen */ 397 message("set pen <weight>"); 398 where = inchar(); 399 switch (where) { 400 case 'f': /* set pen fine */ 401 case 'l': /* set pen light */ 402 message("set pen fine"); 403 penweight = 0; 404 break; 405 case 'h': /* set pen heavy */ 406 case 'b': /* set pen bold */ 407 message("set pen heavy"); 408 penweight = 1; 409 break; 410 default: 411 error("Illegal kind of pen weight"); 412 } 413 break; 414 415 case 's': /* set size of heavy pen */ 416 message("set pen size to <size>"); 417 where = inchar() - '0'; 418 sprintf(msgbuf, "set pen size to %d", where); 419 message(msgbuf); 420 if (where > 0 && where < 10) { 421 setpen(where); 422 } else 423 error("Illegal size"); 424 break; 425 426 case 'd': 427 message("set draw"); 428 pencolor = 1; 429 break; 430 431 case 'e': 432 message("set erase"); 433 pencolor = 0; 434 break; 435 436 default: 437 error("Illegal set"); 438 } 439 } 440 441 /* 442 * setpen: set the heavy pen size to s. 443 * Main work here is defining template of pen. 444 */ 445 setpen(s) 446 int s; 447 { 448 register int i, j; 449 register float radius; 450 451 if (s < 1) 452 s = 1; 453 hpensize = s; 454 radius = hpensize; 455 radius /= 2; 456 for (i=0; i<10; i++) { 457 for (j=0; j<10; j++) { 458 penmat[i][j] = (radius >= sqrtmat[abs(i-4)][abs(j-4)]); 459 } 460 } 461 462 /* 463 * Kludge to make a 2-wide pen possible by specifying 1. 464 */ 465 if (hpensize == 1) 466 penmat[4][5] = 1; 467 468 if (trace) 469 for (i=0; i<10; i++) { 470 for (j=0; j<10; j++) { 471 fprintf(trace, "%c", penmat[i][j] ? 'P' : '.'); 472 } 473 fprintf(trace, "\n"); 474 } 475 } 476 477 /* 478 * error: print the given error message and return for another command. 479 */ 480 error(msg) 481 char *msg; 482 { 483 message(msg); 484 longjmp(env); 485 } 486 487 /* 488 * copymove: do a move or copy command. 489 * cmd is C or M, the command. 490 */ 491 copymove(cmd) 492 char cmd; 493 { 494 char *action; 495 char src, dest; 496 bitmat cpy; 497 char lochr[5]; 498 499 if (cmd == 'C') 500 action = "copy"; 501 else 502 action = "move"; 503 sprintf(msgbuf, "%s <from>", action); 504 message(msgbuf); 505 src = inchar(); 506 sprintf(msgbuf, "%s %s to <to>", action, rdchar(src)); 507 message(msgbuf); 508 dest = inchar(); 509 strcpy(lochr, rdchar(src)); 510 sprintf(msgbuf, "%s %s to %s", action, lochr, rdchar(dest)); 511 message(msgbuf); 512 513 /* Do the copy */ 514 disptable[dest] = disptable[src]; 515 cht[dest] = cht[src]; 516 if (cht[dest].wherewind >= 0) 517 wind[cht[dest].wherewind].used = dest; 518 519 if (cmd == 'C') { 520 if (cht[dest].wherewind != -1) { 521 /* 522 * Make copies of the window so changing 523 * one won't change the other. 524 * The old copy gets the window on the screen, if any, 525 * relegating the new copy to the background. 526 */ 527 cpy = newmat(GLROW, GLCOL); 528 if (cht[dest].wherewind >= 0) 529 bitcopy(cpy, wind[cht[src].wherewind].val, GLROW, GLCOL); 530 else 531 bitcopy(cpy, cht[src].whereat, GLROW, GLCOL); 532 if (cht[dest].wherewind == curwind) 533 curwind = -1; 534 cht[dest].wherewind = -2; 535 cht[dest].whereat = cpy; 536 } 537 } else { 538 /* 539 * Move. Delete the old entries. 540 */ 541 disptable[src].addr = disptable[src].nbytes = 0; 542 cht[src].wherewind = -1; 543 } 544 changes++; 545 } 546 547 /* 548 * cch: make sure there is a current character. 549 */ 550 cch() 551 { 552 if (curwind < 0) 553 error("No current glyph"); 554 } 555 556 /* 557 * confirm: if there have been changes, ask user if he is sure. 558 */ 559 confirm() 560 { 561 char ch; 562 563 if (changes == 0) 564 return; 565 message("Changes since last write -- Are you sure?"); 566 ch = inchar(); 567 if (isupper(ch)) 568 ch = tolower(ch); 569 switch (ch) { 570 case 'y': 571 case 'q': 572 case 'e': 573 return; 574 case 'n': 575 default: 576 error("Not sure - aborted"); 577 } 578 } 579 580 /* 581 * delchar: the D command. Delete a character from the buffer. 582 */ 583 delchar() 584 { 585 register char c, c1, c2; 586 register int w; 587 char buf[5]; 588 589 message("delete <char>"); 590 c1 = inchar(); 591 sprintf(msgbuf, "delete %s through <char>", rdchar(c1)); 592 message(msgbuf); 593 c2 = inchar(); 594 strcpy(buf, rdchar(c1)); 595 sprintf(msgbuf, "delete %s through %s", buf, rdchar(c2)); 596 message(msgbuf); 597 changes++; 598 599 for (c=c1; c<=c2; c++) { 600 if ((w = cht[c].wherewind) >= 0) { 601 zermat(wind[w].val, GLROW, GLCOL); 602 syncwind(w); 603 } 604 cht[c].wherewind = -1; 605 disptable[c].addr = 0; 606 disptable[c].nbytes = 0; 607 disptable[c].up = 0; 608 disptable[c].down = 0; 609 disptable[c].left = 0; 610 disptable[c].right = 0; 611 disptable[c].width = 0; 612 } 613 } 614 615 /* 616 * zoom out to full screen so the screen doean't go nuts when we 617 * print off the current zoom window. Save old value of zoom in 618 * oldzoom so space can put us back. 619 */ 620 zoomout() 621 { 622 if (curzoom != 1) 623 zoomn(curzoom = 1); 624 } 625 626 /* 627 * newglyph: the n command. 628 */ 629 newglyph() 630 { 631 register int i, j; 632 int windno; 633 int vertoff, horoff; 634 char *tmp; 635 636 message("new glyph <char>"); 637 curchar = inchar(); 638 sprintf(msgbuf, "new glyph %s", rdchar(curchar)); 639 message(msgbuf); 640 641 if (trace) 642 fprintf(trace, "\n\nnewglyph(%s)\n", rdchar(curchar)); 643 if (disptable[curchar].nbytes != 0) { 644 if (trace) 645 fprintf(trace, "char exists: %s\n", rdchar(curchar)); 646 sprintf(msgbuf, "char exists: %s", rdchar(curchar)); 647 error(msgbuf); 648 } 649 650 turnofcurs(); 651 /* 652 * Not on screen. First find a suitable window, 653 * using round robin. 654 */ 655 windno = nextwind; 656 if (trace) 657 fprintf(trace, "chose window %d\n", windno); 658 if (++nextwind >= NWIND) 659 nextwind = 0; 660 #ifdef notdef 661 if (nextwind >= 3) 662 nextwind = 0; 663 #endif 664 wind[windno].used = curchar; 665 666 /* Put a box around the current window */ 667 if (windno != curwind) { 668 drawbox(base[curwind].r-1, base[curwind].c-1, 0, GLROW+2, GLCOL+2); 669 drawbox(base[windno].r-1, base[windno].c-1, 1, GLROW+2, GLCOL+2); 670 } 671 672 /* Print the char at the lower left of the window */ 673 sprintf(msgbuf, "%s", rdchar(curchar)); 674 dispmsg(msgbuf, base[windno].c, base[windno].r-11, 2); 675 676 /* Now make room in the window */ 677 if (wind[windno].onscreen == NULL) { 678 /* Brand new window, have to allocate space */ 679 wind[windno].onscreen = newmat(GLROW, GLCOL); 680 } else { 681 /* Save prev glyph for later */ 682 cht[wind[curchar].used].whereat = wind[windno].val; 683 cht[wind[curchar].used].wherewind = -2; 684 } 685 if (wind[windno].undval != NULL) { 686 if (trace) 687 fprintf(trace, "newglyph frees undo: %x\n", wind[windno].undval); 688 free(wind[windno].undval); 689 } 690 wind[windno].undval = NULL; 691 692 /* 693 * Vertical & horizontal offsets. Line up the baseline 694 * of the char at BASELINE from bottom, but center 695 * horizontally. 696 */ 697 wind[windno].val = newmat(GLROW, GLCOL); 698 699 curwind = windno; 700 cht[curchar].wherewind = windno; 701 cht[curchar].rcent = curs_r = GLROW - BASELINE; 702 cht[curchar].ccent = curs_c = GLCOL / 2; 703 704 #ifdef notdef 705 dumpmat("wind[windno].onscreen", wind[windno].onscreen, GLROW, GLCOL); 706 #endif 707 syncwind(windno); 708 709 /* 710 * Mung the zoom out to 1 and back. This is needed to 711 * re-center the glyph on the screen if zoomed in, otherwise 712 * if you move by one window it puts the cursor way over at 713 * the right with only half the window visible. 714 */ 715 if ((i = curzoom) > 1) { 716 zoomn(1); 717 zoomn(i); 718 } 719 } 720 721 /* 722 * numedit: change one of the numerical parameters. 723 */ 724 numedit() 725 { 726 short * sp = 0; 727 char * cp = 0; 728 char c, f; 729 char *fld; 730 short ovalue, nvalue; 731 char numb[20]; 732 733 message("number of <char>"); 734 c = inchar(); 735 sprintf(msgbuf, "number of %s <field>", rdchar(c)); 736 message(msgbuf); 737 f = inchar(); 738 739 switch (f) { 740 case 'a': sp = (short *) 741 &disptable[c].addr; fld = "addr"; break; 742 case 'n': sp = &disptable[c].nbytes; fld = "nbytes"; break; 743 case 'u': cp = &disptable[c].up; fld = "up"; break; 744 case 'd': cp = &disptable[c].down; fld = "down"; break; 745 case 'l': cp = &disptable[c].left; fld = "left"; break; 746 case 'r': cp = &disptable[c].right; fld = "right"; break; 747 case 'w': sp = &disptable[c].width; fld = "width"; break; 748 case 's': sp = (short *) &disptable[c].nbytes; 749 fld = "size"; break; 750 default: error("No such field"); 751 } 752 753 ovalue = sp ? *sp : *cp; 754 sprintf(msgbuf, "number of %s %s (old value %d) is ", rdchar(c), fld, ovalue); 755 readline(msgbuf, numb, sizeof numb); 756 nvalue = atoi(numb); 757 if (cp) 758 *cp = nvalue; 759 else 760 *sp = nvalue; 761 changes++; 762 } 763 764 /* 765 * These routines turn the cursor and rubber band line on and off, 766 * remembering its state for the o and r commands. 767 */ 768 turnoncurs() 769 { 770 curon(); 771 curcurs = 1; 772 } 773 774 turnofcurs() 775 { 776 curoff(); 777 curcurs = 0; 778 } 779 780 turnonrb() 781 { 782 rbon(); 783 currb = 1; 784 } 785 786 turnofrb() 787 { 788 rboff(); 789 currb = 0; 790 } 791 792 synccurs() 793 { 794 register int x, y; 795 796 x = base[curwind].c + curs_c; 797 y = base[curwind].r + GLROW - curs_r - 1; 798 movecurs(x, y); 799 } 800 801 inchar() 802 { 803 sync(); 804 synccurs(); 805 return (rawchar()); 806 } 807 808 /* 809 * fillin - fill in with 1's all the spots that are in the enclosed 810 * area that (x, y) is in. 811 */ 812 fillin(x, y) 813 int x, y; 814 { 815 if (x<0 || x>=GLROW || y<0 || y>=GLCOL || 816 mat(wind[curwind].val, GLROW, GLCOL, x, y)) 817 return; 818 819 setmat(wind[curwind].val, GLROW, GLCOL, x, y, 1); 820 fillin(x-1, y); 821 fillin(x+1, y); 822 fillin(x, y-1); 823 fillin(x, y+1); 824 } 825 826 /* 827 * syncwind: make sure that window #n shows on the screen what it's 828 * supposed to after an arbitrary change. 829 */ 830 syncwind(n) 831 int n; 832 { 833 if (trace) 834 fprintf(trace, "syncwind(%d)\n", n); 835 update(wind[n].onscreen, wind[n].val, GLROW, GLCOL, base[n].r, base[n].c); 836 bitcopy(wind[n].onscreen, wind[n].val, GLROW, GLCOL); 837 } 838 839 /* 840 * Embolden artificially emboldens the glyphs in the font by smearing 841 * them to the right by the current heavy pen size. Or else italicize it. 842 */ 843 artificial() 844 { 845 int low, high, cur; 846 int oldps, newps; 847 char lowch[10]; 848 #define ITAL 0 849 #define BOLD 1 850 #define RESIZE 2 851 #define SMOOTH 3 852 int kind; 853 char *strbold; 854 855 sprintf(msgbuf, "Artificially <embolden/italicize/resize/smooth>"); 856 message(msgbuf); 857 858 cur = inchar(); 859 switch(cur) { 860 case 'i': case 'I': kind = ITAL; strbold = "italicize"; break; 861 case 'e': case 'E': kind = BOLD; strbold = "embolden"; break; 862 case 'r': case 'R': kind = RESIZE; strbold = "resize"; break; 863 case 's': case 'S': kind = SMOOTH; strbold = "smooth"; break; 864 default: error("No such artificial operation"); 865 } 866 867 sprintf(msgbuf, "Artificially %s glyphs from <char>", strbold); 868 message(msgbuf); 869 low = inchar(); 870 strcpy(lowch, rdchar(low)); 871 sprintf(msgbuf, "Artificially %s glyphs from %s to <char>", strbold, lowch); 872 message(msgbuf); 873 high = inchar(); 874 if (kind == RESIZE) { 875 sprintf(msgbuf, "Artificially %s glyphs from %s to %s from <point size>", strbold, lowch, rdchar(high)); 876 oldps = readnum(msgbuf); 877 sprintf(msgbuf, "Artificially %s glyphs from %s to %s from %dP to <point size>P", strbold, lowch, rdchar(high), oldps); 878 newps = readnum(msgbuf); 879 sprintf(msgbuf, "Artificially %s glyphs from %s to %s from %dP to %dP", strbold, lowch, rdchar(high), oldps, newps); 880 message(msgbuf); 881 if (oldps <= 0 || oldps > 36 || newps <= 0 || newps > 36 || oldps == newps) 882 error("Bad point sizes"); 883 } else { 884 sprintf(msgbuf, "Artificially %s glyphs from %s to %s", strbold, lowch, rdchar(high)); 885 message(msgbuf); 886 } 887 888 for (cur=low; cur<=high; cur++) { 889 getglyph(cur); 890 if (curchar == cur) { /* e.g. if the getglyph succeeded */ 891 fflush(stdout); 892 switch (kind) { 893 case BOLD: 894 boldglyph(); 895 break; 896 case ITAL: 897 italglyph(); 898 break; 899 case RESIZE: 900 if (oldps > newps) 901 shrinkglyph(oldps, newps); 902 else 903 blowupglyph(oldps, newps); 904 break; 905 case SMOOTH: 906 smoothglyph(); 907 break; 908 } 909 syncwind(curwind); 910 } 911 } 912 message("Done"); 913 } 914 915 /* 916 * Artificially embolden the current glyph. 917 */ 918 boldglyph() 919 { 920 register int r, c, i; 921 int smear = hpensize < 2 ? 2 : hpensize; 922 923 for (r=0; r<GLROW; r++) 924 for (c=GLCOL-1; c>=smear; c--) 925 for (i=1; i<=smear; i++) 926 if (mat(wind[curwind].val, GLROW, GLCOL, r, c-i)) 927 setmat(wind[curwind].val, GLROW, GLCOL, r, c, 1); 928 } 929 930 /* 931 * Artificially italicize the current glyph. 932 */ 933 italglyph() 934 { 935 register int r, c, i, off; 936 int baser = cht[curchar].rcent; /* GLROW - BASELINE; */ 937 938 for (r=0; r<baser; r++) { 939 off = (baser-r) / SLOPE + 0.5; 940 for (c=GLCOL-1; c>=off; c--) { 941 setmat(wind[curwind].val, GLROW, GLCOL, r, c, 942 mat(wind[curwind].val, GLROW, GLCOL, r, c-off)); 943 } 944 for (c=off-1; c>=0; c--) 945 setmat(wind[curwind].val, GLROW, GLCOL, r, c, 0); 946 } 947 for (r=baser; r<GLROW; r++) { 948 off = (r-baser) * (2.0/7.0) + 0.5; 949 for (c=off; c<GLCOL; c++) 950 setmat(wind[curwind].val, GLROW, GLCOL, r, c-off, 951 mat(wind[curwind].val, GLROW, GLCOL, r, c)); 952 for (c=off-1; c>=0; c--) 953 setmat(wind[curwind].val, GLROW, GLCOL, r, c, 0); 954 } 955 } 956 957 /* 958 * Blow up or shrink a glyph from oldps points to newps points. 959 * The basic idea is that for each on point in the old glyph we 960 * find the corresponding point in the new glyph and copy the value. 961 */ 962 shrinkglyph(oldps, newps) 963 int oldps, newps; 964 { 965 float ratio; 966 register int or, oc, nr, nc; 967 int n; 968 bitmat tmp, curw; 969 int baser = cht[curchar].rcent; 970 int basec = cht[curchar].ccent; 971 972 ratio = (float) newps / (float) oldps; 973 tmp = newmat(GLROW, GLCOL); 974 curw = wind[curwind].val; 975 bitcopy(tmp, curw, GLROW, GLCOL); 976 zermat(curw, GLROW, GLCOL); 977 for (or=0; or<GLROW; or++) { 978 nr = baser + (or-baser)*ratio + 0.5; 979 for (oc=0; oc<GLCOL; oc++) { 980 nc = basec + (oc-basec)*ratio + 0.5; 981 if (nr < 0 || nr >= GLROW || nc < 0 || nc >= GLCOL) 982 n = 0; 983 else 984 n = mat(tmp, GLROW, GLCOL, or, oc); 985 if (n) 986 setmat(curw, GLROW, GLCOL, nr, nc, n); 987 } 988 } 989 disptable[curchar].width = disptable[curchar].width * ratio + 0.5; 990 free(tmp); 991 } 992 993 /* 994 * blow up a glyph. Otherwise like shrinkglyph. 995 */ 996 blowupglyph(oldps, newps) 997 int oldps, newps; 998 { 999 float ratio; 1000 register int or, oc, nr, nc; 1001 int n; 1002 bitmat tmp, curw; 1003 int baser = cht[curchar].rcent; 1004 int basec = cht[curchar].ccent; 1005 1006 ratio = (float) oldps / (float) newps; 1007 tmp = newmat(GLROW, GLCOL); 1008 curw = wind[curwind].val; 1009 bitcopy(tmp, curw, GLROW, GLCOL); 1010 zermat(curw, GLROW, GLCOL); 1011 for (nr=0; nr<GLROW; nr++) { 1012 or = baser + (nr-baser)*ratio + 0.5; 1013 for (nc=0; nc<GLCOL; nc++) { 1014 oc = basec + (nc-basec)*ratio + 0.5; 1015 if (or < 0 || or >= GLROW || oc < 0 || oc >= GLCOL) 1016 n = 0; 1017 else 1018 n = mat(tmp, GLROW, GLCOL, or, oc); 1019 if (n) 1020 setmat(curw, GLROW, GLCOL, nr, nc, n); 1021 } 1022 } 1023 disptable[curchar].width = disptable[curchar].width / ratio + 0.5; 1024 free(tmp); 1025 } 1026 1027 /* 1028 * Smooth a glyph. We look for corners and trim the point. Corners of 1029 * both blanks and dots in all 4 orientations are looked for. 1030 */ 1031 smoothglyph() 1032 { 1033 bitmat tmp, curw; 1034 register int r, c; 1035 register int c3; 1036 int a3, b2, b3, b4, c1, c2, c4, c5, d2, d3, d4, e3; 1037 1038 tmp = newmat(GLROW, GLCOL); 1039 curw = wind[curwind].val; 1040 bitcopy(tmp, curw, GLROW, GLCOL); 1041 for (r=2; r<GLROW-2; r++) 1042 for (c=2; c<GLCOL-2; c++) { 1043 /* 1044 * a3 1045 * b2 b3 b4 1046 * c1 c2 c3 c4 c5 1047 * d2 d3 d4 1048 * d4 1049 * where c3 is the square we are interested in 1050 */ 1051 b3 = mat(tmp, GLROW, GLCOL, r-1, c ); 1052 c2 = mat(tmp, GLROW, GLCOL, r , c-1); 1053 c4 = mat(tmp, GLROW, GLCOL, r , c+1); 1054 d3 = mat(tmp, GLROW, GLCOL, r+1, c ); 1055 /* exactly 2 of the 4 neighbors must be dots */ 1056 if (b3+c2+c4+d3 != 2) continue; 1057 1058 c3 = mat(tmp, GLROW, GLCOL, r , c ); 1059 b2 = mat(tmp, GLROW, GLCOL, r-1, c-1); 1060 b4 = mat(tmp, GLROW, GLCOL, r-1, c+1); 1061 d2 = mat(tmp, GLROW, GLCOL, r+1, c-1); 1062 d4 = mat(tmp, GLROW, GLCOL, r+1, c+1); 1063 /* exactly one of the 4 diags must match the center */ 1064 if (b2+b4+d2+d4 != 3 - 2*c3) continue; 1065 1066 a3 = mat(tmp, GLROW, GLCOL, r-2, c ); 1067 c1 = mat(tmp, GLROW, GLCOL, r , c-2); 1068 c5 = mat(tmp, GLROW, GLCOL, r , c+2); 1069 e3 = mat(tmp, GLROW, GLCOL, r+2, c ); 1070 1071 /* Figure out which of the 4 directions */ 1072 if (b2==c3) { 1073 if (b3+c2+c1+a3 != 4*c3) continue; 1074 } else 1075 if (b4==c3) { 1076 if (b3+c4+c5+a3 != 4*c3) continue; 1077 } else 1078 if (d2==c3) { 1079 if (d3+c2+c1+e3 != 4*c3) continue; 1080 } else 1081 if (d4==c3) { 1082 if (d3+c4+c5+e3 != 4*c3) continue; 1083 } 1084 1085 /* It must be a corner. Toggle it. */ 1086 setmat(curw, GLROW, GLCOL, r, c, !c3); 1087 } 1088 free(tmp); 1089 } 1090 1091 /* 1092 * Read a number from bottom line ala readline. 1093 * This should probably go in lib2648. 1094 */ 1095 int 1096 readnum(prompt) 1097 char *prompt; 1098 { 1099 char buf[10]; 1100 int retval; 1101 1102 readline(prompt, buf, sizeof buf); 1103 retval = atoi(buf); 1104 if (trace) 1105 fprintf(trace, "readline returns '%s', retval=%d\n", buf, retval); 1106 return (retval); 1107 } 1108 1109 invert() 1110 { 1111 register int r, c; 1112 int tmp1, tmp2, kind; 1113 bitmat curw = wind[curwind].val; 1114 1115 message("Invert <horizontally/vertically>"); 1116 kind = inchar(); 1117 switch (kind) { 1118 case 'h': case 'H': 1119 message("Invert horizontally"); 1120 for (r=0; r<GLROW; r++) { 1121 if (trace) 1122 fprintf(trace, "row %d\n", r); 1123 for (c=0; c<=(GLCOL-1)/2; c++) { 1124 tmp1 = mat(curw, GLROW, GLCOL, r, c); 1125 tmp2 = mat(curw, GLROW, GLCOL, r, GLCOL-1-c); 1126 if (trace) 1127 fprintf(trace, "cols %d (%d) <=> %d (%d)\n", c, tmp1, GLCOL-1-c, tmp2); 1128 setmat(curw, GLROW, GLCOL, r, c, tmp2); 1129 setmat(curw, GLROW, GLCOL, r, GLCOL-1-c, tmp1); 1130 } 1131 } 1132 break; 1133 case 'v': case 'V': 1134 message("Invert vertically"); 1135 for (c=0; c<GLCOL; c++) { 1136 for (r=0; r<=(GLROW-1)/2; r++) { 1137 tmp1 = mat(curw, GLROW, GLCOL, r, c); 1138 tmp2 = mat(curw, GLROW, GLCOL, GLROW-1-r, c); 1139 setmat(curw, GLROW, GLCOL, r, c, tmp2); 1140 setmat(curw, GLROW, GLCOL, GLROW-1-r, c, tmp1); 1141 } 1142 } 1143 break; 1144 default: 1145 error("Bad choice"); 1146 } 1147 syncwind(curwind); 1148 } 1149