#include #include #include #include #include #include #include #include "libframe/frame.h" #include #include #include #include "dat.h" #include "fns.h" static Image* scrtmp; static Rectangle scrpos(Rectangle r, uint p0, uint p1, uint tot) { Rectangle q; int h; q = r; h = q.max.y - q.min.y; if (tot == 0) return q; if (tot > 1024 * 1024) { tot >>= 10; p0 >>= 10; p1 >>= 10; } if (p0 > 0) q.min.y += h * p0 / tot; if (p1 < tot) q.max.y -= h * (tot - p1) / tot; if (q.max.y < q.min.y + 2) { if (q.min.y + 2 <= r.max.y) q.max.y = q.min.y + 2; else q.min.y = q.max.y - 2; } return q; } void scrlresize(void) { freeimage(scrtmp); scrtmp = allocimage( display, Rect(0, 0, 32, screen->r.max.y), screen->chan, 0, DNofill); if (scrtmp == nil) error("scroll alloc"); } void textscrdraw(Text* t) { Rectangle r, r1, r2; Image* b; if (t->w == nil || t != &t->w->body) return; if (scrtmp == nil) scrlresize(); r = t->scrollr; b = scrtmp; r1 = r; r1.min.x = 0; r1.max.x = Dx(r); r2 = scrpos(r1, t->org, t->org + t->fr.nchars, t->file->b.nc); if (!eqrect(r2, t->lastsr)) { t->lastsr = r2; draw(b, r1, t->fr.cols[BORD], nil, ZP); draw(b, r2, t->fr.cols[BACK], nil, ZP); r2.min.x = r2.max.x - 1; draw(b, r2, t->fr.cols[BORD], nil, ZP); draw(t->fr.b, r, b, nil, Pt(0, r1.min.y)); /*flushimage(display, 1); // BUG? */ } } void scrsleep(uint dt) { Timer* timer; static Alt alts[3]; timer = timerstart(dt); alts[0].c = timer->c; alts[0].v = nil; alts[0].op = CHANRCV; alts[1].c = mousectl->c; alts[1].v = &mousectl->m; alts[1].op = CHANRCV; alts[2].op = CHANEND; for (;;) switch (alt(alts)) { case 0: timerstop(timer); return; case 1: timercancel(timer); return; } } void textscroll(Text* t, int but) { uint p0, oldp0; Rectangle s; int x, y, my, h, first; s = insetrect(t->scrollr, 1); h = s.max.y - s.min.y; x = (s.min.x + s.max.x) / 2; oldp0 = ~0; first = TRUE; do { flushimage(display, 1); my = mouse->xy.y; if (my < s.min.y) my = s.min.y; if (my >= s.max.y) my = s.max.y; if (!eqpt(mouse->xy, Pt(x, my))) { moveto(mousectl, Pt(x, my)); readmouse(mousectl); /* absorb event generated by moveto() */ } if (but == 2) { y = my; p0 = (vlong)t->file->b.nc * (y - s.min.y) / h; if (p0 >= t->q1) p0 = textbacknl(t, p0, 2); if (oldp0 != p0) textsetorigin(t, p0, FALSE); oldp0 = p0; readmouse(mousectl); continue; } if (but == 1) p0 = textbacknl(t, t->org, (my - s.min.y) / t->fr.font->height); else p0 = t->org + frcharofpt(&t->fr, Pt(s.max.x, my)); if (oldp0 != p0) textsetorigin(t, p0, TRUE); oldp0 = p0; /* debounce */ if (first) { flushimage(display, 1); sleep(200); nbrecv(mousectl->c, &mousectl->m); first = FALSE; } scrsleep(80); } while (mouse->buttons & (1 << (but - 1))); while (mouse->buttons) readmouse(mousectl); }