📄 view.c
字号:
/* * 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;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,};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){ Image *tmp; if(doc->fwdonly) m->lasthit = 0; /* this page */ else m->lasthit = reverse ? doc->npage-1-page : page; esetcursor(&reading); freeimage(im); if((page < 0 || page >= doc->npage) && !doc->fwdonly){ im = nil; return; } im = doc->drawpage(doc, page); if(im == nil) { if(doc->fwdonly) /* this is how we know we're out of pages */ wexits(0); im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack); if(im == nil) { fprint(2, "out of memory: %r\n"); wexits("memory"); } string(im, ZP, display->white, ZP, display->defaultfont, "?"); }else if(resizing){ resize(Dx(im->r), Dy(im->r)); } if(im->r.min.x > 0 || im->r.min.y > 0) { tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill); if(tmp == nil) { fprint(2, "out of memory during showpage: %r\n"); wexits("memory"); } drawop(tmp, tmp->r, im, nil, im->r.min, S); freeimage(im); im = tmp; } switch(angle){ case 90: im = rot90(im); break; case 180: rot180(im); break; case 270: im = rot270(im); break; } 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;}/* 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; 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. */ switch(eread(Emouse|Ekeyboard|Eplumb, &e)){ 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; esetcursor(&reading); rot180(im); esetcursor(nil); angle = (angle+180) % 360; redraw(screen); flushimage(display, 1); 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); m = emouse(); } while(m.buttons == Left); if(m.buttons) { dxy = subpt(xy0, oxy); translate(dxy); } break; case Middle: if(doc->npage == 0) break; n = emenuhit(Middle, &m, &midmenu); 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -