#include #include #include #include #include #include typedef struct Slide { char *cmd; char *arg; int linum; int nlines; char *lines[]; } Slide; enum { MenuNext = 0, MenuPrev, MenuExit, MenuN }; char *menuitems[] = { [MenuNext] = "Next Slide", [MenuPrev] = "Prev Slide", [MenuExit] = "Exit", nil }; Menu menu = { .item = menuitems }; int checkonly, lightmode, nslides, cslide, xm, ym; char *file, *contents, *offset, *tfname, *hfname; Image *bg,*fg,*tmp; Font *tfont, *hfont; Slide **slides; Point SPt(int x, int y) { return addpt(Pt(x, y), screen->r.min); } Rectangle SRect(int x0, int y0, int x1, int y1) { return rectaddpt(Rect(x0, y0, x1, y1), screen->r.min); } Point imagecenter(Image* img) { return divpt(addpt(img->r.min, img->r.max), 2); } double imageradius(Image* img) { Point dims; dims = divpt(subpt(img->r.max, img->r.min), 2); return 1.4 + sqrt(dims.x*dims.x + dims.y*dims.y); } char * nextline(char **p, int *linum) { char *line; for(;;){ (*linum)++; line = *p; while(**p != '\n' && **p != '\0') (*p)++; if(**p == '\0') return nil; **p = '\0'; (*p)++; return line; } } Slide * nextslide(char **p, int *linum) { char *cmd, *arg, *line1, *line, *lineN; int nlines, blines, i, slinum; Slide *s; for(;;){ if((cmd = nextline(p, linum)) == nil) return nil; if(cmd[0] != '%') continue; break; } slinum = *linum; cmd++; arg = cmd; while(*arg != ' ' && *arg != '\t' && *arg != '\0') arg++; if(*arg == '\0') arg = nil; else{ *(arg++) = '\0'; while(*arg == ' ' && *arg == '\t' && *arg != '\0') arg++; if(*arg == '\0') arg = nil; } line1 = nextline(p, linum); if(line1 != nil && *line1 == '%'){ *p = line1; line1[strlen(line1)] = '\n'; line1 = nil; } if(line1 == nil){ s = malloc(sizeof(Slide)); s->cmd = cmd; s->arg = arg; s->linum = slinum; s->nlines = 0; return s; } lineN = line1; nlines = 1; blines = 0; while((line = nextline(p, linum)) != nil){ if(*line == '\0'){ blines++; continue; } if(*line == '%'){ *p = line; line[strlen(line)] = '\n'; break; } nlines += blines; blines = 0; nlines++; lineN = line; } s = malloc(sizeof(Slide) + sizeof(char*) * nlines); s->cmd = cmd; s->arg = arg; s->linum = slinum; s->nlines = nlines; line = line1; for(i = 0; line != lineN; i++){ s->lines[i] = line; line += strlen(line) + 1; } s->lines[i] = lineN; return s; } #pragma varargck argpos checkerr 2 void checkerr(Slide *s, char *msg, ...) { va_list args; va_start(args, msg); fprint(2,"%s:%d: %s: ", file, s->linum, s->cmd); vfprint(2,msg, args); fprint(2,"\n"); } void checkfile(void) { int waserr, linum; char *c2, *p; Slide *s; waserr = 0; linum = 0; c2 = strdup(contents); p = c2; while((s = nextslide(&p, &linum)) != nil){ nslides++; if(strcmp(s->cmd, "") == 0){ nslides--; continue; }else if(strcmp(s->cmd, "bullet") == 0) continue; else if(strcmp(s->cmd, "blank") == 0) continue; else if(strcmp(s->cmd, "text") == 0) continue; else if(strcmp(s->cmd, "title") == 0){ if(s->arg == nil){ waserr = 1; checkerr(s, "missing arg"); } }else{ waserr = 1; checkerr(s, "unknown cmd"); } } if(waserr) exits("checkfile"); } void render(void) { int i, voff, height, width; Point p, center, prog0, prog1, smin, smax; const Slide *s; if(cslide < 0) cslide = 0; else if(cslide >= nslides) cslide = nslides -1; s = slides[cslide]; center = imagecenter(screen); smin = screen->r.min; smax = screen->r.max; draw(screen, screen->r, bg, nil, SPt(0, 0)); prog0 = Pt(smin.x, smax.y); prog1 = Pt(smin.x + cslide + (smax.x - smin.x) / (nslides - 1) * cslide, smax.y); if(cslide != 0) line(screen, prog0, prog1, Endsquare, Enddisc, 5, fg, Pt(0,0)); if(strcmp(s->cmd, "text") == 0){ voff = ym; if(s->arg != nil){ string(screen, SPt(xm, ym), fg, Pt(0, 0), hfont, s->arg); voff += hfont->height; }else voff = xm; for(i = 0; i < s->nlines; i++){ string(screen, SPt(xm + 10, voff), fg, Pt(0, 0), tfont, s->lines[i]); voff += tfont->height; } }else if(strcmp(s->cmd, "title") == 0){ height = hfont->height + tfont->height * s->nlines; voff = center.y - (height / 2); p = string(screen, smax, fg, Pt(0,0), hfont, s->arg); width = p.x - smax.x; string(screen, Pt(center.x - (width / 2), voff), fg, Pt(0,0), hfont, s->arg); voff += hfont->height; for(i = 0; i < s->nlines; i++){ p = string(screen, smax, fg, Pt(0,0), tfont, s->lines[i]); width = p.x - smax.x; string(screen, Pt(center.x - (width / 2), voff), fg, Pt(0,0), tfont, s->lines[i]); voff += tfont->height; } } } void eresized(int new) { if(new && getwindow(display, Refnone) < 0) fprint(2,"can't reattach to window\n"); render(); } void usage(void) { fprint(2,"usage: %s [ -cl ] [ -x xmargin ] [ -y ymargin ] [ -f textfont ] [ -h headerfont ] filename\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { int etype, fd, i, linum; char slabel[32]; Event e; Mouse m, lastm; Dir *d; xm = 50; ym = 10; tfname = "/n/ttf/lucida.ttf.32/font"; hfname = "/n/ttf/lucida.ttf.80/font"; ARGBEGIN{ case 'c': checkonly = 1; break; case 'l': lightmode = 1; break; case 'f': tfname = EARGF(usage()); break; case 'h': hfname = EARGF(usage()); break; case 'x': xm = atoi(EARGF(usage())); break; case 'y': ym = atoi(EARGF(usage())); break; default: usage(); }ARGEND if(argc != 1) usage(); file = argv[0]; if((fd = open(file, OREAD)) < 0) sysfatal("%r"); if((d = dirfstat(fd)) == nil) sysfatal("%r"); contents = malloc(d->length + 2); if(readn(fd, contents, d->length) < 0) sysfatal("%r"); // cursed but makes the handling nicer above contents[d->length] = '\n'; contents[d->length + 1] = '\0'; offset = contents; snprintf(slabel, sizeof(slabel), "%s %s", argv0, d->name); free(d); close(fd); checkfile(); if(checkonly) exits(nil); slides = malloc(nslides*sizeof(Slide*)); for(i = 0; i < nslides; i++){ slides[i] = nextslide(&offset, &linum); if(*slides[i]->cmd == '\0') i--; } if(initdraw(nil, nil, slabel) < 0) sysfatal("initdraw: %r"); bg = allocimage(display, Rect(0,0, 1,1), RGB16, 1, DBlack); if(bg == nil) sysfatal("couldn't allocimage!"); fg = allocimage(display, Rect(0,0, 1,1), RGB16, 1, DWhite); if(fg == nil) sysfatal("couldn't allocimage!"); if(lightmode){ tmp = fg; fg = bg; bg = tmp; } if(strncmp(tfname, "/n/ttf", 6) == 0 || strncmp(tfname, "/n/ttf", 6) == 0){ if(fork() == 0) execl("/bin/truetypefs", "truetypefs", nil); else sleep(200); } tfont = openfont(display, tfname); if(tfont == nil) sysfatal("couldn't open font '%s'", tfname); hfont = openfont(display, hfname); if(hfont == nil) sysfatal("couldn't open font '%s'", hfname); einit(Emouse); for(;;){ render(); etype = event(&e); if(etype == Emouse){ m = e.mouse; if(m.buttons & 1 && !(lastm.buttons & 1)) cslide--; if(m.buttons & 4 && !(lastm.buttons & 4)) cslide++; menu.lasthit = -1; if(m.buttons & 2) emenuhit(2, &m, &menu); switch(menu.lasthit){ case MenuNext: cslide++; break; case MenuPrev: cslide--; break; case MenuExit: exits(nil); break; } lastm = m; } } }