Esempio n. 1
0
/*
 * menur is a rectangle holding all the highlightable text elements.
 * track mouse while inside the box, return what's selected when button
 * is raised, -1 as soon as it leaves box.
 * invariant: nothing is highlighted on entry or exit.
 */
static int
menuscan(Menu *menu, int but, Mouse *m, Rectangle textr, int off, int lasti, Image *save)
{
	int i;

	paintitem(menu, textr, off, lasti, 1, save, nil);
	flushimage(display, 1);	/* in case display->locking is set */
	*m = emouse();
	while(m->buttons & (1<<(but-1))){
		flushimage(display, 1);	/* in case display->locking is set */
		*m = emouse();
		i = menusel(textr, m->xy);
		if(i != -1 && i == lasti)
			continue;
		paintitem(menu, textr, off, lasti, 0, nil, save);
		if(i == -1)
			return i;
		lasti = i;
		paintitem(menu, textr, off, lasti, 1, save, nil);
	}
	return lasti;
}
Esempio n. 2
0
/*
 * menur is a rectangle holding all the highlightable text elements.
 * track mouse while inside the box, return what's selected when button
 * is raised, -1 as soon as it leaves box.
 * invariant: nothing is highlighted on entry or exit.
 */
static int
menuscan(int but, Mouse *m, Rectangle menur, int lasti)
{
    int i;
    Rectangle r;

    r = menurect(menur, lasti);
    bitblt(&screen, r.min, &screen, r, F&~D);
    *m = emouse();
    while(m->buttons & (1<<(but-1))){
        *m = emouse();
        i = menusel(menur, m->xy);
        if(i == lasti)
            continue;
        bitblt(&screen, r.min, &screen, r, F&~D);
        if(i == -1)
            return i;
        r = menurect(menur, i);
        bitblt(&screen, r.min, &screen, r, F&~D);
        lasti = i;
    }
    return lasti;
}
Esempio n. 3
0
void main(void){
	Panel *g;
	binit(0,0,0);
	einit(Emouse);
	plinit(screen.ldepth);
	root=plgroup(0, 0);
	g=plgroup(root, PACKN|EXPAND);
	list=pllist(g, PACKE|EXPAND, genlist, 8, hitgen);
	plscroll(list, 0, plscrollbar(g, PACKW));
	msg=pllabel(root, PACKN|FILLX, "");
	plbutton(root, PACKW, "save", save);
	plbutton(root, PACKW, "revert", revert);
	plbutton(root, PACKE, "done", done);
	ereshaped(screen.r);
	for(;;) plmouse(root, emouse(), &screen);
}
Esempio n. 4
0
void qball(Rectangle r, Mouse *m, Quaternion *result, void (*redraw)(void), Quaternion *ap){
	Quaternion q, down;
	Point rad;
	axis=ap;
	ctlcen=divpt(addpt(r.min, r.max), 2);
	rad=divpt(subpt(r.max, r.min), 2);
	ctlrad=(rad.x<rad.y?rad.x:rad.y)-BORDER;
	down=qinv(mouseq(m->xy));
	q=*result;
	for(;;){
		*m=emouse();
		if(!m->buttons) break;
		*result=qmul(q, qmul(down, mouseq(m->xy)));
		(*redraw)();
	}
}
Esempio n. 5
0
File: life.c Progetto: npe9/harvey
void
idle(void)
{
	int c;

	while (ecanmouse())
		emouse();			/* throw away mouse events */
	while (ecankbd()){
		c = ekbd();
		if (c  == 'q' || c == 0177) /* watch keyboard ones */
			exits(nil);
		if (c >= '1' && c <= '9')
			delay = (c - '0') * 100;
		else if (c == '0')
			delay = 1000;
	}
	if (needresize)
		reshape();
}
Esempio n. 6
0
int waitup(void)
{
	while (mouse.buttons & 7)
		mouse = emouse();
	return mouse.buttons & 7;
}
Esempio n. 7
0
int waitdown(void)	/* wait until some button is down */
{
	while (!(mouse.buttons & 7))
		mouse = emouse();
	return mouse.buttons & 7;
}
Esempio n. 8
0
int
menuhit(int but, Mouse *m, Menu *menu)
{
    int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem;
    bool scrolling;
    Rectangle r, menur, sc, textr, scrollr;
    Bitmap *b;
    Point pt;
    char *item;
    extern unsigned int cursor;
    unsigned int oldcursor = cursor;

    cursorswitch(ArrowCursor);
    sc = screen.clipr;
    clipr(&screen, screen.r);
    maxwid = 0;
    for(nitem = 0;
        (item = menu->item? menu->item[nitem] : (*menu->gen)(nitem));
        nitem++){
        i = strwidth(font, item);
        if(i > maxwid)
            maxwid = i;
    }
    if(menu->lasthit<0 || menu->lasthit>=nitem)
        menu->lasthit = 0;
    screenitem = (Dy(screen.r)-10)/(fontheight()+Vspacing);
    if(nitem>Maxunscroll || nitem>screenitem){
        scrolling = true;
        nitemdrawn = Nscroll;
        if(nitemdrawn > screenitem)
            nitemdrawn = screenitem;
        wid = maxwid + Gap + Scrollwid;
        off = menu->lasthit - nitemdrawn/2;
        if(off < 0)
            off = 0;
        if(off > nitem-nitemdrawn)
            off = nitem-nitemdrawn;
        lasti = menu->lasthit-off;
    }else{
        scrolling = false;
        nitemdrawn = nitem;
        wid = maxwid;
        off = 0;
        lasti = menu->lasthit;
    }
    r = inset(Rect(0, 0, wid, nitemdrawn*(fontheight()+Vspacing)), -Margin);
    r = rsubp(r, Pt(wid/2, lasti*(fontheight()+Vspacing)+fontheight()/2));
    r = raddp(r, m->xy);
    pt = Pt(0, 0);
    if(r.max.x>screen.r.max.x)
        pt.x = screen.r.max.x-r.max.x;
    if(r.max.y>screen.r.max.y)
        pt.y = screen.r.max.y-r.max.y;
    if(r.min.x<screen.r.min.x)
        pt.x = screen.r.min.x-r.min.x;
    if(r.min.y<screen.r.min.y)
        pt.y = screen.r.min.y-r.min.y;
    menur = raddp(r, pt);
    textr.max.x = menur.max.x-Margin;
    textr.min.x = textr.max.x-maxwid;
    textr.min.y = menur.min.y+Margin;
    textr.max.y = textr.min.y + nitemdrawn*(fontheight()+Vspacing);
    if(scrolling){
        scrollr = inset(menur, Border);
        scrollr.max.x = scrollr.min.x+Scrollwid;
    }else
        scrollr = Rect(0, 0, 0, 0);

    b = balloc(menur, screen.ldepth);
    if(b == 0)
        b = &screen;
    bitblt(b, menur.min, &screen, menur, S);
    bitblt(&screen, menur.min, &screen, menur, 0);
    border(&screen, menur, Blackborder, F, _bgpixel);
    r = menurect(textr, lasti);
    cursorset(divpt(add(r.min, r.max), 2));
    menupaint(menu, textr, off, nitemdrawn);
    if(scrolling)
        menuscrollpaint(scrollr, off, nitem, nitemdrawn);
    r = menurect(textr, lasti);
    cursorset(divpt(add(r.min, r.max), 2));
    menupaint(menu, textr, off, nitemdrawn);
    if(scrolling)
        menuscrollpaint(scrollr, off, nitem, nitemdrawn);
    while(m->buttons & (1<<(but-1))){
        lasti = menuscan(but, m, textr, lasti);
        if(lasti >= 0)
            break;
        while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){
            if(scrolling && ptinrect(m->xy, scrollr)){
                noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr);
                noff -= nitemdrawn/2;
                if(noff < 0)
                    noff = 0;
                if(noff > nitem-nitemdrawn)
                    noff = nitem-nitemdrawn;
                if(noff != off){
                    off = noff;
                    menupaint(menu, textr, off, nitemdrawn);
                    menuscrollpaint(scrollr, off, nitem, nitemdrawn);
                }
            }
            *m = emouse();
        }
    }
    bitblt(&screen, menur.min, b, menur, S);
    if(b != &screen)
        bfree(b);
    clipr(&screen, sc);
    if(lasti >= 0){
        menu->lasthit = lasti+off;
        return cursorswitch(oldcursor), menu->lasthit;
    }
    cursorswitch(oldcursor);
    return -1;
}
Esempio n. 9
0
void
buttons(int ud)
{
	while((mouse.buttons==0) != ud)
		mouse = emouse();
}
Esempio n. 10
0
File: io.c Progetto: pocket7878/sam
void
frgetmouse(void)
{
    mouse = emouse();
}
Esempio n. 11
0
void
main(int argc, char *argv[])
{
	Mouse m;
	int i, j;
	unsigned short ran, score, attempt, prev, br[2];
	Image *c[2];
	char *fmt;

	level = 16;
	fmt = "win in %d attempts!";

	ARGBEGIN{
	default:
		goto Usage;
	case 'h':
		level=36;
		break;
	}ARGEND

	if(argc){
    Usage:
		fprint(2, "usage: %s [-h]\n", argv0);
		exits("usage");
	}
	if(initdraw(0,0,"memo") < 0)
		sysfatal("initdraw failed: %r");
	srand(time(0));
	memoinit();
	einit(Emouse);

    Start:
	afaces();
	winflag=0;
	prev=level+1;
	score=attempt=0;
	for(i=0;i!=level;i++)
		block[i].flag = Eninit;

	for(i=0;i!=level/2;i++){
		for(j=0;j!=2;){
			ran = rand()%level;
			if(block[ran].flag == Eninit){
				block[ran].face = face[i];
				block[ran].flag = Eshow;
				j++;
			}
		}
	}
	eresized(0);
	for(;;m=emouse())
		if(m.buttons)
			break;

	for(i=0;i!=level;i++)
		block[i].flag = Ehide;

	redraw();
	j = 0;
	for(;; m=emouse()){
		switch(m.buttons){
		case 1:
			while(m.buttons){
				for(i=0;i!=level;i++){
					if(i!=prev && ptinrect(m.xy,block[i].r)){
						if(block[i].flag==Ehide  && j<2){
							block[i].flag = Eshow;
							draw(screen, block[i].r, block[i].face, nil, ZP);
							c[j] = block[i].face;
							br[j] = prev = i;
							j++;
						}
						break;
					}
				}
				m=emouse();
			}
			break;
		case 4:
			switch(emenuhit(3, &m, &menu)) {
			case 0:	/* restart */
				goto Start;
				break;
			case 1:
				level=16;
				goto Start;
				break;
			case 2:
				level=36;
				goto Start;
				break;
			case 3:
				exits(0);
				break;
			}
		}
		if(j==2){
			attempt++;
			prev = level+1;
			j = 0;
			if(c[0] == c[1]){
				score++;
				block[br[0]].flag = Edisc;
				block[br[1]].flag = Edisc;
			} else{
				block[br[0]].flag = Ehide;
				block[br[1]].flag = Ehide;
			}
			redraw();
			continue;
		}
		if(score == level/2){
			winflag = 1;
			sprint(buf, fmt, attempt);
			redraw();
			for(;;m=emouse())
				if(m.buttons&1 || m.buttons&4)
					break;
			goto Start;
		}
	}
}
Esempio n. 12
0
int
emenuhit(int but, Mouse *m, Menu *menu)
{
	int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem;
	int scrolling;
	Rectangle r, menur, sc, textr, scrollr;
	Image *b, *save;
	Point pt;
	char *item;

	if(back == nil)
		menucolors();
	sc = screen->clipr;
	replclipr(screen, 0, screen->r);
	maxwid = 0;
	for(nitem = 0;
	    item = menu->item? menu->item[nitem] : (*menu->gen)(nitem);
	    nitem++){
		i = stringwidth(font, item);
		if(i > maxwid)
			maxwid = i;
	}
	if(menu->lasthit<0 || menu->lasthit>=nitem)
		menu->lasthit = 0;
	screenitem = (Dy(screen->r)-10)/(font->height+Vspacing);
	if(nitem>Maxunscroll || nitem>screenitem){
		scrolling = 1;
		nitemdrawn = Nscroll;
		if(nitemdrawn > screenitem)
			nitemdrawn = screenitem;
		wid = maxwid + Gap + Scrollwid;
		off = menu->lasthit - nitemdrawn/2;
		if(off < 0)
			off = 0;
		if(off > nitem-nitemdrawn)
			off = nitem-nitemdrawn;
		lasti = menu->lasthit-off;
	}else{
		scrolling = 0;
		nitemdrawn = nitem;
		wid = maxwid;
		off = 0;
		lasti = menu->lasthit;
	}
	r = insetrect(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin);
	r = rectsubpt(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2));
	r = rectaddpt(r, m->xy);
	pt = ZP;
	if(r.max.x>screen->r.max.x)
		pt.x = screen->r.max.x-r.max.x;
	if(r.max.y>screen->r.max.y)
		pt.y = screen->r.max.y-r.max.y;
	if(r.min.x<screen->r.min.x)
		pt.x = screen->r.min.x-r.min.x;
	if(r.min.y<screen->r.min.y)
		pt.y = screen->r.min.y-r.min.y;
	menur = rectaddpt(r, pt);
	textr.max.x = menur.max.x-Margin;
	textr.min.x = textr.max.x-maxwid;
	textr.min.y = menur.min.y+Margin;
	textr.max.y = textr.min.y + nitemdrawn*(font->height+Vspacing);
	if(scrolling){
		scrollr = insetrect(menur, Border);
		scrollr.max.x = scrollr.min.x+Scrollwid;
	}else
		scrollr = Rect(0, 0, 0, 0);

	b = allocimage(display, menur, screen->chan, 0, 0);
	if(b == 0)
		b = screen;
	draw(b, menur, screen, nil, menur.min);
	draw(screen, menur, back, nil, ZP);
	border(screen, menur, Blackborder, bord, ZP);
	save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1);
	r = menurect(textr, lasti);
	emoveto(divpt(addpt(r.min, r.max), 2));
	menupaint(menu, textr, off, nitemdrawn);
	if(scrolling)
		menuscrollpaint(scrollr, off, nitem, nitemdrawn);
	while(m->buttons & (1<<(but-1))){
		lasti = menuscan(menu, but, m, textr, off, lasti, save);
		if(lasti >= 0)
			break;
		while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){
			if(scrolling && ptinrect(m->xy, scrollr)){
				noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr);
				noff -= nitemdrawn/2;
				if(noff < 0)
					noff = 0;
				if(noff > nitem-nitemdrawn)
					noff = nitem-nitemdrawn;
				if(noff != off){
					off = noff;
					menupaint(menu, textr, off, nitemdrawn);
					menuscrollpaint(scrollr, off, nitem, nitemdrawn);
				}
			}
			flushimage(display, 1);	/* in case display->locking is set */
			*m = emouse();
		}
	}
	draw(screen, menur, b, nil, menur.min);
	if(b != screen)
		freeimage(b);
	freeimage(save);
	replclipr(screen, 0, sc);
	flushimage(display, 1);
	if(lasti >= 0){
		menu->lasthit = lasti+off;
		return menu->lasthit;
	}
	return -1;
}
Esempio n. 13
0
void
viewer(Document *dd)
{
	int i, fd, n, oldpage;
	int nxt;
	Menu menu, midmenu;
	Mouse m;
	Event e;
	Point dxy, oxy, xy0;
	Image *tmp;

	static char *fwditems[] = { "this page", "next page", "exit", 0 };
 	static char *miditems[] = {
 		"orig size",
 		"zoom in",
 		"fit window",
 		"rotate 90",
 		"upside down",
 		"",
 		"next",
 		"prev",
		"zerox",
 		"",
 		"reverse",
 		"discard",
 		"write",
 		"",
 		"quit",
 		0
 	};
	char *s;
	enum { Eplumb = 4 };
	Plumbmsg *pm;

	doc = dd;    /* save global for menuhit */
	ul = screen->r.min;
	einit(Emouse|Ekeyboard);
	if(doc->addpage != nil)
		eplumb(Eplumb, "image");

	esetcursor(&reading);

	/*
	 * im is a global pointer to the current image.
	 * eventually, i think we will have a layer between
	 * the display routines and the ps/pdf/whatever routines
	 * to perhaps cache and handle images of different
	 * sizes, etc.
	 */
	im = 0;
	page = reverse ? doc->npage-1 : 0;

	if(doc->fwdonly) {
		menu.item = fwditems;
		menu.gen = 0;
		menu.lasthit = 0;
	} else {
		menu.item = 0;
		menu.gen = menugen;
		menu.lasthit = 0;
	}

	midmenu.item = miditems;
	midmenu.gen = 0;
	midmenu.lasthit = Next;

	if(doc->docname != nil)
		setlabel(doc->docname);
	showpage(page, &menu);
	esetcursor(nil);

	nxt = 0;
	for(;;) {
		/*
		 * throughout, if doc->fwdonly is set, we restrict the functionality
		 * a fair amount.  we don't care about doc->npage anymore, and
		 * all that can be done is select the next page.
		 */
		unlockdisplay(display);
		i = eread(Emouse|Ekeyboard|Eplumb, &e);
		lockdisplay(display);
		switch(i){
		case Ekeyboard:
			if(e.kbdc <= 0xFF && isdigit(e.kbdc)) {
				nxt = nxt*10+e.kbdc-'0';
				break;
			} else if(e.kbdc != '\n')
				nxt = 0;
			switch(e.kbdc) {
			case 'r':	/* reverse page order */
				if(doc->fwdonly)
					break;
				reverse = !reverse;
				menu.lasthit = doc->npage-1-menu.lasthit;

				/*
				 * the theory is that if we are reversing the
				 * document order and are on the first or last
				 * page then we're just starting and really want
		 	 	 * to view the other end.  maybe the if
				 * should be dropped and this should happen always.
				 */
				if(page == 0 || page == doc->npage-1) {
					page = doc->npage-1-page;
					showpage(page, &menu);
				}
				break;
			case 'w':	/* write bitmap of current screen */
				esetcursor(&reading);
				s = writebitmap();
				if(s)
					string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
						display->defaultfont, s);
				esetcursor(nil);
				flushimage(display, 1);
				break;
			case 'd':	/* remove image from working set */
				if(doc->rmpage && page < doc->npage) {
					if(doc->rmpage(doc, page) >= 0) {
						if(doc->npage < 0)
							wexits(0);
						if(page >= doc->npage)
							page = doc->npage-1;
						showpage(page, &menu);
					}
				}
				break;
			case 'q':
			case 0x04: /* ctrl-d */
				wexits(0);
			case 'u':
				if(im==nil)
					break;
				angle = (angle+180) % 360;
				showpage(page, &menu);
				break;
			case '-':
			case '\b':
			case Kleft:
				if(page > 0 && !doc->fwdonly) {
					--page;
					showpage(page, &menu);
				}
				break;
			case '\n':
				if(nxt) {
					nxt--;
					if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly)
						showpage(page=nxt, &menu);
					nxt = 0;
					break;
				}
				goto Gotonext;
			case Kright:
			case ' ':
			Gotonext:
				if(doc->npage && ++page >= doc->npage && !doc->fwdonly)
					wexits(0);
				showpage(page, &menu);
				break;

			/*
			 * The upper y coordinate of the image is at ul.y in screen->r.
			 * Panning up means moving the upper left corner down.  If the
			 * upper left corner is currently visible, we need to go back a page.
			 */
			case Kup:
				if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){
					if(page > 0 && !doc->fwdonly){
						--page;
						showbottom = 1;
						showpage(page, &menu);
					}
				} else {
					i = Dy(screen->r)/2;
					if(i > 10)
						i -= 10;
					if(i+ul.y > screen->r.min.y)
						i = screen->r.min.y - ul.y;
					translate(Pt(0, i));
				}
				break;

			/*
			 * If the lower y coordinate is on the screen, we go to the next page.
			 * The lower y coordinate is at ul.y + Dy(im->r).
			 */
			case Kdown:
				i = ul.y + Dy(im->r);
				if(screen->r.min.y <= i && i <= screen->r.max.y){
					ul.y = screen->r.min.y;
					goto Gotonext;
				} else {
					i = -Dy(screen->r)/2;
					if(i < -10)
						i += 10;
					if(i+ul.y+Dy(im->r) <= screen->r.max.y)
						i = screen->r.max.y - Dy(im->r) - ul.y - 1;
					translate(Pt(0, i));
				}
				break;
			default:
				esetcursor(&query);
				sleep(1000);
				esetcursor(nil);
				break;
			}
			break;

		case Emouse:
			m = e.mouse;
			switch(m.buttons){
			case Left:
				oxy = m.xy;
				xy0 = oxy;
				do {
					dxy = subpt(m.xy, oxy);
					oxy = m.xy;
					translate(dxy);
					unlockdisplay(display);
					m = emouse();
					lockdisplay(display);
				} while(m.buttons == Left);
				if(m.buttons) {
					dxy = subpt(xy0, oxy);
					translate(dxy);
				}
				break;

			case Middle:
				if(doc->npage == 0)
					break;

				unlockdisplay(display);
				n = emenuhit(Middle, &m, &midmenu);
				lockdisplay(display);
				if(n == -1)
					break;
				switch(n){
				case Next: 	/* next */
					if(reverse)
						page--;
					else
						page++;
					if(page < 0) {
						if(reverse) return;
						else page = 0;
					}

					if((page >= doc->npage) && !doc->fwdonly)
						return;

					showpage(page, &menu);
					nxt = 0;
					break;
				case Prev:	/* prev */
					if(reverse)
						page++;
					else
						page--;
					if(page < 0) {
						if(reverse) return;
						else page = 0;
					}

					if((page >= doc->npage) && !doc->fwdonly && !reverse)
						return;

					showpage(page, &menu);
					nxt = 0;
					break;
				case Zerox:	/* prev */
					zerox();
					break;
				case Zin:	/* zoom in */
					{
						double delta;
						Rectangle r;

						r = egetrect(Middle, &m);
						if((rectclip(&r, rectaddpt(im->r, ul)) == 0) ||
							Dx(r) == 0 || Dy(r) == 0)
							break;
						/* use the smaller side to expand */
						if(Dx(r) < Dy(r))
							delta = (double)Dx(im->r)/(double)Dx(r);
						else
							delta = (double)Dy(im->r)/(double)Dy(r);

						esetcursor(&reading);
						tmp = xallocimage(display,
								Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)),
								im->chan, 0, DBlack);
						if(tmp == nil) {
							fprint(2, "out of memory during zoom: %r\n");
							wexits("memory");
						}
						resample(im, tmp);
						im = tmp;
						delayfreeimage(tmp);
						esetcursor(nil);
						ul = screen->r.min;
						redraw(screen);
						flushimage(display, 1);
						break;
					}
				case Fit:	/* fit */
					{
						double delta;
						Rectangle r;

						delta = (double)Dx(screen->r)/(double)Dx(im->r);
						if((double)Dy(im->r)*delta > Dy(screen->r))
							delta = (double)Dy(screen->r)/(double)Dy(im->r);

						r = Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta));
						esetcursor(&reading);
						tmp = xallocimage(display, r, im->chan, 0, DBlack);
						if(tmp == nil) {
							fprint(2, "out of memory during fit: %r\n");
							wexits("memory");
						}
						resample(im, tmp);
						im = tmp;
						delayfreeimage(tmp);
						esetcursor(nil);
						ul = screen->r.min;
						redraw(screen);
						flushimage(display, 1);
						break;
					}
				case Rot:	/* rotate 90 */
					angle = (angle+90) % 360;
					showpage(page, &menu);
					break;
				case Upside: 	/* upside-down */
					angle = (angle+180) % 360;
					showpage(page, &menu);
					break;
				case Restore:	/* restore */
					showpage(page, &menu);
					break;
				case Reverse:	/* reverse */
					if(doc->fwdonly)
						break;
					reverse = !reverse;
					menu.lasthit = doc->npage-1-menu.lasthit;

					if(page == 0 || page == doc->npage-1) {
						page = doc->npage-1-page;
						showpage(page, &menu);
					}
					break;
				case Write: /* write */
					esetcursor(&reading);
					s = writebitmap();
					if(s)
						string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
							display->defaultfont, s);
					esetcursor(nil);
					flushimage(display, 1);
					break;
				case Del: /* delete */
					if(doc->rmpage && page < doc->npage) {
						if(doc->rmpage(doc, page) >= 0) {
							if(doc->npage < 0)
								wexits(0);
							if(page >= doc->npage)
								page = doc->npage-1;
							showpage(page, &menu);
						}
					}
					break;
				case Exit:	/* exit */
					return;
				case Empty1:
				case Empty2:
				case Empty3:
					break;

				};



			case Right:
				if(doc->npage == 0)
					break;

				oldpage = page;
				unlockdisplay(display);
				n = emenuhit(RMenu, &m, &menu);
				lockdisplay(display);
				if(n == -1)
					break;

				if(doc->fwdonly) {
					switch(n){
					case 0:	/* this page */
						break;
					case 1:	/* next page */
						showpage(++page, &menu);
						break;
					case 2:	/* exit */
						return;
					}
					break;
				}

				if(n == doc->npage)
					return;
				else
					page = reverse ? doc->npage-1-n : n;

				if(oldpage != page)
					showpage(page, &menu);
				nxt = 0;
				break;
			}
			break;

		case Eplumb:
			pm = e.v;
			if(pm->ndata <= 0){
				plumbfree(pm);
				break;
			}
			if(plumbquit(pm))
				exits(nil);
			if(showdata(pm)) {
				s = estrdup("/tmp/pageplumbXXXXXXX");
				fd = opentemp(s);
				write(fd, pm->data, pm->ndata);
				/* lose fd reference on purpose; the file is open ORCLOSE */
			} else if(pm->data[0] == '/') {
				s = estrdup(pm->data);
			} else {
				s = emalloc(strlen(pm->wdir)+1+pm->ndata+1);
				sprint(s, "%s/%s", pm->wdir, pm->data);
				cleanname(s);
			}
			if((i = doc->addpage(doc, s)) >= 0) {
				page = i;
				unhide();
				showpage(page, &menu);
			}
			free(s);
			plumbfree(pm);
			break;
		}
	}
}