ref: 3866717cbb020199d58171c1c0cdd7382a74ee82
dir: /libtk/listb.c/
#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;
}
n = strlen(arg);
if(n > Tkmaxitem) {
n = (n*3)/2;
tbuf = malloc(n);
if(tbuf == nil)
return TkNomem;
}
else {
tbuf = buf;
n = sizeof(buf);
}
while(*arg) {
arg = tkword(tk->env->top, arg, tbuf, &tbuf[n], nil);
e = malloc(sizeof(TkLentry)+strlen(tbuf)+1);
if(e == nil)
return TkNomem;
e->flag = 0;
strcpy(e->text, tbuf);
e->link = *el;
*el = e;
el = &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;
l->nitem++;
}
if(tbuf != buf)
free(tbuf);
tklistbgeom(tk);
tk->dirty = tkrect(tk, 1);
return nil;
}
int
tklistbrange(Tk *tk, char *arg, int *s, int *e)
{
char buf[Tkmaxitem];
arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
*s = tklindex(tk, buf);
if(*s == -1)
return -1;
*e = *s;
if(*arg == '\0')
return 0;
tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
*e = tklindex(tk, buf);
if(*e == -1)
return -1;
return 0;
}
char*
tklistbselection(Tk *tk, char *arg, char **val)
{
TkTop *t;
TkLentry *f;
TkListbox *l;
int s, e, indx;
char buf[Tkmaxitem];
l = TKobj(TkListbox, tk);
t = tk->env->top;
arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
if(strcmp(buf, "includes") == 0) {
tkword(t, arg, buf, buf+sizeof(buf), nil);
indx = tklindex(tk, buf);
if(indx == -1)
return TkBadix;
for(f = l->head; f && indx > 0; f = f->link)
indx--;
s = 0;
if(f && (f->flag&Tkactivated))
s = 1;
return tkvalue(val, "%d", s);
}
if(strcmp(buf, "anchor") == 0) {
tkword(t, arg, buf, buf+sizeof(buf), nil);
indx = tklindex(tk, buf);
if(indx == -1)
return TkBadix;
for(f = l->head; f && indx > 0; f = f->link)
indx--;
if(f != nil)
l->anchor = f;
return nil;
}
indx = 0;
if(strcmp(buf, "clear") == 0) {
if(tklistbrange(tk, arg, &s, &e) != 0)
return TkBadix;
for(f = l->head; f; f = f->link) {
if(indx <= e && indx++ >= s)
f->flag &= ~Tkactivated;
}
tk->dirty = tkrect(tk, 1);
return nil;
}
if(strcmp(buf, "set") == 0) {
if(tklistbrange(tk, arg, &s, &e) != 0)
return TkBadix;
for(f = l->head; f; f = f->link) {
if(indx <= e && indx++ >= s)
f->flag |= Tkactivated;
}
tk->dirty = tkrect(tk, 1);
return nil;
}
return TkBadcm;
}
char*
tklistbdelete(Tk *tk, char *arg, char **val)
{
TkLentry *e, **el;
int start, end, indx, bh;
TkListbox *l = TKobj(TkListbox, tk);
USED(val);
if(tklistbrange(tk, arg, &start, &end) != 0)
return TkBadix;
indx = 0;
el = &l->head;
for(e = l->head; e && indx < start; e = e->link) {
indx++;
el = &e->link;
}
while(e != nil && indx <= end) {
*el = e->link;
if(e->width == l->nwidth)
l->nwidth = 0;
if (e == l->anchor)
l->anchor = nil;
if (e == l->active)
l->active = nil;
free(e);
e = *el;
indx++;
l->nitem--;
}
if(l->nwidth == 0) {
for(e = l->head; e; e = e->link)
if(e->width > l->nwidth)
l->nwidth = e->width;
}
bh = tk->act.height/lineheight(tk); /* Box height */
if(l->yelem + bh > l->nitem)
l->yelem = l->nitem - bh;
if(l->yelem < 0)
l->yelem = 0;
tklistbgeom(tk);
tk->dirty = tkrect(tk, 1);
return nil;
}
char*
tklistbget(Tk *tk, char *arg, char **val)
{
TkLentry *e;
char *r, *fmt;
int start, end, indx;
TkListbox *l = TKobj(TkListbox, tk);
if(tklistbrange(tk, arg, &start, &end) != 0)
return TkBadix;
indx = 0;
for(e = l->head; e && indx < start; e = e->link)
indx++;
fmt = "%s";
while(e != nil && indx <= end) {
r = tkvalue(val, fmt, e->text);
if(r != nil)
return r;
indx++;
fmt = " %s";
e = e->link;
}
return nil;
}
char*
tklistbcursel(Tk *tk, char *arg, char **val)
{
int indx;
TkLentry *e;
char *r, *fmt;
TkListbox *l = TKobj(TkListbox, tk);
USED(arg);
indx = 0;
fmt = "%d";
for(e = l->head; e; e = e->link) {
if(e->flag & Tkactivated) {
r = tkvalue(val, fmt, indx);
if(r != nil)
return r;
fmt = " %d";
}
indx++;
}
return nil;
}
static char*
tklistbview(Tk *tk, char *arg, char **val, int nl, int *posn, int max)
{
int top, bot, amount;
char buf[Tkmaxitem];
char *v, *e;
top = 0;
if(*arg == '\0') {
if ( max <= nl || max == 0 ) { /* Double test redundant at
* this time, but want to
* protect against future
* calls. -- DBK */
top = 0;
bot = TKI2F(1);
}
else {
top = TKI2F(*posn)/max;
bot = TKI2F(*posn+nl)/max;
}
v = tkfprint(buf, top);
*v++ = ' ';
tkfprint(v, bot);
return tkvalue(val, "%s", buf);
}
arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
if(strcmp(buf, "moveto") == 0) {
e = tkfracword(tk->env->top, &arg, &top, nil);
if (e != nil)
return e;
*posn = TKF2I((top+1)*max);
}
else
if(strcmp(buf, "scroll") == 0) {
arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
amount = atoi(buf);
tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
if(buf[0] == 'p') /* Pages */
amount *= nl;
*posn += amount;
}
else {
top = tklindex(tk, buf);
if(top == -1)
return TkBadix;
*posn = top;
}
bot = max - nl;
if(*posn > bot)
*posn = bot;
if(*posn < 0)
*posn = 0;
tk->dirty = tkrect(tk, 1);
return nil;
}
static int
entrysee(Tk *tk, int index)
{
TkListbox *l = TKobj(TkListbox, tk);
int bh;
/* Box height in lines */
bh = tk->act.height/lineheight(tk);
if (bh > l->nitem)
bh = l->nitem;
if (index >= l->nitem)
index = l->nitem -1;
if (index < 0)
index = 0;
/* If the item is already visible, do nothing */
if (l->nitem == 0 || index >= l->yelem && index < l->yelem+bh)
return index;
if (index < l->yelem)
l->yelem = index;
else
l->yelem = index - (bh-1);
tklistsv(tk);
tk->dirty = tkrect(tk, 1);
return index;
}
char*
tklistbsee(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;
entrysee(tk, index);
return nil;
}
char*
tklistbyview(Tk *tk, char *arg, char **val)
{
int bh;
char *e;
TkListbox *l = TKobj(TkListbox, tk);
bh = tk->act.height/lineheight(tk); /* Box height */
e = tklistbview(tk, arg, val, bh, &l->yelem, l->nitem);
tklistsv(tk);
return e;
}
char*
tklistbxview(Tk *tk, char *arg, char **val)
{
char *e;
TkListbox *l = TKobj(TkListbox, tk);
e = tklistbview(tk, arg, val, tk->act.width, &l->xdelta, l->nwidth);
tklistsh(tk);
return e;
}
static TkLentry*
entryset(TkListbox *l, int indx, int toggle)
{
TkLentry *e, *anchor;
anchor = nil;
for(e = l->head; e; e = e->link) {
if (indx-- == 0) {
anchor = e;
if (toggle) {
e->flag ^= Tkactivated;
break;
} else
e->flag |= Tkactivated;
continue;
}
if (!toggle)
e->flag &= ~Tkactivated;
}
return anchor;
}
static void
selectto(TkListbox *l, int indx)
{
TkLentry *e;
int inrange;
if (l->anchor == nil)
return;
inrange = 0;
for(e = l->head; e; e = e->link) {
if(indx == 0)
inrange = !inrange;
if(e == l->anchor)
inrange = !inrange;
if(inrange || e == l->anchor || indx == 0)
e->flag |= Tkactivated;
else
e->flag &= ~Tkactivated;
indx--;
}
}
static char*
dragto(Tk *tk, int y)
{
int indx;
TkLentry *e;
TkListbox *l = TKobj(TkListbox, tk);
indx = y/lineheight(tk);
if (y < 0)
indx--; /* int division rounds towards 0 */
if (y < tk->act.height && indx >= l->nitem)
return nil;
indx = entrysee(tk, l->yelem+indx);
entryactivate(tk, indx);
if(l->selmode == TKsingle || l->selmode == TKmultiple)
return nil;
if(l->selmode == TKbrowse) {
for(e = l->head; e; e = e->link) {
if(indx-- == 0) {
if (e == l->anchor)
return nil;
l->anchor = e;
e->flag |= Tkactivated;
} else
e->flag &= ~Tkactivated;
}
return nil;
}
/* extended selection mode */
selectto(l, indx);
tk->dirty = tkrect(tk, 1);
return nil;
}
static void
autoselect(Tk *tk, void *v, int cancelled)
{
Point pt;
int y, eh, ne;
USED(v);
if (cancelled)
return;
pt = tkposn(tk);
pt.y += tk->borderwidth;
y = tk->env->top->ctxt->mstate.y;
y -= pt.y;
eh = lineheight(tk);
ne = tk->act.height/eh;
if (y >= 0 && y < eh*ne)
return;
dragto(tk, y);
tkdirty(tk);
tkupdate(tk->env->top);
}
static char*
tklistbbutton1p(Tk *tk, char *arg, char **val)
{
TkListbox *l = TKobj(TkListbox, tk);
int y, indx;
USED(val);
y = atoi(arg);
indx = y/lineheight(tk);
indx += l->yelem;
if (indx < l->nitem) {
l->anchor = entryset(l, indx, l->selmode == TKmultiple);
entryactivate(tk, indx);
entrysee(tk, indx);
}
tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
return nil;
}
char *
tklistbbutton1r(Tk *tk, char *arg, char **val)
{
USED(arg);
USED(val);
tkcancelrepeat(tk);
return nil;
}
char*
tklistbbutton1m(Tk *tk, char *arg, char **val)
{
int y, eh, ne;
USED(val);
eh = lineheight(tk);
ne = tk->act.height/eh;
y = atoi(arg);
/* If outside the box, let autoselect handle it */
if (y < 0 || y >= ne * eh)
return nil;
return dragto(tk, y);
}
char*
tklistbkey(Tk *tk, char *arg, char **val)
{
TkListbox *l = TKobj(TkListbox, tk);
TkLentry *e;
int key, active;
USED(val);
if(tk->flag & Tkdisabled)
return nil;
key = strtol(arg, nil, 0);
active = 0;
for (e = l->head; e != nil; e = e->link) {
if (e->flag & Tkactive)
break;
active++;
}
if (key == '\n' || key == ' ') {
l->anchor = entryset(l, active, l->selmode == TKmultiple);
tk->dirty = tkrect(tk, 0);
return nil;
}
if (key == Up)
active--;
else if (key == Down)
active++;
else
return nil;
if (active < 0)
active = 0;
if (active >= l->nitem)
active = l->nitem-1;
entryactivate(tk, active);
if (l->selmode == TKextended) {
selectto(l, active);
tk->dirty = tkrect(tk, 0);
}
entrysee(tk, active);
return nil;
}
static
TkCmdtab tklistcmd[] =
{
"activate", tklistbactivate,
"cget", tklistbcget,
"configure", tklistbconf,
"curselection", tklistbcursel,
"delete", tklistbdelete,
"get", tklistbget,
"index", tklistbindex,
"insert", tklistbinsert,
"nearest", tklistbnearest,
"selection", tklistbselection,
"see", tklistbsee,
"size", tklistbsize,
"xview", tklistbxview,
"yview", tklistbyview,
"tkListbButton1P", tklistbbutton1p,
"tkListbButton1R", tklistbbutton1r,
"tkListbButton1MP", tklistbbutton1m,
"tkListbKey", tklistbkey,
nil
};
TkMethod listboxmethod = {
"listbox",
tklistcmd,
tkfreelistb,
tkdrawlistb,
tklistbgeom
};