Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <cursor.h>
5 #include <event.h>
6 #include <bio.h>
7 #include "proof.h"
9 int res;
10 int hpos;
11 int vpos;
12 int DIV = 11;
14 Point offset;
15 Point xyoffset = { 0,0 };
17 Rectangle view[MAXVIEW];
18 Rectangle bound[MAXVIEW]; /* extreme points */
19 int nview = 1;
21 int lastp; /* last page number we were on */
23 #define NPAGENUMS 200
24 struct pagenum {
25 int num;
26 long adr;
27 } pagenums[NPAGENUMS];
28 int npagenums;
30 int curfont, cursize;
32 char *getcmdstr(void);
34 static void initpage(void);
35 static void view_setup(int);
36 static Point scale(Point);
37 static void clearview(Rectangle);
38 static int addpage(int);
39 static void spline(Image *, int, Point *);
40 static int skipto(int, int);
41 static void wiggly(int);
42 static void devcntrl(void);
43 static void eatline(void);
44 static int getn(void);
45 static int botpage(int);
46 static void getstr(char *);
47 /*
48 static void getutf(char *);
49 */
51 #define Do screen->r.min
52 #define Dc screen->r.max
54 /* declarations and definitions of font stuff are in font.c and main.c */
56 static void
57 initpage(void)
58 {
59 int i;
61 view_setup(nview);
62 for (i = 0; i < nview-1; i++)
63 draw(screen, view[i], screen, nil, view[i+1].min);
64 clearview(view[nview-1]);
65 offset = view[nview-1].min;
66 vpos = 0;
67 }
69 static void
70 view_setup(int n)
71 {
72 int i, j, v, dx, dy, r, c;
74 switch (n) {
75 case 1: r = 1; c = 1; break;
76 case 2: r = 1; c = 2; break;
77 case 3: r = 1; c = 3; break;
78 case 4: r = 2; c = 2; break;
79 case 5: case 6: r = 2; c = 3; break;
80 case 7: case 8: case 9: r = 3; c = 3; break;
81 default: r = (n+2)/3; c = 3; break; /* finking out */
82 }
83 dx = (Dc.x - Do.x) / c;
84 dy = (Dc.y - Do.y) / r;
85 v = 0;
86 for (i = 0; i < r && v < n; i++)
87 for (j = 0; j < c && v < n; j++) {
88 view[v] = screen->r;
89 view[v].min.x = Do.x + j * dx;
90 view[v].max.x = Do.x + (j+1) * dx;
91 view[v].min.y = Do.y + i * dy;
92 view[v].max.y = Do.y + (i+1) * dy;
93 v++;
94 }
95 }
97 static void
98 clearview(Rectangle r)
99 {
100 draw(screen, r, display->white, nil, r.min);
103 int resized;
104 void eresized(int new)
106 /* this is called if we are resized */
107 if(new && getwindow(display, Refnone) < 0)
108 drawerror(display, "can't reattach to window");
109 initpage();
110 resized = 1;
113 static Point
114 scale(Point p)
116 p.x /= DIV;
117 p.y /= DIV;
118 return addpt(xyoffset, addpt(offset,p));
121 static int
122 addpage(int n)
124 int i;
126 for (i = 0; i < npagenums; i++)
127 if (n == pagenums[i].num)
128 return i;
129 if (npagenums < NPAGENUMS-1) {
130 pagenums[npagenums].num = n;
131 pagenums[npagenums].adr = offsetc();
132 npagenums++;
134 return npagenums;
137 void
138 readpage(void)
140 int c, i, a, alpha, phi;
141 static int first = 0;
142 int m, n, gonow = 1;
143 Rune r[32], t;
144 Point p,q,qq;
146 offset = screen->clipr.min;
147 esetcursor(&deadmouse);
148 while (gonow)
150 c = getc();
151 switch (c)
153 case -1:
154 esetcursor(0);
155 if (botpage(lastp+1)) {
156 initpage();
157 break;
159 exits(0);
160 case 'p': /* new page */
161 lastp = getn();
162 addpage(lastp);
163 if (first++ > 0) {
164 esetcursor(0);
165 botpage(lastp);
166 esetcursor(&deadmouse);
168 initpage();
169 break;
170 case '\n': /* when input is text */
171 case ' ':
172 case 0: /* occasional noise creeps in */
173 break;
174 case '0': case '1': case '2': case '3': case '4':
175 case '5': case '6': case '7': case '8': case '9':
176 /* two motion digits plus a character */
177 hpos += (c-'0')*10 + getc()-'0';
179 /* FALLS THROUGH */
180 case 'c': /* single ascii character */
181 r[0] = getrune();
182 r[1] = 0;
183 dochar(r);
184 break;
186 case 'C':
187 for(i=0; ; i++){
188 t = getrune();
189 if(isspace(t))
190 break;
191 r[i] = t;
193 r[i] = 0;
194 dochar(r);
195 break;
197 case 'N':
198 r[0] = getn();
199 r[1] = 0;
200 dochar(r);
201 break;
203 case 'D': /* draw function */
204 switch (getc())
206 case 'l': /* draw a line */
207 n = getn();
208 m = getn();
209 p = Pt(hpos,vpos);
210 q = addpt(p, Pt(n,m));
211 hpos += n;
212 vpos += m;
213 line(screen, scale(p), scale(q), 0, 0, 0, display->black, ZP);
214 break;
215 case 'c': /* circle */
216 /*nop*/
217 m = getn()/2;
218 p = Pt(hpos+m,vpos);
219 hpos += 2*m;
220 ellipse(screen, scale(p), m/DIV, m/DIV, 0, display->black, ZP);
221 /* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/
222 break;
223 case 'e': /* ellipse */
224 /*nop*/
225 m = getn()/2;
226 n = getn()/2;
227 p = Pt(hpos+m,vpos);
228 hpos += 2*m;
229 ellipse(screen, scale(p), m/DIV, n/DIV, 0, display->black, ZP);
230 break;
231 case 'a': /* arc */
232 p = scale(Pt(hpos,vpos));
233 n = getn();
234 m = getn();
235 hpos += n;
236 vpos += m;
237 q = scale(Pt(hpos,vpos));
238 n = getn();
239 m = getn();
240 hpos += n;
241 vpos += m;
242 qq = scale(Pt(hpos,vpos));
243 /*
244 * tricky: convert from 3-point clockwise to
245 * center, angle1, delta-angle counterclockwise.
246 */
247 a = hypot(qq.x-q.x, qq.y-q.y);
248 phi = atan2(q.y-p.y, p.x-q.x)*180./PI;
249 alpha = atan2(q.y-qq.y, qq.x-q.x)*180./PI - phi;
250 if(alpha < 0)
251 alpha += 360;
252 arc(screen, q, a, a, 0, display->black, ZP, phi, alpha);
253 break;
254 case '~': /* wiggly line */
255 wiggly(0);
256 break;
257 default:
258 break;
260 eatline();
261 break;
262 case 's':
263 n = getn(); /* ignore fractional sizes */
264 if (cursize == n)
265 break;
266 cursize = n;
267 if (cursize >= NFONT)
268 cursize = NFONT-1;
269 break;
270 case 'f':
271 curfont = getn();
272 break;
273 case 'H': /* absolute horizontal motion */
274 hpos = getn();
275 break;
276 case 'h': /* relative horizontal motion */
277 hpos += getn();
278 break;
279 case 'w': /* word space */
280 break;
281 case 'V':
282 vpos = getn();
283 break;
284 case 'v':
285 vpos += getn();
286 break;
287 case '#': /* comment */
288 case 'n': /* end of line */
289 eatline();
290 break;
291 case 'x': /* device control */
292 devcntrl();
293 break;
294 default:
295 fprint(2, "unknown input character %o %c at offset %lud\n", c, c, offsetc());
296 exits("bad char");
299 esetcursor(0);
302 static void
303 spline(Image *b, int n, Point *pp)
305 long w, t1, t2, t3, fac=1000;
306 int i, j, steps=10;
307 Point p, q;
309 for (i = n; i > 0; i--)
310 pp[i] = pp[i-1];
311 pp[n+1] = pp[n];
312 n += 2;
313 p = pp[0];
314 for(i = 0; i < n-2; i++)
316 for(j = 0; j < steps; j++)
318 w = fac * j / steps;
319 t1 = w * w / (2 * fac);
320 w = w - fac/2;
321 t2 = 3*fac/4 - w * w / fac;
322 w = w - fac/2;
323 t3 = w * w / (2*fac);
324 q.x = (t1*pp[i+2].x + t2*pp[i+1].x +
325 t3*pp[i].x + fac/2) / fac;
326 q.y = (t1*pp[i+2].y + t2*pp[i+1].y +
327 t3*pp[i].y + fac/2) / fac;
328 line(b, p, q, 0, 0, 0, display->black, ZP);
329 p = q;
334 /* Have to parse skipped pages, to find out what fonts are loaded. */
335 static int
336 skipto(int gotop, int curp)
338 char *p;
339 int i;
341 if (gotop == curp)
342 return 1;
343 for (i = 0; i < npagenums; i++)
344 if (pagenums[i].num == gotop) {
345 if (seekc(pagenums[i].adr) == Beof) {
346 fprint(2, "can't rewind input\n");
347 return 0;
349 return 1;
351 if (gotop <= curp) {
352 restart:
353 if (seekc(0) == Beof) {
354 fprint(2, "can't rewind input\n");
355 return 0;
358 for(;;){
359 p = rdlinec();
360 if (p == 0) {
361 if(gotop>curp){
362 gotop = curp;
363 goto restart;
365 return 0;
366 } else if (*p == 'p') {
367 lastp = curp = atoi(p+1);
368 addpage(lastp); /* maybe 1 too high */
369 if (curp>=gotop)
370 return 1;
375 static void
376 wiggly(int skip)
378 Point p[300];
379 int c,i,n;
380 for (n = 1; (c = getc()) != '\n' && c>=0; n++) {
381 ungetc();
382 p[n].x = getn();
383 p[n].y = getn();
385 p[0] = Pt(hpos, vpos);
386 for (i = 1; i < n; i++)
387 p[i] = addpt(p[i],p[i-1]);
388 hpos = p[n-1].x;
389 vpos = p[n-1].y;
390 for (i = 0; i < n; i++)
391 p[i] = scale(p[i]);
392 if (!skip)
393 spline(screen,n,p);
396 static void
397 devcntrl(void) /* interpret device control functions */
399 char str[80];
400 int n;
402 getstr(str);
403 switch (str[0]) { /* crude for now */
404 case 'i': /* initialize */
405 break;
406 case 'T': /* device name */
407 getstr(devname);
408 break;
409 case 't': /* trailer */
410 break;
411 case 'p': /* pause -- can restart */
412 break;
413 case 's': /* stop */
414 break;
415 case 'r': /* resolution assumed when prepared */
416 res=getn();
417 DIV = floor(.5 + res/(100.0*mag));
418 if (DIV < 1)
419 DIV = 1;
420 mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */
421 break;
422 case 'f': /* font used */
423 n = getn();
424 getstr(str);
425 loadfontname(n, str);
426 break;
427 /* these don't belong here... */
428 case 'H': /* char height */
429 break;
430 case 'S': /* slant */
431 break;
432 case 'X':
433 break;
435 eatline();
438 int
439 isspace(int c)
441 return c==' ' || c=='\t' || c=='\n';
444 static void
445 getstr(char *is)
447 uchar *s = (uchar *) is;
449 for (*s = getc(); isspace(*s); *s = getc())
451 for (; !isspace(*s); *++s = getc())
453 ungetc();
454 *s = 0;
457 #if 0
458 static void
459 getutf(char *s) /* get next utf char, as bytes */
461 int c, i;
463 for (i=0;;) {
464 c = getc();
465 if (c < 0)
466 return;
467 s[i++] = c;
469 if (fullrune(s, i)) {
470 s[i] = 0;
471 return;
475 #endif
477 static void
478 eatline(void)
480 int c;
482 while ((c=getc()) != '\n' && c >= 0)
486 static int
487 getn(void)
489 int n, c, sign;
491 while (c = getc())
492 if (!isspace(c))
493 break;
494 if(c == '-'){
495 sign = -1;
496 c = getc();
497 }else
498 sign = 1;
499 for (n = 0; '0'<=c && c<='9'; c = getc())
500 n = n*10 + c - '0';
501 while (c == ' ')
502 c = getc();
503 ungetc();
504 return(n*sign);
507 static int
508 botpage(int np) /* called at bottom of page np-1 == top of page np */
510 char *p;
511 int n;
513 while (p = getcmdstr()) {
514 if (*p == '\0')
515 return 0;
516 if (*p == 'q')
517 exits(p);
518 if (*p == 'c') /* nop */
519 continue;
520 if (*p == 'm') {
521 mag = atof(p+1);
522 if (mag <= .1 || mag >= 10)
523 mag = DEFMAG;
524 allfree(); /* zap fonts */
525 DIV = floor(.5 + res/(100.0*mag));
526 if (DIV < 1)
527 DIV = 1;
528 mag = res/(100.0*DIV);
529 return skipto(np-1, np); /* reprint the page */
531 if (*p == 'x') {
532 xyoffset.x += atoi(p+1)*100;
533 skipto(np-1, np);
534 return 1;
536 if (*p == 'y') {
537 xyoffset.y += atoi(p+1)*100;
538 skipto(np-1, np);
539 return 1;
541 if (*p == '/') { /* divide into n pieces */
542 nview = atoi(p+1);
543 if (nview < 1)
544 nview = 1;
545 else if (nview > MAXVIEW)
546 nview = MAXVIEW;
547 return skipto(np-1, np);
549 if (*p == 'p') {
550 if (p[1] == '\0'){ /* bare 'p' */
551 if(skipto(np-1, np))
552 return 1;
553 continue;
555 p++;
557 if ('0'<=*p && *p<='9') {
558 n = atoi(p);
559 if(skipto(n, np))
560 return 1;
561 continue;
563 if (*p == '-' || *p == '+') {
564 n = atoi(p);
565 if (n == 0)
566 n = *p == '-' ? -1 : 1;
567 if(skipto(np - 1 + n, np))
568 return 1;
569 continue;
571 if (*p == 'd') {
572 dbg = 1 - dbg;
573 continue;
576 fprint(2, "illegal; try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n");
578 return 0;