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 */
initialize()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 */
showfont()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 */
typein()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 */
placechar(ch,llr,llc,zero)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 */
redraw()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
findbits(c,nr,nc,horoff,vertoff,rcenter,ccenter)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 */
bufmod()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 */
undo()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 */
drawline(from_r,from_c,to_r,to_c)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 */
drawpoint(r,c)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 */
setcmd()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 */
setpen(s)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 */
error(msg)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 */
copymove(cmd)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 */
cch()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 */
confirm()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 */
delchar()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 */
zoomout()620 zoomout()
621 {
622 if (curzoom != 1)
623 zoomn(curzoom = 1);
624 }
625
626 /*
627 * newglyph: the n command.
628 */
newglyph()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 */
numedit()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 */
turnoncurs()768 turnoncurs()
769 {
770 curon();
771 curcurs = 1;
772 }
773
turnofcurs()774 turnofcurs()
775 {
776 curoff();
777 curcurs = 0;
778 }
779
turnonrb()780 turnonrb()
781 {
782 rbon();
783 currb = 1;
784 }
785
turnofrb()786 turnofrb()
787 {
788 rboff();
789 currb = 0;
790 }
791
synccurs()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
inchar()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 */
fillin(x,y)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 */
syncwind(n)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 */
artificial()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 */
boldglyph()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 */
italglyph()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 */
shrinkglyph(oldps,newps)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 */
blowupglyph(oldps,newps)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 */
smoothglyph()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
readnum(prompt)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
invert()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