1075 lines · 21.8 KB · C
RawDownload
/* * the actual viewer that handles screen stuff */ #include <u.h>#include <libc.h>#include <draw.h>#include <cursor.h>#include <event.h>#include <bio.h>#include <plumb.h>#include <ctype.h>#include <keyboard.h>#include "page.h" Document *doc;Image *im;Image *tofree;int page;int angle = 0;int showbottom = 0;		/* on the next showpage, move the image so the bottom is visible. */ Rectangle ulrange;	/* the upper left corner of the image must be in this rectangle */Point ul;			/* the upper left corner of the image is at this point on the screen */ Point pclip(Point, Rectangle);Rectangle mkrange(Rectangle screenr, Rectangle imr);void redraw(Image*); Cursor reading={	{-1, -1},	{0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, 	 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0, 	 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0, 	 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },	{0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00, 	 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0, 	 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40, 	 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }}; Cursor query = {	{-7,-7},	{0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 	 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, 	 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, 	 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, },	{0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 	 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 	 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, 	 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }}; enum {	Left = 1,	Middle = 2,	Right = 4, 	RMenu = 3,}; static voiddelayfreeimage(Image *m){	if(m == tofree)		return;	if(tofree)		freeimage(tofree);	tofree = m;} voidunhide(void){	static int wctl = -1; 	if(wctl < 0)		wctl = open("/dev/wctl", OWRITE);	if(wctl < 0)		return; 	write(wctl, "unhide", 6);} int max(int a, int b){	return a > b ? a : b;} int min(int a, int b){	return a < b ? a : b;}  char*menugen(int n){	static char menustr[32];	char *p;	int len; 	if(n == doc->npage)		return "exit";	if(n > doc->npage)		return nil; 	if(reverse)		n = doc->npage-1-n; 	p = doc->pagename(doc, n);	len = (sizeof menustr)-2; 	if(strlen(p) > len && strrchr(p, '/'))		p = strrchr(p, '/')+1;	if(strlen(p) > len)		p = p+strlen(p)-len; 	strcpy(menustr+1, p);	if(page == n)		menustr[0] = '>';	else		menustr[0] = ' ';	return menustr;} voidshowpage(int page, Menu *m){	if(doc->fwdonly)		m->lasthit = 0;	/* this page */	else		m->lasthit = reverse ? doc->npage-1-page : page;		esetcursor(&reading);	delayfreeimage(nil);	im = cachedpage(doc, angle, page);	if(im == nil)		wexits(0);	if(resizing)		resize(Dx(im->r), Dy(im->r)); 	esetcursor(nil);	if(showbottom){		ul.y = screen->r.max.y - Dy(im->r);		showbottom = 0;	} 	redraw(screen);	flushimage(display, 1);} char*writebitmap(void){	char basename[64];	char name[64+30];	static char result[200];	char *p, *q;	int fd; 	if(im == nil)		return "no image"; 	memset(basename, 0, sizeof basename);	if(doc->docname)		strncpy(basename, doc->docname, sizeof(basename)-1);	else if((p = menugen(page)) && p[0] != '\0')		strncpy(basename, p+1, sizeof(basename)-1); 	if(basename[0]) {		if(q = strrchr(basename, '/'))			q++;		else			q = basename;		if(p = strchr(q, '.'))			*p = 0;				memset(name, 0, sizeof name);		snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1);		if(access(name, 0) >= 0) {			strcat(name, "XXXX");			mktemp(name);		}		if(access(name, 0) >= 0)			return "couldn't think of a name for bitmap";	} else {		strcpy(name, "bitXXXX");		mktemp(name);		if(access(name, 0) >= 0) 			return "couldn't think of a name for bitmap";	} 	if((fd = create(name, OWRITE, 0666)) < 0) {		snprint(result, sizeof result, "cannot create %s: %r", name);		return result;	} 	if(writeimage(fd, im, 0) < 0) {		snprint(result, sizeof result, "cannot writeimage: %r");		close(fd);		return result;	}	close(fd); 	snprint(result, sizeof result, "wrote %s", name);	return result;} static void translate(Point); static intshowdata(Plumbmsg *msg){	char *s; 	s = plumblookup(msg->attr, "action");	return s && strcmp(s, "showdata")==0;} static intplumbquit(Plumbmsg *msg){	char *s; 	s = plumblookup(msg->attr, "action");	return s && strcmp(s, "quit")==0;} /* correspond to entries in miditems[] below, * changing one means you need to change */enum{	Restore = 0,	Zin,	Fit,	Rot,	Upside,	Empty1,	Next,	Prev,	Zerox,	Empty2,	Reverse,	Del,	Write,	Empty3,	Exit,}; voidviewer(Document *dd){	int i, fd, n, oldpage;	int nxt;	Menu menu, midmenu;	Mouse m;	Event e;	Point dxy, oxy, xy0;	Rectangle r;	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);	r.min = ZP; 	/*	 * 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;

Lines 1–500 of 1075.