static void ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) { struct Draw *d; Point p0, p1; Rectangle oclipr, srcr, r, mr; int ok; d = etc; if(insave && d->dstlayer->save==nil) return; p0 = addpt(screenr.min, d->deltas); p1 = addpt(screenr.min, d->deltam); if(insave){ r = rectsubpt(screenr, d->dstlayer->delta); clipr = rectsubpt(clipr, d->dstlayer->delta); }else r = screenr; /* now in logical coordinates */ /* clipr may have narrowed what we should draw on, so clip if necessary */ if(!rectinrect(r, clipr)){ oclipr = dst->clipr; dst->clipr = clipr; ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr); dst->clipr = oclipr; if(!ok) return; } memdraw(dst, r, d->src, p0, d->mask, p1, d->op); }
void resize(void) { Rectangle old, r; int dxo, dyo, dxn, dyn; Win *w; old = screen->r; dxo = Dx(old); dyo = Dy(old); if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); dxn = Dx(screen->r); dyn = Dy(screen->r); freescreen(scr); scr = allocscreen(screen, display->white, 0); if(scr == nil) sysfatal("allocscreen: %r"); for(w = wlist.next; w != &wlist; w = w->next){ r = rectsubpt(w->entire, old.min); r.min.x = muldiv(r.min.x, dxn, dxo); r.max.x = muldiv(r.max.x, dxn, dxo); r.min.y = muldiv(r.min.y, dyn, dyo); r.max.y = muldiv(r.max.y, dyn, dyo); w->entire = rectaddpt(r, screen->r.min); w->inner = insetrect(w->entire, BORDSIZ); freeimage(w->im); w->im = allocwindow(scr, w->entire, Refbackup, 0); if(w->im == nil) sysfatal("allocwindow: %r"); draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP); border(w->im, w->entire, BORDSIZ, w->tab->cols[w == actw ? BORD : DISB], ZP); w->tab->draw(w); } }
static bool cwin_expose(Window *w, void *aux, XExposeEvent *e) { fill(w, rectsubpt(w->r, w->r.min), &def.focuscolor.bg); fill(w, w->r, &def.focuscolor.bg); return false; }
void xfillcolor(Memimage *m, Rectangle r, ulong v) { GC gc; Xmem *dxm; dxm = m->X; assert(dxm != nil); r = rectsubpt(r, m->r.min); if(m->chan == GREY1){ gc = xgcfill0; if(xgcfillcolor0 != v){ XSetForeground(xdisplay, gc, v); xgcfillcolor0 = v; } }else{ if(m->chan == CMAP8 && xtblbit) v = plan9tox11[v]; gc = xgcfill; if(xgcfillcolor != v){ XSetForeground(xdisplay, gc, v); xgcfillcolor = v; } } XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r)); }
void drawtable(Box *b, Page *p, Image *im) { Rectangle r, cr; Tablecell *c; Table *t; t = ((Itable *)b->i)->table; r = rectsubpt(b->r, p->pos); draw(im, r, getcolor(t->background.color), nil, ZP); if(t->border) border(im, r, t->border, display->black, ZP); for(c=t->cells; c!=nil; c=c->next){ cr = rectsubpt(c->lay->r, p->pos); if(c->background.color != t->background.color) draw(im, cr, getcolor(c->background.color), nil, ZP); if(t->border) border(im, cr, t->border, display->black, ZP); laydraw(p, im, c->lay); } }
static void lhideop(Memimage *src, Rectangle screenr, Rectangle clipr, void *etc, int insave) { Rectangle r; Memlayer *l; USED(clipr.min.x); USED(insave); l = etc; if(src != l->save){ /* do nothing if src is already in save area */ r = rectsubpt(screenr, l->delta); memdraw(l->save, r, src, screenr.min, nil, screenr.min, S); } }
static void tkcvsseesub(Tk *tk, Rectangle *rr, Point *pp) { Rectangle r; Point p; TkCanvas *c; c = TKobj(TkCanvas, tk); r = rectaddpt(*rr, c->view); p = addpt(*pp, c->view); tkcvsseerect(tk, r, p); *rr = rectsubpt(r, c->view); *pp = subpt(p, c->view); }
static void lexposeop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) { Memlayer *l; Rectangle r; USED(clipr.min.x); if(insave) /* if dst is save area, don't bother */ return; l = etc; r = rectsubpt(screenr, l->delta); if(l->save) memdraw(dst, screenr, l->save, r.min, nil, r.min, S); else l->refreshfn(dst, r, l->refreshptr); }
static void llineop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) { struct Lline *ll; Point p0, p1; USED(screenr.min.x); ll = etc; if(insave && ll->dstlayer->save==nil) return; if(!rectclip(&clipr, screenr)) return; if(insave){ p0 = subpt(ll->p0, ll->delta); p1 = subpt(ll->p1, ll->delta); clipr = rectsubpt(clipr, ll->delta); }else{ p0 = ll->p0; p1 = ll->p1; } _memline(dst, p0, p1, ll->end0, ll->end1, ll->radius, ll->src, ll->sp, clipr, ll->op); }
Rectangle sizehint(WinHints *h, Rectangle r) { Point p, aspect, origin; if(h == nil) return r; origin = r.min; r = rectsubpt(r, origin); /* Min/max */ r.max.x = max(r.max.x, h->min.x); r.max.y = max(r.max.y, h->min.y); r.max.x = min(r.max.x, h->max.x); r.max.y = min(r.max.y, h->max.y); /* Increment */ p = subpt(r.max, h->base); r.max.x -= p.x % h->inc.x; r.max.y -= p.y % h->inc.y; /* Aspect */ p = subpt(r.max, h->baspect); p.y = max(p.y, 1); aspect = h->aspect.min; if(p.x * aspect.y / p.y < aspect.x) r.max.y = 1 + h->baspect.y + p.x * aspect.y / aspect.x; aspect = h->aspect.max; if(p.x * aspect.y / p.y > aspect.x) r.max.x = h->baspect.x + p.y * aspect.x / aspect.y; return rectaddpt(r, origin); }
void tkcvswinddraw(Image *img, TkCitem *i, TkEnv *pe) { TkCwind *w; Point rel; Rectangle r; Tk *sub; USED(img); /* See tkimageof */ USED(pe); w = TKobj(TkCwind, i); sub = w->sub; if(sub != nil) { int dirty; r = i->p.bb; rel.x = r.min.x + sub->borderwidth; rel.y = r.min.y + sub->borderwidth; if (rectclip(&r, img->clipr)) { sub->dirty = rectsubpt(r, rel); sub->flag |= Tkrefresh; tkdrawslaves(sub, ZP, &dirty); /* XXX - Tad: propagate err? */ } } }
int eenter(char *ask, char *buf, int len, Mouse *m) { int done, down, tick, n, h, w, l, i; Image *b, *save, *backcol, *bordcol; Point p, o, t; Rectangle r, sc; Event ev; Rune k; o = screen->r.min; backcol = allocimagemix(display, DPurpleblue, DWhite); bordcol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue); if(backcol == nil || bordcol == nil) return -1; while(ecankbd()) ekbd(); if(m) o = m->xy; if(buf && len > 0) n = strlen(buf); else { buf = nil; len = 0; n = 0; } k = -1; tick = n; save = nil; done = down = 0; p = stringsize(font, " "); h = p.y; w = p.x; b = screen; sc = b->clipr; replclipr(b, 0, b->r); while(!done){ p = stringsize(font, buf ? buf : ""); if(ask && ask[0]){ if(buf) p.x += w; p.x += stringwidth(font, ask); } r = rectaddpt(insetrect(Rpt(ZP, p), -4), o); p.x = 0; r = rectsubpt(r, p); p = ZP; if(r.min.x < screen->r.min.x) p.x = screen->r.min.x - r.min.x; if(r.min.y < screen->r.min.y) p.y = screen->r.min.y - r.min.y; r = rectaddpt(r, p); p = ZP; if(r.max.x > screen->r.max.x) p.x = r.max.x - screen->r.max.x; if(r.max.y > screen->r.max.y) p.y = r.max.y - screen->r.max.y; r = rectsubpt(r, p); r = insetrect(r, -2); if(save == nil){ save = allocimage(display, r, b->chan, 0, DNofill); if(save == nil){ n = -1; break; } draw(save, r, b, nil, r.min); } draw(b, r, backcol, nil, ZP); border(b, r, 2, bordcol, ZP); p = addpt(r.min, Pt(6, 6)); if(ask && ask[0]){ p = string(b, p, bordcol, ZP, font, ask); if(buf) p.x += w; } if(buf){ t = p; p = stringn(b, p, display->black, ZP, font, buf, utfnlen(buf, tick)); draw(b, Rect(p.x-1, p.y, p.x+2, p.y+3), display->black, nil, ZP); draw(b, Rect(p.x, p.y, p.x+1, p.y+h), display->black, nil, ZP); draw(b, Rect(p.x-1, p.y+h-3, p.x+2, p.y+h), display->black, nil, ZP); p = string(b, p, display->black, ZP, font, buf+tick); } flushimage(display, 1); nodraw: i = Ekeyboard; if(m != nil) i |= Emouse; replclipr(b, 0, sc); i = eread(i, &ev); /* screen might have been resized */ if(b != screen || !eqrect(screen->clipr, sc)){ freeimage(save); save = nil; } b = screen; sc = b->clipr; replclipr(b, 0, b->r); switch(i){ default: done = 1; n = -1; break; case Ekeyboard: k = ev.kbdc; if(buf == nil || k == Keof || k == '\n'){ done = 1; break; } if(k == Knack || k == Kesc){ done = !n; buf[n = tick = 0] = 0; break; } if(k == Ksoh || k == Khome){ tick = 0; continue; } if(k == Kenq || k == Kend){ tick = n; continue; } if(k == Kright){ if(tick < n) tick += chartorune(&k, buf+tick); continue; } if(k == Kleft){ for(i = 0; i < n; i += l){ l = chartorune(&k, buf+tick); if(i+l >= tick){ tick = i; break; } } continue; } if(k == Ketb){ while(tick > 0){ tick--; if(tick == 0 || strchr(" !\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", buf[tick-1])) break; } buf[n = tick] = 0; break; } if(k == Kbs){ if(tick <= 0) continue; for(i = 0; i < n; i += l){ l = chartorune(&k, buf+i); if(i+l >= tick){ memmove(buf+i, buf+i+l, n - (i+l)); buf[n -= l] = 0; tick -= l; break; } } break; } if(k < 0x20 || k == Kdel || (k & 0xFF00) == KF || (k & 0xFF00) == Spec) continue; if((len-n) <= (l = runelen(k))) continue; memmove(buf+tick+l, buf+tick, n - tick); runetochar(buf+tick, &k); buf[n += l] = 0; tick += l; break; case Emouse: *m = ev.mouse; if(!ptinrect(m->xy, r)){ down = 0; goto nodraw; } if(m->buttons & 7){ down = 1; if(buf && m->xy.x >= (t.x - w)){ down = 0; for(i = 0; i < n; i += l){ l = chartorune(&k, buf+i); t.x += stringnwidth(font, buf+i, 1); if(t.x > m->xy.x) break; } tick = i; } continue; } done = down; break; } if(save){ draw(b, save->r, save, nil, save->r.min); freeimage(save); save = nil; } } replclipr(b, 0, sc); freeimage(backcol); freeimage(bordcol); flushimage(display, 1); return n; }
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 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; }
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); }
static void cwin_expose(Window *w, XExposeEvent *e) { fill(w, rectsubpt(w->r, w->r.min), def.focuscolor.bg); fill(w, w->r, def.focuscolor.bg); }
int menuhit(int but, Mousectl *mc, Menu *menu, Screen *scr) { int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; int scrolling; Rectangle r, menur, sc, textr, scrollr; Image *b, *save, *backup; 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, mc->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); if(scr){ b = allocwindow(scr, menur, Refbackup, DWhite); if(b == nil) b = screen; backup = nil; }else{ b = screen; backup = allocimage(display, menur, screen->chan, 0, -1); if(backup) draw(backup, menur, screen, nil, menur.min); } draw(b, menur, back, nil, ZP); border(b, menur, Blackborder, bord, ZP); save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1); r = menurect(textr, lasti); moveto(mc, divpt(addpt(r.min, r.max), 2)); menupaint(b, menu, textr, off, nitemdrawn); if(scrolling) menuscrollpaint(b, scrollr, off, nitem, nitemdrawn); while(mc->m.buttons & (1<<(but-1))){ lasti = menuscan(b, menu, but, mc, textr, off, lasti, save); if(lasti >= 0) break; while(!ptinrect(mc->m.xy, textr) && (mc->m.buttons & (1<<(but-1)))){ if(scrolling && ptinrect(mc->m.xy, scrollr)){ noff = ((mc->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(b, menu, textr, off, nitemdrawn); menuscrollpaint(b, scrollr, off, nitem, nitemdrawn); } } readmouse(mc); } } if(b != screen) freeimage(b); if(backup){ draw(screen, menur, backup, nil, menur.min); freeimage(backup); } freeimage(save); replclipr(screen, 0, sc); flushimage(display, 1); if(lasti >= 0){ menu->lasthit = lasti+off; return menu->lasthit; } return -1; }
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); }