|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)subr.c 4.2 (Berkeley) 8/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.