123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368 |
- #include <lib9.h>
- #include <kernel.h>
- #include "draw.h"
- #include "keyboard.h"
- #include "tk.h"
- /* Widget Commands (+ means implemented)
- +bbox
- +cget
- +configure
- +delete
- +get
- +icursor
- +index
- scan
- +selection
- +xview
- +see
- */
- #define O(t, e) ((long)(&((t*)0)->e))
- #define CNTL(c) ((c)&0x1f)
- #define DEL 0x7f
- /* Layout constants */
- enum {
- Entrypady = 0,
- Entrypadx = 0,
- Inswidth = 2,
- Ecursoron = 1<<0,
- Ecenter = 1<<1,
- Eright = 1<<2,
- Eleft = 1<<3,
- Ewordsel = 1<<4,
- Ejustify = Ecenter|Eleft|Eright
- };
- static TkStab tkjust[] =
- {
- "left", Eleft,
- "right", Eright,
- "center", Ecenter,
- nil
- };
- static
- TkEbind b[] =
- {
- {TkKey, "%W delete sel.first sel.last; %W insert insert {%A};%W see insert"},
- {TkKey|CNTL('a'), "%W icursor 0;%W see insert;%W selection clear"},
- {TkKey|Home, "%W icursor 0;%W see insert;%W selection clear"},
- {TkKey|CNTL('d'), "%W delete insert; %W see insert"},
- {TkKey|CNTL('e'), "%W icursor end; %W see insert;%W selection clear"},
- {TkKey|End, "%W icursor end; %W see insert;%W selection clear"},
- {TkKey|CNTL('h'), "%W tkEntryBS;%W see insert"},
- {TkKey|CNTL('k'), "%W delete insert end;%W see insert"},
- {TkKey|CNTL('u'), "%W delete 0 end;%W see insert"},
- {TkKey|CNTL('w'), "%W delete sel.first sel.last; %W tkEntryBW;%W see insert"},
- {TkKey|DEL, "%W tkEntryBS 1;%W see insert"},
- {TkKey|CNTL('\\'), "%W selection clear"},
- {TkKey|CNTL('/'), "%W selection range 0 end"},
- {TkKey|Left, "%W icursor insert-1;%W selection clear;%W selection from insert;%W see insert"},
- {TkKey|Right, "%W icursor insert+1;%W selection clear;%W selection from insert;%W see insert"},
- {TkButton1P, "focus %W; %W tkEntryB1P %X"},
- {TkButton1P|TkMotion, "%W tkEntryB1M %X"},
- {TkButton1R, "%W tkEntryB1R"},
- {TkButton1P|TkDouble, "%W tkEntryB1P %X;%W selection word @%x"},
- {TkButton2P, "%W tkEntryB2P %x"},
- {TkButton2P|TkMotion, "%W xview scroll %x scr"},
- {TkFocusin, "%W tkEntryFocus in"},
- {TkFocusout, "%W tkEntryFocus out"},
- {TkKey|APP|'\t', ""},
- {TkKey|BackTab, ""},
- };
- typedef struct TkEntry TkEntry;
- struct TkEntry
- {
- Rune* text;
- int textlen;
- char* xscroll;
- char* show;
- int flag;
- int oldx;
- int icursor; /* index of insertion cursor */
- int anchor; /* selection anchor point */
- int sel0; /* index of start of selection */
- int sel1; /* index of end of selection */
- int x0; /* x-offset of visible area */
- /* derived values */
- int v0; /* index of first visible character */
- int v1; /* index of last visible character + 1 */
- int xlen; /* length of text in pixels*/
- int xv0; /* position of first visible character */
- int xsel0; /* position of start of selection */
- int xsel1; /* position of end of selection */
- int xicursor; /* position of insertion cursor */
- };
- static void blinkreset(Tk*);
- static
- TkOption opts[] =
- {
- "xscrollcommand", OPTtext, O(TkEntry, xscroll), nil,
- "justify", OPTstab, O(TkEntry, flag), tkjust,
- "show", OPTtext, O(TkEntry, show), nil,
- nil
- };
- static int
- xinset(Tk *tk)
- {
- return Entrypadx + tk->highlightwidth;
- }
- static int
- yinset(Tk *tk)
- {
- return Entrypady + tk->highlightwidth;
- }
- static void
- tksizeentry(Tk *tk)
- {
- if((tk->flag & Tksetwidth) == 0)
- tk->req.width = tk->env->wzero*25 + 2*xinset(tk) + Inswidth;
- if((tk->flag & Tksetheight) == 0)
- tk->req.height = tk->env->font->height+ 2*yinset(tk);
- }
- int
- entrytextwidth(Tk *tk, int n)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- Rune c;
- Font *f;
- f = tk->env->font;
- if (tke->show != nil) {
- chartorune(&c, tke->show);
- return n * runestringnwidth(f, &c, 1);
- }
- return runestringnwidth(f, tke->text, n);
- }
- static int
- x2index(Tk *tk, int x, int *xc)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- int t0, t1, r, q;
- t0 = 0;
- t1 = tke->textlen;
- while (t0 <= t1) {
- r = (t0 + t1) / 2;
- q = entrytextwidth(tk, r);
- if (q == x) {
- if (xc != nil)
- *xc = q;
- return r;
- }
- if (q < x)
- t0 = r + 1;
- else
- t1 = r - 1;
- }
- if (xc != nil)
- *xc = t1 > 0 ? entrytextwidth(tk, t1) : 0;
- if (t1 < 0)
- t1 = 0;
- return t1;
- }
- /*
- * recalculate derived values
- */
- static void
- recalcentry(Tk *tk)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- int x, avail, locked;
- locked = lockdisplay(tk->env->top->display);
- tke->xlen = entrytextwidth(tk, tke->textlen) + Inswidth;
- avail = tk->act.width - 2*xinset(tk);
- if (tke->xlen < avail) {
- switch(tke->flag & Ejustify) {
- default:
- tke->x0 = 0;
- break;
- case Eright:
- tke->x0 = -(avail - tke->xlen);
- break;
- case Ecenter:
- tke->x0 = -(avail - tke->xlen) / 2;
- break;
- }
- }
- tke->v0 = x2index(tk, tke->x0, &tke->xv0);
- tke->v1 = x2index(tk, tk->act.width + tke->x0, &x);
- /* perhaps include partial last character */
- if (tke->v1 < tke->textlen && x < avail + tke->x0)
- tke->v1++;
- tke->xsel0 = entrytextwidth(tk, tke->sel0);
- tke->xsel1 = entrytextwidth(tk, tke->sel1);
- tke->xicursor = entrytextwidth(tk, tke->icursor);
- if (locked)
- unlockdisplay(tk->env->top->display);
- }
- char*
- tkentry(TkTop *t, char *arg, char **ret)
- {
- Tk *tk;
- char *e;
- TkName *names;
- TkEntry *tke;
- TkOptab tko[3];
- tk = tknewobj(t, TKentry, sizeof(Tk)+sizeof(TkEntry));
- if(tk == nil)
- return TkNomem;
- tk->relief = TKsunken;
- tk->borderwidth = 1;
- tk->flag |= Tktakefocus;
- tk->highlightwidth = 1;
- tke = TKobj(TkEntry, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tke;
- 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));
- tksizeentry(tk);
- 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;
- recalcentry(tk);
- return tkvalue(ret, "%s", tk->name->name);
- }
- static char*
- tkentrycget(Tk *tk, char *arg, char **val)
- {
- TkOptab tko[3];
- TkEntry *tke = TKobj(TkEntry, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tke;
- tko[1].optab = opts;
- tko[2].ptr = nil;
- return tkgencget(tko, arg, val, tk->env->top);
- }
- void
- tkfreeentry(Tk *tk)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- free(tke->xscroll);
- free(tke->text);
- free(tke->show);
- }
- static void
- tkentrytext(Image *i, Rectangle s, Tk *tk, TkEnv *env)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- Point dp;
- int s0, s1, xs0, xs1, j;
- Rectangle r;
- Rune showr, *text;
- dp = Pt(s.min.x - (tke->x0 - tke->xv0), s.min.y);
- if (tke->show) {
- chartorune(&showr, tke->show);
- text = mallocz(sizeof(Rune) * (tke->textlen+1), 0);
- if (text == nil)
- return;
- for (j = 0; j < tke->textlen; j++)
- text[j] = showr;
- } else
- text = tke->text;
- runestringn(i, dp, tkgc(env, TkCforegnd), dp, env->font,
- text+tke->v0, tke->v1-tke->v0);
- if (tke->sel0 < tke->v1 && tke->sel1 > tke->v0) {
- if (tke->sel0 < tke->v0) {
- s0 = tke->v0;
- xs0 = tke->xv0 - tke->x0;
- } else {
- s0 = tke->sel0;
- xs0 = tke->xsel0 - tke->x0;
- }
- if (tke->sel1 > tke->v1) {
- s1 = tke->v1;
- xs1 = s.max.x;
- } else {
- s1 = tke->sel1;
- xs1 = tke->xsel1 - tke->x0;
- }
- r = rectaddpt(Rect(xs0, 0, xs1, env->font->height), s.min);
- tktextsdraw(i, r, env, 1);
- runestringn(i, r.min, tkgc(env, TkCselectfgnd), r.min, env->font,
- text+s0, s1-s0);
- }
- if((tke->flag&Ecursoron) && tke->icursor >= tke->v0 && tke->icursor <= tke->v1) {
- r = Rect(
- tke->xicursor - tke->x0, 0,
- tke->xicursor - tke->x0 + Inswidth, env->font->height
- );
- draw(i, rectaddpt(r, s.min), tkgc(env, TkCforegnd), nil, ZP);
- }
- if (tke->show)
- free(text);
- }
- char*
- tkdrawentry(Tk *tk, Point orig)
- {
- Point p;
- TkEnv *env;
- Rectangle r, s;
- Image *i;
- int xp, yp;
- 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;
- xp = tk->borderwidth + xinset(tk);
- yp = tk->borderwidth + yinset(tk);
- s = r;
- s.min.x += xp;
- s.max.x -= xp;
- s.min.y += yp;
- s.max.y -= yp;
- tkentrytext(i, s, tk, env);
- tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
- if (tkhaskeyfocus(tk))
- tkbox(i, insetrect(r, tk->borderwidth), tk->highlightwidth, tkgc(tk->env, TkChighlightfgnd));
- 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;
- }
-
- char*
- tkentrysh(Tk *tk)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- int dx, top, bot;
- char *val, *cmd, *v, *e;
- if(tke->xscroll == nil)
- return nil;
- bot = 0;
- top = Tkfpscalar;
- if(tke->text != 0 && tke->textlen != 0) {
- dx = tk->act.width - 2*xinset(tk);
- if (tke->xlen > dx) {
- bot = TKI2F(tke->x0) / tke->xlen;
- top = TKI2F(tke->x0 + dx) / tke->xlen;
- }
- }
- val = mallocz(Tkminitem, 0);
- if(val == nil)
- return TkNomem;
- v = tkfprint(val, bot);
- *v++ = ' ';
- tkfprint(v, top);
- cmd = mallocz(Tkminitem, 0);
- if(cmd == nil) {
- free(val);
- return TkNomem;
- }
- sprint(cmd, "%s %s", tke->xscroll, val);
- e = tkexec(tk->env->top, cmd, nil);
- free(cmd);
- free(val);
- return e;
- }
- void
- tkentrygeom(Tk *tk)
- {
- char *e;
- e = tkentrysh(tk);
- if ((e != nil) && /* XXX - Tad: should propagate not print */
- (tk->name != nil))
- print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
- recalcentry(tk);
- }
- static char*
- tkentryconf(Tk *tk, char *arg, char **val)
- {
- char *e;
- TkGeom g;
- int bd;
- TkOptab tko[3];
- TkEntry *tke = TKobj(TkEntry, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tke;
- tko[1].optab = opts;
- tko[2].ptr = nil;
- if(*arg == '\0')
- return tkconflist(tko, val);
- bd = tk->borderwidth;
- g = tk->req;
- e = tkparse(tk->env->top, arg, tko, nil);
- tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
- tksizeentry(tk);
- tkgeomchg(tk, &g, bd);
- recalcentry(tk);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- static char*
- tkentryparseindex(Tk *tk, char *buf, int *index)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- TkEnv *env;
- char *mod;
- int i, x, locked, modstart;
- modstart = 0;
- for(mod = buf; *mod != '\0'; mod++)
- if(*mod == '-' || *mod == '+') {
- modstart = *mod;
- *mod = '\0';
- break;
- }
- if(strcmp(buf, "end") == 0)
- i = tke->textlen;
- else
- if(strcmp(buf, "anchor") == 0)
- i = tke->anchor;
- else
- if(strcmp(buf, "insert") == 0)
- i = tke->icursor;
- else
- if(strcmp(buf, "sel.first") == 0)
- i = tke->sel0;
- else
- if(strcmp(buf, "sel.last") == 0)
- i = tke->sel1;
- else
- if(buf[0] >= '0' && buf[0] <= '9')
- i = atoi(buf);
- else
- if(buf[0] == '@') {
- x = atoi(buf+1) - xinset(tk);
- if(tke->textlen == 0) {
- *index = 0;
- return nil;
- }
- env = tk->env;
- locked = lockdisplay(env->top->display);
- i = x2index(tk, x + tke->x0, nil); /* XXX could possibly select nearest character? */
- if(locked)
- unlockdisplay(env->top->display);
- }
- else
- return TkBadix;
- if(i < 0 || i > tke->textlen)
- return TkBadix;
- if(modstart) {
- *mod = modstart;
- i += atoi(mod);
- if(i < 0)
- i = 0;
- if(i > tke->textlen)
- i = tke->textlen;
- }
- *index = i;
- return nil;
- }
- /*
- * return bounding box of character at index, in coords relative to
- * the top left position of the text.
- */
- static Rectangle
- tkentrybbox(Tk *tk, int index)
- {
- TkEntry *tke;
- TkEnv *env;
- Display *d;
- int x, cw, locked;
- Rectangle r;
- tke = TKobj(TkEntry, tk);
- env = tk->env;
- d = env->top->display;
- locked = lockdisplay(d);
- x = entrytextwidth(tk, index);
- if (index < tke->textlen)
- cw = entrytextwidth(tk, index+1) - x;
- else
- cw = Inswidth;
- if(locked)
- unlockdisplay(d);
- r.min.x = x;
- r.min.y = 0;
- r.max.x = x + cw;
- r.max.y = env->font->height;
- return r;
- }
- static void
- tkentrysee(Tk *tk, int index, int jump)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- int dx, margin;
- Rectangle r;
- r = tkentrybbox(tk, index);
- dx = tk->act.width - 2*xinset(tk);
- if (jump)
- margin = dx / 4;
- else
- margin = 0;
- if (r.min.x <= tke->x0 || r.max.x > tke->x0 + dx) {
- if (r.min.x <= tke->x0) {
- tke->x0 = r.min.x - margin;
- if (tke->x0 < 0)
- tke->x0 = 0;
- } else if (r.max.x >= tke->x0 + dx) {
- tke->x0 = r.max.x - dx + margin;
- if (tke->x0 > tke->xlen - dx)
- tke->x0 = tke->xlen - dx;
- }
- tk->dirty = tkrect(tk, 0);
- }
- r = rectaddpt(r, Pt(xinset(tk) - tke->x0, yinset(tk)));
- tksee(tk, r, r.min);
- }
- static char*
- tkentryseecmd(Tk *tk, char *arg, char **val)
- {
- int index;
- char *e, *buf;
- USED(val);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &index);
- free(buf);
- if(e != nil)
- return e;
- tkentrysee(tk, index, 1);
- recalcentry(tk);
-
- return nil;
- }
- static char*
- tkentrybboxcmd(Tk *tk, char *arg, char **val)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- char *r, *buf;
- int index;
- Rectangle bbox;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- r = tkentryparseindex(tk, buf, &index);
- free(buf);
- if(r != nil)
- return r;
- bbox = rectaddpt(tkentrybbox(tk, index), Pt(xinset(tk) - tke->x0, yinset(tk)));
- return tkvalue(val, "%d %d %d %d", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
- }
- static char*
- tkentryindex(Tk *tk, char *arg, char **val)
- {
- int index;
- char *r, *buf;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- r = tkentryparseindex(tk, buf, &index);
- free(buf);
- if(r != nil)
- return r;
- return tkvalue(val, "%d", index);
- }
- static char*
- tkentryicursor(Tk *tk, char *arg, char **val)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- int index, locked;
- char *r, *buf;
- USED(val);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- r = tkentryparseindex(tk, buf, &index);
- free(buf);
- if(r != nil)
- return r;
- tke->icursor = index;
- locked = lockdisplay(tk->env->top->display);
- tke->xicursor = entrytextwidth(tk, tke->icursor);
- if (locked)
- unlockdisplay(tk->env->top->display);
- blinkreset(tk);
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static int
- adjustforins(int i, int n, int q)
- {
- if (i <= q)
- q += n;
- return q;
- }
- static int
- adjustfordel(int d0, int d1, int q)
- {
- if (d1 <= q)
- q -= d1 - d0;
- else if (d0 <= q && q <= d1)
- q = d0;
- return q;
- }
- static char*
- tkentryget(Tk *tk, char *arg, char **val)
- {
- TkTop *top;
- TkEntry *tke;
- int first, last;
- char *e, *buf;
- tke = TKobj(TkEntry, tk);
- if(tke->text == nil)
- return nil;
- arg = tkskip(arg, " \t");
- if(*arg == '\0')
- return tkvalue(val, "%.*S", tke->textlen, tke->text);
- top = tk->env->top;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &first);
- if(e != nil) {
- free(buf);
- return e;
- }
- last = first+1;
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- if(buf[0] != '\0') {
- e = tkentryparseindex(tk, buf, &last);
- if(e != nil) {
- free(buf);
- return e;
- }
- }
- free(buf);
- if(last <= first || tke->textlen == 0 || first == tke->textlen)
- return tkvalue(val, "%S", L"");
- return tkvalue(val, "%.*S", last-first, tke->text+first);
- }
- static char*
- tkentryinsert(Tk *tk, char *arg, char **val)
- {
- TkTop *top;
- TkEntry *tke;
- int ins, i, n, locked;
- char *e, *t, *text, *buf;
- Rune *etext;
- USED(val);
- tke = TKobj(TkEntry, tk);
- top = tk->env->top;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &ins);
- free(buf);
- if(e != nil)
- return e;
- if(*arg == '\0')
- return nil;
- n = strlen(arg) + 1;
- if(n < Tkmaxitem)
- n = Tkmaxitem;
- text = malloc(n);
- if(text == nil)
- return TkNomem;
- tkword(top, arg, text, text+n, nil);
- n = utflen(text);
- etext = realloc(tke->text, (tke->textlen+n+1)*sizeof(Rune));
- if(etext == nil) {
- free(text);
- return TkNomem;
- }
- tke->text = etext;
- memmove(tke->text+ins+n, tke->text+ins, (tke->textlen-ins)*sizeof(Rune));
- t = text;
- for(i=0; i<n; i++)
- t += chartorune(tke->text+ins+i, t);
- free(text);
- tke->textlen += n;
- tke->sel0 = adjustforins(ins, n, tke->sel0);
- tke->sel1 = adjustforins(ins, n, tke->sel1);
- tke->icursor = adjustforins(ins, n, tke->icursor);
- tke->anchor = adjustforins(ins, n, tke->anchor);
- locked = lockdisplay(tk->env->top->display);
- if (ins < tke->v0)
- tke->x0 += entrytextwidth(tk, tke->v0 + n) + (tke->x0 - tke->xv0);
- if (locked)
- unlockdisplay(tk->env->top->display);
- recalcentry(tk);
- e = tkentrysh(tk);
- blinkreset(tk);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- static char*
- tkentrydelete(Tk *tk, char *arg, char **val)
- {
- TkTop *top;
- TkEntry *tke;
- int d0, d1, locked;
- char *e, *buf;
- Rune *text;
- USED(val);
- tke = TKobj(TkEntry, tk);
- top = tk->env->top;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &d0);
- if(e != nil) {
- free(buf);
- return e;
- }
- d1 = d0+1;
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- if(buf[0] != '\0') {
- e = tkentryparseindex(tk, buf, &d1);
- if(e != nil) {
- free(buf);
- return e;
- }
- }
- free(buf);
- if(d1 <= d0 || tke->textlen == 0 || d0 >= tke->textlen)
- return nil;
- memmove(tke->text+d0, tke->text+d1, (tke->textlen-d1)*sizeof(Rune));
- tke->textlen -= d1 - d0;
- text = realloc(tke->text, (tke->textlen+1) * sizeof(Rune));
- if (text != nil)
- tke->text = text;
- tke->sel0 = adjustfordel(d0, d1, tke->sel0);
- tke->sel1 = adjustfordel(d0, d1, tke->sel1);
- tke->icursor = adjustfordel(d0, d1, tke->icursor);
- tke->anchor = adjustfordel(d0, d1, tke->anchor);
- locked = lockdisplay(tk->env->top->display);
- if (d1 < tke->v0)
- tke->x0 = entrytextwidth(tk, tke->v0 - (d1 - d0)) + (tke->x0 - tke->xv0);
- else if (d0 < tke->v0)
- tke->x0 = entrytextwidth(tk, d0);
- if (locked)
- unlockdisplay(tk->env->top->display);
- recalcentry(tk);
- e = tkentrysh(tk);
- blinkreset(tk);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- /* Used for both backspace and DEL. If a selection exists, delete it.
- * Otherwise delete the character to the left(right) of the insertion
- * cursor, if any.
- */
- static char*
- tkentrybs(Tk *tk, char *arg, char **val)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- char *buf, *e;
- int ix;
- USED(val);
- USED(arg);
- if(tke->textlen == 0)
- return nil;
- if(tke->sel0 < tke->sel1)
- return tkentrydelete(tk, "sel.first sel.last", nil);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- ix = -1;
- if(buf[0] != '\0') {
- e = tkentryparseindex(tk, buf, &ix);
- if(e != nil) {
- free(buf);
- return e;
- }
- }
- if(ix > -1) { /* DEL */
- if(tke->icursor >= tke->textlen) {
- free(buf);
- return nil;
- }
- }
- else { /* backspace */
- if(tke->icursor == 0) {
- free(buf);
- return nil;
- }
- tke->icursor--;
- }
- snprint(buf, Tkmaxitem, "%d", tke->icursor);
- e = tkentrydelete(tk, buf, nil);
- free(buf);
- return e;
- }
- static char*
- tkentrybw(Tk *tk, char *arg, char **val)
- {
- int start;
- Rune *text;
- TkEntry *tke;
- char buf[32];
- USED(val);
- USED(arg);
- tke = TKobj(TkEntry, tk);
- if(tke->textlen == 0 || tke->icursor == 0)
- return nil;
- text = tke->text;
- start = tke->icursor-1;
- while(start > 0 && !tkiswordchar(text[start]))
- --start;
- while(start > 0 && tkiswordchar(text[start-1]))
- --start;
- snprint(buf, sizeof(buf), "%d %d", start, tke->icursor);
- return tkentrydelete(tk, buf, nil);
- }
- char*
- tkentryselect(Tk *tk, char *arg, char **val)
- {
- TkTop *top;
- int start, from, to, locked;
- TkEntry *tke;
- char *e, *buf;
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- tke = TKobj(TkEntry, tk);
- top = tk->env->top;
- arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
- if(strcmp(buf, "clear") == 0) {
- tke->sel0 = 0;
- tke->sel1 = 0;
- }
- else
- if(strcmp(buf, "from") == 0) {
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &tke->anchor);
- tke->flag &= ~Ewordsel;
- free(buf);
- return e;
- }
- else
- if(strcmp(buf, "to") == 0) {
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &to);
- if(e != nil) {
- free(buf);
- return e;
- }
-
- if(to < tke->anchor) {
- if(tke->flag & Ewordsel)
- while(to > 0 && tkiswordchar(tke->text[to-1]))
- --to;
- tke->sel0 = to;
- tke->sel1 = tke->anchor;
- }
- else
- if(to >= tke->anchor) {
- if(tke->flag & Ewordsel)
- while(to < tke->textlen &&
- tkiswordchar(tke->text[to]))
- to++;
- tke->sel0 = tke->anchor;
- tke->sel1 = to;
- }
- tkentrysee(tk, to, 0);
- recalcentry(tk);
- }
- else
- if(strcmp(buf, "word") == 0) { /* inferno invention */
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &start);
- if(e != nil) {
- free(buf);
- return e;
- }
- from = start;
- while(from > 0 && tkiswordchar(tke->text[from-1]))
- --from;
- to = start;
- while(to < tke->textlen && tkiswordchar(tke->text[to]))
- to++;
- tke->sel0 = from;
- tke->sel1 = to;
- tke->anchor = from;
- tke->icursor = from;
- tke->flag |= Ewordsel;
- locked = lockdisplay(tk->env->top->display);
- tke->xicursor = entrytextwidth(tk, tke->icursor);
- if (locked)
- unlockdisplay(tk->env->top->display);
- }
- else
- if(strcmp(buf, "present") == 0) {
- e = tkvalue(val, "%d", tke->sel1 > tke->sel0);
- free(buf);
- return e;
- }
- else
- if(strcmp(buf, "range") == 0) {
- arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &from);
- if(e != nil) {
- free(buf);
- return e;
- }
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &to);
- if(e != nil) {
- free(buf);
- return e;
- }
- tke->sel0 = from;
- tke->sel1 = to;
- if(to <= from) {
- tke->sel0 = 0;
- tke->sel1 = 0;
- }
- }
- else
- if(strcmp(buf, "adjust") == 0) {
- tkword(top, arg, buf, buf+Tkmaxitem, nil);
- e = tkentryparseindex(tk, buf, &to);
- if(e != nil) {
- free(buf);
- return e;
- }
- if(tke->sel0 == 0 && tke->sel1 == 0) {
- tke->sel0 = tke->anchor;
- tke->sel1 = to;
- }
- else {
- if(abs(tke->sel0-to) < abs(tke->sel1-to)) {
- tke->sel0 = to;
- tke->anchor = tke->sel1;
- }
- else {
- tke->sel1 = to;
- tke->anchor = tke->sel0;
- }
- }
- if(tke->sel0 > tke->sel1) {
- to = tke->sel0;
- tke->sel0 = tke->sel1;
- tke->sel1 = to;
- }
- }
- else {
- free(buf);
- return TkBadcm;
- }
- locked = lockdisplay(tk->env->top->display);
- tke->xsel0 = entrytextwidth(tk, tke->sel0);
- tke->xsel1 = entrytextwidth(tk, tke->sel1);
- if (locked)
- unlockdisplay(tk->env->top->display);
- tk->dirty = tkrect(tk, 1);
- free(buf);
- return nil;
- }
- static char*
- tkentryb2p(Tk *tk, char *arg, char **val)
- {
- TkEntry *tke;
- char *buf;
- USED(val);
- tke = TKobj(TkEntry, tk);
- buf = malloc(Tkmaxitem);
- if (buf == nil)
- return TkNomem;
- tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
- tke->oldx = atoi(buf);
- return nil;
- }
- static char*
- tkentryxview(Tk *tk, char *arg, char **val)
- {
- int locked;
- TkEnv *env;
- TkEntry *tke;
- char *buf, *v;
- int dx, top, bot, amount, ix, x;
- char *e;
- tke = TKobj(TkEntry, tk);
- env = tk->env;
- dx = tk->act.width - 2*xinset(tk);
- buf = mallocz(Tkmaxitem, 0);
- if(buf == nil)
- return TkNomem;
- if(*arg == '\0') {
- if (tke->textlen == 0 || tke->xlen < dx) {
- bot = TKI2F(0);
- top = TKI2F(1);
- } else {
- bot = TKI2F(tke->x0) / tke->xlen;
- top = TKI2F(tke->x0 + dx) / tke->xlen;
- }
- v = tkfprint(buf, bot);
- *v++ = ' ';
- tkfprint(v, top);
- e = tkvalue(val, "%s", buf);
- free(buf);
- return e;
- }
- arg = tkitem(buf, arg);
- if(strcmp(buf, "moveto") == 0) {
- e = tkfracword(env->top, &arg, &top, nil);
- if (e != nil) {
- free(buf);
- return e;
- }
- tke->x0 = TKF2I(top*tke->xlen);
- }
- else
- if(strcmp(buf, "scroll") == 0) {
- arg = tkitem(buf, arg);
- amount = atoi(buf);
- if(*arg == 'p') /* Pages */
- amount *= (9*tke->xlen)/10;
- else
- if(*arg == 's') { /* Inferno-ism, "scr", must be used in the context of button2p */
- x = amount;
- amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0);
- tke->oldx = x;
- }
- tke->x0 += amount;
- }
- else {
- e = tkentryparseindex(tk, buf, &ix);
- if(e != nil) {
- free(buf);
- return e;
- }
- locked = lockdisplay(env->top->display);
- tke->x0 = entrytextwidth(tk, ix);
- if (locked)
- unlockdisplay(env->top->display);
- }
- free(buf);
- if (tke->x0 > tke->xlen - dx)
- tke->x0 = tke->xlen - dx;
- if (tke->x0 < 0)
- tke->x0 = 0;
- recalcentry(tk);
- e = tkentrysh(tk);
- blinkreset(tk);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- static void
- autoselect(Tk *tk, void *v, int cancelled)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- Rectangle hitr;
- char buf[32];
- Point p;
- USED(v);
- if (cancelled)
- return;
- p = tkscrn2local(tk, Pt(tke->oldx, 0));
- p.y = 0;
- if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
- return;
- snprint(buf, sizeof(buf), "to @%d", p.x);
- tkentryselect(tk, buf, nil);
- tkdirty(tk);
- tkupdate(tk->env->top);
- }
- static char*
- tkentryb1p(Tk *tk, char* arg, char **ret)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- Point p;
- int i, locked, x;
- char buf[32], *e;
- USED(ret);
- x = atoi(arg);
- p = tkscrn2local(tk, Pt(x, 0));
- sprint(buf, "@%d", p.x);
- e = tkentryparseindex(tk, buf, &i);
- if (e != nil)
- return e;
- tke->sel0 = 0;
- tke->sel1 = 0;
- tke->icursor = i;
- tke->anchor = i;
- tke->flag &= ~Ewordsel;
- locked = lockdisplay(tk->env->top->display);
- tke->xsel0 = 0;
- tke->xsel1 = 0;
- tke->xicursor = entrytextwidth(tk, tke->icursor);
- if (locked)
- unlockdisplay(tk->env->top->display);
- tke->oldx = x;
- blinkreset(tk);
- tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
- tk->dirty = tkrect(tk, 0);
- return nil;
- }
- static char*
- tkentryb1m(Tk *tk, char* arg, char **ret)
- {
- TkEntry *tke = TKobj(TkEntry, tk);
- Point p;
- Rectangle hitr;
- char buf[32];
- USED(ret);
- p.x = atoi(arg);
- tke->oldx = p.x;
- p = tkscrn2local(tk, p);
- p.y = 0;
- if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
- return nil;
- snprint(buf, sizeof(buf), "to @%d", p.x);
- tkentryselect(tk, buf, nil);
- return nil;
- }
- static char*
- tkentryb1r(Tk *tk, char* arg, char **ret)
- {
- USED(tk);
- USED(arg);
- USED(ret);
- tkcancelrepeat(tk);
- return nil;
- }
- static void
- blinkreset(Tk *tk)
- {
- TkEntry *e = TKobj(TkEntry, tk);
- if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
- return;
- e->flag |= Ecursoron;
- tkblinkreset(tk);
- }
- static void
- showcaret(Tk *tk, int on)
- {
- TkEntry *e = TKobj(TkEntry, tk);
- if (on)
- e->flag |= Ecursoron;
- else
- e->flag &= ~Ecursoron;
- tk->dirty = tkrect(tk, 0);
- }
- char*
- tkentryfocus(Tk *tk, char* arg, char **ret)
- {
- int on = 0;
- USED(ret);
- if (tk->flag&Tkdisabled)
- return nil;
- if(strcmp(arg, " in") == 0) {
- tkblink(tk, showcaret);
- on = 1;
- }
- else
- tkblink(nil, nil);
- showcaret(tk, on);
- return nil;
- }
- static
- TkCmdtab tkentrycmd[] =
- {
- "cget", tkentrycget,
- "configure", tkentryconf,
- "delete", tkentrydelete,
- "get", tkentryget,
- "icursor", tkentryicursor,
- "index", tkentryindex,
- "insert", tkentryinsert,
- "selection", tkentryselect,
- "xview", tkentryxview,
- "tkEntryBS", tkentrybs,
- "tkEntryBW", tkentrybw,
- "tkEntryB1P", tkentryb1p,
- "tkEntryB1M", tkentryb1m,
- "tkEntryB1R", tkentryb1r,
- "tkEntryB2P", tkentryb2p,
- "tkEntryFocus", tkentryfocus,
- "bbox", tkentrybboxcmd,
- "see", tkentryseecmd,
- nil
- };
- TkMethod entrymethod = {
- "entry",
- tkentrycmd,
- tkfreeentry,
- tkdrawentry,
- tkentrygeom
- };
|