| #include <u.h> |
| #include <libc.h> |
| #include <draw.h> |
| #include <thread.h> |
| #include <cursor.h> |
| #include <mouse.h> |
| #include <keyboard.h> |
| #include <frame.h> |
| #include <fcall.h> |
| #include "dat.h" |
| #include "fns.h" |
| |
| static Image *scrtmp; |
| |
| static |
| void |
| scrtemps(void) |
| { |
| int h; |
| |
| if(scrtmp) |
| return; |
| h = BIG*Dy(screen->r); |
| scrtmp = allocimage(display, Rect(0, 0, 32, h), screen->chan, 0, DWhite); |
| if(scrtmp == nil) |
| error("scrtemps"); |
| } |
| |
| void |
| freescrtemps(void) |
| { |
| freeimage(scrtmp); |
| scrtmp = nil; |
| } |
| |
| 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 |
| wscrdraw(Window *w) |
| { |
| Rectangle r, r1, r2; |
| Image *b; |
| |
| scrtemps(); |
| if(w->i == nil) |
| error("scrdraw"); |
| r = w->scrollr; |
| b = scrtmp; |
| r1 = r; |
| r1.min.x = 0; |
| r1.max.x = Dx(r); |
| r2 = scrpos(r1, w->org, w->org+w->f.nchars, w->nr); |
| if(!eqrect(r2, w->lastsr)){ |
| w->lastsr = r2; |
| /* move r1, r2 to (0,0) to avoid clipping */ |
| r2 = rectsubpt(r2, r1.min); |
| r1 = rectsubpt(r1, r1.min); |
| draw(b, r1, w->f.cols[BORD], nil, ZP); |
| draw(b, r2, w->f.cols[BACK], nil, ZP); |
| r2.min.x = r2.max.x-1; |
| draw(b, r2, w->f.cols[BORD], nil, ZP); |
| draw(w->i, r, b, nil, Pt(0, r1.min.y)); |
| } |
| } |
| |
| void |
| wscrsleep(Window *w, uint dt) |
| { |
| Timer *timer; |
| int y, b; |
| static Alt alts[3]; |
| |
| timer = timerstart(dt); |
| y = w->mc.m.xy.y; |
| b = w->mc.m.buttons; |
| alts[0].c = timer->c; |
| alts[0].v = nil; |
| alts[0].op = CHANRCV; |
| alts[1].c = w->mc.c; |
| alts[1].v = &w->mc.m; |
| alts[1].op = CHANRCV; |
| alts[2].op = CHANEND; |
| for(;;) |
| switch(alt(alts)){ |
| case 0: |
| timerstop(timer); |
| return; |
| case 1: |
| if(abs(w->mc.m.xy.y-y)>2 || w->mc.m.buttons!=b){ |
| timercancel(timer); |
| return; |
| } |
| break; |
| } |
| } |
| |
| void |
| wscroll(Window *w, int but) |
| { |
| uint p0, oldp0; |
| Rectangle s; |
| int x, y, my, h, first; |
| |
| s = insetrect(w->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); |
| if(w->mc.m.xy.x<s.min.x || s.max.x<=w->mc.m.xy.x){ |
| readmouse(&w->mc); |
| }else{ |
| my = w->mc.m.xy.y; |
| if(my < s.min.y) |
| my = s.min.y; |
| if(my >= s.max.y) |
| my = s.max.y; |
| if(!eqpt(w->mc.m.xy, Pt(x, my))){ |
| wmovemouse(w, Pt(x, my)); |
| readmouse(&w->mc); /* absorb event generated by moveto() */ |
| } |
| if(but == 2){ |
| y = my; |
| if(y > s.max.y-2) |
| y = s.max.y-2; |
| if(w->nr > 1024*1024) |
| p0 = ((w->nr>>10)*(y-s.min.y)/h)<<10; |
| else |
| p0 = w->nr*(y-s.min.y)/h; |
| if(oldp0 != p0) |
| wsetorigin(w, p0, FALSE); |
| oldp0 = p0; |
| readmouse(&w->mc); |
| continue; |
| } |
| if(but == 1) |
| p0 = wbacknl(w, w->org, (my-s.min.y)/w->f.font->height); |
| else |
| p0 = w->org+frcharofpt(&w->f, Pt(s.max.x, my)); |
| if(oldp0 != p0) |
| wsetorigin(w, p0, TRUE); |
| oldp0 = p0; |
| /* debounce */ |
| if(first){ |
| flushimage(display, 1); |
| sleep(200); |
| nbrecv(w->mc.c, &w->mc.m); |
| first = FALSE; |
| } |
| wscrsleep(w, 100); |
| } |
| }while(w->mc.m.buttons & (1<<(but-1))); |
| while(w->mc.m.buttons) |
| readmouse(&w->mc); |
| } |