#include "lib9.h"#include "draw.h"#include "keyboard.h"#include "tk.h"#include "listb.h" #define O(t, e) ((long)(&((t*)0)->e)) /* Layout constants */enum { Listpadx = 2, /* X padding of text in listboxes */}; typedef struct TkLentry TkLentry;typedef struct TkListbox TkListbox; struct TkLentry{ TkLentry* link; int flag; int width; char text[TKSTRUCTALIGN];}; struct TkListbox{ TkLentry* head; TkLentry* anchor; TkLentry* active; int yelem; /* Y element at top of box */ int xdelta; /* h-scroll position */ int nitem; int nwidth; int selmode; int sborderwidth; char* xscroll; char* yscroll;}; TkStab tkselmode[] ={ "single", TKsingle, "browse", TKbrowse, "multiple", TKmultiple, "extended", TKextended, nil}; staticTkOption opts[] ={ "xscrollcommand", OPTtext, O(TkListbox, xscroll), nil, "yscrollcommand", OPTtext, O(TkListbox, yscroll), nil, "selectmode", OPTstab, O(TkListbox, selmode), tkselmode, "selectborderwidth", OPTnndist, O(TkListbox, sborderwidth), nil, nil}; staticTkEbind b[] = { {TkButton1P, "%W tkListbButton1P %y"}, {TkButton1R, "%W tkListbButton1R"}, {TkButton1P|TkMotion, "%W tkListbButton1MP %y"}, {TkMotion, ""}, {TkKey, "%W tkListbKey 0x%K"},}; static intlineheight(Tk *tk){ TkListbox *l = TKobj(TkListbox, tk); return tk->env->font->height+2*(l->sborderwidth+tk->highlightwidth);} char*tklistbox(TkTop *t, char *arg, char **ret){ Tk *tk; char *e; TkName *names; TkListbox *tkl; TkOptab tko[3]; tk = tknewobj(t, TKlistbox, sizeof(Tk)+sizeof(TkListbox)); if(tk == nil) return TkNomem; tkl = TKobj(TkListbox, tk); tkl->sborderwidth = 1; tk->relief = TKsunken; tk->borderwidth = 1; tk->highlightwidth = 1; tk->flag |= Tktakefocus; tk->req.width = 170; tk->req.height = lineheight(tk)*10; tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tkl; tko[1].optab = opts; tko[2].ptr = nil; names = nil; e = tkparse(t, arg, tko, &names); if(e != nil) { tkfreeobj(tk); return e; } tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); e = tkbindings(t, tk, b, nelem(b)); if(e != nil) { tkfreeobj(tk); return e; } e = tkaddchild(t, tk, &names); tkfreename(names); if(e != nil) { tkfreeobj(tk); return e; } tk->name->link = nil; return tkvalue(ret, "%s", tk->name->name);} char*tklistbcget(Tk *tk, char *arg, char **val){ TkOptab tko[3]; TkListbox *tkl = TKobj(TkListbox, tk); tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tkl; tko[1].optab = opts; tko[2].ptr = nil; return tkgencget(tko, arg, val, tk->env->top);} voidtkfreelistb(Tk *tk){ TkLentry *e, *next; TkListbox *l = TKobj(TkListbox, tk); for(e = l->head; e; e = next) { next = e->link; free(e); } if(l->xscroll != nil) free(l->xscroll); if(l->yscroll != nil) free(l->yscroll);} char*tkdrawlistb(Tk *tk, Point orig){ Point p; TkEnv *env; TkLentry *e; int lh, w, n, ly; Rectangle r, a; Image *i, *fg; TkListbox *l = TKobj(TkListbox, tk); env = tk->env; r.min = ZP; r.max.x = tk->act.width + 2*tk->borderwidth; r.max.y = tk->act.height + 2*tk->borderwidth; i = tkitmp(env, r.max, TkCbackgnd); if(i == nil) return nil; w = tk->act.width; if (w < l->nwidth) w = l->nwidth; lh = lineheight(tk); ly = tk->borderwidth; p.x = tk->borderwidth+l->sborderwidth+tk->highlightwidth+Listpadx-l->xdelta; p.y = tk->borderwidth+l->sborderwidth+tk->highlightwidth; n = 0; for(e = l->head; e && ly < r.max.y; e = e->link) { if(n++ < l->yelem) continue; a.min.x = tk->borderwidth; a.min.y = ly; a.max.x = a.min.x + tk->act.width; a.max.y = a.min.y + lh; if(e->flag & Tkactivated) { draw(i, a, tkgc(env, TkCselectbgnd), nil, ZP); } if(e->flag & Tkactivated) fg = tkgc(env, TkCselectfgnd); else fg = tkgc(env, TkCforegnd); string(i, p, fg, p, env->font, e->text); if((e->flag & Tkactive) && tkhaskeyfocus(tk)) { a.min.x = tk->borderwidth-l->xdelta; a.max.x = a.min.x+w; a = insetrect(a, l->sborderwidth); tkbox(i, a, tk->highlightwidth, fg); } ly += lh; p.y += lh; } tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief); p.x = tk->act.x + orig.x; p.y = tk->act.y + orig.y; r = rectaddpt(r, p); draw(tkimageof(tk), r, i, nil, ZP); return nil;} inttklindex(Tk *tk, char *buf){ int index; TkListbox *l; TkLentry *e, *s; l = TKobj(TkListbox, tk); if(*buf == '@') { while(*buf && *buf != ',') buf++; index = l->yelem + atoi(buf+1)/lineheight(tk); if (index < 0) return 0; if (index > l->nitem) return l->nitem; return index; } if(*buf >= '0' && *buf <= '9') return atoi(buf); if(strcmp(buf, "end") == 0) { if(l->nitem == 0) return 0; return l->nitem-1; } index = 0; if(strcmp(buf, "active") == 0) s = l->active; else if(strcmp(buf, "anchor") == 0) s = l->anchor; else return -1; for(e = l->head; e; e = e->link) { if(e == s) return index; index++; } return -1;} voidtklistsv(Tk *tk){ TkListbox *l; int nl, lh, top, bot; char val[Tkminitem], cmd[Tkmaxitem], *v, *e; l = TKobj(TkListbox, tk); if(l->yscroll == nil) return; top = 0; bot = TKI2F(1); if(l->nitem != 0) { lh = lineheight(tk); nl = tk->act.height/lh; /* Lines in the box */ top = TKI2F(l->yelem)/l->nitem; bot = TKI2F(l->yelem+nl)/l->nitem; } v = tkfprint(val, top); *v++ = ' '; tkfprint(v, bot); snprint(cmd, sizeof(cmd), "%s %s", l->yscroll, val); e = tkexec(tk->env->top, cmd, nil); if ((e != nil) && (tk->name != nil)) print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);} voidtklistsh(Tk *tk){ int nl, top, bot; char val[Tkminitem], cmd[Tkmaxitem], *v, *e; TkListbox *l = TKobj(TkListbox, tk); if(l->xscroll == nil) return; top = 0; bot = TKI2F(1); if(l->nwidth != 0) { nl = tk->act.width; top = TKI2F(l->xdelta)/l->nwidth; bot = TKI2F(l->xdelta+nl)/l->nwidth; } v = tkfprint(val, top); *v++ = ' '; tkfprint(v, bot); snprint(cmd, sizeof(cmd), "%s %s", l->xscroll, val); e = tkexec(tk->env->top, cmd, nil); if ((e != nil) && (tk->name != nil)) print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);} voidtklistbgeom(Tk *tk){ tklistsv(tk); tklistsh(tk);} static voidlistbresize(Tk *tk){ TkLentry *e; TkListbox *l = TKobj(TkListbox, tk); l->nwidth = 0; for (e = l->head; e != nil; e = e->link) { e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth); if(e->width > l->nwidth) l->nwidth = e->width; } tklistbgeom(tk);} /* Widget Commands (+ means implemented) +activate bbox +cget +configure +curselection +delete +get +index +insert +nearest +see +selection +size +xview +yview*/ char*tklistbconf(Tk *tk, char *arg, char **val){ char *e; TkGeom g; int bd, sbw, hlw; TkOptab tko[3]; Font *f; TkListbox *tkl = TKobj(TkListbox, tk); sbw = tkl->sborderwidth; hlw = tk->highlightwidth; f = tk->env->font; tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tkl; tko[1].optab = opts; tko[2].ptr = nil; if(*arg == '\0') return tkconflist(tko, val); g = tk->req; bd = tk->borderwidth; e = tkparse(tk->env->top, arg, tko, nil); tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); tkgeomchg(tk, &g, bd); if (sbw != tkl->sborderwidth || f != tk->env->font || hlw != tk->highlightwidth) listbresize(tk); tk->dirty = tkrect(tk, 1); return e;} static voidentryactivate(Tk *tk, int index){ TkListbox *l = TKobj(TkListbox, tk); TkLentry *e; int flag = Tkactive; if (l->selmode == TKbrowse) flag |= Tkactivated; for(e = l->head; e; e = e->link) { if(index-- == 0) { e->flag |= flag; l->active = e; } else e->flag &= ~flag; } tk->dirty = tkrect(tk, 1);} char*tklistbactivate(Tk *tk, char *arg, char **val){ int index; char buf[Tkmaxitem]; USED(val); tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); index = tklindex(tk, buf); if(index == -1) return TkBadix; entryactivate(tk, index); return nil;} char*tklistbnearest(Tk *tk, char *arg, char **val){ int lh, y, index; TkListbox *l = TKobj(TkListbox, tk); lh = lineheight(tk); /* Line height */ y = atoi(arg); index = l->yelem + y/lh; if(index > l->nitem) index = l->nitem; return tkvalue(val, "%d", index);} char*tklistbindex(Tk *tk, char *arg, char **val){ int index; char buf[Tkmaxitem]; tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); index = tklindex(tk, buf); if(index == -1) return TkBadix; return tkvalue(val, "%d", index);} char*tklistbsize(Tk *tk, char *arg, char **val){ TkListbox *l = TKobj(TkListbox, tk); USED(arg); return tkvalue(val, "%d", l->nitem);} char*tklistbinsert(Tk *tk, char *arg, char **val){ int n, index; TkListbox *l; TkLentry *e, **el; char *tbuf, buf[Tkmaxitem]; USED(val); l = TKobj(TkListbox, tk); arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); if(strcmp(buf, "end") == 0) { el = &l->head; if(*el != nil) { for(e = *el; e->link; e = e->link) ; el = &e->link; } } else { index = tklindex(tk, buf); if(index == -1) return TkBadix; el = &l->head; for(e = *el; e && index-- > 0; e = e->link) el = &e->link;Lines 1–500 of 1065. Load more
#include "lib9.h" #include "draw.h" #include "keyboard.h" #include "tk.h" #include "listb.h" #define O(t, e) ((long)(&((t*)0)->e)) /* Layout constants */ enum { Listpadx = 2, /* X padding of text in listboxes */ }; typedef struct TkLentry TkLentry; typedef struct TkListbox TkListbox; struct TkLentry { TkLentry* link; int flag; int width; char text[TKSTRUCTALIGN]; }; struct TkListbox { TkLentry* head; TkLentry* anchor; TkLentry* active; int yelem; /* Y element at top of box */ int xdelta; /* h-scroll position */ int nitem; int nwidth; int selmode; int sborderwidth; char* xscroll; char* yscroll; }; TkStab tkselmode[] = { "single", TKsingle, "browse", TKbrowse, "multiple", TKmultiple, "extended", TKextended, nil }; static TkOption opts[] = { "xscrollcommand", OPTtext, O(TkListbox, xscroll), nil, "yscrollcommand", OPTtext, O(TkListbox, yscroll), nil, "selectmode", OPTstab, O(TkListbox, selmode), tkselmode, "selectborderwidth", OPTnndist, O(TkListbox, sborderwidth), nil, nil }; static TkEbind b[] = { {TkButton1P, "%W tkListbButton1P %y"}, {TkButton1R, "%W tkListbButton1R"}, {TkButton1P|TkMotion, "%W tkListbButton1MP %y"}, {TkMotion, ""}, {TkKey, "%W tkListbKey 0x%K"}, }; static int lineheight(Tk *tk) { TkListbox *l = TKobj(TkListbox, tk); return tk->env->font->height+2*(l->sborderwidth+tk->highlightwidth); } char* tklistbox(TkTop *t, char *arg, char **ret) { Tk *tk; char *e; TkName *names; TkListbox *tkl; TkOptab tko[3]; tk = tknewobj(t, TKlistbox, sizeof(Tk)+sizeof(TkListbox)); if(tk == nil) return TkNomem; tkl = TKobj(TkListbox, tk); tkl->sborderwidth = 1; tk->relief = TKsunken; tk->borderwidth = 1; tk->highlightwidth = 1; tk->flag |= Tktakefocus; tk->req.width = 170; tk->req.height = lineheight(tk)*10; tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tkl; tko[1].optab = opts; tko[2].ptr = nil; names = nil; e = tkparse(t, arg, tko, &names); if(e != nil) { tkfreeobj(tk); return e; } tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); e = tkbindings(t, tk, b, nelem(b)); if(e != nil) { tkfreeobj(tk); return e; } e = tkaddchild(t, tk, &names); tkfreename(names); if(e != nil) { tkfreeobj(tk); return e; } tk->name->link = nil; return tkvalue(ret, "%s", tk->name->name); } char* tklistbcget(Tk *tk, char *arg, char **val) { TkOptab tko[3]; TkListbox *tkl = TKobj(TkListbox, tk); tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tkl; tko[1].optab = opts; tko[2].ptr = nil; return tkgencget(tko, arg, val, tk->env->top); } void tkfreelistb(Tk *tk) { TkLentry *e, *next; TkListbox *l = TKobj(TkListbox, tk); for(e = l->head; e; e = next) { next = e->link; free(e); } if(l->xscroll != nil) free(l->xscroll); if(l->yscroll != nil) free(l->yscroll); } char* tkdrawlistb(Tk *tk, Point orig) { Point p; TkEnv *env; TkLentry *e; int lh, w, n, ly; Rectangle r, a; Image *i, *fg; TkListbox *l = TKobj(TkListbox, tk); env = tk->env; r.min = ZP; r.max.x = tk->act.width + 2*tk->borderwidth; r.max.y = tk->act.height + 2*tk->borderwidth; i = tkitmp(env, r.max, TkCbackgnd); if(i == nil) return nil; w = tk->act.width; if (w < l->nwidth) w = l->nwidth; lh = lineheight(tk); ly = tk->borderwidth; p.x = tk->borderwidth+l->sborderwidth+tk->highlightwidth+Listpadx-l->xdelta; p.y = tk->borderwidth+l->sborderwidth+tk->highlightwidth; n = 0; for(e = l->head; e && ly < r.max.y; e = e->link) { if(n++ < l->yelem) continue; a.min.x = tk->borderwidth; a.min.y = ly; a.max.x = a.min.x + tk->act.width; a.max.y = a.min.y + lh; if(e->flag & Tkactivated) { draw(i, a, tkgc(env, TkCselectbgnd), nil, ZP); } if(e->flag & Tkactivated) fg = tkgc(env, TkCselectfgnd); else fg = tkgc(env, TkCforegnd); string(i, p, fg, p, env->font, e->text); if((e->flag & Tkactive) && tkhaskeyfocus(tk)) { a.min.x = tk->borderwidth-l->xdelta; a.max.x = a.min.x+w; a = insetrect(a, l->sborderwidth); tkbox(i, a, tk->highlightwidth, fg); } ly += lh; p.y += lh; } tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief); p.x = tk->act.x + orig.x; p.y = tk->act.y + orig.y; r = rectaddpt(r, p); draw(tkimageof(tk), r, i, nil, ZP); return nil; } int tklindex(Tk *tk, char *buf) { int index; TkListbox *l; TkLentry *e, *s; l = TKobj(TkListbox, tk); if(*buf == '@') { while(*buf && *buf != ',') buf++; index = l->yelem + atoi(buf+1)/lineheight(tk); if (index < 0) return 0; if (index > l->nitem) return l->nitem; return index; } if(*buf >= '0' && *buf <= '9') return atoi(buf); if(strcmp(buf, "end") == 0) { if(l->nitem == 0) return 0; return l->nitem-1; } index = 0; if(strcmp(buf, "active") == 0) s = l->active; else if(strcmp(buf, "anchor") == 0) s = l->anchor; else return -1; for(e = l->head; e; e = e->link) { if(e == s) return index; index++; } return -1; } void tklistsv(Tk *tk) { TkListbox *l; int nl, lh, top, bot; char val[Tkminitem], cmd[Tkmaxitem], *v, *e; l = TKobj(TkListbox, tk); if(l->yscroll == nil) return; top = 0; bot = TKI2F(1); if(l->nitem != 0) { lh = lineheight(tk); nl = tk->act.height/lh; /* Lines in the box */ top = TKI2F(l->yelem)/l->nitem; bot = TKI2F(l->yelem+nl)/l->nitem; } v = tkfprint(val, top); *v++ = ' '; tkfprint(v, bot); snprint(cmd, sizeof(cmd), "%s %s", l->yscroll, val); e = tkexec(tk->env->top, cmd, nil); if ((e != nil) && (tk->name != nil)) print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e); } void tklistsh(Tk *tk) { int nl, top, bot; char val[Tkminitem], cmd[Tkmaxitem], *v, *e; TkListbox *l = TKobj(TkListbox, tk); if(l->xscroll == nil) return; top = 0; bot = TKI2F(1); if(l->nwidth != 0) { nl = tk->act.width; top = TKI2F(l->xdelta)/l->nwidth; bot = TKI2F(l->xdelta+nl)/l->nwidth; } v = tkfprint(val, top); *v++ = ' '; tkfprint(v, bot); snprint(cmd, sizeof(cmd), "%s %s", l->xscroll, val); e = tkexec(tk->env->top, cmd, nil); if ((e != nil) && (tk->name != nil)) print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e); } void tklistbgeom(Tk *tk) { tklistsv(tk); tklistsh(tk); } static void listbresize(Tk *tk) { TkLentry *e; TkListbox *l = TKobj(TkListbox, tk); l->nwidth = 0; for (e = l->head; e != nil; e = e->link) { e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth); if(e->width > l->nwidth) l->nwidth = e->width; } tklistbgeom(tk); } /* Widget Commands (+ means implemented) +activate bbox +cget +configure +curselection +delete +get +index +insert +nearest +see +selection +size +xview +yview */ char* tklistbconf(Tk *tk, char *arg, char **val) { char *e; TkGeom g; int bd, sbw, hlw; TkOptab tko[3]; Font *f; TkListbox *tkl = TKobj(TkListbox, tk); sbw = tkl->sborderwidth; hlw = tk->highlightwidth; f = tk->env->font; tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tkl; tko[1].optab = opts; tko[2].ptr = nil; if(*arg == '\0') return tkconflist(tko, val); g = tk->req; bd = tk->borderwidth; e = tkparse(tk->env->top, arg, tko, nil); tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); tkgeomchg(tk, &g, bd); if (sbw != tkl->sborderwidth || f != tk->env->font || hlw != tk->highlightwidth) listbresize(tk); tk->dirty = tkrect(tk, 1); return e; } static void entryactivate(Tk *tk, int index) { TkListbox *l = TKobj(TkListbox, tk); TkLentry *e; int flag = Tkactive; if (l->selmode == TKbrowse) flag |= Tkactivated; for(e = l->head; e; e = e->link) { if(index-- == 0) { e->flag |= flag; l->active = e; } else e->flag &= ~flag; } tk->dirty = tkrect(tk, 1); } char* tklistbactivate(Tk *tk, char *arg, char **val) { int index; char buf[Tkmaxitem]; USED(val); tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); index = tklindex(tk, buf); if(index == -1) return TkBadix; entryactivate(tk, index); return nil; } char* tklistbnearest(Tk *tk, char *arg, char **val) { int lh, y, index; TkListbox *l = TKobj(TkListbox, tk); lh = lineheight(tk); /* Line height */ y = atoi(arg); index = l->yelem + y/lh; if(index > l->nitem) index = l->nitem; return tkvalue(val, "%d", index); } char* tklistbindex(Tk *tk, char *arg, char **val) { int index; char buf[Tkmaxitem]; tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); index = tklindex(tk, buf); if(index == -1) return TkBadix; return tkvalue(val, "%d", index); } char* tklistbsize(Tk *tk, char *arg, char **val) { TkListbox *l = TKobj(TkListbox, tk); USED(arg); return tkvalue(val, "%d", l->nitem); } char* tklistbinsert(Tk *tk, char *arg, char **val) { int n, index; TkListbox *l; TkLentry *e, **el; char *tbuf, buf[Tkmaxitem]; USED(val); l = TKobj(TkListbox, tk); arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); if(strcmp(buf, "end") == 0) { el = &l->head; if(*el != nil) { for(e = *el; e->link; e = e->link) ; el = &e->link; } } else { index = tklindex(tk, buf); if(index == -1) return TkBadix; el = &l->head; for(e = *el; e && index-- > 0; e = e->link) el = &e->link;