/* * 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; }
/* * 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; }
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); }
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)(); } }
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(); }
int waitup(void) { while (mouse.buttons & 7) mouse = emouse(); return mouse.buttons & 7; }
int waitdown(void) /* wait until some button is down */ { while (!(mouse.buttons & 7)) mouse = emouse(); return mouse.buttons & 7; }
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; }
void buttons(int ud) { while((mouse.buttons==0) != ud) mouse = emouse(); }
void frgetmouse(void) { mouse = emouse(); }
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; } } }
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; }
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; } } }