#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <draw.h>
#include <event.h>
#include <cursor.h>
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;
}
}
}