123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124 |
- #include "lib9.h"
- #include "draw.h"
- #include "tk.h"
- struct TkCol
- {
- ulong rgba1;
- ulong rgba3; /* if mixed, otherwise DNotacolor */
- Image* i;
- TkCol* forw;
- };
- extern void rptwakeup(void*, void*);
- extern void* rptproc(char*, int, void*, int (*)(void*), int (*)(void*,int), void (*)(void*));
- typedef struct Cmd Cmd;
- struct Cmd
- {
- char* name;
- char* (*fn)(TkTop*, char*, char**);
- };
- static struct Cmd cmdmain[] =
- {
- "bind", tkbind,
- "button", tkbutton,
- "canvas", tkcanvas,
- "checkbutton", tkcheckbutton,
- "choicebutton", tkchoicebutton,
- "cursor", tkcursorcmd,
- "destroy", tkdestroy,
- "entry", tkentry,
- "focus", tkfocus,
- "frame", tkframe,
- "grab", tkgrab,
- "grid", tkgrid,
- "image", tkimage,
- "label", tklabel,
- "listbox", tklistbox,
- "lower", tklower,
- "menu", tkmenu,
- "menubutton", tkmenubutton,
- "pack", tkpack,
- "panel", tkpanel,
- "puts", tkputs,
- "radiobutton", tkradiobutton,
- "raise", tkraise,
- "scale", tkscale,
- "scrollbar", tkscrollbar,
- "see", tkseecmd,
- "send", tksend,
- "text", tktext,
- "update", tkupdatecmd,
- "variable", tkvariable,
- "winfo", tkwinfo,
- };
- char* tkfont;
- /*
- * auto-repeating support
- * should perhaps be one rptproc per TkCtxt
- * This is not done for the moment as there isn't
- * a mechanism for terminating the rptproc
- */
- static void *autorpt;
- static int rptid;
- static Tk *rptw;
- static void *rptnote;
- static void (*rptcb)(Tk*, void*, int);
- static long rptto;
- static int rptint;
- /* blinking carets - should be per TkCtxt */
- static void *blinkrpt;
- static Tk *blinkw;
- static void (*blinkcb)(Tk*, int);
- static int blinkignore;
- static int blinkon;
- ulong
- tkrgba(int r, int g, int b, int a)
- {
- ulong p;
- if(r < 0)
- r = 0;
- else if(r > 255)
- r = 255;
- if(g < 0)
- g = 0;
- else if(g > 255)
- g = 255;
- if(b < 0)
- b = 0;
- else if(b > 255)
- b = 255;
- p = (r<<24)|(g<<16)|(b<<8)|0xFF;
- if(a == 255)
- return p;
- return setalpha(p, a);
- }
- /* to be replaced */
- static int
- revalpha(int c, int a)
- {
- if (a == 0)
- return 0;
- return (c & 0xff) * 255 / a;
- }
- void
- tkrgbavals(ulong rgba, int *R, int *G, int *B, int *A)
- {
- int a;
- a = rgba & 0xff;
- *A = a;
- if (a != 0xff) {
- *R = revalpha(rgba>>24, a);
- *G = revalpha((rgba>>16) & 0xFF, a);
- *B = revalpha((rgba >> 8) & 0xFF, a);
- } else {
- *R = (rgba>>24);
- *G = ((rgba>>16) & 0xFF);
- *B = ((rgba >> 8) & 0xFF);
- }
- }
- static int
- tkcachecol(TkCtxt *c, Image *i, ulong one, ulong three)
- {
- TkCol *cc;
- cc = malloc(sizeof(*cc));
- if(cc == nil)
- return 0;
- cc->rgba1 = one;
- cc->rgba3 = three;
- cc->i = i;
- cc->forw = c->chead;
- c->chead = cc;
- c->ncol++;
- /* we'll do LRU management at some point */
- if(c->ncol > TkColcachesize){
- static int warn;
- if(warn == 0){
- warn = 1;
- print("tk: %d colours cached\n", TkColcachesize);
- }
- }
- return 1;
- }
- static Image*
- tkfindcol(TkCtxt *c, ulong one, ulong three)
- {
- TkCol *cc, **l;
- for(l = &c->chead; (cc = *l) != nil; l = &cc->forw)
- if(cc->rgba1 == one && cc->rgba3 == three){
- /* move it up in the list */
- *l = cc->forw;
- cc->forw = c->chead;
- c->chead = cc;
- /* we assume it will be used right away and not stored */
- return cc->i;
- }
- return nil;
- }
- void
- tkfreecolcache(TkCtxt *c)
- {
- TkCol *cc;
- if(c == nil)
- return;
- while((cc = c->chead) != nil){
- c->chead = cc->forw;
- freeimage(cc->i);
- free(cc);
- }
- c->ctail = nil;
- c->ncol = 0;
- }
- Image*
- tkcolormix(TkCtxt *c, ulong one, ulong three)
- {
- Image *i;
- Display *d;
- i = tkfindcol(c, one, three);
- if(i != nil)
- return i;
- d = c->display;
- i = allocimagemix(d, one, three);
- if(i == nil)
- return d->black;
- if(!tkcachecol(c, i, one, three)){
- freeimage(i);
- return d->black;
- }
- return i;
- }
- Image*
- tkcolor(TkCtxt *c, ulong pix)
- {
- Image *i;
- Display *d;
- Rectangle r;
- d = c->display;
- if(pix == DWhite)
- return d->white;
- if(pix == DBlack)
- return d->black;
- i = tkfindcol(c, pix, DNotacolor);
- if(i != nil)
- return i;
- r.min = ZP;
- r.max.x = 1;
- r.max.y = 1;
- if ((pix & 0xff) == 0xff)
- i = allocimage(d, r, RGB24, 1, pix);
- else
- i = allocimage(d, r, RGBA32, 1, pix);
- if(i == nil)
- return d->black;
- if(!tkcachecol(c, i, pix, DNotacolor)) {
- freeimage(i);
- return d->black;
- }
- return i;
- }
- Image*
- tkgradient(TkCtxt *c, Rectangle r, int dir, ulong pix0, ulong pix1)
- {
- Display *d;
- Image *i;
- uchar *b, *p, *e;
- int c0[3], c1[3], delta[3], a, j, x, y, n, locked;
- Rectangle s;
- d = c->display;
- y = Dy(r);
- x = Dx(r);
- if(x <= 0 || y <= 0) {
- r = Rect(0, 0, 1, 1);
- x = y = 1;
- }
- /* TO DO: diagonal */
- s = r;
- if(dir == Tkhorizontal){
- n = x;
- r.max.y = r.min.y+1;
- }else{
- n = y;
- r.max.x = r.min.x+1;
- }
- b = mallocz(3*n, 0);
- if(b == nil)
- return nil;
- locked = lockdisplay(d);
- i = allocimage(d, r, RGB24, 1, DNofill);
- if(i == nil)
- goto Ret;
- tkrgbavals(pix0, &c0[2], &c0[1], &c0[0], &a);
- tkrgbavals(pix1, &c1[2], &c1[1], &c1[0], &a);
- for(j = 0; j < 3; j++){
- c0[j] <<= 12;
- c1[j] <<= 12;
- delta[j] = ((c1[j]-c0[j])+(1<<11))/n;
- }
- e = b+3*n;
- for(p = b; p < e; p += 3) {
- p[0] = c0[0]>>12;
- p[1] = c0[1]>>12;
- p[2] = c0[2]>>12;
- c0[0] += delta[0];
- c0[1] += delta[1];
- c0[2] += delta[2];
- }
- loadimage(i, r, b, 3*n);
- replclipr(i, 1, s);
- Ret:
- if(locked)
- unlockdisplay(d);
- free(b);
- return i;
- }
- /*
- * XXX should be in libdraw?
- */
- int
- tkchanhastype(ulong c, int t)
- {
- for(; c; c>>=8)
- if(TYPE(c) == t)
- return 1;
- return 0;
- }
- void
- tksettransparent(Tk *tk, int transparent)
- {
- if (transparent)
- tk->flag |= Tktransparent;
- else
- tk->flag &= ~Tktransparent;
- }
- int
- tkhasalpha(TkEnv *e, int col)
- {
- return (e->colors[col] & 0xff) != 0xff;
- }
- Image*
- tkgc(TkEnv *e, int col)
- {
- return tkcolor(e->top->ctxt, e->colors[col]);
- }
- /*
- * Todo: improve the fixed-point code
- * the 255 scale factor is used because RGB ranges 0-255
- */
- static void
- rgb2hsv(int r, int g, int b, int *h, int *s, int *v)
- {
- int min, max, delta;
- max = r;
- if(g > max)
- max = g;
- if(b > max)
- max = b;
- min = r;
- if(g < min)
- min = g;
- if(b < min)
- min = b;
- *v = max;
- if (max != 0)
- *s = ((max - min)*255) / max;
- else
- *s = 0;
- if (*s == 0) {
- *h = 0; /* undefined */
- } else {
- delta = max - min;
- if (r == max)
- *h = (g - b)*255 / delta;
- else if (g == max)
- *h = (2*255) + ((b - r)*255) / delta;
- else if (b == max)
- *h = (4*255) + ((r - g)*255)/ delta;
- *h *= 60;
- if (*h < 0)
- *h += 360*255;
- *h /= 255;
- }
- }
- static void
- hsv2rgb(int h, int s, int v, int *r, int *g, int *b)
- {
- int i;
- int f,p,q,t;
- if (s == 0 && h == 0) {
- *r = *g = *b = v; /* achromatic case */
- } else {
- if (h >= 360)
- h = 0;
- i = h / 60;
- h *= 255;
- h /= 60;
- f = h % 255;
- p = v * (255 - s);
- q = v * (255 - ((s * f)/255));
- t = v * (255- ((s * (255 - f))/255));
- p /= 255;
- q /= 255;
- t /= 255;
- switch (i) {
- case 0: *r = v; *g = t; *b = p; break;
- case 1: *r = q; *g = v; *b = p; break;
- case 2: *r = p; *g = v; *b = t; break;
- case 3: *r = p; *g = q; *b = v; break;
- case 4: *r = t; *g = p; *b = v; break;
- case 5: *r = v; *g = p; *b = q; break;
- }
- }
- }
- enum {
- MINDELTA = 0x10,
- DELTA = 0x30,
- };
- ulong
- tkrgbashade(ulong rgba, int shade)
- {
- int R, G, B, A, h, s, v, vl, vd;
- if (shade == TkSameshade)
- return rgba;
- tkrgbavals(rgba, &R, &G, &B, &A);
- h = s = v = 0;
- rgb2hsv(R, G, B, &h, &s, &v);
- if (v < MINDELTA) {
- vd = v+DELTA;
- vl = vd+DELTA;
- } else if (v > 255-MINDELTA) {
- vl = v-DELTA;
- vd = vl-DELTA;
- } else {
- vl = v+DELTA;
- vd = v-DELTA;
- }
- v = (shade == TkLightshade)?vl:vd;
- if (v < 0)
- v = 0;
- if (v > 255)
- v = 255;
- hsv2rgb(h, s, v, &R, &G, &B);
- return tkrgba(R, G, B, A);
- }
- Image*
- tkgshade(TkEnv *e, int col, int shade)
- {
- ulong rgba;
- if (col == TkCbackgnd || col == TkCselectbgnd || col == TkCactivebgnd)
- return tkgc(e, col+shade);
- rgba = tkrgbashade(e->colors[col], shade);
- return tkcolor(e->top->ctxt, rgba);
- }
- TkEnv*
- tknewenv(TkTop *t)
- {
- TkEnv *e;
- e = malloc(sizeof(TkEnv));
- if(e == nil)
- return nil;
- e->ref = 1;
- e->top = t;
- return e;
- }
- TkEnv*
- tkdefaultenv(TkTop *t)
- {
- int locked;
- TkEnv *env;
- Display *d;
- if(t->env != nil) {
- t->env->ref++;
- return t->env;
- }
- t->env = malloc(sizeof(TkEnv));
- if(t->env == nil)
- return nil;
- env = t->env;
- env->ref = 1;
- env->top = t;
- if(tkfont == nil)
- tkfont = "/fonts/pelm/unicode.8.font";
- d = t->display;
- env->font = font_open(d, tkfont);
- if(env->font == nil) {
- static int warn;
- if(warn == 0) {
- warn = 1;
- print("tk: font not found: %s\n", tkfont);
- }
- env->font = font_open(d, "*default*");
- if(env->font == nil) {
- free(t->env);
- t->env = nil;
- return nil;
- }
- }
- locked = lockdisplay(d);
- env->wzero = stringwidth(env->font, "0");
- if ( env->wzero <= 0 )
- env->wzero = env->font->height / 2;
- if(locked)
- unlockdisplay(d);
- tksetenvcolours(env);
- return env;
- }
- void
- tkputenv(TkEnv *env)
- {
- Display *d;
- int locked;
- if(env == nil)
- return;
- env->ref--;
- if(env->ref != 0)
- return;
- d = env->top->display;
- locked = lockdisplay(d);
- if(env->font != nil)
- font_close(env->font);
- if(locked)
- unlockdisplay(d);
- free(env);
- }
- TkEnv*
- tkdupenv(TkEnv **env)
- {
- Display *d;
- TkEnv *e, *ne;
- e = *env;
- if(e->ref == 1)
- return e;
- ne = malloc(sizeof(TkEnv));
- if(ne == nil)
- return nil;
- ne->ref = 1;
- ne->top = e->top;
- d = e->top->display;
- memmove(ne->colors, e->colors, sizeof(e->colors));
- ne->set = e->set;
- ne->font = font_open(d, e->font->name);
- ne->wzero = e->wzero;
- e->ref--;
- *env = ne;
- return ne;
- }
- Tk*
- tknewobj(TkTop *t, int type, int n)
- {
- Tk *tk;
- tk = malloc(n);
- if(tk == 0)
- return 0;
- tk->type = type; /* Defaults */
- tk->flag = Tktop;
- tk->relief = TKflat;
- tk->env = tkdefaultenv(t);
- if(tk->env == nil) {
- free(tk);
- return nil;
- }
- return tk;
- }
- void
- tkfreebind(TkAction *a)
- {
- TkAction *next;
- while(a != nil) {
- next = a->link;
- if((a->type & 0xff) == TkDynamic)
- free(a->arg);
- free(a);
- a = next;
- }
- }
- void
- tkfreename(TkName *f)
- {
- TkName *n;
- while(f != nil) {
- n = f->link;
- free(f);
- f = n;
- }
- }
- void
- tkfreeobj(Tk *tk)
- {
- TkCtxt *c;
- c = tk->env->top->ctxt;
- if(c != nil) {
- if(c->tkkeygrab == tk)
- c->tkkeygrab = nil;
- if(c->mgrab == tk)
- tksetmgrab(tk->env->top, nil);
- if(c->mfocus == tk)
- c->mfocus = nil;
- if(c->entered == tk)
- c->entered = nil;
- }
- if (tk == rptw) {
- /* cancel the autorepeat without notifying the widget */
- rptid++;
- rptw = nil;
- }
- if (tk == blinkw)
- blinkw = nil;
- tkextnfreeobj(tk);
- tkmethod[tk->type]->free(tk);
- tkputenv(tk->env);
- tkfreebind(tk->binds);
- if(tk->name != nil)
- free(tk->name);
- free(tk);
- }
- char*
- tkaddchild(TkTop *t, Tk *tk, TkName **names)
- {
- TkName *n;
- Tk *f, **l;
- int found, len;
- char *s, *ep;
- n = *names;
- if(n == nil || n->name[0] != '.'){
- if(n != nil)
- tkerr(t, n->name);
- return TkBadwp;
- }
- if (n->name[1] == '\0')
- return TkDupli;
- /*
- * check that the name is well-formed.
- * ep will point to end of parent component of the name.
- */
- ep = nil;
- for (s = n->name + 1; *s; s++) {
- if (*s == '.'){
- tkerr(t, n->name);
- return TkBadwp;
- }
- for (; *s && *s != '.'; s++)
- ;
- if (*s == '\0')
- break;
- ep = s;
- }
- if (ep == s - 1){
- tkerr(t, n->name);
- return TkBadwp;
- }
- if (ep == nil)
- ep = n->name + 1;
- len = ep - n->name;
- found = 0;
- l = &t->root;
- for(f = *l; f; f = f->siblings) {
- if (f->name != nil) {
- if (strcmp(n->name, f->name->name) == 0)
- return TkDupli;
- if (!found &&
- strncmp(n->name, f->name->name, len) == 0 &&
- f->name->name[len] == '\0')
- found = 1;
- }
- l = &f->siblings;
- }
- if (0) { /* don't enable this until a reasonably major release... if ever */
- /*
- * parent widget must already exist
- */
- if (!found){
- tkerr(t, n->name);
- return TkBadwp;
- }
- }
- *l = tk;
- tk->name = n;
- *names = n->link;
- return nil;
- }
- Tk*
- tklook(TkTop *t, char *wp, int parent)
- {
- Tk *f;
- char *p, *q;
- if(wp == nil)
- return nil;
- if(parent) {
- p = strdup(wp);
- if(p == nil)
- return nil;
- q = strrchr(p, '.');
- if(q == nil)
- abort();
- if(q == p) {
- free(p);
- return t->root;
- }
- *q = '\0';
- } else
- p = wp;
- for(f = t->root; f; f = f->siblings)
- if ((f->name != nil) && (strcmp(f->name->name, p) == 0))
- break;
- if(f != nil && (f->flag & Tkdestroy))
- f = nil;
- if (parent)
- free(p);
- return f;
- }
- void
- tktextsdraw(Image *img, Rectangle r, TkEnv *e, int sbw)
- {
- Image *l, *d;
- Rectangle s;
- draw(img, r, tkgc(e, TkCselectbgnd), nil, ZP);
- s.min = r.min;
- s.min.x -= sbw;
- s.min.y -= sbw;
- s.max.x = r.max.x;
- s.max.y = r.min.y;
- l = tkgc(e, TkCselectbgndlght);
- draw(img, s, l, nil, ZP);
- s.max.x = s.min.x + sbw;
- s.max.y = r.max.y + sbw;
- draw(img, s, l, nil, ZP);
- s.max = r.max;
- s.max.x += sbw;
- s.max.y += sbw;
- s.min.x = r.min.x;
- s.min.y = r.max.y;
- d = tkgc(e, TkCselectbgnddark);
- draw(img, s, d, nil, ZP);
- s.min.x = r.max.x;
- s.min.y = r.min.y - sbw;
- draw(img, s, d, nil, ZP);
- }
- void
- tkbox(Image *i, Rectangle r, int bd, Image *fill)
- {
- if (bd > 0) {
- draw(i, Rect(r.min.x, r.min.y, r.max.x, r.min.y+bd), fill, nil, ZP);
- draw(i, Rect(r.min.x, r.min.y+bd, r.min.x+bd, r.max.y-bd), fill, nil, ZP);
- draw(i, Rect(r.min.x, r.max.y-bd, r.max.x, r.max.y), fill, nil, ZP);
- draw(i, Rect(r.max.x-bd, r.min.y+bd, r.max.x, r.max.y), fill, nil, ZP);
- }
- }
- void
- tkbevel(Image *i, Point o, int w, int h, int bw, Image *top, Image *bottom)
- {
- Rectangle r;
- int x, border;
- border = 2 * bw;
- r.min = o;
- r.max.x = r.min.x + w + border;
- r.max.y = r.min.y + bw;
- draw(i, r, top, nil, ZP);
- r.max.x = r.min.x + bw;
- r.max.y = r.min.y + h + border;
- draw(i, r, top, nil, ZP);
- r.max.x = o.x + w + border;
- r.max.y = o.y + h + border;
- r.min.x = o.x + bw;
- r.min.y = r.max.y - bw;
- for(x = 0; x < bw; x++) {
- draw(i, r, bottom, nil, ZP);
- r.min.x--;
- r.min.y++;
- }
- r.min.x = o.x + bw + w;
- r.min.y = o.y + bw;
- for(x = bw; x >= 0; x--) {
- draw(i, r, bottom, nil, ZP);
- r.min.x++;
- r.min.y--;
- }
- }
- /*
- * draw a relief border.
- * color is an index into tk->env->colors and assumes
- * light and dark versions following immediately after
- * that index
- */
- void
- tkdrawrelief(Image *i, Tk *tk, Point o, int color, int rlf)
- {
- TkEnv *e;
- Image *l, *d, *t;
- int h, w, bd, bd1, bd2;
- if(tk->borderwidth == 0)
- return;
- h = tk->act.height;
- w = tk->act.width;
- e = tk->env;
- if (color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
- l = tkgc(e, color+TkLightshade);
- d = tkgc(e, color+TkDarkshade);
- } else {
- l = tkgshade(e, color, TkLightshade);
- d = tkgshade(e, color, TkDarkshade);
- }
- bd = tk->borderwidth;
- if(rlf < 0)
- rlf = TKraised;
- switch(rlf) {
- case TKflat:
- break;
- case TKsunken:
- tkbevel(i, o, w, h, bd, d, l);
- break;
- case TKraised:
- tkbevel(i, o, w, h, bd, l, d);
- break;
- case TKgroove:
- t = d;
- d = l;
- l = t;
- /* fall through */
- case TKridge:
- bd1 = bd/2;
- bd2 = bd - bd1;
- if(bd1 > 0)
- tkbevel(i, o, w + 2*bd2, h + 2*bd2, bd1, l, d);
- o.x += bd1;
- o.y += bd1;
- tkbevel(i, o, w, h, bd2, d, l);
- break;
- }
- }
- Point
- tkstringsize(Tk *tk, char *text)
- {
- char *q;
- int locked;
- Display *d;
- Point p, t;
- if(text == nil) {
- p.x = 0;
- p.y = tk->env->font->height;
- return p;
- }
- d = tk->env->top->display;
- locked = lockdisplay(d);
- p = ZP;
- while(*text) {
- q = strchr(text, '\n');
- if(q != nil)
- *q = '\0';
- t = stringsize(tk->env->font, text);
- p.y += t.y;
- if(p.x < t.x)
- p.x = t.x;
- if(q == nil)
- break;
- text = q+1;
- *q = '\n';
- }
- if(locked)
- unlockdisplay(d);
- return p;
- }
- static void
- tkulall(Image *i, Point o, Image *col, Font *f, char *text)
- {
- Rectangle r;
- r.max = stringsize(f, text);
- r.max = addpt(r.max, o);
- r.min.x = o.x;
- r.min.y = r.max.y - 1;
- draw(i, r, col, nil, ZP);
- }
- static void
- tkul(Image *i, Point o, Image *col, int ul, Font *f, char *text)
- {
- char c, *v;
- Rectangle r;
- v = text+ul+1;
- c = *v;
- *v = '\0';
- r.max = stringsize(f, text);
- r.max = addpt(r.max, o);
- r.min = stringsize(f, v-1);
- *v = c;
- r.min.x = r.max.x - r.min.x;
- r.min.y = r.max.y - 1;
- r.max.y++;
- draw(i, r, col, nil, ZP);
- }
- void
- tkdrawstring(Tk *tk, Image *i, Point o, char *text, int ul, Image *col, int j)
- {
- int n, l, maxl, sox;
- char *q, *txt;
- Point p;
- TkEnv *e;
- e = tk->env;
- sox = maxl = 0;
- if(j != Tkleft){
- maxl = 0;
- txt = text;
- while(*txt){
- q = strchr(txt, '\n');
- if(q != nil)
- *q = '\0';
- l = stringwidth(e->font, txt);
- if(l > maxl)
- maxl = l;
- if(q == nil)
- break;
- txt = q+1;
- *q = '\n';
- }
- sox = o.x;
- }
- while(*text) {
- q = strchr(text, '\n');
- if(q != nil)
- *q = '\0';
- if(j != Tkleft){
- o.x = sox;
- l = stringwidth(e->font, text);
- if(j == Tkcenter)
- o.x += (maxl-l)/2;
- else
- o.x += maxl-l;
- }
- p = string(i, o, col, o, e->font, text);
- if(ul >= 0) {
- n = strlen(text);
- if(ul < n) {
- tkul(i, o, col, ul, e->font, text);
- ul = -1;
- } else if(ul == n) {
- tkulall(i, o, col, e->font, text);
- ul = -1;
- } else
- ul -= n;
- }
- o.y += e->font->height;
- if(q == nil)
- break;
- text = q+1;
- *q = '\n';
- }
- }
- /* for debugging */
- char*
- tkname(Tk *tk)
- {
- if(tk == nil)
- return "(nil)";
- if(tk->name == nil)
- return "(noname)";
- return tk->name->name;
- }
- Tk*
- tkdeliver(Tk *tk, int event, void *data)
- {
- Tk *dest;
- if(tk != nil && ((ulong)tk->type >= TKwidgets || (ulong)tk->name < 4096 && tk->name != nil)){
- print("invalid Tk: type %d name %p\n", tk->type, tk->name);
- abort();
- }
- //print("tkdeliver %v to %s\n", event, tkname(tk));
- if(tk == nil || ((tk->flag&Tkdestroy) && event != TkDestroy))
- return tk;
- if(event&(TkFocusin|TkFocusout) && (tk->flag&Tktakefocus))
- tk->dirty = tkrect(tk, 1);
- if (tkmethod[tk->type]->deliver != nil) {
- dest = tkmethod[tk->type]->deliver(tk, event, data);
- if (dest == nil)
- return tk;
- tkdirty(tk);
- return dest;
- }
- if((tk->flag & Tkdisabled) == 0)
- tksubdeliver(tk, tk->binds, event, data, 0);
- tkdirty(tk);
- return tk;
- }
- static int
- nullop(char *fmt, ...)
- {
- USED(fmt);
- return 0;
- }
- int
- tksubdeliver(Tk *tk, TkAction *binds, int event, void *data, int extn)
- {
- TkAction *a;
- int delivered, genkey, delivered2, iskey;
- //int (*debug)(char *fmt, ...);
- if (!extn)
- return tkextndeliver(tk, binds, event, data);
- //debug = (tk->name && !strcmp(tk->name->name, ".cd")) ? print : nullop;
- //debug("subdeliver %v\n", event);
- if (event & TkTakefocus) {
- if (tk->flag & Tktakefocus)
- tksetkeyfocus(tk->env->top, tk, 0);
- return TkDdelivered;
- }
- delivered = TkDnone;
- genkey = 0;
- for(a = binds; a != nil; a = a->link) {
- if(event == a->event) {
- //debug(" exact match on %v\n", a->event);
- tkcmdbind(tk, event, a->arg, data);
- delivered = TkDdelivered;
- } else if (a->event == TkKey && (a->type>>8)==TkAadd)
- genkey = 1;
- }
- if(delivered != TkDnone && !((event & TkKey) && genkey))
- return delivered;
- delivered2 = delivered;
- for(a = binds; a != nil; a = a->link) {
- /*
- * only bind to non-specific key events; if a specific
- * key event has already been delivered, only deliver event if
- * the non-specific binding was added. (TkAadd)
- */
- if (a->event & TkExtns)
- continue;
- iskey = (a->event & TkKey);
- if (iskey ^ (event & TkKey))
- continue;
- if(iskey && (TKKEY(a->event) != 0
- || ((a->type>>8) != TkAadd && delivered != TkDnone)))
- continue;
- if(!iskey && (a->event & TkMotion) && (a->event&TkEpress) != 0)
- continue;
- if(!(event & TkDouble) && (a->event & TkDouble))
- continue;
- if((event & ~TkDouble) & a->event) {
- //debug(" partial match on %v\n", a->event);
- tkcmdbind(tk, event, a->arg, data);
- delivered2 = TkDdelivered;
- }
- }
- return delivered2;
- }
- void
- tkcancel(TkAction **l, int event)
- {
- TkAction *a;
- for(a = *l; a; a = *l) {
- if(a->event == event) {
- *l = a->link;
- a->link = nil;
- tkfreebind(a);
- continue;
- }
- l = &a->link;
- }
- }
- static void
- tkcancela(TkAction **l, int event, int type, char *arg)
- {
- TkAction *a;
- for(a = *l; a; a = *l) {
- if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
- *l = a->link;
- a->link = nil;
- tkfreebind(a);
- continue;
- }
- l = &a->link;
- }
- }
- char*
- tkaction(TkAction **l, int event, int type, char *arg, int how)
- {
- TkAction *a;
- if(arg == nil)
- return nil;
- if(how == TkArepl)
- tkcancel(l, event);
- else if(how == TkAadd){
- for(a = *l; a; a = a->link)
- if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
- a->type = type + (how << 8);
- return nil;
- }
- }
- else if(how == TkAsub){
- tkcancela(l, event, type, arg);
- if(type == TkDynamic) /* should always be the case */
- free(arg);
- return nil;
- }
- a = malloc(sizeof(TkAction));
- if(a == nil) {
- if(type == TkDynamic)
- free(arg);
- return TkNomem;
- }
- a->event = event;
- a->arg = arg;
- a->type = type + (how << 8);
- a->link = *l;
- *l = a;
- return nil;
- }
- char*
- tkitem(char *buf, char *a)
- {
- char *e;
- while(*a && (*a == ' ' || *a == '\t'))
- a++;
- e = buf + Tkmaxitem - 1;
- while(*a && *a != ' ' && *a != '\t' && buf < e)
- *buf++ = *a++;
- *buf = '\0';
- while(*a && (*a == ' ' || *a == '\t'))
- a++;
- return a;
- }
- /*
- * if tk is a subwindow or a descendent, return the subwindow;
- * return nil otherwise
- */
- Tk*
- tkfindsub(Tk *tk)
- {
- for(; tk != nil; tk = tk->master){
- if(tk->parent != nil)
- return tk; /* tk->parent is canvas or text */
- }
- return nil;
- }
- /*
- * Return absolute screen position of tk (just outside its top-left border).
- * When a widget is embedded in a text or canvas widget, we need to
- * use the text or canvas's relpos() function instead of act{x,y}, and we
- * need to folow up the parent pointer rather than the master one.
- */
- Point
- tkposn(Tk *tk)
- {
- Tk *f, *last;
- Point g;
- last = tk;
- if(tk->parent != nil) {
- g = tkmethod[tk->parent->type]->relpos(tk);
- f = tk->parent;
- } else {
- g.x = tk->act.x;
- g.y = tk->act.y;
- f = tk->master;
- }
- while(f != nil) {
- g.x += f->borderwidth;
- g.y += f->borderwidth;
- last = f;
- if(f->parent != nil) {
- g = addpt(g, tkmethod[f->parent->type]->relpos(f));
- f = f->parent;
- } else {
- g.x += f->act.x;
- g.y += f->act.y;
- f = f->master;
- }
- }
- if (last->flag & Tkwindow)
- g = addpt(g, TKobj(TkWin, last)->req);
- return g;
- }
- /*
- * convert screen coords to local widget coords
- */
- Point
- tkscrn2local(Tk *tk, Point p)
- {
- p = subpt(p, tkposn(tk));
- p.x -= tk->borderwidth;
- p.y -= tk->borderwidth;
- return p;
- }
- int
- tkvisiblerect(Tk *tk, Rectangle *rr)
- {
- Rectangle r;
- Point g;
- Tk *f, *last;
- g = Pt(tk->borderwidth, tk->borderwidth);
- last = tk;
- if(tk->parent != nil) {
- g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
- f = tk->parent;
- } else {
- g.x += tk->act.x;
- g.y += tk->act.y;
- f = tk->master;
- }
- if (f == nil) {
- *rr = tkrect(tk, 1);
- return 1;
- }
- r = rectaddpt(tkrect(tk, 1), g);
- while (f) {
- if (!rectclip(&r, tkrect(f, 0)))
- return 0;
- g.x = f->borderwidth;
- g.y = f->borderwidth;
- last = f;
- if (f->parent != nil) {
- g = addpt(g, tkmethod[f->parent->type]->relpos(f));
- f = f->parent;
- } else {
- g.x += f->act.x;
- g.y += f->act.y;
- f = f->master;
- }
- r = rectaddpt(r, g);
- }
- if (last->flag & Tkwindow)
- r = rectaddpt(r, TKobj(TkWin, last)->act);
- /*
- * now we have the visible rectangle in screen coords;
- * subtract actx+borderwidth and we've got it back in
- * widget-local coords again
- */
- r = rectsubpt(r, tkposn(tk));
- *rr = rectsubpt(r, Pt(tk->borderwidth, tk->borderwidth));
- return 1;
- }
- Point
- tkanchorpoint(Rectangle r, Point size, int anchor)
- {
- int dx, dy;
- Point p;
- p = r.min;
- dx = Dx(r) - size.x;
- dy = Dy(r) - size.y;
- if((anchor & (Tknorth|Tksouth)) == 0)
- p.y += dy/2;
- else if(anchor & Tksouth)
- p.y += dy;
- if((anchor & (Tkeast|Tkwest)) == 0)
- p.x += dx/2;
- else if(anchor & Tkeast)
- p.x += dx;
- return p;
- }
-
- static char*
- tkunits(char c, int *d, TkEnv *e)
- {
- switch(c) {
- default:
- if(c >= '0' || c <= '9' || c == '.')
- break;
- return TkBadvl;
- case '\0':
- break;
- case 'c': /* Centimeters */
- *d *= (Tkdpi*100)/254;
- break;
- case 'm': /* Millimeters */
- *d *= (Tkdpi*10)/254;
- break;
- case 'i': /* Inches */
- *d *= Tkdpi;
- break;
- case 'p': /* Points */
- *d = (*d*Tkdpi)/72;
- break;
- case 'w': /* Character width */
- if(e == nil)
- return TkBadvl;
- *d = *d * e->wzero;
- break;
- case 'h': /* Character height */
- if(e == nil)
- return TkBadvl;
- *d = *d * e->font->height;
- break;
- }
- return nil;
- }
- int
- TKF2I(int f)
- {
- if (f >= 0)
- return (f + Tkfpscalar/2) / Tkfpscalar;
- return (f - Tkfpscalar/2) / Tkfpscalar;
- }
- /*
- * Parse a floating point number into a decimal fixed point representation
- */
- char*
- tkfrac(char **arg, int *f, TkEnv *env)
- {
- int c, minus, i, fscale, seendigit;
- char *p, *e;
- seendigit = 0;
- p = *arg;
- p = tkskip(p, " \t");
- minus = 0;
- if(*p == '-') {
- minus = 1;
- p++;
- }
- i = 0;
- while(*p) {
- c = *p;
- if(c == '.')
- break;
- if(c < '0' || c > '9')
- break;
- i = i*10 + (c - '0');
- seendigit = 1;
- p++;
- }
- i *= Tkfpscalar;
- if(*p == '.')
- p++;
- fscale = Tkfpscalar;
- while(*p && *p >= '0' && *p <= '9') {
- fscale /= 10;
- i += fscale * (*p++ - '0');
- seendigit = 1;
- }
- if(minus)
- i = -i;
- if(!seendigit)
- return TkBadvl;
- e = tkunits(*p, &i, env);
- if (e != nil)
- return e;
- while (*p && *p != ' ' && *p != '\t')
- p++;
- *arg = p;
- *f = i;
- return nil;
- }
- char*
- tkfracword(TkTop *t, char **arg, int *f, TkEnv *env)
- {
- char *p;
- char buf[Tkminitem];
- *arg = tkword(t, *arg, buf, buf+sizeof(buf), nil);
- p = buf;
- return tkfrac(&p, f, env);
- }
- char*
- tkfprint(char *v, int frac)
- {
- int fscale;
- if(frac < 0) {
- *v++ = '-';
- frac = -frac;
- }
- v += sprint(v, "%d", frac/Tkfpscalar);
- frac = frac%Tkfpscalar;
- if(frac != 0)
- *v++ = '.';
- fscale = Tkfpscalar/10;
- while(frac) {
- *v++ = '0' + frac/fscale;
- frac %= fscale;
- fscale /= 10;
- }
- *v = '\0';
- return v;
- }
- char*
- tkvalue(char **val, char *fmt, ...)
- {
- va_list arg;
- Fmt fmtx;
- if(val == nil)
- return nil;
- fmtstrinit(&fmtx);
- if(*val != nil)
- if(fmtprint(&fmtx, "%s", *val) < 0)
- return TkNomem;
- va_start(arg, fmt);
- fmtvprint(&fmtx, fmt, arg);
- va_end(arg);
- free(*val);
- *val = fmtstrflush(&fmtx);
- if(*val == nil)
- return TkNomem;
- return nil;
- }
- static char*
- tkwidgetcmd(TkTop *t, Tk *tk, char *arg, char **val)
- {
- TkMethod *cm;
- TkCmdtab *ct;
- int bot, top, new, r;
- char *e, *buf;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
- if(val != nil)
- *val = nil;
- cm = tkmethod[tk->type];
- e = TkBadcm;
- bot = 0;
- top = cm->ncmd - 1;
- while(bot <= top) {
- new = (bot + top)/2;
- ct = &cm->cmd[new];
- r = strcmp(ct->name, buf);
- if(r == 0) {
- e = ct->fn(tk, arg, val);
- break;
- }
- if(r < 0)
- bot = new + 1;
- else
- top = new - 1;
- }
- free(buf);
- tkdirty(tk);
- return e;
- }
- Rectangle
- tkrect(Tk *tk, int withborder)
- {
- Rectangle r;
- int bd;
- bd = withborder? tk->borderwidth: 0;
- r.min.x = -bd;
- r.min.y = -bd;
- r.max.x = tk->act.width + bd;
- r.max.y = tk->act.height + bd;
- return r;
- }
- void
- tkdirty(Tk *tk)
- {
- Tk *sub;
- Point rel;
- Rectangle dirty;
- int isdirty, transparent;
- /*
- * mark as dirty all views underneath a dirty transparent widget
- * down to the first opaque widget.
- * inform parents about any dirtiness.
- * XXX as Tksubsub never gets reset, testing against Tksubsub doesn't *exactly* test
- * whether we're in a canvas/text widget, but merely
- * whether it has ever been. Tksubsub should probably be reset on unpack.
- */
- isdirty = Dx(tk->dirty) > 0;
- transparent = tk->flag & Tktransparent;
- sub = tk;
- while (isdirty && ((tk->flag&Tksubsub) || transparent)) {
- if (tk->master != nil) {
- if (transparent) {
- rel.x = tk->act.x + tk->borderwidth;
- rel.y = tk->act.y + tk->borderwidth;
- dirty = rectaddpt(sub->dirty, rel);
- sub = tk->master;
- combinerect(&sub->dirty, dirty);
- transparent = sub->flag & Tktransparent;
- }
- tk = tk->master;
- } else if (tk->parent != nil) {
- tkmethod[tk->parent->type]->dirtychild(sub);
- tk = sub = tk->parent;
- isdirty = Dx(sub->dirty) > 0;
- transparent = sub->flag & Tktransparent;
- } else
- break;
- }
- }
- static int
- qcmdcmp(const void *a, const void *b)
- {
- return strcmp(((TkCmdtab*)a)->name, ((TkCmdtab*)b)->name);
- }
- void
- tksorttable(void)
- {
- int i;
- TkMethod *c;
- TkCmdtab *cmd;
- for(i = 0; i < TKwidgets; i++) {
- c = tkmethod[i];
- if(c->cmd == nil)
- continue;
- for(cmd = c->cmd; cmd->name != nil; cmd++)
- ;
- c->ncmd = cmd - c->cmd;
- qsort(c->cmd, c->ncmd, sizeof(TkCmdtab), qcmdcmp);
- }
- }
- static char*
- tksinglecmd(TkTop *t, char *arg, char **val)
- {
- Tk *tk;
- int bot, top, new;
- char *e, *buf;
- if(t->debug)
- print("tk: '%s'\n", arg);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
- switch(buf[0]) {
- case '\0':
- free(buf);
- return nil;
- case '.':
- tk = tklook(t, buf, 0);
- if(tk == nil){
- tkerr(t, buf);
- free(buf);
- return TkBadwp;
- }
- e = tkwidgetcmd(t, tk, arg, val);
- free(buf);
- return e;
- }
- bot = 0;
- top = nelem(cmdmain) - 1;
- e = TkBadcm;
- while(bot <= top) {
- int rc;
- new = (bot + top)/2;
- rc = strcmp(cmdmain[new].name, buf);
- if(!rc) {
- e = cmdmain[new].fn(t, arg, val);
- break;
- }
- if(rc < 0)
- bot = new + 1;
- else
- top = new - 1;
- }
- free(buf);
- return e;
- }
- static char*
- tkmatch(int inc, int dec, char *p)
- {
- int depth, esc, c;
- esc = 0;
- depth = 1;
- while(*p) {
- c = *p;
- if(esc == 0) {
- if(c == inc)
- depth++;
- if(c == dec)
- depth--;
- if(depth == 0)
- return p;
- }
- if(c == '\\' && esc == 0)
- esc = 1;
- else
- esc = 0;
- p++;
- }
- return nil;
- }
- char*
- tkexec(TkTop *t, char *arg, char **val)
- {
- int cmdsz, n;
- char *p, *cmd, *e, *c;
- if(t->execdepth >= 0 && ++t->execdepth > 128)
- return TkDepth;
- cmd = nil;
- cmdsz = 0;
- p = arg;
- for(;;) {
- switch(*p++) {
- case '[':
- p = tkmatch('[', ']', p);
- if(p == nil){
- free(cmd);
- return TkSyntx;
- }
- break;
- case '{':
- p = tkmatch('{', '}', p);
- if(p == nil){
- free(cmd);
- return TkSyntx;
- }
- break;
- case ';':
- n = p - arg - 1;
- if(cmdsz < n)
- cmdsz = n;
- c = realloc(cmd, cmdsz+1);
- if(c == nil){
- free(cmd);
- return TkNomem;
- }
- cmd = c;
- memmove(cmd, arg, n);
- cmd[n] = '\0';
- e = tksinglecmd(t, cmd, nil);
- if(e != nil) {
- t->err = e;
- strncpy(t->errcmd, cmd, sizeof(t->errcmd));
- t->errcmd[sizeof(t->errcmd)-1] = '\0';
- free(cmd);
- return e;
- }
- arg = p;
- break;
- case '\0':
- case '\'':
- free(cmd);
- e = tksinglecmd(t, arg, val);
- if(e != nil) {
- t->err = e;
- strncpy(t->errcmd, arg, sizeof(t->errcmd));
- t->errcmd[sizeof(t->errcmd)-1] = '\0';
- }
- return e;
- }
- }
- }
- static struct {
- char *name;
- int mask;
- } events[] = {
- "Button1P", TkButton1P,
- "Button1R", TkButton1R,
- "Button2P", TkButton2P,
- "Button2R", TkButton2R,
- "Button3P", TkButton3P,
- "Button3R", TkButton3R,
- "Button4P", TkButton4P,
- "Button4R", TkButton4R,
- "Button5P", TkButton5P,
- "Button5R", TkButton5R,
- "Button6P", TkButton6P,
- "Button6R", TkButton6R,
- "Extn1", TkExtn1,
- "Extn2", TkExtn2,
- "Takefocus", TkTakefocus,
- "Destroy", TkDestroy,
- "Enter", TkEnter,
- "Leave", TkLeave,
- "Motion", TkMotion,
- "Map", TkMap,
- "Unmap", TkUnmap,
- "Key", TkKey,
- "Focusin", TkFocusin,
- "Focusout", TkFocusout,
- "Configure", TkConfigure,
- "Double", TkDouble,
- 0
- };
- int
- tkeventfmt(Fmt *f)
- {
- int k, i, d;
- int e;
- e = va_arg(f->args, int);
- if ((f->flags & FmtSharp) && e == TkMotion)
- return 0;
- fmtprint(f, "<");
- k = -1;
- if (e & TkKey) {
- k = e & 0xffff;
- e &= ~0xffff;
- }
- d = 0;
- for (i = 0; events[i].name; i++) {
- if (e & events[i].mask) {
- if (d++)
- fmtprint(f, "|");
- fmtprint(f, "%s", events[i].name);
- }
- }
- if (k != -1) {
- fmtprint(f, "[%c]", k);
- } else if (e == 0)
- fmtprint(f, "Noevent");
- fmtprint(f, ">");
- return 0;
- }
- void
- tkerr(TkTop *t, char *e)
- {
- if(t != nil && e != nil){
- strncpy(t->errx, e, sizeof(t->errx));
- t->errx[sizeof(t->errx)-1] = '\0';
- }
- }
- char*
- tkerrstr(TkTop *t, char *e)
- {
- char *s = malloc(strlen(e)+1+strlen(t->errx)+1);
- if(s == nil)
- return nil;
- strcpy(s, e);
- if(*e == '!'){
- strcat(s, " ");
- strcat(s, t->errx);
- }
- t->errx[0] = '\0';
- return s;
- }
- char*
- tksetmgrab(TkTop *t, Tk *tk)
- {
- Tk *omgrab;
- TkCtxt *c;
- c = t->ctxt;
- if (tk == nil) {
- omgrab = c->mgrab;
- c->mgrab = nil;
- /*
- * don't enterleave if grab reset would cause no leave event
- */
- if (!(omgrab != nil && (omgrab->flag & Tknograb) &&
- c->entered != nil && (c->entered->flag & Tknograb)))
- tkenterleave(t);
- } else {
- if (c->focused && c->mfocus != nil && c->mfocus->env->top != tk->env->top)
- return "!grab already taken on another toplevel";
- c->mgrab = tk;
- if (tk->flag & Tknograb) {
- if (c->focused) {
- c->focused = 0;
- c->mfocus = nil;
- }
- } else if (c->focused || c->mstate.b != 0) {
- c->focused = 1;
- c->mfocus = tk;
- }
- //print("setmgrab(%s) focus now %s\n", tkname(tk), tkname(c->mfocus));
- tkenterleave(t);
- }
- return nil;
- }
- int
- tkinsidepoly(Point *poly, int np, int winding, Point p)
- {
- Point pi, pj;
- int i, j, hit;
- hit = 0;
- j = np - 1;
- for(i = 0; i < np; j = i++) {
- pi = poly[i];
- pj = poly[j];
- if((pi.y <= p.y && p.y < pj.y || pj.y <= p.y && p.y < pi.y) &&
- p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) {
- if(winding == 1 || pi.y > p.y)
- hit++;
- else
- hit--;
- }
- }
- return (hit & winding) != 0;
- }
- int
- tklinehit(Point *a, int np, int w, Point p)
- {
- Point *b;
- int z, nx, ny, nrm;
- while(np-- > 1) {
- b = a+1;
- nx = a->y - b->y;
- ny = b->x - a->x;
- nrm = (nx < 0? -nx : nx) + (ny < 0? -ny : ny);
- if(nrm)
- z = (p.x-b->x)*nx/nrm + (p.y-b->y)*ny/nrm;
- else
- z = (p.x-b->x) + (p.y-b->y);
- if(z < 0)
- z = -z;
- if(z < w)
- return 1;
- a++;
- }
- return 0;
- }
- int
- tkiswordchar(int c)
- {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c >= 0xA0;
- }
- int
- tkhaskeyfocus(Tk *tk)
- {
- if (tk == nil || tk->env->top->focused == 0)
- return 0;
- return tk == tk->env->top->ctxt->tkkeygrab;
- }
- static int
- rptactive(void *v)
- {
- int id = (int)v;
- if (id == rptid)
- return 1;
- return 0;
- }
- static int
- ckrpt(void *v, int interval)
- {
- int id = (int)v;
- if (id != rptid)
- return -1;
- if (interval < rptto)
- return 0;
- return 1;
- }
- static void
- dorpt(void *v)
- {
- int id = (int)v;
- if (id == rptid) {
- rptto = rptint;
- (*rptcb)(rptw, rptnote, 0);
- if (rptint <= 0) {
- rptid++;
- rptw = nil;
- }
- }
- }
- void
- tkcancelrepeat(Tk *tk)
- {
- if (tk == rptw) {
- rptid++;
- rptw = nil;
- }
- }
- void
- tkrepeat(Tk *tk, void (*callback)(Tk*, void*, int), void *note, int pause, int interval)
- {
- rptid++;
- if (tk != rptw && rptw != nil)
- /* existing callback being replaced- report to owner */
- (*rptcb)(rptw, rptnote, 1);
- rptw = tk;
- if (tk == nil || callback == nil)
- return;
- rptnote = note;
- rptcb = callback;
- rptto = pause;
- rptint = interval;
- if (!autorpt)
- autorpt = rptproc("autorepeat", TkRptclick, (void*)rptid, rptactive, ckrpt, dorpt);
- else
- rptwakeup((void*)rptid, autorpt);
- }
- static int
- blinkactive(void *v)
- {
- USED(v);
- return blinkw != nil;
- }
- static int
- ckblink(void *v, int interval)
- {
- USED(v);
- USED(interval);
- if (blinkw == nil)
- return -1;
- if (blinkignore) {
- blinkignore = 0;
- return 0;
- }
- return 1;
- }
- static void
- doblink(void *v)
- {
- USED(v);
- if (blinkw == nil)
- return;
- blinkcb(blinkw, blinkon++ & 1);
- tkupdate(blinkw->env->top);
- }
- void
- tkblinkreset(Tk *tk)
- {
- if (blinkw == tk) {
- blinkignore = 1;
- blinkon = 0;
- }
- }
- void
- tkblink(Tk *tk, void (*callback)(Tk*, int))
- {
- if (tk == nil || callback == nil) {
- blinkw = nil;
- return;
- }
- blinkw = tk;
- blinkcb = callback;
- if (!blinkrpt)
- blinkrpt = rptproc("blinker", TkBlinkinterval, nil, blinkactive, ckblink, doblink);
- else
- rptwakeup(nil, blinkrpt);
- }
- /*
- * debugging
- */
- void
- tkdump(Tk *tk)
- {
- Tk *sl;
- if(tk == nil)
- return;
- if((uint)tk->type < TKwidgets)
- print("%s", tkmethod[tk->type]->name);
- else
- print("TYPE#%#ux", tk->type);
- if(tk->name == nil || (ulong)tk->name < 512)
- print(" NAME %p", tk->name);
- else
- print(" %s", tkname(tk));
- print(" # tk %#p flag %#ux grid %#p", tk, tk->flag, tk->grid);
- if(tk->parent != nil)
- print(" parent [%#p %q]", tk->parent, tkname(tk->parent));
- if(tk->master != nil)
- print(" master [%#p %q]", tk->master, tkname(tk->master));
- if(tk->slave != nil){
- print(" slaves");
- for(sl = tk->slave; sl != nil; sl = sl->next)
- print(" [%#p %q]", sl, tkname(sl));
- }
- print("\n");
- if(tk->type != TKcanvas)
- return;
- tkcvsdump(tk);
- }
- void
- tktopdump(Tk *tk)
- {
- TkTop *top;
- Tk *sub;
- if(tk == nil || tk->env == nil){
- print("# %#p no top\n", tk);
- return;
- }
- top = tk->env->top;
- print("# env %#p top %#p\n", tk->env, top);
- if(top != nil){
- for(sub = top->root; sub != nil; sub = sub->siblings)
- tkdump(sub);
- }
- }
|