ref: ca9d65e40b3f78d2580fff9ff1844bad1be08673
dir: /sys/src/cmd/samterm/scroll.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <thread.h> #include <mouse.h> #include <keyboard.h> #include <frame.h> #include "flayer.h" #include "samterm.h" static Image *scrtmp; static Image *scrback; void scrtemps(void) { int h; if(scrtmp) return; if(screensize(0, &h) == 0) h = 2048; scrtmp = allocimage(display, Rect(0, 0, 32, h), screen->chan, 0, 0); scrback = allocimage(display, Rect(0, 0, 32, h), screen->chan, 0, 0); if(scrtmp==0 || scrback==0) panic("scrtemps"); } Rectangle scrpos(Rectangle r, long p0, long p1, long tot) { Rectangle q; int h; q = r; h = q.max.y-q.min.y; if(tot == 0) return q; if(tot > 1024L*1024L) 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 scrmark(Flayer *l, Rectangle r) { r.max.x--; if(rectclip(&r, l->scroll)) { if (l->f.b == nil) panic("scrmark: nil l->f.b"); draw(l->f.b, r, l->f.cols[HIGH], nil, ZP); } } void scrunmark(Flayer *l, Rectangle r) { if(rectclip(&r, l->scroll)) { if (l->f.b == nil) panic("scrunmark: nil l->f.b"); draw(l->f.b, r, scrback, nil, Pt(0, r.min.y-l->scroll.min.y)); } } void scrdraw(Flayer *l, long tot) { Rectangle r, r1, r2; Image *b; scrtemps(); if(l->f.b == 0) panic("scrdraw"); r = l->scroll; r1 = r; if(l->visible == All){ b = scrtmp; r1.min.x = 0; r1.max.x = Dx(r); }else b = l->f.b; r2 = scrpos(r1, l->origin, l->origin+l->f.nchars, tot); if(!eqrect(r2, l->lastsr)){ l->lastsr = r2; draw(b, r1, l->f.cols[BORD], nil, ZP); draw(b, r2, l->f.cols[BACK], nil, r2.min); r2 = r1; r2.min.x = r2.max.x-1; draw(b, r2, l->f.cols[BORD], nil, ZP); if(b!=l->f.b) draw(l->f.b, r, b, nil, r1.min); } } void scroll(Flayer *l, int but) { int in = 0, oin; long tot = scrtotal(l); Rectangle scr, r, s, rt; int x, y, my, oy, h; long p0; s = l->scroll; x = s.min.x+FLSCROLLWID/2; scr = scrpos(l->scroll, l->origin, l->origin+l->f.nchars, tot); r = scr; y = scr.min.y; my = mousep->xy.y; draw(scrback, Rect(0,0,Dx(l->scroll), Dy(l->scroll)), l->f.b, nil, l->scroll.min); do{ oin = in; in = (but > 3) || (but == 2) || abs(x-mousep->xy.x)<=FLSCROLLWID/2; if(oin && !in) scrunmark(l, r); if(in){ scrmark(l, r); oy = y; my = mousep->xy.y; if(my < s.min.y) my = s.min.y; if(my >= s.max.y) my = s.max.y; if(but == 1 || but == 4){ p0 = l->origin-frcharofpt(&l->f, Pt(s.max.x, my)); rt = scrpos(l->scroll, p0, p0+l->f.nchars, tot); y = rt.min.y; }else if(but == 2){ y = my; if(y > s.max.y-2) y = s.max.y-2; }else if(but == 3 || but == 5){ p0 = l->origin+frcharofpt(&l->f, Pt(s.max.x, my)); rt = scrpos(l->scroll, p0, p0+l->f.nchars, tot); y = rt.min.y; } if(y != oy){ scrunmark(l, r); r = rectaddpt(scr, Pt(0, y-scr.min.y)); scrmark(l, r); } } }while(but <= 3 && button(but)); if(in){ h = s.max.y-s.min.y; scrunmark(l, r); p0 = 0; if(but == 1 || but == 4){ but = 1; p0 = (long)(my-s.min.y)/l->f.font->height+1; }else if(but == 2){ if(tot > 1024L*1024L) p0 = ((tot>>10)*(y-s.min.y)/h)<<10; else p0 = tot*(y-s.min.y)/h; }else if(but == 3 || but == 5){ but = 3; p0 = l->origin+frcharofpt(&l->f, Pt(s.max.x, my)); if(p0 > tot) p0 = tot; } scrorigin(l, but, p0); } }