1 #include <u.h> 2 #include <libc.h> 3 #include <libg.h> 4 #include <frame.h> 5 #include "flayer.h" 6 #include "samterm.h" 7 8 #define DELTA 10 9 10 static Flayer **llist; /* front to back */ 11 static int nllist; 12 static int nlalloc; 13 static Rectangle lDrect; 14 15 extern Bitmap screen; 16 extern Mouse mouse; 17 18 Vis visibility(Flayer *); 19 void newvisibilities(int); 20 void llinsert(Flayer*); 21 void lldelete(Flayer*); 22 23 void 24 flstart(Rectangle r) 25 { 26 lDrect = r; 27 } 28 29 void 30 flnew(Flayer *l, Rune *(*fn)(Flayer*, long, ulong*), int u0, void *u1) 31 { 32 if(nllist == nlalloc){ 33 nlalloc += DELTA; 34 llist = realloc(llist, nlalloc*sizeof(Flayer**)); 35 if(llist == 0) 36 panic("flnew"); 37 } 38 l->textfn = fn; 39 l->user0 = u0; 40 l->user1 = u1; 41 llinsert(l); 42 } 43 44 Rectangle 45 flrect(Flayer *l, Rectangle r) 46 { 47 rectclip(&r, lDrect); 48 l->entire = r; 49 l->scroll = inset(r, FLMARGIN); 50 r.min.x = 51 l->scroll.max.x = r.min.x+FLMARGIN+FLSCROLLWID+(FLGAP-FLMARGIN); 52 return r; 53 } 54 55 void 56 flinit(Flayer *l, Rectangle r, Font *ft) 57 { 58 lldelete(l); 59 llinsert(l); 60 l->visible = All; 61 l->origin = l->p0 = l->p1 = 0; 62 frinit(&l->f, inset(flrect(l, r), FLMARGIN), ft, &screen); 63 newvisibilities(1); 64 bitblt(&screen, l->entire.min, &screen, l->entire, 0); 65 scrdraw(l, 0L); 66 flborder(l, 0); 67 } 68 69 void 70 flclose(Flayer *l) 71 { 72 if(l->visible == All) 73 bitblt(&screen, l->entire.min, &screen, l->entire, 0); 74 else if(l->visible == Some){ 75 if(l->f.b == 0) 76 l->f.b = balloc(l->entire, screen.ldepth); 77 if(l->f.b){ 78 bitblt(l->f.b, l->entire.min, l->f.b, l->entire, 0); 79 flrefresh(l, l->entire, 0); 80 } 81 } 82 frclear(&l->f); 83 lldelete(l); 84 if(l->f.b && l->visible!=All) 85 bfree(l->f.b); 86 l->textfn = 0; 87 newvisibilities(1); 88 } 89 90 void 91 flborder(Flayer *l, int wide) 92 { 93 if(flprepare(l)){ 94 border(l->f.b, l->entire, FLMARGIN, 0); 95 border(l->f.b, l->entire, wide? FLMARGIN : 1, F&~D); 96 if(l->visible==Some) 97 flrefresh(l, l->entire, 0); 98 } 99 } 100 101 Flayer * 102 flwhich(Point p) 103 { 104 int i; 105 106 if(p.x==0 && p.y==0) 107 return nllist? llist[0] : 0; 108 for(i=0; i<nllist; i++) 109 if(ptinrect(p, llist[i]->entire)) 110 return llist[i]; 111 return 0; 112 } 113 114 void 115 flupfront(Flayer *l) 116 { 117 int v = l->visible; 118 119 lldelete(l); 120 llinsert(l); 121 if(v!=All) 122 newvisibilities(0); 123 } 124 125 void 126 newvisibilities(int redraw) 127 /* if redraw false, we know it's a flupfront, and needn't 128 * redraw anyone becoming partially covered */ 129 { 130 int i; 131 Vis ov; 132 Flayer *l; 133 134 for(i = 0; i<nllist; i++){ 135 l = llist[i]; 136 ov = l->visible; 137 l->visible = visibility(l); 138 #define V(a, b) (((a)<<2)|((b))) 139 switch(V(ov, l->visible)){ 140 case V(Some, None): 141 if(l->f.b) 142 bfree(l->f.b); 143 case V(All, None): 144 case V(All, Some): 145 l->f.b = 0; 146 frclear(&l->f); 147 break; 148 149 case V(Some, Some): 150 if(l->f.b==0 && redraw) 151 case V(None, Some): 152 flprepare(l); 153 if(l->f.b && redraw){ 154 flrefresh(l, l->entire, 0); 155 bfree(l->f.b); 156 l->f.b = 0; 157 frclear(&l->f); 158 } 159 case V(None, None): 160 case V(All, All): 161 break; 162 163 case V(Some, All): 164 if(l->f.b){ 165 bitblt(&screen, l->entire.min, l->f.b, l->entire, S); 166 bfree(l->f.b); 167 l->f.b = &screen; 168 break; 169 } 170 case V(None, All): 171 flprepare(l); 172 break; 173 } 174 if(ov==None && l->visible!=None) 175 flnewlyvisible(l); 176 } 177 } 178 179 void 180 llinsert(Flayer *l) 181 { 182 int i; 183 for(i=nllist; i>0; --i) 184 llist[i]=llist[i-1]; 185 llist[0]=l; 186 nllist++; 187 } 188 189 void 190 lldelete(Flayer *l) 191 { 192 int i; 193 194 for(i=0; i<nllist; i++) 195 if(llist[i]==l){ 196 --nllist; 197 for(; i<nllist; i++) 198 llist[i] = llist[i+1]; 199 return; 200 } 201 panic("lldelete"); 202 } 203 204 void 205 flinsert(Flayer *l, Rune *sp, Rune *ep, long p0) 206 { 207 if(flprepare(l)){ 208 frinsert(&l->f, sp, ep, p0-l->origin); 209 scrdraw(l, scrtotal(l)); 210 if(l->visible==Some) 211 flrefresh(l, l->entire, 0); 212 } 213 } 214 215 void 216 fldelete(Flayer *l, long p0, long p1) 217 { 218 if(flprepare(l)){ 219 p0 -= l->origin; 220 if(p0 < 0) 221 p0 = 0; 222 p1 -= l->origin; 223 if(p1<0) 224 p1 = 0; 225 frdelete(&l->f, p0, p1); 226 scrdraw(l, scrtotal(l)); 227 if(l->visible==Some) 228 flrefresh(l, l->entire, 0); 229 } 230 } 231 232 int 233 flselect(Flayer *l) 234 { 235 int ret = 0; 236 if(l->visible!=All) 237 flupfront(l); 238 frselect(&l->f, &mouse); 239 if(l->f.p0==l->f.p1){ 240 if(mouse.msec-l->click<Clicktime && l->f.p0+l->origin==l->p0){ 241 ret = 1; 242 l->click = 0; 243 }else 244 l->click = mouse.msec; 245 }else 246 l->click = 0; 247 l->p0 = l->f.p0+l->origin, l->p1 = l->f.p1+l->origin; 248 return ret; 249 } 250 251 void 252 flsetselect(Flayer *l, long p0, long p1) 253 { 254 ulong fp0, fp1; 255 256 l->click = 0; 257 if(l->visible==None || !flprepare(l)){ 258 l->p0 = p0, l->p1 = p1; 259 return; 260 } 261 l->p0 = p0, l->p1 = p1; 262 flfp0p1(l, &fp0, &fp1); 263 if(fp0==l->f.p0 && fp1==l->f.p1) 264 return; 265 frselectp(&l->f, F&~D); 266 l->f.p0 = fp0, l->f.p1 = fp1; 267 frselectp(&l->f, F&~D); 268 if(l->visible==Some) 269 flrefresh(l, l->entire, 0); 270 } 271 272 void 273 flfp0p1(Flayer *l, ulong *pp0, ulong *pp1) 274 { 275 long p0 = l->p0-l->origin, p1 = l->p1-l->origin; 276 277 if(p0 < 0) 278 p0 = 0; 279 if(p1 < 0) 280 p1 = 0; 281 if(p0 > l->f.nchars) 282 p0 = l->f.nchars; 283 if(p1 > l->f.nchars) 284 p1 = l->f.nchars; 285 *pp0 = p0; 286 *pp1 = p1; 287 } 288 289 Rectangle 290 rscale(Rectangle r, Point old, Point new) 291 { 292 r.min.x = r.min.x*new.x/old.x; 293 r.min.y = r.min.y*new.y/old.y; 294 r.max.x = r.max.x*new.x/old.x; 295 r.max.y = r.max.y*new.y/old.y; 296 return r; 297 } 298 299 void 300 flreshape(Rectangle dr) 301 { 302 int i; 303 Flayer *l; 304 Frame *f; 305 Rectangle r, olDrect; 306 int move; 307 308 olDrect = lDrect; 309 lDrect = dr; 310 move = 0; 311 if(Dx(dr)==Dx(olDrect) && Dy(dr)==Dy(olDrect)) 312 move = 1; 313 else 314 bitblt(&screen, lDrect.min, &screen, lDrect, 0); 315 for(i=0; i<nllist; i++){ 316 l = llist[i]; 317 f = &l->f; 318 if(move) 319 r = raddp(rsubp(l->entire, olDrect.min), dr.min); 320 else{ 321 r = raddp(rscale(rsubp(l->entire, olDrect.min), 322 sub(olDrect.max, olDrect.min), 323 sub(dr.max, dr.min)), dr.min); 324 if(l->visible==Some && f->b){ 325 bfree(f->b); 326 frclear(f); 327 } 328 f->b = 0; 329 if(l->visible!=None) 330 frclear(f); 331 } 332 if(!rectclip(&r, dr)) 333 panic("flreshape"); 334 if(r.max.x-r.min.x<100) 335 r.min.x = dr.min.x; 336 if(r.max.x-r.min.x<100) 337 r.max.x = dr.max.x; 338 if(r.max.y-r.min.y<2*FLMARGIN+f->font->height) 339 r.min.y = dr.min.y; 340 if(r.max.y-r.min.y<2*FLMARGIN+f->font->height) 341 r.max.y = dr.max.y; 342 if(!move) 343 l->visible = None; 344 frsetrects(f, inset(flrect(l, r), FLMARGIN), f->b); 345 if(!move && f->b) 346 scrdraw(l, scrtotal(l)); 347 } 348 newvisibilities(1); 349 } 350 351 int 352 flprepare(Flayer *l) 353 { 354 Frame *f; 355 ulong n; 356 Rune *r; 357 358 if(l->visible == None) 359 return 0; 360 f = &l->f; 361 if(f->b == 0){ 362 if(l->visible == All) 363 f->b = &screen; 364 else if((f->b = balloc(l->entire, screen.ldepth))==0) 365 return 0; 366 bitblt(f->b, l->entire.min, f->b, l->entire, 0); 367 border(f->b, l->entire, l==llist[0]? FLMARGIN : 1, F&~D); 368 n = f->nchars; 369 frinit(f, f->entire, f->font, f->b); 370 r = (*l->textfn)(l, n, &n); 371 frinsert(f, r, r+n, (ulong)0); 372 frselectp(f, F&~D); 373 flfp0p1(l, &l->f.p0, &l->f.p1); 374 frselectp(f, F&~D); 375 scrdraw(l, scrtotal(l)); 376 } 377 return 1; 378 } 379 380 static int somevis, someinvis, justvis; 381 382 Vis 383 visibility(Flayer *l) 384 { 385 somevis = someinvis = 0; 386 justvis = 1; 387 flrefresh(l, l->entire, 0); 388 justvis = 0; 389 if(somevis==0) 390 return None; 391 if(someinvis==0) 392 return All; 393 return Some; 394 } 395 396 void 397 flrefresh(Flayer *l, Rectangle r, int i) 398 { 399 Flayer *t; 400 Rectangle s; 401 402 Top: 403 if((t=llist[i++]) == l){ 404 if(!justvis) 405 bitblt(&screen, r.min, l->f.b, r, S); 406 somevis = 1; 407 }else{ 408 if(!rectXrect(t->entire, r)) 409 goto Top; /* avoid stacking unnecessarily */ 410 if(t->entire.min.x>r.min.x){ 411 s = r; 412 s.max.x = t->entire.min.x; 413 flrefresh(l, s, i); 414 r.min.x = t->entire.min.x; 415 } 416 if(t->entire.min.y>r.min.y){ 417 s = r; 418 s.max.y = t->entire.min.y; 419 flrefresh(l, s, i); 420 r.min.y = t->entire.min.y; 421 } 422 if(t->entire.max.x<r.max.x){ 423 s = r; 424 s.min.x = t->entire.max.x; 425 flrefresh(l, s, i); 426 r.max.x = t->entire.max.x; 427 } 428 if(t->entire.max.y<r.max.y){ 429 s = r; 430 s.min.y = t->entire.max.y; 431 flrefresh(l, s, i); 432 r.max.y = t->entire.max.y; 433 } 434 /* remaining piece of r is blocked by t; forget about it */ 435 someinvis = 1; 436 } 437 } 438