scrl.c (3271B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <thread.h> 5 #include <cursor.h> 6 #include <mouse.h> 7 #include <keyboard.h> 8 #include <frame.h> 9 #include <fcall.h> 10 #include "dat.h" 11 #include "fns.h" 12 13 static Image *scrtmp; 14 15 static 16 void 17 scrtemps(void) 18 { 19 int h; 20 21 if(scrtmp) 22 return; 23 h = BIG*Dy(screen->r); 24 scrtmp = allocimage(display, Rect(0, 0, 32, h), screen->chan, 0, DWhite); 25 if(scrtmp == nil) 26 error("scrtemps"); 27 } 28 29 void 30 freescrtemps(void) 31 { 32 freeimage(scrtmp); 33 scrtmp = nil; 34 } 35 36 static 37 Rectangle 38 scrpos(Rectangle r, uint p0, uint p1, uint tot) 39 { 40 Rectangle q; 41 int h; 42 43 q = r; 44 h = q.max.y-q.min.y; 45 if(tot == 0) 46 return q; 47 if(tot > 1024*1024){ 48 tot>>=10; 49 p0>>=10; 50 p1>>=10; 51 } 52 if(p0 > 0) 53 q.min.y += h*p0/tot; 54 if(p1 < tot) 55 q.max.y -= h*(tot-p1)/tot; 56 if(q.max.y < q.min.y+2){ 57 if(q.min.y+2 <= r.max.y) 58 q.max.y = q.min.y+2; 59 else 60 q.min.y = q.max.y-2; 61 } 62 return q; 63 } 64 65 void 66 wscrdraw(Window *w) 67 { 68 Rectangle r, r1, r2; 69 Image *b; 70 71 scrtemps(); 72 if(w->i == nil) 73 error("scrdraw"); 74 r = w->scrollr; 75 b = scrtmp; 76 r1 = r; 77 r1.min.x = 0; 78 r1.max.x = Dx(r); 79 r2 = scrpos(r1, w->org, w->org+w->f.nchars, w->nr); 80 if(!eqrect(r2, w->lastsr)){ 81 w->lastsr = r2; 82 /* move r1, r2 to (0,0) to avoid clipping */ 83 r2 = rectsubpt(r2, r1.min); 84 r1 = rectsubpt(r1, r1.min); 85 draw(b, r1, w->f.cols[BORD], nil, ZP); 86 draw(b, r2, w->f.cols[BACK], nil, ZP); 87 r2.min.x = r2.max.x-1; 88 draw(b, r2, w->f.cols[BORD], nil, ZP); 89 draw(w->i, r, b, nil, Pt(0, r1.min.y)); 90 } 91 } 92 93 void 94 wscrsleep(Window *w, uint dt) 95 { 96 Timer *timer; 97 int y, b; 98 static Alt alts[3]; 99 100 timer = timerstart(dt); 101 y = w->mc.m.xy.y; 102 b = w->mc.m.buttons; 103 alts[0].c = timer->c; 104 alts[0].v = nil; 105 alts[0].op = CHANRCV; 106 alts[1].c = w->mc.c; 107 alts[1].v = &w->mc.m; 108 alts[1].op = CHANRCV; 109 alts[2].op = CHANEND; 110 for(;;) 111 switch(alt(alts)){ 112 case 0: 113 timerstop(timer); 114 return; 115 case 1: 116 if(abs(w->mc.m.xy.y-y)>2 || w->mc.m.buttons!=b){ 117 timercancel(timer); 118 return; 119 } 120 break; 121 } 122 } 123 124 void 125 wscroll(Window *w, int but) 126 { 127 uint p0, oldp0; 128 Rectangle s; 129 int x, y, my, h, first; 130 131 s = insetrect(w->scrollr, 1); 132 h = s.max.y-s.min.y; 133 x = (s.min.x+s.max.x)/2; 134 oldp0 = ~0; 135 first = TRUE; 136 do{ 137 flushimage(display, 1); 138 if(w->mc.m.xy.x<s.min.x || s.max.x<=w->mc.m.xy.x){ 139 readmouse(&w->mc); 140 }else{ 141 my = w->mc.m.xy.y; 142 if(my < s.min.y) 143 my = s.min.y; 144 if(my >= s.max.y) 145 my = s.max.y; 146 if(!eqpt(w->mc.m.xy, Pt(x, my))){ 147 wmovemouse(w, Pt(x, my)); 148 readmouse(&w->mc); /* absorb event generated by moveto() */ 149 } 150 if(but == 2){ 151 y = my; 152 if(y > s.max.y-2) 153 y = s.max.y-2; 154 if(w->nr > 1024*1024) 155 p0 = ((w->nr>>10)*(y-s.min.y)/h)<<10; 156 else 157 p0 = w->nr*(y-s.min.y)/h; 158 if(oldp0 != p0) 159 wsetorigin(w, p0, FALSE); 160 oldp0 = p0; 161 readmouse(&w->mc); 162 continue; 163 } 164 if(but == 1) 165 p0 = wbacknl(w, w->org, (my-s.min.y)/w->f.font->height); 166 else 167 p0 = w->org+frcharofpt(&w->f, Pt(s.max.x, my)); 168 if(oldp0 != p0) 169 wsetorigin(w, p0, TRUE); 170 oldp0 = p0; 171 /* debounce */ 172 if(first){ 173 flushimage(display, 1); 174 sleep(200); 175 nbrecv(w->mc.c, &w->mc.m); 176 first = FALSE; 177 } 178 wscrsleep(w, 100); 179 } 180 }while(w->mc.m.buttons & (1<<(but-1))); 181 while(w->mc.m.buttons) 182 readmouse(&w->mc); 183 }