1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840 |
- #include "lib9.h"
- #include "draw.h"
- #include "keyboard.h"
- #include "tk.h"
- #include "frame.h"
- #include "label.h"
- /*
- arrow annotation for choicebutton: how do we make sure
- the menu items come up the same size?
- - set menu items to same req.width & height as button itself.
- autorepeat:
- when we get mouse event at the edge of the screen
- and the menu overlaps that edge,
- start autorepeat timer to slide the menu the opposite direction.
- variable setting + command invocation:
- is the value of the variable the text or the index?
- same for the value appended to the command, text or index?
- if it's reimplemented as a custom widget, how does the custom widget
- get notified of variable changes?
- */
- /* Widget Commands (+ means implemented)
- +activate
- +add
- +cget
- +configure
- +delete
- +entrycget
- +entryconfigure
- +index
- +insert
- +invoke
- +post
- +postcascade
- +type
- +unpost
- +yposition
- */
- #define O(t, e) ((long)(&((t*)0)->e))
- /* Layout constants */
- enum {
- Sepheight = 6, /* Height of menu separator */
- };
- #define NOCHOICE "-----"
- enum {
- Startspeed = TKI2F(1),
- };
- static
- TkOption mbopts[] =
- {
- "text", OPTtext, O(TkLabel, text), nil,
- "anchor", OPTflag, O(TkLabel, anchor), tkanchor,
- "underline", OPTdist, O(TkLabel, ul), nil,
- "justify", OPTstab, O(TkLabel, justify), tkjustify,
- "menu", OPTtext, O(TkLabel, menu), nil,
- "bitmap", OPTbmap, O(TkLabel, bitmap), nil,
- "image", OPTimag, O(TkLabel, img), nil,
- nil
- };
- static
- TkOption choiceopts[] =
- {
- "variable", OPTtext, O(TkLabel, variable), nil,
- "values", OPTlist, O(TkLabel, values), nil,
- "command", OPTtext, O(TkLabel, command), nil,
- nil
- };
- static
- TkEbind mbbindings[] =
- {
- {TkEnter, "%W tkMBenter %s"},
- {TkLeave, "%W tkMBleave"},
- {TkButton1P, "%W tkMBpress 1"},
- {TkKey, "%W tkMBkey 0x%K"},
- {TkButton1P|TkMotion, "%W tkMBpress 0"},
- };
- extern Rectangle bbnil;
- static char* tkmpost(Tk*, int, int, int, int, int);
- static void menuclr(Tk*);
- static void freemenu(Tk*);
- static void appenditem(Tk*, Tk*, int);
- static void layout(Tk*);
- static Tk* tkmenuindex2ptr(Tk*, char**);
- static void activateitem(Tk*);
- /*
- * unmap menu cascade upto (but not including) tk
- */
- static void
- tkunmapmenus(TkTop *top, Tk *tk)
- {
- TkTop *t;
- Tk *menu;
- TkWin *tkw;
- menu = top->ctxt->tkmenu;
- if (menu == nil)
- return;
- t = menu->env->top;
- /* if something went wrong, clear down all menus */
- if (tk != nil && tk->env->top != t)
- tk = nil;
- while (menu != nil && menu != tk) {
- menuclr(menu);
- tkunmap(menu);
- tkcancelrepeat(menu);
- tkw = TKobj(TkWin, menu);
- if (tkw->cascade != nil) {
- menu = tklook(t, tkw->cascade, 0);
- free(tkw->cascade);
- tkw->cascade = nil;
- } else
- menu = nil;
- }
- top->ctxt->tkmenu = menu;
- tksetmgrab(top, menu);
- }
- static void
- tkunmapmenu(Tk *tk)
- {
- TkTop *t;
- TkWin *tkw;
- Tk *parent;
- parent = nil;
- tkw = TKobj(TkWin, tk);
- t = tk->env->top;
- if (tkw->cascade != nil)
- parent = tklook(t, tkw->cascade, 0);
- tkunmapmenus(t, parent);
- if (tkw->freeonunmap)
- freemenu(tk);
- }
- static void
- tksizemenubutton(Tk *tk)
- {
- int w, h;
- char **v, *cur;
- TkLabel *tkl = TKobj(TkLabel, tk);
- tksizelabel(tk);
- if(tk->type != TKchoicebutton)
- return;
- w = tk->req.width;
- h = tk->req.height;
- v = tkl->values;
- if (v == nil || *v == nil)
- return;
- cur = tkl->text;
- for (; *v; v++) {
- tkl->text = *v;
- tksizelabel(tk);
- if (tk->req.width > w)
- w = tk->req.width;
- if (tk->req.height > h)
- h = tk->req.height;
- }
- tkl->text = cur;
- tksizelabel(tk);
- tk->req.width = w;
- tk->req.height = h;
- }
- static char*
- tkmkmenubutton(TkTop *t, char *arg, char **ret, int type, TkOption *opts)
- {
- Tk *tk;
- char *e, **v;
- TkName *names;
- TkLabel *tkl;
- TkOptab tko[3];
- /* need to get the label from elsewhere */
- tk = tknewobj(t, type, sizeof(Tk)+sizeof(TkLabel));
- if(tk == nil)
- return TkNomem;
- tk->borderwidth = 2;
- tk->flag |= Tknograb;
- tkl = TKobj(TkLabel, tk);
- tkl->ul = -1;
- if(type == TKchoicebutton)
- tkl->anchor = Tknorth|Tkwest;
- 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;
- }
- tkl->nvalues = 0;
- if (tkl->values != nil) {
- for (v = tkl->values; *v; v++)
- ;
- tkl->nvalues = v - tkl->values;
- }
- if(type == TKchoicebutton){
- if(tkl->nvalues > 0)
- tkl->text = strdup(tkl->values[0]);
- else
- tkl->text = strdup(NOCHOICE);
- }
- tksettransparent(tk,
- tkhasalpha(tk->env, TkCbackgnd) ||
- tkhasalpha(tk->env, TkCselectbgnd) ||
- tkhasalpha(tk->env, TkCactivebgnd));
- e = tkbindings(t, tk, mbbindings, nelem(mbbindings));
- if(e != nil) {
- tkfreeobj(tk);
- return e;
- }
- tksizemenubutton(tk);
- 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*
- tkchoicebutton(TkTop *t, char *arg, char **ret)
- {
- return tkmkmenubutton(t, arg, ret, TKchoicebutton, choiceopts);
- }
- char*
- tkmenubutton(TkTop *t, char *arg, char **ret)
- {
- return tkmkmenubutton(t, arg, ret, TKmenubutton, mbopts);
- }
- static char*
- tkmenubutcget(Tk *tk, char *arg, char **val)
- {
- TkOptab tko[3];
- TkLabel *tkl = TKobj(TkLabel, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tkl;
- tko[1].optab = (tk->type == TKchoicebutton ? choiceopts : mbopts);
- tko[2].ptr = nil;
- return tkgencget(tko, arg, val, tk->env->top);
- }
- static char*
- tkmenubutconf(Tk *tk, char *arg, char **val)
- {
- char *e, **v;
- TkGeom g;
- int bd;
- TkOptab tko[3];
- TkLabel *tkl = TKobj(TkLabel, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tkl;
- tko[1].optab = (tk->type == TKchoicebutton ? choiceopts : mbopts);
- 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);
- if (tk->type == TKchoicebutton) {
- tkl->nvalues = 0;
- if (tkl->values != nil) {
- for (v = tkl->values; *v; v++)
- ;
- tkl->nvalues = v - tkl->values;
- }
- if (tkl->check >= tkl->nvalues || strcmp(tkl->text, tkl->values[tkl->check])) {
- /*
- * try to keep selected value the same if possible
- */
- for (v = tkl->values; v && *v; v++)
- if (!strcmp(*v, tkl->text))
- break;
- free(tkl->text);
- if (v == nil || *v == nil) {
- tkl->text = strdup(tkl->nvalues > 0 ? tkl->values[0] : NOCHOICE);
- tkl->check = 0;
- } else {
- tkl->check = v - tkl->values;
- tkl->text = strdup(*v);
- }
- }
- }
- tksettransparent(tk,
- tkhasalpha(tk->env, TkCbackgnd) ||
- tkhasalpha(tk->env, TkCselectbgnd) ||
- tkhasalpha(tk->env, TkCactivebgnd));
- tksizemenubutton(tk);
- tkgeomchg(tk, &g, bd);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- static char*
- tkMBleave(Tk *tk, char *arg, char **val)
- {
- USED(arg);
- USED(val);
- tk->flag &= ~Tkactive;
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static Tk*
- mkchoicemenu(Tk *tkb)
- {
- Tk *menu, *tkc;
- int i;
- TkLabel *tkl, *tkcl;
- TkWin *tkw;
- TkTop *t;
- tkl = TKobj(TkLabel, tkb);
- t = tkb->env->top;
- menu = tknewobj(t, TKmenu, sizeof(Tk)+sizeof(TkWin));
- if(menu == nil)
- return nil;
- menu->relief = TKraised;
- menu->flag |= Tknograb;
- menu->borderwidth = 1;
- tkputenv(menu->env);
- menu->env = tkb->env;
- menu->env->ref++;
- menu->flag |= Tkwindow;
- menu->geom = tkmoveresize;
- tkw = TKobj(TkWin, menu);
- tkw->cbname = strdup(tkb->name->name);
- tkw->di = (void*)-1; // XXX
- for(i = tkl->nvalues - 1; i >= 0; i--){
- tkc = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
- /* XXX recover from malloc failure */
- tkc->flag = Tkwest|Tkfillx|Tktop;
- tkc->highlightwidth = 0;
- tkc->borderwidth = 1;
- tkc->relief = TKflat;
- tkputenv(tkc->env);
- tkc->env = tkb->env;
- tkc->env->ref++;
- tkcl = TKobj(TkLabel, tkc);
- tkcl->anchor = Tkwest;
- tkcl->ul = -1;
- tkcl->justify = Tkleft;
- tkcl->text = strdup(tkl->values[i]);
- tkcl->command = smprint("%s invoke %d", tkb->name->name, i);
- /* XXX recover from malloc failure */
- tksizelabel(tkc);
- tkc->req.height = tkb->req.height;
- appenditem(menu, tkc, 0);
- }
- layout(menu);
- tkw->next = t->windows;
- tkw->freeonunmap = 1;
- t->windows = menu;
- return menu;
- }
- static char*
- tkMBpress(Tk *tk, char *arg, char **val)
- {
- Tk *menu, *item;
- TkLabel *tkl = TKobj(TkLabel, tk);
- Point g;
- char buf[12], *bufp, *e;
- USED(arg);
- USED(val);
- g = tkposn(tk);
- if (tk->type == TKchoicebutton) {
- menu = mkchoicemenu(tk);
- if (menu == nil)
- return TkNomem;
- sprint(buf, "%d", tkl->check);
- bufp = buf;
- item = tkmenuindex2ptr(menu, &bufp);
- if(item == nil)
- return nil;
- g.y -= item->act.y;
- e = tkmpost(menu, g.x, g.y, 0, 0, 0);
- activateitem(item);
- return e;
- } else {
- if (tkl->menu == nil)
- return nil;
- menu = tklook(tk->env->top, tkl->menu, 0);
- if(menu == nil || menu->type != TKmenu)
- return TkBadwp;
- if(menu->flag & Tkmapped) {
- if(atoi(arg))
- tkunmapmenu(menu);
- return nil;
- }
- return tkmpost(menu, g.x, g.y, 0, tk->act.height + 2*tk->borderwidth, 1);
- }
- }
- static char*
- tkMBkey(Tk *tk, char *arg, char **val)
- {
- int key;
- USED(val);
- if(tk->flag & Tkdisabled)
- return nil;
- key = strtol(arg, nil, 0);
- if (key == '\n' || key == ' ')
- return tkMBpress(tk, "1", nil);
- return nil;
- }
- static char*
- tkMBenter(Tk *tk, char *arg, char **val)
- {
- USED(arg);
- USED(val);
- tk->flag |= Tkactive;
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static char*
- tkchoicebutset(Tk *tk, char *arg, char **val)
- {
- char buf[12], *e;
- int v;
- TkLabel *tkl = TKobj(TkLabel, tk);
- USED(val);
- tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
- if (*buf == '\0')
- return TkBadvl;
- v = atoi(buf);
- if (v < 0 || v >= tkl->nvalues)
- return TkBadvl;
- if (v == tkl->check)
- return nil;
- free(tkl->text);
- tkl->text = strdup(tkl->values[v]);
- /* XXX recover from malloc error */
- tkl->check = v;
- sprint(buf, "%d", v);
- e = tksetvar(tk->env->top, tkl->variable, buf);
- if(e != nil)
- return e;
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static char*
- tkchoicebutinvoke(Tk *tk, char *arg, char **val)
- {
- TkLabel *tkl = TKobj(TkLabel, tk);
- char *e;
- e = tkchoicebutset(tk, arg, val);
- if(e != nil)
- return e;
- if(tkl->command)
- return tkexec(tk->env->top, tkl->command, val);
- return nil;
- }
- static char*
- tkchoicebutgetvalue(Tk *tk, char *arg, char **val)
- {
- char buf[12];
- int gotarg, v;
- TkLabel *tkl = TKobj(TkLabel, tk);
- if (tkl->nvalues == 0)
- return nil;
- tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
- if (!gotarg)
- return tkvalue(val, "%s", tkl->values[tkl->check]);
- v = atoi(buf);
- if (buf[0] < '0' || buf[0] > '9' || v >= tkl->nvalues)
- return TkBadvl;
- return tkvalue(val, "%s", tkl->values[tkl->check]);
- }
- static char*
- tkchoicebutsetvalue(Tk *tk, char *arg, char **val)
- {
- char *buf;
- char **v;
- int gotarg;
- TkLabel *tkl = TKobj(TkLabel, tk);
- USED(val);
- if (tkl->nvalues == 0)
- return TkBadvl;
- buf = mallocz(Tkmaxitem, 0);
- if (buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, &gotarg);
- if (!gotarg) {
- free(buf);
- return TkBadvl;
- }
- for (v = tkl->values; *v; v++)
- if (strcmp(*v, buf) == 0)
- break;
- free(buf);
- if (*v == nil)
- return TkBadvl;
- free(tkl->text);
- tkl->text = strdup(*v);
- /* XXX recover from malloc error */
- tkl->check = v - tkl->values;
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static char*
- tkchoicebutget(Tk *tk, char *arg, char **val)
- {
- TkLabel *tkl = TKobj(TkLabel, tk);
- char *buf, **v;
- int gotarg;
-
- if (tkl->nvalues == 0)
- return nil;
- buf = mallocz(Tkmaxitem, 0);
- if (buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, &gotarg);
- if (!gotarg) {
- free(buf);
- return tkvalue(val, "%d", tkl->check);
- }
- for (v = tkl->values; *v; v++)
- if (strcmp(*v, buf) == 0)
- break;
- free(buf);
- if (*v)
- return tkvalue(val, "%d", v - tkl->values);
- return nil;
- }
- static char*
- tkchoicebutvaluecount(Tk *tk, char *arg, char **val)
- {
- TkLabel *tkl = TKobj(TkLabel, tk);
- USED(arg);
- return tkvalue(val, "%d", tkl->nvalues);
- }
- static void
- tkchoicevarchanged(Tk *tk, char *var, char *value)
- {
- TkLabel *tkl = TKobj(TkLabel, tk);
- int v;
- if(tkl->variable != nil && strcmp(tkl->variable, var) == 0){
- if(value[0] < '0' || value[0] > '9')
- return;
- v = atoi(value);
- if(v < 0 || v >= tkl->nvalues)
- return; /* what else can we do? */
- free(tkl->text);
- tkl->text = strdup(tkl->values[v]);
- /* XXX recover from malloc error */
- tkl->check = v;
- tk->dirty = tkrect(tk, 0);
- tkdirty(tk);
- }
- }
- Tk *
- tkfindchoicemenu(Tk *tkb)
- {
- Tk *tk, *next;
- TkTop *top;
- TkWin *tkw;
- top = tkb->env->top;
- for (tk = top->windows; tk != nil; tk = next){
- tkw = TKobj(TkWin, tk);
- if(tk->name == nil){
- assert(strcmp(tkw->cbname, tkb->name->name) == 0);
- return tk;
- }
- next = tkw->next;
- }
- return nil;
- }
- static
- TkOption menuopt[] =
- {
- "postcommand", OPTtext, O(TkWin, postcmd), nil,
- nil,
- };
- char*
- tkmenu(TkTop *t, char *arg, char **ret)
- {
- Tk *tk;
- char *e;
- TkWin *tkw;
- TkName *names;
- TkOptab tko[3];
- tk = tknewobj(t, TKmenu, sizeof(Tk)+sizeof(TkWin));
- if(tk == nil)
- return TkNomem;
- tkw = TKobj(TkWin, tk);
- tkw->di = (void*)-1; // XXX
- tk->relief = TKraised;
- tk->flag |= Tknograb;
- tk->borderwidth = 1;
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tkw;
- tko[1].optab = menuopt;
- tko[2].ptr = nil;
- names = nil;
- e = tkparse(t, arg, tko, &names);
- 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;
- tk->flag |= Tkwindow;
- tk->geom = tkmoveresize;
- tkw->next = t->windows;
- t->windows = tk;
- return tkvalue(ret, "%s", tk->name->name);
- }
- static void
- freemenu(Tk *top)
- {
- Tk *tk, *f, *nexttk, *nextf;
- TkWin *tkw;
- tkunmapmenu(top);
- tkw = TKobj(TkWin, top);
- for(tk = tkw->slave; tk; tk = nexttk) {
- nexttk = tk->next;
- for(f = tk->slave; f; f = nextf) {
- nextf = f->next;
- tkfreeobj(f);
- }
- tkfreeobj(tk);
- }
- top->slave = nil;
- tkfreeframe(top);
- }
- static
- TkOption mopt[] =
- {
- "menu", OPTtext, O(TkLabel, menu), nil,
- nil,
- };
- static void
- tkbuildmopt(TkOptab *tko, int n, Tk *tk)
- {
- memset(tko, 0, n*sizeof(TkOptab));
- n = 0;
- tko[n].ptr = tk;
- tko[n++].optab = tkgeneric;
- switch(tk->type) {
- case TKcascade:
- tko[n].ptr = TKobj(TkLabel, tk);
- tko[n++].optab = mopt;
- goto norm;
- case TKradiobutton:
- tko[n].ptr = TKobj(TkLabel, tk);
- tko[n++].optab = tkradopts;
- goto norm;
- case TKcheckbutton:
- tko[n].ptr = TKobj(TkLabel, tk);
- tko[n++].optab = tkcbopts;
- /* fall through */
- case TKlabel:
- norm:
- tko[n].ptr = TKobj(TkLabel, tk);
- tko[n].optab = tkbutopts;
- break;
- }
- }
- static char*
- tkmenuentryconf(Tk *menu, Tk *tk, char *arg)
- {
- char *e;
- TkOptab tko[4];
- USED(menu);
- tkbuildmopt(tko, nelem(tko), tk);
- e = tkparse(tk->env->top, arg, tko, nil);
- switch (tk->type) {
- case TKlabel:
- case TKcascade:
- tksizelabel(tk);
- break;
- case TKradiobutton:
- case TKcheckbutton:
- tksizebutton(tk);
- }
- return e;
- }
- static void
- layout(Tk *menu)
- {
- TkWin *tkw;
- Tk *tk;
- int m, w, y, maxmargin, maxw;
- y = 0;
- maxmargin = 0;
- maxw = 0;
- tkw = TKobj(TkWin, menu);
- /* determine padding for item text alignment */
- for (tk = tkw->slave; tk != nil; tk = tk->next) {
- m = tkbuttonmargin(tk); /* TO DO: relies on buttonmargin defaulting to labelmargin */
- tk->act.x = m; /* temp store */
- if (m > maxmargin)
- maxmargin = m;
- }
- /* set x pos and determine max width */
- for (tk = tkw->slave; tk != nil; tk = tk->next) {
- tk->act.x = tk->borderwidth + maxmargin - tk->act.x;
- tk->act.y = y + tk->borderwidth;
- tk->act.height = tk->req.height;
- tk->act.width = tk->req.width;
- y += tk->act.height+2*tk->borderwidth;
- w = tk->act.x + tk->req.width + 2* tk->borderwidth;
- if (w > maxw)
- maxw = w;
- }
- /* expand separators and cascades and mark all as dirty */
- for (tk = tkw->slave; tk != nil; tk = tk->next) {
- switch (tk->type) {
- case TKseparator:
- tk->act.x = tk->borderwidth;
- /*FALLTHRU*/
- case TKcascade:
- tk->act.width = (maxw - tk->act.x) - tk->borderwidth;
- }
- tk->dirty = tkrect(tk, 1);
- }
- menu->dirty = tkrect(menu, 1);
- tkmoveresize(menu, 0, 0, maxw, y);
- }
- static void
- menuitemgeom(Tk *sub, int x, int y, int w, int h)
- {
- if (sub->parent == nil)
- return;
- if(w < 0)
- w = 0;
- if(h < 0)
- h = 0;
- sub->req.x = x;
- sub->req.y = y;
- sub->req.width = w;
- sub->req.height = h;
- layout(sub->parent);
- }
- static void
- appenditem(Tk *menu, Tk *item, int where)
- {
- TkWin *tkw;
- Tk *f, **l;
- tkw = TKobj(TkWin, menu);
- l = &tkw->slave;
- for (f = *l; f != nil; f = f->next) {
- if (where-- == 0)
- break;
- l = &f->next;
- }
- *l = item;
- item->next = f;
- item->parent = menu;
- item->geom = menuitemgeom;
- }
- static char*
- menuadd(Tk *menu, char *arg, int where)
- {
- Tk *tkc;
- int configure;
- char *e;
- TkTop *t;
- TkLabel *tkl;
- char buf[Tkmaxitem];
-
- t = menu->env->top;
- arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
- configure = 1;
- e = nil;
- if(strcmp(buf, "checkbutton") == 0)
- tkc = tkmkbutton(t, TKcheckbutton);
- else if(strcmp(buf, "radiobutton") == 0)
- tkc = tkmkbutton(t, TKradiobutton);
- else if(strcmp(buf, "command") == 0)
- tkc = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
- else if(strcmp(buf, "cascade") == 0)
- tkc = tknewobj(t, TKcascade, sizeof(Tk)+sizeof(TkLabel));
- else if(strcmp(buf, "separator") == 0) {
- tkc = tknewobj(t, TKseparator, sizeof(Tk)); /* it's really a frame */
- if (tkc != nil) {
- tkc->flag = Tkfillx|Tktop;
- tkc->req.height = Sepheight;
- configure = 0;
- }
- }
- else
- return TkBadvl;
- if (tkc == nil)
- e = TkNomem;
- if (e == nil) {
- if(tkc->env == t->env && menu->env != t->env) {
- tkputenv(tkc->env);
- tkc->env = menu->env;
- tkc->env->ref++;
- }
- if (configure) {
- tkc->flag = Tkwest|Tkfillx|Tktop;
- tkc->highlightwidth = 0;
- tkc->borderwidth = 1;
- tkc->relief = TKflat;
- tkl = TKobj(TkLabel, tkc);
- tkl->anchor = Tkwest;
- tkl->ul = -1;
- tkl->justify = Tkleft;
- e = tkmenuentryconf(menu, tkc, arg);
- }
- }
- if(e != nil) {
- if (tkc != nil)
- tkfreeobj(tkc);
- return e;
- }
- appenditem(menu, tkc, where);
- layout(menu);
- return nil;
- }
- static int
- tkmindex(Tk *tk, char *p)
- {
- TkWin *tkw;
- int y, n;
- if(*p >= '0' && *p <= '9')
- return atoi(p);
- tkw = TKobj(TkWin, tk);
- n = 0;
- if(*p == '@') {
- y = atoi(p+1);
- for(tk = tkw->slave; tk; tk = tk->next) {
- if(y >= tk->act.y && y < tk->act.y+tk->act.height+2*tk->borderwidth )
- return n;
- n++;
- }
- }
- if(strcmp(p, "end") == 0 || strcmp(p, "last") == 0) {
- for(tk = tkw->slave; tk && tk->next; tk = tk->next)
- n++;
- return n;
- }
- if(strcmp(p, "active") == 0) {
- for(tk = tkw->slave; tk; tk = tk->next) {
- if(tk->flag & Tkactive)
- return n;
- n++;
- }
- return -2;
- }
- if(strcmp(p, "none") == 0)
- return -2;
- return -1;
- }
- static int
- tkmenudel(Tk *tk, int y)
- {
- TkWin *tkw;
- Tk *f, **l, *next;
- tkw = TKobj(TkWin, tk);
- l = &tkw->slave;
- for(tk = *l; tk; tk = tk->next) {
- if(y-- == 0) {
- *l = tk->next;
- for(f = tk->slave; f; f = next) {
- next = f->next;
- tkfreeobj(f);
- }
- tkfreeobj(tk);
- return 1;
- }
- l = &tk->next;
- }
- return 0;
- }
- static char*
- tkmpost(Tk *tk, int x, int y, int cascade, int bh, int adjust)
- {
- char *e;
- TkWin *w;
- TkTop *t;
- Rectangle *dr;
- t = tk->env->top;
- if(adjust){
- dr = &t->screenr;
- if(x+tk->act.width > dr->max.x)
- x = dr->max.x - tk->act.width;
- if(x < 0)
- x = 0;
- if(y+bh+tk->act.height > dr->max.y)
- y -= tk->act.height + 2* tk->borderwidth;
- else
- y += bh;
- if(y < 0)
- y = 0;
- }
- menuclr(tk);
- tkmovewin(tk, Pt(x, y));
- /* stop possible postcommand recursion */
- if (tk->flag & Tkmapped)
- return nil;
- w = TKobj(TkWin, tk);
- if(w->postcmd != nil) {
- e = tkexec(tk->env->top, w->postcmd, nil);
- if(e != nil) {
- print("%s: postcommand: %s: %s\n", tkname(tk), w->postcmd, e);
- return e;
- }
- }
- if (!cascade)
- tkunmapmenus(t, nil);
- e = tkmap(tk);
- if(e != nil)
- return e;
- if (t->ctxt->tkmenu != nil)
- w->cascade = strdup(t->ctxt->tkmenu->name->name);
- t->ctxt->tkmenu = tk;
- tksetmgrab(t, tk);
- /* Make sure slaves are redrawn */
- return tkupdate(tk->env->top);
- }
- static Tk*
- tkmenuindex2ptr(Tk *tk, char **arg)
- {
- TkWin *tkw;
- int index;
- char *buf;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return nil;
- *arg = tkword(tk->env->top, *arg, buf, buf+Tkmaxitem, nil);
- index = tkmindex(tk, buf);
- free(buf);
- if(index < 0)
- return nil;
- tkw = TKobj(TkWin, tk);
- for(tk = tkw->slave; tk && index; tk = tk->next)
- index--;
- if(tk == nil)
- return nil;
- return tk;
- }
- static char*
- tkmenuentrycget(Tk *tk, char *arg, char **val)
- {
- Tk *etk;
- TkOptab tko[4];
- etk = tkmenuindex2ptr(tk, &arg);
- if(etk == nil)
- return TkBadix;
- tkbuildmopt(tko, nelem(tko), etk);
- return tkgencget(tko, arg, val, tk->env->top);
- }
- static char*
- tkmenucget(Tk *tk, char *arg, char **val)
- {
- TkWin *tkw;
- TkOptab tko[4];
- tkw = TKobj(TkWin, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tkw;
- tko[1].optab = tktop;
- tko[2].ptr = tkw;
- tko[2].optab = menuopt;
- tko[3].ptr = nil;
- return tkgencget(tko, arg, val, tk->env->top);
- }
- static char*
- tkmenuconf(Tk *tk, char *arg, char **val)
- {
- char *e;
- TkGeom g;
- int bd;
- TkWin *tkw;
- TkOptab tko[3];
- tkw = TKobj(TkWin, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tkw;
- tko[1].optab = menuopt;
- 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);
- tkgeomchg(tk, &g, bd);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- static char*
- tkmenuadd(Tk *tk, char *arg, char **val)
- {
- USED(val);
- return menuadd(tk, arg, -1);
- }
- static char*
- tkmenuinsert(Tk *tk, char *arg, char **val)
- {
- int index;
- char *buf;
- USED(val);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- index = tkmindex(tk, buf);
- free(buf);
- if (index < 0)
- return TkBadix;
- return menuadd(tk, arg, index);
- }
- static void
- menuitemdirty(Tk *item)
- {
- Tk *menu;
- Rectangle r;
- menu = item->parent;
- if (menu == nil)
- return;
- item->dirty = tkrect(item, 1);
- r = rectaddpt(item->dirty, Pt(item->act.x, item->act.y));
- combinerect(&menu->dirty, r);
- }
- static void
- menuclr(Tk *tk)
- {
- TkWin *tkw;
- Tk *f;
- tkw = TKobj(TkWin, tk);
- for(f = tkw->slave; f; f = f->next) {
- if(f->flag & Tkactive) {
- f->flag &= ~Tkactive;
- menuitemdirty(f);
- }
- }
- }
- static char*
- tkpostcascade(Tk *parent, Tk *tk, int toggle)
- {
- Tk *tkm;
- TkWin *tkw;
- Point g;
- TkTop *t;
- TkLabel *tkl;
- char *e;
- if(tk->flag & Tkdisabled)
- return nil;
- tkl = TKobj(TkLabel, tk);
- t = tk->env->top;
- tkm = tklook(t, tkl->menu, 0);
- if(tkm == nil || tkm->type != TKmenu)
- return TkBadwp;
- if((tkm->flag & Tkmapped)) {
- if (toggle) {
- tkunmapmenus(t, parent);
- return nil;
- } else {
- /* check that it is immediate cascade */
- tkw = TKobj(TkWin, t->ctxt->tkmenu);
- if (strcmp(tkw->cascade, parent->name->name) == 0)
- return nil;
- }
- }
- tkunmapmenus(t, parent);
- tkl = TKobj(TkLabel, tk);
- if(tkl->command != nil) {
- e = tkexec(t, tkl->command, nil);
- if (e != nil)
- return e;
- }
- g = tkposn(tk);
- g.x += tk->act.width;
- g.y -= tkm->borderwidth;
- e = tkmpost(tkm, g.x, g.y, 1, 0, 1);
- return e;
- }
- static void
- activateitem(Tk *item)
- {
- Tk *menu;
- if (item == nil || (menu = item->parent) == nil)
- return;
- menuclr(menu);
- if (!(item->flag & Tkdisabled)) {
- item->flag |= Tkactive;
- menuitemdirty(item);
- }
- }
- static char*
- tkmenuactivate(Tk *tk, char *arg, char **val)
- {
- Tk *f;
- TkWin *tkw;
- int index;
- char *buf;
-
- USED(val);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- index = tkmindex(tk, buf);
- free(buf);
- if (index == -1)
- return TkBadix;
- if (index == -2) {
- menuclr(tk);
- return nil;
- }
- tkw = TKobj(TkWin, tk);
- for(f = tkw->slave; f; f = f->next)
- if(index-- == 0)
- break;
- if(f == nil || f->flag & Tkdisabled) {
- menuclr(tk);
- return nil;
- }
- if(f->flag & Tkactive)
- return nil;
- activateitem(f);
- return nil;
- }
- static int
- iteminvoke(Tk *tk, Tk *tki, char *arg)
- {
- int unmap = 0;
- menuitemdirty(tki);
- switch(tki->type) {
- case TKlabel:
- unmap = 1;
- case TKcheckbutton:
- case TKradiobutton:
- tkbuttoninvoke(tki, arg, nil);
- break;
- case TKcascade:
- tkpostcascade(tk, tki, 0);
- break;
- }
- return unmap;
- }
- static char*
- tkmenuinvoke(Tk *tk, char *arg, char **val)
- {
- Tk *tki;
- USED(val);
- tki = tkmenuindex2ptr(tk, &arg);
- if(tki == nil)
- return nil;
- iteminvoke(tk, tki, arg);
- return nil;
- }
- static char*
- tkmenudelete(Tk *tk, char *arg, char **val)
- {
- int index1, index2;
- char *buf;
- USED(val);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkitem(buf, arg);
- index1 = tkmindex(tk, buf);
- if(index1 < 0) {
- free(buf);
- return TkBadix;
- }
- index2 = index1;
- if(*arg != '\0') {
- tkitem(buf, arg);
- index2 = tkmindex(tk, buf);
- }
- free(buf);
- if(index2 < 0)
- return TkBadix;
- while(index2 >= index1 && tkmenudel(tk, index2))
- index2--;
- layout(tk);
- return nil;
- }
- static char*
- tkmenupost(Tk *tk, char *arg, char **val)
- {
- int x, y;
- TkTop *t;
- char *buf;
- USED(val);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- t = tk->env->top;
- arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
- if(buf[0] == '\0') {
- free(buf);
- return TkBadvl;
- }
- x = atoi(buf);
- tkword(t, arg, buf, buf+Tkmaxitem, nil);
- if(buf[0] == '\0') {
- free(buf);
- return TkBadvl;
- }
- y = atoi(buf);
- free(buf);
- return tkmpost(tk, x, y, 0, 0, 1);
- }
- static char*
- tkmenuunpost(Tk *tk, char *arg, char **val)
- {
- USED(arg);
- USED(val);
- tkunmapmenu(tk);
- return nil;
- }
- static char*
- tkmenuindex(Tk *tk, char *arg, char **val)
- {
- char *buf;
- int index;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- index = tkmindex(tk, buf);
- free(buf);
- if (index == -1)
- return TkBadix;
- if (index == -2)
- return "none";
- return tkvalue(val, "%d", index);
- }
- static char*
- tkmenuyposn(Tk *tk, char *arg, char **val)
- {
- tk = tkmenuindex2ptr(tk, &arg);
- if(tk == nil)
- return TkBadix;
- return tkvalue(val, "%d", tk->act.y);
- }
- static char*
- tkmenupostcascade(Tk *tk, char *arg, char **val)
- {
- Tk *tki;
- USED(val);
- tki = tkmenuindex2ptr(tk, &arg);
- if(tki == nil || tki->type != TKcascade)
- return nil;
- return tkpostcascade(tk, tki, 0);
- }
- static char*
- tkmenutype(Tk *tk, char *arg, char **val)
- {
- tk = tkmenuindex2ptr(tk, &arg);
- if(tk == nil)
- return TkBadix;
- return tkvalue(val, tk->type == TKlabel ? "command" : tkmethod[tk->type]->name);
- }
- static char*
- tkmenususpend(Tk *tk, char *arg, char **val)
- {
- USED(arg);
- USED(val);
- if(tk->type == TKchoicebutton){
- tk = tkfindchoicemenu(tk);
- if(tk == nil)
- return TkNotwm;
- }
- tk->flag |= Tksuspended;
- return nil;
- }
- static char*
- tkmenuentryconfig(Tk *tk, char *arg, char **val)
- {
- Tk *etk;
- char *e;
- USED(val);
- etk = tkmenuindex2ptr(tk, &arg);
- if(etk == nil)
- return TkBadix;
- e = tkmenuentryconf(tk, etk, arg);
- layout(tk);
- return e;
- }
- static Tk*
- xymenuitem(Tk *tk, int x, int y)
- {
- TkWin *tkw = TKobj(TkWin, tk);
- x -= tkw->act.x;
- y -= tkw->act.y;
- x -= tk->borderwidth;
- y -= tk->act.y + tk->borderwidth;
- if (x < tk->act.x || x > tk->act.x+tk->act.width)
- return nil;
- for(tk = tkw->slave; tk; tk = tk->next) {
- if(y >= tk->act.y && y < tk->act.y+tk->act.height+2*tk->borderwidth)
- return tk;
- }
- return nil;
- }
- static char *
- menukey(Tk *tk, int key)
- {
- Tk *scan, *active, *first, *last, *prev, *next;
- TkWin *tkw;
- TkTop *top;
- top = tk->env->top;
- active = first = last = prev = next = nil;
- tkw = TKobj(TkWin, tk);
- for(scan = tkw->slave; scan != nil; scan = scan->next) {
- if(scan->type == TKseparator)
- continue;
- if(first == nil)
- first = scan;
- if (active != nil && next == nil)
- next = scan;
- if(active == nil && scan->flag & Tkactive)
- active = scan;
- if (active == nil)
- prev = scan;
- last = scan;
- }
- if (next == nil)
- next = first;
- if (prev == nil)
- prev = last;
- switch (key) {
- case Esc:
- tkunmapmenus(top, nil);
- break;
- case Left:
- if (tkw->cascade != nil)
- tkunmapmenu(tk);
- break;
- case Right:
- if (active == nil || active->type != TKcascade)
- break;
- case ' ':
- case '\n':
- if (active != nil) {
- if (iteminvoke(tk, active, nil))
- tkunmapmenus(top, nil);
- }
- break;
- case Up:
- next = prev;
- case Down:
- if (next != nil)
- activateitem(next);
- }
- return nil;
- }
- static char*
- drawmenu(Tk *tk, Point orig)
- {
- Image *dst;
- TkWin *tkw;
- Tk *sub;
- Point p, bd;
- int bg;
- Rectangle mainr, clientr, subr;
- tkw = TKobj(TkWin, tk);
- dst = tkimageof(tk);
- bd = Pt(tk->borderwidth, tk->borderwidth);
- mainr.min = addpt(orig, Pt(tk->act.x, tk->act.y));
- clientr.min = addpt(mainr.min, bd);
- clientr.max = addpt(clientr.min, Pt(tk->act.width, tk->act.height));
- mainr.max = addpt(clientr.max, bd);
- /*
- * note that we draw item background to get full menu width
- * active indicator, this means we must dirty the entire
- * item rectangle to ensure it is fully redrawn
- */
- p = clientr.min;
- subr = clientr;
- for (sub = tkw->slave; sub != nil; sub = sub->next) {
- if (Dx(sub->dirty) == 0)
- continue;
- subr.min.y = p.y + sub->act.y - sub->borderwidth;
- subr.max.y = p.y + sub->act.y + sub->act.height + sub->borderwidth;
- bg = TkCbackgnd;
- if (sub->flag & Tkactive)
- bg = TkCactivebgnd;
- draw(dst, subr, tkgc(sub->env, bg), nil, ZP);
- sub->dirty = tkrect(sub, 1);
- sub->flag |= Tkrefresh;
- tkmethod[sub->type]->draw(sub, p);
- sub->dirty = bbnil;
- sub->flag &= ~Tkrefresh;
- }
- /* todo: dirty check */
- tkdrawrelief(dst, tk, mainr.min, TkCbackgnd, tk->relief);
- return nil;
- }
- static void
- menudirty(Tk *sub)
- {
- menuitemdirty(sub);
- }
- static Point
- menurelpos(Tk *sub)
- {
- return Pt(sub->act.x-sub->borderwidth, sub->act.y-sub->borderwidth);
- }
- static void
- autoscroll(Tk *tk, void *v, int cancelled)
- {
- TkWin *tkw;
- Rectangle r, dr;
- Point delta, od;
- TkMouse *m;
- Tk *item;
- USED(v);
- tkw = TKobj(TkWin, tk);
- if (cancelled) {
- tkw->speed = 0;
- return;
- }
- if(!eqpt(tkw->act, tkw->req)){
- print("not autoscrolling, act: %P, req: %P\n", tkw->act, tkw->req);
- return;
- }
- dr = tk->env->top->screenr;
- delta.x = TKF2I(tkw->delta.x * tkw->speed);
- delta.y = TKF2I(tkw->delta.y * tkw->speed);
- r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
- od = delta;
- /* make sure we don't go too far */
- if (delta.x > 0 && r.min.x + delta.x > dr.min.x)
- delta.x = dr.min.x - r.min.x;
- else if (delta.x < 0 && r.max.x + delta.x < dr.max.x)
- delta.x = dr.max.x - r.max.x;
- if (delta.y > 0 && r.min.y + delta.y > dr.min.y)
- delta.y = dr.min.y - r.min.y;
- else if (delta.y < 0 && r.max.y + delta.y < dr.max.y)
- delta.y = dr.max.y - r.max.y;
- m = &tk->env->top->ctxt->mstate;
- item = xymenuitem(tk, m->x - delta.x, m->y - delta.y);
- if (item == nil)
- menuclr(tk);
- else
- activateitem(item);
- tkmovewin(tk, Pt(tkw->req.x + delta.x, tkw->req.y + delta.y));
- tkupdate(tk->env->top);
- /* tkenterleave won't do this for us, so we have to do it ourselves */
- tkw->speed += tkw->speed / 3;
- r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
- if((delta.y > 0 && r.min.x >= dr.min.x) || (delta.x < 0 && r.max.x <= dr.max.x))
- tkw->delta.x = 0;
- if((delta.y > 0 && r.min.y >= dr.min.y) || (delta.y < 0 && r.max.y <= dr.max.y))
- tkw->delta.y = 0;
- if (eqpt(tkw->delta, ZP)) {
- tkcancelrepeat(tk);
- tkw->speed = 0;
- }
- }
- static void
- startautoscroll(Tk *tk, TkMouse *m)
- {
- Rectangle dr, r;
- Point d;
- TkWin *tkw;
- tkw = TKobj(TkWin, tk);
- dr = tk->env->top->screenr;
- r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
- d = Pt(0, 0);
- if(m->x <= 0 && r.min.x < dr.min.x)
- d.x = 1;
- else if (m->x >= dr.max.x - 1 && r.max.x >= dr.max.x)
- d.x = -1;
- if(m->y <= 0 && r.min.y < dr.min.y)
- d.y = 1;
- else if (m->y >= dr.max.y - 1 && r.max.y >= dr.max.y)
- d.y = -1;
- //print("startautoscroll, delta %P\n", d);
- if (d.x == 0 && d.y == 0){
- if (tkw->speed > 0){
- tkcancelrepeat(tk);
- tkw->speed = 0;
- }
- return;
- }
- if (tkw->speed == 0) {
- tkw->speed = TKI2F(Dy(r)) / 100;
- tkrepeat(tk, autoscroll, nil, 0, TkRptinterval/2);
- }
- tkw->delta = d;
- }
- static void
- menuevent1(Tk *tk, int event, void *a)
- {
- TkMouse *m;
- Tk *item;
- if (event & TkKey) {
- menukey(tk, event & 0xffff);
- return;
- }
- if (event & TkLeave) {
- menuclr(tk);
- return;
- }
- if ((!(event & TkEmouse) || (event & TkTakefocus)) && !(event & TkEnter))
- return;
- m = (TkMouse*)a;
- startautoscroll(tk, m);
- item = xymenuitem(tk, m->x, m->y);
- if (item == nil)
- menuclr(tk);
- else
- activateitem(item);
- if ((event & (TkMotion|TkEnter)) && item == nil)
- return;
- if (event & TkEpress) {
- if (item == nil) {
- tkunmapmenus(tk->env->top, nil);
- return;
- }
- if (item->type == TKcascade)
- tkpostcascade(tk, item, !(event & TkMotion));
- else
- tkunmapmenus(tk->env->top, tk);
- return;
- }
- if ((event & TkErelease) && m->b == 0) {
- if (item != nil) {
- if (item->type == TKcascade)
- return;
- if (!iteminvoke(tk, item, nil))
- return;
- }
- tkunmapmenus(tk->env->top, nil);
- }
- }
- static Tk*
- menuevent(Tk *tk, int event, void *a)
- {
- menuevent1(tk, event, a);
- tksubdeliver(tk, tk->binds, event, a, 0);
- return nil;
- }
- static
- TkCmdtab menucmd[] =
- {
- "activate", tkmenuactivate,
- "add", tkmenuadd,
- "cget", tkmenucget,
- "configure", tkmenuconf,
- "delete", tkmenudelete,
- "entryconfigure", tkmenuentryconfig,
- "entrycget", tkmenuentrycget,
- "index", tkmenuindex,
- "insert", tkmenuinsert,
- "invoke", tkmenuinvoke,
- "post", tkmenupost,
- "postcascade", tkmenupostcascade,
- "type", tkmenutype,
- "unpost", tkmenuunpost,
- "yposition", tkmenuyposn,
- "suspend", tkmenususpend,
- nil
- };
- static
- TkCmdtab menubutcmd[] =
- {
- "cget", tkmenubutcget,
- "configure", tkmenubutconf,
- "tkMBenter", tkMBenter,
- "tkMBleave", tkMBleave,
- "tkMBpress", tkMBpress,
- "tkMBkey", tkMBkey,
- nil
- };
- static
- TkCmdtab choicebutcmd[] =
- {
- "cget", tkmenubutcget,
- "configure", tkmenubutconf,
- "set", tkchoicebutset,
- "get", tkchoicebutget,
- "setvalue", tkchoicebutsetvalue,
- "getvalue", tkchoicebutgetvalue,
- "invoke", tkchoicebutinvoke,
- "valuecount", tkchoicebutvaluecount,
- "tkMBenter", tkMBenter,
- "tkMBleave", tkMBleave,
- "tkMBpress", tkMBpress,
- "tkMBkey", tkMBkey,
- "suspend", tkmenususpend,
- nil
- };
- TkMethod menumethod = {
- "menu",
- menucmd,
- freemenu,
- drawmenu,
- nil,
- nil,
- nil,
- menudirty,
- menurelpos,
- menuevent
- };
- TkMethod menubuttonmethod = {
- "menubutton",
- menubutcmd,
- tkfreelabel,
- tkdrawlabel
- };
- TkMethod choicebuttonmethod = {
- "choicebutton",
- choicebutcmd,
- tkfreelabel,
- tkdrawlabel,
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- tkchoicevarchanged
- };
- TkMethod separatormethod = {
- "separator",
- nil,
- tkfreeframe,
- tkdrawframe
- };
- TkMethod cascademethod = {
- "cascade",
- nil,
- tkfreelabel,
- tkdrawlabel
- };
|