ref: 02c6058f5d529e41afb0208c69f0cbf694b02b18
dir: /sys/src/cmd/mothra/libpanel/list.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <event.h> #include <panel.h> #include "pldefs.h" typedef struct List List; struct List{ void (*hit)(Panel *, int, int); /* call user back on hit */ char *(*gen)(Panel *, int); /* return text given index or 0 if out of range */ int lo; /* indices of first, last items displayed */ int sel; /* index of hilited item */ int len; /* # of items in list */ Rectangle listr; Point minsize; int buttons; }; #define MAXHGT 12 void pl_listsel(Panel *p, int sel, int on){ List *lp; int hi; Rectangle r; lp=p->data; hi=lp->lo+(lp->listr.max.y-lp->listr.min.y)/font->height; if(lp->lo>=0 && lp->lo<=sel && sel<hi && sel<lp->len){ r=lp->listr; r.min.y+=(sel-lp->lo)*font->height; r.max.y=r.min.y+font->height; if(on) pl_highlight(p->b, r); else{ pl_fill(p->b, r); pl_drawicon(p->b, r, PLACEW, 0, lp->gen(p, sel)); } } } void pl_liststrings(Panel *p, int lo, int hi, Rectangle r){ Panel *sb; List *lp; char *s; int i; lp=p->data; for(i=lo;i!=hi && (s=lp->gen(p, i));i++){ r.max.y=r.min.y+font->height; pl_drawicon(p->b, r, PLACEW, 0, s); r.min.y+=font->height; } if(lo<=lp->sel && lp->sel<hi) pl_listsel(p, lp->sel, 1); sb=p->yscroller; if(sb && sb->setscrollbar) sb->setscrollbar(sb, lp->lo, lp->lo+(lp->listr.max.y-lp->listr.min.y)/font->height, lp->len); } void pl_drawlist(Panel *p){ List *lp; lp=p->data; lp->listr=pl_box(p->b, p->r, UP); pl_liststrings(p, lp->lo, lp->lo+(lp->listr.max.y-lp->listr.min.y)/font->height, lp->listr); } int pl_hitlist(Panel *p, Mouse *m){ int oldsel, hitme; Point ul, size; List *lp; lp=p->data; hitme=0; ul=p->r.min; size=subpt(p->r.max, p->r.min); pl_interior(p->state, &ul, &size); oldsel=lp->sel; if(m->buttons&OUT){ p->state=UP; if(m->buttons&~OUT) lp->sel=-1; } else if(p->state==DOWN || m->buttons&7){ lp->sel=(m->xy.y-ul.y)/font->height+lp->lo; if(m->buttons&7){ lp->buttons=m->buttons; p->state=DOWN; } else{ hitme=1; p->state=UP; } } if(oldsel!=lp->sel){ pl_listsel(p, oldsel, 0); pl_listsel(p, lp->sel, 1); } if(hitme && 0<=lp->sel && lp->sel<lp->len && lp->hit) lp->hit(p, lp->buttons, lp->sel); return 0; } void pl_scrolllist(Panel *p, int dir, int buttons, int val, int len){ Point ul, size; int nlist, oldlo, hi, nline, y; List *lp; Rectangle r; lp=p->data; ul=p->r.min; size=subpt(p->r.max, p->r.min); pl_interior(p->state, &ul, &size); nlist=size.y/font->height; oldlo=lp->lo; if(dir==VERT) switch(buttons){ case 1: lp->lo-=nlist*val/len; break; case 2: lp->lo=lp->len*val/len; break; case 4: lp->lo+=nlist*val/len; break; } if(lp->lo<0) lp->lo=0; if(lp->lo>=lp->len) lp->lo=lp->len-1; if(lp->lo==oldlo) return; p->scr.pos.y=lp->lo; r=lp->listr; nline=(r.max.y-r.min.y)/font->height; hi=lp->lo+nline; if(hi<=oldlo || lp->lo>=oldlo+nline){ pl_box(p->b, r, PASSIVE); pl_liststrings(p, lp->lo, hi, r); } else if(lp->lo<oldlo){ y=r.min.y+(oldlo-lp->lo)*font->height; pl_cpy(p->b, Pt(r.min.x, y), Rect(r.min.x, r.min.y, r.max.x, r.min.y+(hi-oldlo)*font->height)); r.max.y=y; pl_box(p->b, r, PASSIVE); pl_liststrings(p, lp->lo, oldlo, r); } else{ pl_cpy(p->b, r.min, Rect(r.min.x, r.min.y+(lp->lo-oldlo)*font->height, r.max.x, r.max.y)); r.min.y=r.min.y+(oldlo+nline-lp->lo)*font->height; pl_box(p->b, r, PASSIVE); pl_liststrings(p, oldlo+nline, hi, r); } } void pl_typelist(Panel *g, Rune c){ USED(g, c); } Point pl_getsizelist(Panel *p, Point children){ USED(children); return pl_boxsize(((List *)p->data)->minsize, p->state); } void pl_childspacelist(Panel *g, Point *ul, Point *size){ USED(g, ul, size); } void plinitlist(Panel *v, int flags, char *(*gen)(Panel *, int), int nlist, void (*hit)(Panel *, int, int)){ List *lp; int wid, max; char *str; lp=v->data; v->flags=flags|LEAF; v->state=UP; v->draw=pl_drawlist; v->hit=pl_hitlist; v->type=pl_typelist; v->getsize=pl_getsizelist; v->childspace=pl_childspacelist; lp->gen=gen; lp->hit=hit; max=0; for(lp->len=0;str=gen(v, lp->len);lp->len++){ wid=stringwidth(font, str); if(wid>max) max=wid; } if(flags&(FILLX|EXPAND)){ for(lp->len=0;gen(v, lp->len);lp->len++); lp->minsize=Pt(0, nlist*font->height); } else{ max=0; for(lp->len=0;str=gen(v, lp->len);lp->len++){ wid=stringwidth(font, str); if(wid>max) max=wid; } lp->minsize=Pt(max, nlist*font->height); } lp->sel=-1; lp->lo=0; v->scroll=pl_scrolllist; v->scr.pos=Pt(0,0); v->scr.size=Pt(0,lp->len); v->kind="list"; } Panel *pllist(Panel *parent, int flags, char *(*gen)(Panel *, int), int nlist, void (*hit)(Panel *, int, int)){ Panel *v; v=pl_newpanel(parent, sizeof(List)); plinitlist(v, flags, gen, nlist, hit); return v; }