void move(Point m) { Point p, nm; int x, y; nm = subpt(m, screen->r.min); /* figure out where the click falls */ p = pix2board(nm.x, nm.y); if(grid[p.x][p.y] >= 999) return; /* reset the board scores */ grid[p.x][p.y] = 999; for(x = 0; x < SzX; x++) for(y = 0; y < SzY; y++) if(grid[x][y] != 999 && grid[x][y] != 1000) grid[x][y] = 100; nextglenda(); }
void resize() { Point p, q; Rectangle r; r = screen->r; draw(screen, r, light, nil, ZP); p = string(screen, addpt(r.min, Pt(4,4)), text, ZP, display->defaultfont, title); p.x = r.min.x+4; p.y += display->defaultfont->height+4; q = subpt(r.max, Pt(4,4)); rbar = Rpt(p, q); border(screen, rbar, -2, dark, ZP); last = 0; lastp = -1; flushimage(display, 1); drawbar(); }
/* * Translate the image in the window by delta. */ static void translate(Point delta) { Point u; Rectangle r, or; if(im == nil) return; u = pclip(addpt(ul, delta), ulrange); delta = subpt(u, ul); if(delta.x == 0 && delta.y == 0) return; /* * The upper left corner of the image is currently at ul. * We want to move it to u. */ or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul); r = rectaddpt(or, delta); drawop(screen, r, screen, nil, ul, S); ul = u; /* fill in gray where image used to be but isn't. */ drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP, S); /* fill in black border */ drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S); /* fill in image where it used to be off the screen. */ if(rectclip(&or, screen->r)) drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min, S); else drawop(screen, r, im, nil, im->r.min, S); flushimage(display, 1); }
void drawscreen(int clear) { int i; if(clear){ geometry(screen->r); draw(screen, screen->r, bkgd, nil, ZP); } border(screen, rbig, -1, display->black, ZP); draw(screen, rbig, orig, nil, orig->r.min); border(screen, rramp, -1, display->black, ZP); draw(screen, rramp, ramp, nil, ramp->r.min); drawrampbar(red, &state); border(screen, rectaddpt(state.selr, subpt(rbig.min, orig->r.min)), -2, red, ZP); if(clear){ drawface(-1); for(i=0; i<nelem(face); i++) drawface(i); } }
static void polygon(int cnt[], double *pts[], Windrule w, int v) { Edge *edges, *ep, *nextep, **ylist, **eylist, **yp; Point p, q, p0, p1, p10; int i, dy, nbig, y, left, right, wind, nwind, nvert; int *cntp; double **ptsp, *xp; nvert=0; for(cntp=cnt; *cntp; cntp++) nvert+=*cntp; edges=(Edge *)malloc(nvert*sizeof(Edge)); if(edges==0) { NoSpace: sysfatal("polygon: no space"); } ylist=(Edge **)malloc(Dy(screen->r)*sizeof(Edge *)); if(ylist==0) goto NoSpace; eylist=ylist+Dy(screen->r); for(yp=ylist; yp!=eylist; yp++) *yp=0; ep=edges; for(cntp=cnt,ptsp=pts; *cntp; cntp++,ptsp++) { p.x=SCX((*ptsp)[*cntp*2-2]); p.y=SCY((*ptsp)[*cntp*2-1]); nvert=*cntp; for(xp=*ptsp,i=0; i!=nvert; xp+=2,i++) { q=p; p.x=SCX(xp[0]); p.y=SCY(xp[1]); if(p.y==q.y) continue; if(p.y<q.y) { p0=p; p1=q; ep->dwind=1; } else { p0=q; p1=p; ep->dwind=-1; } if(p1.y<=screen->r.min.y) continue; if(p0.y>=screen->r.max.y) continue; ep->p=p0; if(p1.y>screen->r.max.y) ep->maxy=screen->r.max.y; else ep->maxy=p1.y; p10=subpt(p1, p0); if(p10.x>=0) { ep->dx=p10.x/p10.y; ep->dx1=ep->dx+1; } else { p10.x=-p10.x; ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */ ep->dx1=ep->dx-1; } ep->x=0; ep->num=p10.x%p10.y; ep->den=p10.y; if(ep->p.y<screen->r.min.y) { dy=screen->r.min.y-ep->p.y; ep->x+=dy*ep->num; nbig=ep->x/ep->den; ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig); ep->x%=ep->den; ep->p.y=screen->r.min.y; } insert(ep, ylist+(ep->p.y-screen->r.min.y)); ep++; } } left = 0; for(yp=ylist,y=screen->r.min.y; yp!=eylist; yp++,y++) { wind=0; for(ep=*yp; ep; ep=nextep) { nwind=wind+ep->dwind; if(nwind&w) { /* inside */ if(!(wind&w)) { left=ep->p.x; if(left<screen->r.min.x) left=screen->r.min.x; } } else if(wind&w) { right=ep->p.x; if(right>=screen->r.max.x) right=screen->r.max.x; #define BART_BUG_FIXED /* what goes on here?? -rob */ #ifdef BART_BUG_FIXED if(right>left) line(screen, Pt(left, y), Pt(right, y), Endsquare, Endsquare, 0, getcolor(v), ZP); #else if(right>left) { switch(v) { default: segment(&screen, Pt(left, y), Pt(right, y), ~0, D&~S); segment(&screen, Pt(left, y), Pt(right, y), v, f); break; case 0: segment(&screen, Pt(left, y), Pt(right, y), ~0, D&~S); break; case 3: segment(&screen, Pt(left, y), Pt(right, y), v, f); break; } } #endif } wind=nwind; nextep=ep->next; if(++ep->p.y!=ep->maxy) { ep->x+=ep->num; if(ep->x>=ep->den) { ep->x-=ep->den; ep->p.x+=ep->dx1; } else ep->p.x+=ep->dx; insert(ep, yp+1); } } } free((char *)edges); free((char *)ylist); }
Rectangle tktbbox(Tk *tk, TkTindex *ix) { Rectangle r; int d, w; TkTitem *i; TkTline *l; TkEnv env; TkTtabstop *tb = nil; Tk *sub; TkText *tkt = TKobj(TkText, tk); int opts[TkTnumopts]; l = ix->line; /* r in V space */ r.min = subpt(l->orig, tkt->deltatv); r.min.y += l->ascent; /* tabs dependon tags of first non-mark on display line */ for(i = l->items; i->kind == TkTmark; ) i = i->next; tkttagopts(tk, i, opts, &env, &tb, 1); for(i = l->items; i != nil; i = i->next) { if(i == ix->item) { tkttagopts(tk, i, opts, &env, nil, 1); r.min.y -= opts[TkToffset]; switch(i->kind) { case TkTascii: case TkTrune: d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, ix->pos); w = tktdispwidth(tk, tb, i, nil, r.min.x, ix->pos, 1); r.min.x += d; r.min.y -= env.font->ascent; r.max.x = r.min.x + w; r.max.y = r.min.y + env.font->height; break; case TkTwin: sub = i->iwin->sub; if(sub == nil) break; r.min.x += sub->act.x; r.min.y += sub->act.y; r.max.x = r.min.x + sub->act.width + 2*sub->borderwidth; r.max.y = r.min.y + sub->act.height + 2*sub->borderwidth; break; case TkTnewline: r.max.x = r.min.x; r.min.y -= l->ascent; r.max.y = r.min.y + l->height; break; default: d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1); r.max.x = r.min.x + d; r.max.y = r.min.y; break; } return r; } r.min.x += tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1); } r.min.x = 0; r.min.y = 0; r.max.x = 0; r.max.y = 0; return r; }
char* tkdrawcanv(Tk *tk, Point orig) { Image *dst; TkCitem *i; Display *d; TkCanvas *c; Rectangle r, bufr, oclipr; int vis, alpha, buffer; Point rel, p; TkCimeth *imeth; c = TKobj(TkCanvas, tk); d = tk->env->top->display; dst = tkimageof(tk); /* * translation from local to screen coords */ rel.x = orig.x + tk->act.x + tk->borderwidth; rel.y = orig.y + tk->act.y + tk->borderwidth; buffer = c->buffer; if (buffer == TkCbufauto) buffer = TkCbufvisible; /* buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */ if (buffer == TkCbufnone) { if(c->image != nil && c->ialloc) freeimage(c->image); c->image = dst; c->ialloc = 0; r = tkrect(tk, 0); bufr = r; rectclip(&bufr, tk->dirty); oclipr = dst->clipr; replclipr(dst, 0, rectaddpt(bufr, rel)); draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP); p = subpt(rel, c->view); p.x = TKI2F(p.x); p.y = TKI2F(p.y); bufr = rectaddpt(bufr, c->view); for(i = c->head; i; i = i->next) { if(rectXrect(i->p.bb, bufr)) { imeth = &tkcimethod[i->type]; imeth->coord(i, nil, p.x, p.y); imeth->draw(dst, i, tk->env); imeth->coord(i, nil, -p.x, -p.y); } } replclipr(dst, 0, oclipr); } else { if (c->buffer == TkCbufall) bufr = c->region; else { bufr.min = c->view; bufr.max.x = c->view.x + tk->act.width; bufr.max.y = c->view.y + tk->act.height; } alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff; if(c->image == nil || eqrect(bufr, c->image->r) == 0) { if(c->image != nil && c->ialloc) freeimage(c->image); c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]); c->ialloc = 1; c->update = bufr; tkcvssetdirty(tk); /* unnecessary? */ } if(c->image == nil) return nil; r = c->update; if (rectclip(&r, c->image->r)) { if (alpha) drawop(c->image, c->update, nil, nil, ZP, Clear); draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view); replclipr(c->image, 0, r); for(i = c->head; i; i = i->next) { if(rectXrect(i->p.bb, r)) tkcimethod[i->type].draw(c->image, i, tk->env); } replclipr(c->image, 0, c->image->r); } /* * if the visible area of the canvas image doesn't * fit completely within the dirty rectangle, * then we'll need to draw the background behind it */ r = tkrect(tk, 0); bufr = rectsubpt(bufr, c->view); vis = rectclip(&bufr, tkrect(tk, 0)); if (!vis || !rectinrect(tk->dirty, bufr)) draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view); if (vis && rectclip(&bufr, tk->dirty)) draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view)); } /* * if the border is dirty too, then draw that */ if (!rectinrect(tk->dirty, bufr)) { r.min = addpt(r.min, rel); r.min.x -= tk->borderwidth; r.min.y -= tk->borderwidth; tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief); } c->update = bbnil; return nil; }
static void _memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op) { Rectangle r; struct Lline ll; Point d; int srcclipped; Memlayer *dl; if(radius < 0) return; if(src->layer) /* can't draw line with layered source */ return; srcclipped = 0; Top: dl = dst->layer; if(dl == nil){ _memimageline(dst, p0, p1, end0, end1, radius, src, sp, clipr, op); return; } if(!srcclipped){ d = subpt(sp, p0); if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0) return; if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0) return; srcclipped = 1; } /* dst is known to be a layer */ p0.x += dl->delta.x; p0.y += dl->delta.y; p1.x += dl->delta.x; p1.y += dl->delta.y; clipr.min.x += dl->delta.x; clipr.min.y += dl->delta.y; clipr.max.x += dl->delta.x; clipr.max.y += dl->delta.y; if(dl->clear){ dst = dst->layer->screen->image; goto Top; } /* XXX */ /* this is not the correct set of tests */ // if(log2[dst->depth] != log2[src->depth] || log2[dst->depth]!=3) // return; /* can't use sutherland-cohen clipping because lines are wide */ r = memlinebbox(p0, p1, end0, end1, radius); /* * r is now a bounding box for the line; * use it as a clipping rectangle for subdivision */ if(rectclip(&r, clipr) == 0) return; ll.p0 = p0; ll.p1 = p1; ll.end0 = end0; ll.end1 = end1; ll.sp = sp; ll.dstlayer = dst->layer; ll.src = src; ll.radius = radius; ll.delta = dl->delta; ll.op = op; _memlayerop(llineop, dst, r, r, &ll); }
int in_poly(Ppoly_t argpoly, Ppoint_t q) { int i, i1; /* point index; i1 = i-1 mod n */ double x; /* x intersection of e with ray */ int crossings = 0; /* 2 * number of edge/ray crossings */ Ppoly_t poly; /* original O'Rourke code overwrites the arg polygon! */ Ppoint_t *P; int n; /* Shift so that q is the origin. */ poly = copypoly(argpoly); P = poly.ps; n = poly.pn; for (i = 0; i < n; i++) poly.ps[i] = subpt(poly.ps[i],q); /* For each edge e=(i-1,i), see if crosses ray. */ for (i = 0; i < n; i++ ) { i1 = ( i + n - 1 ) % n; /* if edge is horizontal, test to see if the point is on it */ if ((P[i].y == 0 ) && ( P[i1].y == 0)) { if ((P[i].x * P[i1].x) < 0) return TRUE; else continue; } /* if e straddles the x-axis... */ if (((P[i].y >= 0 ) && ( P[i1].y <= 0 ) ) || ( ( P[i1].y >= 0 ) && ( P[i].y <= 0 ) ) ) { /* e straddles ray, so compute intersection with ray. */ x = (P[i].x * P[i1].y - P[i1].x * P[i].y) / (double)(P[i1].y - P[i].y); /* if intersect at origin, we've found intersection */ if (x == 0) return TRUE; /* crosses ray if strictly positive intersection. */ if (x > 0) { if ( P[i].y == 0 ) { if ( P[(i-1+n)%n].y*P[(1+i)%n].y < 0) { /* count half a crossing */ crossings++; } else if ( P[i].y*P[(2+i)%n].y < 0) { /* count half a crossing */ crossings++; } } else { /* count a full crossing */ crossings += 2; } } } } freepoly(poly); /* q inside if an odd number of crossings. */ if( (crossings % 4) >= 2 ) return TRUE; else return FALSE; }
void memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) { struct Draw d; Rectangle srcr, tr, mr; Memlayer *dl, *sl; if(drawdebug) iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1); if(mask == nil) mask = memopaque; if(mask->layer){ if(drawdebug) iprint("mask->layer != nil\n"); return; /* too hard, at least for now */ } Top: if(dst->layer==nil && src->layer==nil){ memimagedraw(dst, r, src, p0, mask, p1, op); return; } if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){ if(drawdebug) iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr); return; } /* * Convert to screen coordinates. */ dl = dst->layer; if(dl != nil){ r.min.x += dl->delta.x; r.min.y += dl->delta.y; r.max.x += dl->delta.x; r.max.y += dl->delta.y; } Clearlayer: if(dl!=nil && dl->clear){ if(src == dst){ p0.x += dl->delta.x; p0.y += dl->delta.y; src = dl->screen->image; } dst = dl->screen->image; goto Top; } sl = src->layer; if(sl != nil){ p0.x += sl->delta.x; p0.y += sl->delta.y; srcr.min.x += sl->delta.x; srcr.min.y += sl->delta.y; srcr.max.x += sl->delta.x; srcr.max.y += sl->delta.y; } /* * Now everything is in screen coordinates. * mask is an image. dst and src are images or obscured layers. */ /* * if dst and src are the same layer, just draw in save area and expose. */ if(dl!=nil && dst==src){ if(dl->save == nil) return; /* refresh function makes this case unworkable */ if(rectXrect(r, srcr)){ tr = r; if(srcr.min.x < tr.min.x){ p1.x += tr.min.x - srcr.min.x; tr.min.x = srcr.min.x; } if(srcr.min.y < tr.min.y){ p1.y += tr.min.x - srcr.min.x; tr.min.y = srcr.min.y; } if(srcr.max.x > tr.max.x) tr.max.x = srcr.max.x; if(srcr.max.y > tr.max.y) tr.max.y = srcr.max.y; memlhide(dst, tr); }else{ memlhide(dst, r); memlhide(dst, srcr); } memdraw(dl->save, rectsubpt(r, dl->delta), dl->save, subpt(srcr.min, src->layer->delta), mask, p1, op); memlexpose(dst, r); return; } if(sl){ if(sl->clear){ src = sl->screen->image; if(dl != nil){ r.min.x -= dl->delta.x; r.min.y -= dl->delta.y; r.max.x -= dl->delta.x; r.max.y -= dl->delta.y; } goto Top; } /* relatively rare case; use save area */ if(sl->save == nil) return; /* refresh function makes this case unworkable */ memlhide(src, srcr); /* convert back to logical coordinates */ p0.x -= sl->delta.x; p0.y -= sl->delta.y; srcr.min.x -= sl->delta.x; srcr.min.y -= sl->delta.y; srcr.max.x -= sl->delta.x; srcr.max.y -= sl->delta.y; src = src->layer->save; } /* * src is now an image. dst may be an image or a clear layer */ if(dst->layer==nil) goto Top; if(dst->layer->clear) goto Clearlayer; /* * dst is an obscured layer */ d.deltas = subpt(p0, r.min); d.deltam = subpt(p1, r.min); d.dstlayer = dl; d.src = src; d.op = op; d.mask = mask; _memlayerop(ldrawop, dst, r, r, &d); }
void lockscreen(void) { enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, }; char *s; char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen]; int fd, dx, dy; Image *i; Point p; Rectangle r; Tm *tm; fd = open("/dev/screen", OREAD); if(fd < 0) error("can't open /dev/screen: %r"); if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen) error("can't read /dev/screen: %r"); close(fd); buf[sizeof buf-1] = 0; if(tokenize(buf, flds, Nfld) != Nfld) error("can't tokenize /dev/screen header"); snprint(newcmd, sizeof newcmd, "-r %s %s %d %d", flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1); newwindow(newcmd); if (initdraw(nil, nil, "screenlock") < 0) sysfatal("initdraw failed"); if(display == nil) error("no display"); /* screen is now open and covered. grab mouse and hold on tight */ procrfork(grabmouse, nil, 4096, RFFDG); procrfork(blanker, nil, 4096, RFFDG); fd = open(pic, OREAD); if(fd > 0){ i = readimage(display, fd, 0); if(i){ r = screen->r; p = Pt(r.max.x / 2, r.max.y * 2 / 3); dx = (Dx(screen->r) - Dx(i->r)) / 2; r.min.x += dx; r.max.x -= dx; dy = (Dy(screen->r) - Dy(i->r)) / 2; r.min.y += dy; r.max.y -= dy; draw(screen, screen->r, display->black, nil, ZP); draw(screen, r, i, nil, i->r.min); flushimage(display, 1); } close(fd); /* identify the user on screen, centered */ tm = localtime(time(0)); s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min); p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0)); screenstring(p, s); } /* clear the cursor */ fd = open("/dev/cursor", OWRITE); if(fd > 0){ memset(cbuf, 0, sizeof cbuf); write(fd, cbuf, sizeof cbuf); /* leave it open */ } }
static void resample(Memimage *dst, Rectangle r, Memimage *src, Rectangle sr) { Point sp, dp; Point _sp, qp; Point ssize, dsize; uchar *pdst0, *pdst, *psrc0, *psrc; ulong s00, s01, s10, s11; int tx, ty, bpp, bpl; ssize = subpt(subpt(sr.max, sr.min), Pt(1,1)); dsize = subpt(subpt(r.max, r.min), Pt(1,1)); pdst0 = byteaddr(dst, r.min); bpp = src->depth/8; bpl = src->width*sizeof(int); qp = Pt(0, 0); if(dsize.x > 0) qp.x = (ssize.x<<12)/dsize.x; if(dsize.y > 0) qp.y = (ssize.y<<12)/dsize.y; _sp.y = sr.min.y<<12; for(dp.y=0; dp.y<=dsize.y; dp.y++){ sp.y = _sp.y>>12; ty = _sp.y&0xFFF; pdst = pdst0; sp.x = sr.min.x; psrc0 = byteaddr(src, sp); _sp.x = 0; for(dp.x=0; dp.x<=dsize.x; dp.x++){ sp.x = _sp.x>>12; tx = _sp.x&0xFFF; psrc = psrc0 + sp.x*bpp; s00 = (0x1000-tx)*(0x1000-ty); s01 = tx*(0x1000-ty); s10 = (0x1000-tx)*ty; s11 = tx*ty; switch(bpp){ case 4: pdst[3] = (s11*psrc[bpl+bpp+3] + s10*psrc[bpl+3] + s01*psrc[bpp+3] + s00*psrc[3]) >>24; case 3: pdst[2] = (s11*psrc[bpl+bpp+2] + s10*psrc[bpl+2] + s01*psrc[bpp+2] + s00*psrc[2]) >>24; pdst[1] = (s11*psrc[bpl+bpp+1] + s10*psrc[bpl+1] + s01*psrc[bpp+1] + s00*psrc[1]) >>24; case 1: pdst[0] = (s11*psrc[bpl+bpp] + s10*psrc[bpl] + s01*psrc[bpp] + s00*psrc[0]) >>24; } pdst += bpp; _sp.x += qp.x; } pdst0 += dst->width*sizeof(int); _sp.y += qp.y; } }
border(screen, rramp, -1, display->black, ZP); draw(screen, rramp, ramp, nil, ramp->r.min); drawrampbar(red, &state); border(screen, rectaddpt(state.selr, subpt(rbig.min, orig->r.min)), -2, red, ZP); if(clear){ drawface(-1); for(i=0; i<nelem(face); i++) drawface(i); } } void moveframe(Rectangle old, Rectangle new) { border(screen, rectaddpt(old, subpt(rbig.min, orig->r.min)), -2, orig, old.min); border(screen, rectaddpt(new, subpt(rbig.min, orig->r.min)), -2, red, ZP); } /* * Initialize gamma ramp; should dither for * benefit of non-true-color displays. */ void initramp(void) { int k, x, y; uint8_t dat[256*256]; double g;
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; } } }
/* * make a "wedge" mask covering the desired angle and contained in * a surrounding square; draw a full ellipse; intersect that with the * wedge to make a mask through which to copy src to dst. */ void memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op) { int i, w, beta, tmp, c1, c2, m, m1; Rectangle rect; Point p, bnd[8]; Memimage *wedge, *figure, *mask; if(a < 0) a = -a; if(b < 0) b = -b; w = t; if(w < 0) w = 0; alpha = -alpha; /* compensate for upside-down coords */ phi = -phi; beta = alpha + phi; if(phi < 0){ tmp = alpha; alpha = beta; beta = tmp; phi = -phi; } if(phi >= 360){ memellipse(dst, c, a, b, t, src, sp, op); return; } while(alpha < 0) alpha += 360; while(beta < 0) beta += 360; c1 = alpha/90 & 3; /* number of nearest corner */ c2 = beta/90 & 3; /* * icossin returns point at radius ICOSSCALE. * multiplying by m1 moves it outside the ellipse */ rect = Rect(-a-w, -b-w, a+w+1, b+w+1); m = rect.max.x; /* inradius of bounding square */ if(m < rect.max.y) m = rect.max.y; m1 = (m+ICOSSCALE-1) >> 10; m = m1 << 10; /* assure m1*cossin is inside */ i = 0; bnd[i++] = Pt(0,0); icossin(alpha, &p.x, &p.y); bnd[i++] = mulpt(p, m1); for(;;) { bnd[i++] = mulpt(corners[c1], m); if(c1==c2 && phi<180) break; c1 = (c1+1) & 3; phi -= 90; } icossin(beta, &p.x, &p.y); bnd[i++] = mulpt(p, m1); figure = nil; mask = nil; wedge = allocmemimage(rect, GREY1); if(wedge == nil) goto Return; memfillcolor(wedge, DTransparent); memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S); figure = allocmemimage(rect, GREY1); if(figure == nil) goto Return; memfillcolor(figure, DTransparent); memellipse(figure, p00, a, b, t, memopaque, p00, S); mask = allocmemimage(rect, GREY1); if(mask == nil) goto Return; memfillcolor(mask, DTransparent); memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S); c = subpt(c, dst->r.min); memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op); Return: freememimage(wedge); freememimage(figure); freememimage(mask); }
int pl_hitpopup(Panel *g, Mouse *m){ Panel *p; Point d; Popup *pp; pp=g->data; if(g->state==UP){ switch(m->buttons&7){ case 0: p=g->child; break; case 1: p=pp->pop[0]; g->state=DOWN1; break; case 2: p=pp->pop[1]; g->state=DOWN2; break; case 4: p=pp->pop[2]; g->state=DOWN3; break; default: p=0; break; } if(p==0){ p=g->child; g->state=DOWN; } else if(g->state!=UP){ plpack(p, screen->clipr); if(p->lastmouse) d=subpt(m->xy, divpt(addpt(p->lastmouse->r.min, p->lastmouse->r.max), 2)); else d=subpt(m->xy, divpt(addpt(p->r.min, p->r.max), 2)); if(p->r.min.x+d.x<g->r.min.x) d.x=g->r.min.x-p->r.min.x; if(p->r.max.x+d.x>g->r.max.x) d.x=g->r.max.x-p->r.max.x; if(p->r.min.y+d.y<g->r.min.y) d.y=g->r.min.y-p->r.min.y; if(p->r.max.y+d.y>g->r.max.y) d.y=g->r.max.y-p->r.max.y; plmove(p, d); pp->save=allocimage(display, p->r, g->b->chan, 0, DNofill); if(pp->save!=0) draw(pp->save, p->r, g->b, 0, p->r.min); pl_invis(p, 0); pldraw(p, g->b); } } else{ switch(g->state){ default: SET(p); break; /* can't happen! */ case DOWN1: p=pp->pop[0]; break; case DOWN2: p=pp->pop[1]; break; case DOWN3: p=pp->pop[2]; break; case DOWN: p=g->child; break; } if((m->buttons&7)==0){ if(g->state!=DOWN){ if(pp->save!=0){ draw(g->b, p->r, pp->save, 0, p->r.min); flushimage(display, 1); freeimage(pp->save); pp->save=0; } pl_invis(p, 1); } g->state=UP; } } plmouse(p, m); if((m->buttons&7)==0) g->state=UP; return (m->buttons&7)!=0; }
/* * Place i so i->r.min = log, i->layer->screenr.min == scr. */ int memlorigin(Memimage *i, Point log, Point scr) { Memlayer *l; Memscreen *s; Memimage *t, *shad, *nsave; Rectangle x, newr, oldr; Point delta; int overlap, eqlog, eqscr, wasclear; l = i->layer; s = l->screen; oldr = l->screenr; newr = Rect(scr.x, scr.y, scr.x+Dx(oldr), scr.y+Dy(oldr)); eqscr = eqpt(scr, oldr.min); eqlog = eqpt(log, i->r.min); if(eqscr && eqlog) return 0; nsave = nil; if(eqlog==0 && l->save!=nil){ nsave = allocmemimage(Rect(log.x, log.y, log.x+Dx(oldr), log.y+Dy(oldr)), i->chan); if(nsave == nil) return -1; } /* * Bring it to front and move logical coordinate system. */ memltofront(i); wasclear = l->clear; if(nsave){ if(!wasclear) memimagedraw(nsave, nsave->r, l->save, l->save->r.min, nil, Pt(0,0), S); freememimage(l->save); l->save = nsave; } delta = subpt(log, i->r.min); i->r = rectaddpt(i->r, delta); i->clipr = rectaddpt(i->clipr, delta); l->delta = subpt(l->screenr.min, i->r.min); if(eqscr) return 0; /* * To clean up old position, make a shadow window there, don't paint it, * push it behind this one, and (later) delete it. Because the refresh function * for this fake window is a no-op, this will cause no graphics action except * to restore the background and expose the windows previously hidden. */ shad = memlalloc(s, oldr, memlnorefresh, nil, DNofill); if(shad == nil) return -1; s->frontmost = i; if(s->rearmost == i) s->rearmost = shad; else l->rear->layer->front = shad; shad->layer->front = i; shad->layer->rear = l->rear; l->rear = shad; l->front = nil; shad->layer->clear = 0; /* * Shadow is now holding down the fort at the old position. * Move the window and hide things obscured by new position. */ for(t=l->rear->layer->rear; t!=nil; t=t->layer->rear){ x = newr; overlap = rectclip(&x, t->layer->screenr); if(overlap){ memlhide(t, x); t->layer->clear = 0; } } l->screenr = newr; l->delta = subpt(scr, i->r.min); l->clear = rectinrect(newr, l->screen->image->clipr); /* * Everything's covered. Copy to new position and delete shadow window. */ if(wasclear) memdraw(s->image, newr, s->image, oldr.min, nil, Pt(0,0), S); else memlexpose(i, newr); memldelete(shad); return 1; }
static int xdraw(Memdrawparam *par) { int dy, dx; unsigned m; Memimage *src, *dst, *mask; Xmem *dxm, *sxm, *mxm; GC gc; Rectangle r, sr, mr; ulong sdval; dx = Dx(par->r); dy = Dy(par->r); src = par->src; dst = par->dst; mask = par->mask; r = par->r; sr = par->sr; mr = par->mr; sdval = par->sdval; return 0; if((dxm = dst->X) == nil) return 0; /* * If we have an opaque mask and source is one opaque pixel we can convert to the * destination format and just XFillRectangle. */ m = Simplesrc|Simplemask|Fullmask; if((par->state&m)==m){ xfillcolor(dst, r, sdval); dirtyXdata(dst, par->r); return 1; } /* * If no source alpha, an opaque mask, we can just copy the * source onto the destination. If the channels are the same and * the source is not replicated, XCopyArea suffices. */ m = Simplemask|Fullmask; if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){ sxm = src->X; r = rectsubpt(r, dst->r.min); sr = rectsubpt(sr, src->r.min); if(dst->chan == GREY1) gc = xgccopy0; else gc = xgccopy; XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc, sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y); dirtyXdata(dst, par->r); return 1; } /* * If no source alpha, a 1-bit mask, and a simple source * we can just copy through the mask onto the destination. */ if(dst->X && mask->X && !(mask->flags&Frepl) && mask->chan == GREY1 && (par->state&Simplesrc)){ Point p; mxm = mask->X; r = rectsubpt(r, dst->r.min); mr = rectsubpt(mr, mask->r.min); p = subpt(r.min, mr.min); if(dst->chan == GREY1){ gc = xgcsimplesrc0; if(xgcsimplecolor0 != sdval){ XSetForeground(xdisplay, gc, sdval); xgcsimplecolor0 = sdval; } if(xgcsimplepm0 != mxm->pmid){ XSetStipple(xdisplay, gc, mxm->pmid); xgcsimplepm0 = mxm->pmid; } }else{ /* somehow this doesn't work on rob's mac gc = xgcsimplesrc; if(dst->chan == CMAP8 && xtblbit) sdval = plan9tox11[sdval]; if(xgcsimplecolor != sdval){ XSetForeground(xdisplay, gc, sdval); xgcsimplecolor = sdval; } if(xgcsimplepm != mxm->pmid){ XSetStipple(xdisplay, gc, mxm->pmid); xgcsimplepm = mxm->pmid; } */ return 0; } XSetTSOrigin(xdisplay, gc, p.x, p.y); XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy); dirtyXdata(dst, par->r); return 1; } return 0; }