flayer.c (10337B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <thread.h> 5 #include <mouse.h> 6 #include <cursor.h> 7 #include <keyboard.h> 8 #include <frame.h> 9 #include "flayer.h" 10 #include "samterm.h" 11 12 #define DELTA 10 13 14 static Flayer **llist; /* front to back */ 15 static int nllist; 16 static int nlalloc; 17 static Rectangle lDrect; 18 19 Vis visibility(Flayer *); 20 void newvisibilities(int); 21 void llinsert(Flayer*); 22 void lldelete(Flayer*); 23 24 Image *maincols[NCOL]; 25 Image *cmdcols[NCOL]; 26 27 void 28 flstart(Rectangle r) 29 { 30 lDrect = r; 31 32 /* Main text is yellowish */ 33 maincols[BACK] = allocimagemix(display, DPaleyellow, DWhite); 34 maincols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); 35 maincols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DYellowgreen); 36 maincols[TEXT] = display->black; 37 maincols[HTEXT] = display->black; 38 39 /* Command text is blueish */ 40 cmdcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite); 41 cmdcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen); 42 cmdcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DPurpleblue); 43 cmdcols[TEXT] = display->black; 44 cmdcols[HTEXT] = display->black; 45 } 46 47 void 48 flnew(Flayer *l, Rune *(*fn)(Flayer*, long, ulong*), int u0, void *u1) 49 { 50 if(nllist == nlalloc){ 51 nlalloc += DELTA; 52 llist = realloc(llist, nlalloc*sizeof(Flayer**)); 53 if(llist == 0) 54 panic("flnew"); 55 } 56 l->textfn = fn; 57 l->user0 = u0; 58 l->user1 = u1; 59 l->lastsr = ZR; 60 llinsert(l); 61 } 62 63 Rectangle 64 flrect(Flayer *l, Rectangle r) 65 { 66 rectclip(&r, lDrect); 67 l->entire = r; 68 l->scroll = insetrect(r, FLMARGIN(l)); 69 r.min.x = 70 l->scroll.max.x = r.min.x+FLMARGIN(l)+FLSCROLLWID(l)+(FLGAP(l)-FLMARGIN(l)); 71 return r; 72 } 73 74 void 75 flinit(Flayer *l, Rectangle r, Font *ft, Image **cols) 76 { 77 lldelete(l); 78 llinsert(l); 79 l->visible = All; 80 l->origin = l->p0 = l->p1 = 0; 81 l->f.display = display; // for FLMARGIN 82 frinit(&l->f, insetrect(flrect(l, r), FLMARGIN(l)), ft, screen, cols); 83 l->f.maxtab = maxtab*stringwidth(ft, "0"); 84 newvisibilities(1); 85 draw(screen, l->entire, l->f.cols[BACK], nil, ZP); 86 scrdraw(l, 0L); 87 flborder(l, 0); 88 } 89 90 void 91 flclose(Flayer *l) 92 { 93 if(l->visible == All) 94 draw(screen, l->entire, display->white, nil, ZP); 95 else if(l->visible == Some){ 96 if(l->f.b == 0) 97 l->f.b = allocimage(display, l->entire, screen->chan, 0, DNofill); 98 if(l->f.b){ 99 draw(l->f.b, l->entire, display->white, nil, ZP); 100 flrefresh(l, l->entire, 0); 101 } 102 } 103 frclear(&l->f, 1); 104 lldelete(l); 105 if(l->f.b && l->visible!=All) 106 freeimage(l->f.b); 107 l->textfn = 0; 108 newvisibilities(1); 109 } 110 111 void 112 flborder(Flayer *l, int wide) 113 { 114 if(flprepare(l)){ 115 border(l->f.b, l->entire, FLMARGIN(l), l->f.cols[BACK], ZP); 116 border(l->f.b, l->entire, wide? FLMARGIN(l) : 1, l->f.cols[BORD], ZP); 117 if(l->visible==Some) 118 flrefresh(l, l->entire, 0); 119 } 120 } 121 122 Flayer * 123 flwhich(Point p) 124 { 125 int i; 126 127 if(p.x==0 && p.y==0) 128 return nllist? llist[0] : 0; 129 for(i=0; i<nllist; i++) 130 if(ptinrect(p, llist[i]->entire)) 131 return llist[i]; 132 return 0; 133 } 134 135 void 136 flupfront(Flayer *l) 137 { 138 int v = l->visible; 139 140 lldelete(l); 141 llinsert(l); 142 if(v!=All) 143 newvisibilities(0); 144 } 145 146 void 147 newvisibilities(int redraw) 148 /* if redraw false, we know it's a flupfront, and needn't 149 * redraw anyone becoming partially covered */ 150 { 151 int i; 152 Vis ov; 153 Flayer *l; 154 155 for(i = 0; i<nllist; i++){ 156 l = llist[i]; 157 l->lastsr = ZR; /* make sure scroll bar gets redrawn */ 158 ov = l->visible; 159 l->visible = visibility(l); 160 #define V(a, b) (((a)<<2)|((b))) 161 switch(V(ov, l->visible)){ 162 case V(Some, None): 163 if(l->f.b) 164 freeimage(l->f.b); 165 case V(All, None): 166 case V(All, Some): 167 l->f.b = 0; 168 frclear(&l->f, 0); 169 break; 170 171 case V(Some, Some): 172 case V(None, Some): 173 if(ov == None || (l->f.b==0 && redraw)) 174 flprepare(l); 175 if(l->f.b && redraw){ 176 flrefresh(l, l->entire, 0); 177 freeimage(l->f.b); 178 l->f.b = 0; 179 frclear(&l->f, 0); 180 } 181 case V(None, None): 182 case V(All, All): 183 break; 184 185 case V(Some, All): 186 if(l->f.b){ 187 draw(screen, l->entire, l->f.b, nil, l->entire.min); 188 freeimage(l->f.b); 189 l->f.b = screen; 190 break; 191 } 192 case V(None, All): 193 flprepare(l); 194 break; 195 } 196 if(ov==None && l->visible!=None) 197 flnewlyvisible(l); 198 } 199 } 200 201 void 202 llinsert(Flayer *l) 203 { 204 int i; 205 for(i=nllist; i>0; --i) 206 llist[i]=llist[i-1]; 207 llist[0]=l; 208 nllist++; 209 } 210 211 void 212 lldelete(Flayer *l) 213 { 214 int i; 215 216 for(i=0; i<nllist; i++) 217 if(llist[i]==l){ 218 --nllist; 219 for(; i<nllist; i++) 220 llist[i] = llist[i+1]; 221 return; 222 } 223 panic("lldelete"); 224 } 225 226 void 227 flinsert(Flayer *l, Rune *sp, Rune *ep, long p0) 228 { 229 if(flprepare(l)){ 230 frinsert(&l->f, sp, ep, p0-l->origin); 231 scrdraw(l, scrtotal(l)); 232 if(l->visible==Some) 233 flrefresh(l, l->entire, 0); 234 } 235 } 236 237 void 238 fldelete(Flayer *l, long p0, long p1) 239 { 240 if(flprepare(l)){ 241 p0 -= l->origin; 242 if(p0 < 0) 243 p0 = 0; 244 p1 -= l->origin; 245 if(p1<0) 246 p1 = 0; 247 frdelete(&l->f, p0, p1); 248 scrdraw(l, scrtotal(l)); 249 if(l->visible==Some) 250 flrefresh(l, l->entire, 0); 251 } 252 } 253 254 int 255 flselect(Flayer *l) 256 { 257 int ret; 258 if(l->visible!=All) 259 flupfront(l); 260 frselect(&l->f, mousectl); 261 ret = 0; 262 if(l->f.p0==l->f.p1){ 263 if(mousep->msec-l->click<Clicktime && l->f.p0+l->origin==l->p0){ 264 ret = 1; 265 l->click = 0; 266 }else 267 l->click = mousep->msec; 268 }else 269 l->click = 0; 270 l->p0 = l->f.p0+l->origin, l->p1 = l->f.p1+l->origin; 271 return ret; 272 } 273 274 void 275 flsetselect(Flayer *l, long p0, long p1) 276 { 277 ulong fp0, fp1; 278 int ticked; 279 280 l->click = 0; 281 if(l->visible==None || !flprepare(l)){ 282 l->p0 = p0, l->p1 = p1; 283 return; 284 } 285 l->p0 = p0, l->p1 = p1; 286 flfp0p1(l, &fp0, &fp1, &ticked); 287 if(fp0==l->f.p0 && fp1==l->f.p1){ 288 if(l->f.ticked != ticked) 289 frtick(&l->f, frptofchar(&l->f, fp0), ticked); 290 return; 291 } 292 293 if(fp1<=l->f.p0 || fp0>=l->f.p1 || l->f.p0==l->f.p1 || fp0==fp1){ 294 /* no overlap or trivial repainting */ 295 frdrawsel(&l->f, frptofchar(&l->f, l->f.p0), l->f.p0, l->f.p1, 0); 296 if(fp0 != fp1 || ticked) 297 frdrawsel(&l->f, frptofchar(&l->f, fp0), fp0, fp1, 1); 298 goto Refresh; 299 } 300 /* the current selection and the desired selection overlap and are both non-empty */ 301 if(fp0 < l->f.p0){ 302 /* extend selection backwards */ 303 frdrawsel(&l->f, frptofchar(&l->f, fp0), fp0, l->f.p0, 1); 304 }else if(fp0 > l->f.p0){ 305 /* trim first part of selection */ 306 frdrawsel(&l->f, frptofchar(&l->f, l->f.p0), l->f.p0, fp0, 0); 307 } 308 if(fp1 > l->f.p1){ 309 /* extend selection forwards */ 310 frdrawsel(&l->f, frptofchar(&l->f, l->f.p1), l->f.p1, fp1, 1); 311 }else if(fp1 < l->f.p1){ 312 /* trim last part of selection */ 313 frdrawsel(&l->f, frptofchar(&l->f, fp1), fp1, l->f.p1, 0); 314 } 315 316 Refresh: 317 l->f.p0 = fp0; 318 l->f.p1 = fp1; 319 if(l->visible==Some) 320 flrefresh(l, l->entire, 0); 321 } 322 323 void 324 flfp0p1(Flayer *l, ulong *pp0, ulong *pp1, int *ticked) 325 { 326 long p0 = l->p0-l->origin, p1 = l->p1-l->origin; 327 328 *ticked = p0 == p1; 329 if(p0 < 0){ 330 *ticked = 0; 331 p0 = 0; 332 } 333 if(p1 < 0) 334 p1 = 0; 335 if(p0 > l->f.nchars) 336 p0 = l->f.nchars; 337 if(p1 > l->f.nchars){ 338 *ticked = 0; 339 p1 = l->f.nchars; 340 } 341 *pp0 = p0; 342 *pp1 = p1; 343 } 344 345 Rectangle 346 rscale(Rectangle r, Point old, Point new) 347 { 348 r.min.x = r.min.x*new.x/old.x; 349 r.min.y = r.min.y*new.y/old.y; 350 r.max.x = r.max.x*new.x/old.x; 351 r.max.y = r.max.y*new.y/old.y; 352 return r; 353 } 354 355 void 356 flresize(Rectangle dr) 357 { 358 int i; 359 Flayer *l; 360 Frame *f; 361 Rectangle r, olDrect; 362 int move; 363 364 olDrect = lDrect; 365 lDrect = dr; 366 move = 0; 367 /* no moving on rio; must repaint */ 368 if(0 && Dx(dr)==Dx(olDrect) && Dy(dr)==Dy(olDrect)) 369 move = 1; 370 else 371 draw(screen, lDrect, display->white, nil, ZP); 372 for(i=0; i<nllist; i++){ 373 l = llist[i]; 374 l->lastsr = ZR; 375 f = &l->f; 376 if(move) 377 r = rectaddpt(rectsubpt(l->entire, olDrect.min), dr.min); 378 else{ 379 r = rectaddpt(rscale(rectsubpt(l->entire, olDrect.min), 380 subpt(olDrect.max, olDrect.min), 381 subpt(dr.max, dr.min)), dr.min); 382 if(l->visible==Some && f->b){ 383 freeimage(f->b); 384 frclear(f, 0); 385 } 386 f->b = 0; 387 if(l->visible!=None) 388 frclear(f, 0); 389 } 390 if(!rectclip(&r, dr)) 391 panic("flresize"); 392 if(r.max.x-r.min.x<100) 393 r.min.x = dr.min.x; 394 if(r.max.x-r.min.x<100) 395 r.max.x = dr.max.x; 396 if(r.max.y-r.min.y<2*FLMARGIN(l)+f->font->height) 397 r.min.y = dr.min.y; 398 if(r.max.y-r.min.y<2*FLMARGIN(l)+f->font->height) 399 r.max.y = dr.max.y; 400 if(!move) 401 l->visible = None; 402 frsetrects(f, insetrect(flrect(l, r), FLMARGIN(l)), f->b); 403 if(!move && f->b) 404 scrdraw(l, scrtotal(l)); 405 } 406 newvisibilities(1); 407 } 408 409 int 410 flprepare(Flayer *l) 411 { 412 Frame *f; 413 ulong n; 414 Rune *r; 415 int ticked; 416 417 if(l->visible == None) 418 return 0; 419 f = &l->f; 420 if(f->b == 0){ 421 if(l->visible == All) 422 f->b = screen; 423 else if((f->b = allocimage(display, l->entire, screen->chan, 0, 0))==0) 424 return 0; 425 draw(f->b, l->entire, f->cols[BACK], nil, ZP); 426 border(f->b, l->entire, l==llist[0]? FLMARGIN(l) : 1, f->cols[BORD], ZP); 427 n = f->nchars; 428 frinit(f, f->entire, f->font, f->b, 0); 429 f->maxtab = maxtab*stringwidth(f->font, "0"); 430 r = (*l->textfn)(l, n, &n); 431 frinsert(f, r, r+n, (ulong)0); 432 frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 0); 433 flfp0p1(l, &f->p0, &f->p1, &ticked); 434 if(f->p0 != f->p1 || ticked) 435 frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 1); 436 l->lastsr = ZR; 437 scrdraw(l, scrtotal(l)); 438 } 439 return 1; 440 } 441 442 static int somevis, someinvis, justvis; 443 444 Vis 445 visibility(Flayer *l) 446 { 447 somevis = someinvis = 0; 448 justvis = 1; 449 flrefresh(l, l->entire, 0); 450 justvis = 0; 451 if(somevis==0) 452 return None; 453 if(someinvis==0) 454 return All; 455 return Some; 456 } 457 458 void 459 flrefresh(Flayer *l, Rectangle r, int i) 460 { 461 Flayer *t; 462 Rectangle s; 463 464 Top: 465 if((t=llist[i++]) == l){ 466 if(!justvis) 467 draw(screen, r, l->f.b, nil, r.min); 468 somevis = 1; 469 }else{ 470 if(!rectXrect(t->entire, r)) 471 goto Top; /* avoid stacking unnecessarily */ 472 if(t->entire.min.x>r.min.x){ 473 s = r; 474 s.max.x = t->entire.min.x; 475 flrefresh(l, s, i); 476 r.min.x = t->entire.min.x; 477 } 478 if(t->entire.min.y>r.min.y){ 479 s = r; 480 s.max.y = t->entire.min.y; 481 flrefresh(l, s, i); 482 r.min.y = t->entire.min.y; 483 } 484 if(t->entire.max.x<r.max.x){ 485 s = r; 486 s.min.x = t->entire.max.x; 487 flrefresh(l, s, i); 488 r.max.x = t->entire.max.x; 489 } 490 if(t->entire.max.y<r.max.y){ 491 s = r; 492 s.min.y = t->entire.max.y; 493 flrefresh(l, s, i); 494 r.max.y = t->entire.max.y; 495 } 496 /* remaining piece of r is blocked by t; forget about it */ 497 someinvis = 1; 498 } 499 } 500 501 int 502 flscale(Flayer *l, int n) 503 { 504 if(l == nil) 505 return n; 506 return scalesize(l->f.display, n); 507 }