plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }