137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "keyboard.h"
437da2899SCharles.Forsyth #include "tk.h"
537da2899SCharles.Forsyth #include "textw.h"
637da2899SCharles.Forsyth
737da2899SCharles.Forsyth /*
837da2899SCharles.Forsyth * useful text widget info to be found at:
937da2899SCharles.Forsyth * :/coordinate.systems - what coord. systems are in use
1037da2899SCharles.Forsyth * textu.c:/assumed.invariants - some invariants that must be preserved
1137da2899SCharles.Forsyth */
1237da2899SCharles.Forsyth
1337da2899SCharles.Forsyth #define istring u.string
1437da2899SCharles.Forsyth #define iwin u.win
1537da2899SCharles.Forsyth #define imark u.mark
1637da2899SCharles.Forsyth #define iline u.line
1737da2899SCharles.Forsyth
1837da2899SCharles.Forsyth #define FLUSH() flushimage(tk->env->top->display, 1)
1937da2899SCharles.Forsyth
2037da2899SCharles.Forsyth #define O(t, e) ((long)(&((t*)0)->e))
2137da2899SCharles.Forsyth
2237da2899SCharles.Forsyth /* Layout constants */
2337da2899SCharles.Forsyth enum {
2437da2899SCharles.Forsyth Textpadx = 2,
2537da2899SCharles.Forsyth Textpady = 0,
2637da2899SCharles.Forsyth };
2737da2899SCharles.Forsyth
2837da2899SCharles.Forsyth typedef struct Interval {
2937da2899SCharles.Forsyth int lo;
3037da2899SCharles.Forsyth int hi;
3137da2899SCharles.Forsyth } Interval;
3237da2899SCharles.Forsyth
3337da2899SCharles.Forsyth typedef struct Mprint Mprint;
3437da2899SCharles.Forsyth struct Mprint
3537da2899SCharles.Forsyth {
3637da2899SCharles.Forsyth char* buf;
3737da2899SCharles.Forsyth int ptr;
3837da2899SCharles.Forsyth int len;
3937da2899SCharles.Forsyth };
4037da2899SCharles.Forsyth
4137da2899SCharles.Forsyth typedef struct TkDump TkDump;
4237da2899SCharles.Forsyth struct TkDump
4337da2899SCharles.Forsyth {
4437da2899SCharles.Forsyth int sgml;
4537da2899SCharles.Forsyth int metrics;
4637da2899SCharles.Forsyth };
4737da2899SCharles.Forsyth
4837da2899SCharles.Forsyth static
4937da2899SCharles.Forsyth TkOption dumpopts[] =
5037da2899SCharles.Forsyth {
5137da2899SCharles.Forsyth "sgml", OPTbool, O(TkDump, sgml), nil,
5237da2899SCharles.Forsyth "metrics", OPTbool, O(TkDump, metrics), nil,
5337da2899SCharles.Forsyth nil
5437da2899SCharles.Forsyth };
5537da2899SCharles.Forsyth
5637da2899SCharles.Forsyth static
5737da2899SCharles.Forsyth TkStab tkcompare[] =
5837da2899SCharles.Forsyth {
5937da2899SCharles.Forsyth "<", TkLt,
6037da2899SCharles.Forsyth "<=", TkLte,
6137da2899SCharles.Forsyth "==", TkEq,
6237da2899SCharles.Forsyth ">=", TkGte,
6337da2899SCharles.Forsyth ">", TkGt,
6437da2899SCharles.Forsyth "!=", TkNeq,
6537da2899SCharles.Forsyth nil
6637da2899SCharles.Forsyth };
6737da2899SCharles.Forsyth
6837da2899SCharles.Forsyth static
6937da2899SCharles.Forsyth TkOption textopts[] =
7037da2899SCharles.Forsyth {
7137da2899SCharles.Forsyth "wrap", OPTstab, O(TkText, opts[TkTwrap]), tkwrap,
7237da2899SCharles.Forsyth "spacing1", OPTnndist, O(TkText, opts[TkTspacing1]), (void *)O(Tk, env),
7337da2899SCharles.Forsyth "spacing2", OPTnndist, O(TkText, opts[TkTspacing2]), (void *)O(Tk, env),
7437da2899SCharles.Forsyth "spacing3", OPTnndist, O(TkText, opts[TkTspacing3]), (void *)O(Tk, env),
7537da2899SCharles.Forsyth "tabs", OPTtabs, O(TkText, tabs), (void *)O(Tk, env),
7637da2899SCharles.Forsyth "xscrollcommand", OPTtext, O(TkText, xscroll), nil,
7737da2899SCharles.Forsyth "yscrollcommand", OPTtext, O(TkText, yscroll), nil,
7837da2899SCharles.Forsyth "insertwidth", OPTnndist, O(TkText, inswidth), nil,
7937da2899SCharles.Forsyth "tagshare", OPTwinp, O(TkText, tagshare), nil,
8037da2899SCharles.Forsyth "propagate", OPTstab, O(TkText, propagate), tkbool,
8137da2899SCharles.Forsyth "selectborderwidth", OPTnndist, O(TkText, sborderwidth), nil,
8237da2899SCharles.Forsyth nil
8337da2899SCharles.Forsyth };
8437da2899SCharles.Forsyth
8537da2899SCharles.Forsyth #define CNTL(c) ((c)&0x1f)
8637da2899SCharles.Forsyth #define DEL 0x7f
8737da2899SCharles.Forsyth
8837da2899SCharles.Forsyth static TkEbind tktbinds[] = {
8937da2899SCharles.Forsyth {TkButton1P, "%W tkTextButton1 %X %Y"},
9037da2899SCharles.Forsyth {TkButton1P|TkMotion, "%W tkTextSelectTo %X %Y"},
9137da2899SCharles.Forsyth {TkButton1P|TkDouble, "%W tkTextSelectTo %X %Y double"},
9237da2899SCharles.Forsyth {TkButton1R, "%W tkTextButton1R"},
9337da2899SCharles.Forsyth {TkButton2P, "%W scan mark %x %y"},
9437da2899SCharles.Forsyth {TkButton2P|TkMotion, "%W scan dragto %x %y"},
9537da2899SCharles.Forsyth {TkKey, "%W tkTextInsert {%A}"},
9637da2899SCharles.Forsyth {TkKey|CNTL('a'), "%W tkTextSetCursor {insert linestart}"},
9737da2899SCharles.Forsyth {TkKey|Home, "%W tkTextSetCursor {insert linestart}"},
9837da2899SCharles.Forsyth {TkKey|CNTL('<'), "%W tkTextSetCursor {insert linestart}"},
9937da2899SCharles.Forsyth {TkKey|CNTL('b'), "%W tkTextSetCursor insert-1c"},
10037da2899SCharles.Forsyth {TkKey|Left, "%W tkTextSetCursor insert-1c"},
101*3a78c580Sforsyth {TkKey|CNTL('d'), "%W tkTextDelIns"},
10237da2899SCharles.Forsyth {TkKey|CNTL('e'), "%W tkTextSetCursor {insert lineend}"},
10337da2899SCharles.Forsyth {TkKey|End, "%W tkTextSetCursor {insert lineend}"},
10437da2899SCharles.Forsyth {TkKey|CNTL('>'), "%W tkTextSetCursor {insert lineend}"},
10537da2899SCharles.Forsyth {TkKey|CNTL('f'), "%W tkTextSetCursor insert+1c"},
10637da2899SCharles.Forsyth {TkKey|Right, "%W tkTextSetCursor insert+1c"},
10737da2899SCharles.Forsyth {TkKey|CNTL('h'), "%W tkTextDelIns -c"},
108*3a78c580Sforsyth {TkKey|DEL, "%W tkTextDelIns"},
109*3a78c580Sforsyth {TkKey|CNTL('k'), "%W tkTextDelIns +l"},
11037da2899SCharles.Forsyth {TkKey|CNTL('n'), "%W tkTextSetCursor {insert+1l}"},
11137da2899SCharles.Forsyth {TkKey|Down, "%W tkTextSetCursor {insert+1l}"},
11237da2899SCharles.Forsyth {TkKey|CNTL('o'), "%W tkTextInsert {\n}; %W mark set insert insert-1c"},
11337da2899SCharles.Forsyth {TkKey|CNTL('p'), "%W tkTextSetCursor {insert-1l}"},
11437da2899SCharles.Forsyth {TkKey|Up, "%W tkTextSetCursor {insert-1l}"},
11537da2899SCharles.Forsyth {TkKey|CNTL('u'), "%W tkTextDelIns -l"},
1166e425a9dSCharles.Forsyth {TkKey|CNTL('v'), "%W yview scroll 0.75 page"},
1176e425a9dSCharles.Forsyth {TkKey|Pgdown, "%W yview scroll 0.75 page"},
11837da2899SCharles.Forsyth {TkKey|CNTL('w'), "%W tkTextDelIns -w"},
1196e425a9dSCharles.Forsyth {TkKey|Pgup, "%W yview scroll -0.75 page"},
1205849851aSforsyth {TkButton4P, "%W yview scroll -0.2 page"},
1215849851aSforsyth {TkButton5P, "%W yview scroll 0.2 page"},
12237da2899SCharles.Forsyth {TkFocusout, "%W tkTextCursor delete"},
12337da2899SCharles.Forsyth {TkKey|APP|'\t', ""},
12437da2899SCharles.Forsyth {TkKey|BackTab, ""},
12537da2899SCharles.Forsyth };
12637da2899SCharles.Forsyth
12737da2899SCharles.Forsyth static int tktclickmatch(TkText *, int, int, int, TkTindex *);
12837da2899SCharles.Forsyth static void tktdoubleclick(TkText *, TkTindex *, TkTindex *);
12937da2899SCharles.Forsyth static char* tktdrawline(Image*, Tk*, TkTline*, Point);
13037da2899SCharles.Forsyth static void tktextcursordraw(Tk *, int);
13137da2899SCharles.Forsyth static char* tktsetscroll(Tk*, int);
13237da2899SCharles.Forsyth static void tktsetclip(Tk *);
13337da2899SCharles.Forsyth static char* tktview(Tk*, char*, char**, int, int*, int, int);
13437da2899SCharles.Forsyth static Interval tkttranslate(Tk*, Interval, int);
13537da2899SCharles.Forsyth static void tktfixscroll(Tk*, Point);
13637da2899SCharles.Forsyth static void tktnotdrawn(Tk*, int, int, int);
13737da2899SCharles.Forsyth static void tktdrawbg(Tk*, int, int, int);
13837da2899SCharles.Forsyth static int tktwidbetween(Tk*, int, TkTindex*, TkTindex*);
13937da2899SCharles.Forsyth static int tktpostspace(Tk*, TkTline*);
14037da2899SCharles.Forsyth static int tktprespace(Tk*, TkTline*);
14137da2899SCharles.Forsyth static void tktsee(Tk*, TkTindex*, int);
14237da2899SCharles.Forsyth static Point tktrelpos(Tk*);
14337da2899SCharles.Forsyth static void autoselect(Tk*, void*, int);
14437da2899SCharles.Forsyth static void blinkreset(Tk*);
14537da2899SCharles.Forsyth
14637da2899SCharles.Forsyth /* debugging */
14737da2899SCharles.Forsyth extern int tktdbg;
14837da2899SCharles.Forsyth extern void tktprinttext(TkText*);
14937da2899SCharles.Forsyth extern void tktprintindex(TkTindex*);
15037da2899SCharles.Forsyth extern void tktprintitem(TkTitem*);
15137da2899SCharles.Forsyth extern void tktprintline(TkTline*);
15237da2899SCharles.Forsyth extern void tktcheck(TkText*, char*);
15337da2899SCharles.Forsyth extern int tktutfpos(char *, int);
15437da2899SCharles.Forsyth
15537da2899SCharles.Forsyth char*
tktext(TkTop * t,char * arg,char ** ret)15637da2899SCharles.Forsyth tktext(TkTop *t, char* arg, char **ret)
15737da2899SCharles.Forsyth {
15837da2899SCharles.Forsyth Tk *tk;
15937da2899SCharles.Forsyth char *e;
16037da2899SCharles.Forsyth TkEnv *ev;
16137da2899SCharles.Forsyth TkTline *l;
16237da2899SCharles.Forsyth TkTitem *it = nil;
16337da2899SCharles.Forsyth TkName *names = nil;
16437da2899SCharles.Forsyth TkTtaginfo *ti = nil;
16537da2899SCharles.Forsyth TkOptab tko[3];
16637da2899SCharles.Forsyth TkTmarkinfo *mi = nil;
16737da2899SCharles.Forsyth TkText *tkt, *tktshare;
16837da2899SCharles.Forsyth
16937da2899SCharles.Forsyth tk = tknewobj(t, TKtext, sizeof(Tk)+sizeof(TkText));
17037da2899SCharles.Forsyth if(tk == nil)
17137da2899SCharles.Forsyth return TkNomem;
17237da2899SCharles.Forsyth
17337da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
17437da2899SCharles.Forsyth
17537da2899SCharles.Forsyth tk->relief = TKsunken;
176c9ccdbd5Sforsyth tk->borderwidth = 1;
17737da2899SCharles.Forsyth tk->ipad.x = Textpadx * 2;
17837da2899SCharles.Forsyth tk->ipad.y = Textpady * 2;
17937da2899SCharles.Forsyth tk->flag |= Tktakefocus;
18037da2899SCharles.Forsyth tkt->sborderwidth = 0;
18137da2899SCharles.Forsyth tkt->inswidth = 2;
18237da2899SCharles.Forsyth tkt->cur_flag = 0; /* text cursor doesn't show up initially */
18337da2899SCharles.Forsyth tkt->opts[TkTwrap] = Tkwrapchar;
18437da2899SCharles.Forsyth tkt->opts[TkTrelief] = TKflat;
18537da2899SCharles.Forsyth tkt->opts[TkTjustify] = Tkleft;
18637da2899SCharles.Forsyth tkt->propagate = BoolX;
18737da2899SCharles.Forsyth
18837da2899SCharles.Forsyth tko[0].ptr = tk;
18937da2899SCharles.Forsyth tko[0].optab = tkgeneric;
19037da2899SCharles.Forsyth tko[1].ptr = tkt;
19137da2899SCharles.Forsyth tko[1].optab = textopts;
19237da2899SCharles.Forsyth tko[2].ptr = nil;
19337da2899SCharles.Forsyth
19437da2899SCharles.Forsyth tk->req.width = tk->env->wzero*Textwidth;
19537da2899SCharles.Forsyth tk->req.height = tk->env->font->height*Textheight;
19637da2899SCharles.Forsyth
19737da2899SCharles.Forsyth names = nil;
19837da2899SCharles.Forsyth e = tkparse(t, arg, tko, &names);
19937da2899SCharles.Forsyth if(e != nil)
20037da2899SCharles.Forsyth goto err;
20137da2899SCharles.Forsyth tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
20237da2899SCharles.Forsyth if(names == nil) {
20337da2899SCharles.Forsyth /* tkerr(t, arg); XXX */
20437da2899SCharles.Forsyth e = TkBadwp;
20537da2899SCharles.Forsyth goto err;
20637da2899SCharles.Forsyth }
20737da2899SCharles.Forsyth
20837da2899SCharles.Forsyth if(tkt->tagshare != nil) {
20937da2899SCharles.Forsyth tkputenv(tk->env);
21037da2899SCharles.Forsyth tk->env = tkt->tagshare->env;
21137da2899SCharles.Forsyth tk->env->ref++;
21237da2899SCharles.Forsyth }
21337da2899SCharles.Forsyth
21437da2899SCharles.Forsyth if(tk->flag&Tkdisabled)
21537da2899SCharles.Forsyth tkt->inswidth = 0;
21637da2899SCharles.Forsyth
21737da2899SCharles.Forsyth if(tkt->tabs == nil) {
21837da2899SCharles.Forsyth tkt->tabs = malloc(sizeof(TkTtabstop));
21937da2899SCharles.Forsyth if(tkt->tabs == nil)
22037da2899SCharles.Forsyth goto err;
22137da2899SCharles.Forsyth tkt->tabs->pos = 8*tk->env->wzero;
22237da2899SCharles.Forsyth tkt->tabs->justify = Tkleft;
22337da2899SCharles.Forsyth tkt->tabs->next = nil;
22437da2899SCharles.Forsyth }
22537da2899SCharles.Forsyth
22637da2899SCharles.Forsyth if(tkt->tagshare != nil) {
22737da2899SCharles.Forsyth tktshare = TKobj(TkText, tkt->tagshare);
22837da2899SCharles.Forsyth tkt->tags = tktshare->tags;
22937da2899SCharles.Forsyth tkt->nexttag = tktshare->nexttag;
23037da2899SCharles.Forsyth }
23137da2899SCharles.Forsyth else {
23237da2899SCharles.Forsyth /* Note: sel should have id == TkTselid == 0 */
23337da2899SCharles.Forsyth e = tktaddtaginfo(tk, "sel", &ti);
23437da2899SCharles.Forsyth if(e != nil)
23537da2899SCharles.Forsyth goto err;
23637da2899SCharles.Forsyth
23737da2899SCharles.Forsyth tkputenv(ti->env);
23837da2899SCharles.Forsyth ti->env = tknewenv(t);
23937da2899SCharles.Forsyth if(ti->env == nil)
24037da2899SCharles.Forsyth goto err;
24137da2899SCharles.Forsyth
24237da2899SCharles.Forsyth ev = ti->env;
24337da2899SCharles.Forsyth ev->colors[TkCbackgnd] = tk->env->colors[TkCselectbgnd];
24437da2899SCharles.Forsyth ev->colors[TkCbackgndlght] = tk->env->colors[TkCselectbgndlght];
24537da2899SCharles.Forsyth ev->colors[TkCbackgnddark] = tk->env->colors[TkCselectbgnddark];
24637da2899SCharles.Forsyth ev->colors[TkCforegnd] = tk->env->colors[TkCselectfgnd];
24737da2899SCharles.Forsyth ev->set = (1<<TkCbackgnd)|(1<<TkCbackgndlght)|
24837da2899SCharles.Forsyth (1<<TkCbackgnddark)|(1<<TkCforegnd);
24937da2899SCharles.Forsyth
25037da2899SCharles.Forsyth ti->opts[TkTborderwidth] = tkt->sborderwidth;
25137da2899SCharles.Forsyth if(tkt->sborderwidth > 0)
25237da2899SCharles.Forsyth ti->opts[TkTrelief] = TKraised;
25337da2899SCharles.Forsyth }
25437da2899SCharles.Forsyth
25537da2899SCharles.Forsyth e = tktaddmarkinfo(tkt, "current", &mi);
25637da2899SCharles.Forsyth if(e != nil)
25737da2899SCharles.Forsyth goto err;
25837da2899SCharles.Forsyth
25937da2899SCharles.Forsyth e = tktaddmarkinfo(tkt, "insert", &mi);
26037da2899SCharles.Forsyth if(e != nil)
26137da2899SCharles.Forsyth goto err;
26237da2899SCharles.Forsyth
26337da2899SCharles.Forsyth tkt->start.flags = TkTfirst|TkTlast;
26437da2899SCharles.Forsyth tkt->end.flags = TkTlast;
26537da2899SCharles.Forsyth
26637da2899SCharles.Forsyth e = tktnewitem(TkTnewline, 0, &it);
26737da2899SCharles.Forsyth
26837da2899SCharles.Forsyth if(e != nil)
26937da2899SCharles.Forsyth goto err;
27037da2899SCharles.Forsyth
27137da2899SCharles.Forsyth e = tktnewline(TkTfirst|TkTlast, it, &tkt->start, &tkt->end, &l);
27237da2899SCharles.Forsyth if(e != nil)
27337da2899SCharles.Forsyth goto err;
27437da2899SCharles.Forsyth
27537da2899SCharles.Forsyth e = tktnewitem(TkTmark, 0, &it);
27637da2899SCharles.Forsyth if(e != nil)
27737da2899SCharles.Forsyth goto err;
27837da2899SCharles.Forsyth
27937da2899SCharles.Forsyth it->next = l->items;
28037da2899SCharles.Forsyth l->items = it;
28137da2899SCharles.Forsyth it->imark = mi;
28237da2899SCharles.Forsyth mi->cur = it;
28337da2899SCharles.Forsyth tkt->nlines = 1;
28437da2899SCharles.Forsyth tkt->scrolltop[Tkvertical] = -1;
28537da2899SCharles.Forsyth tkt->scrolltop[Tkhorizontal] = -1;
28637da2899SCharles.Forsyth tkt->scrollbot[Tkvertical] = -1;
28737da2899SCharles.Forsyth tkt->scrollbot[Tkhorizontal] = -1;
28837da2899SCharles.Forsyth
28937da2899SCharles.Forsyth if(tkt->tagshare != nil)
29037da2899SCharles.Forsyth tk->binds = tkt->tagshare->binds;
29137da2899SCharles.Forsyth else {
29237da2899SCharles.Forsyth e = tkbindings(t, tk, tktbinds, nelem(tktbinds));
29337da2899SCharles.Forsyth
29437da2899SCharles.Forsyth if(e != nil)
29537da2899SCharles.Forsyth goto err;
29637da2899SCharles.Forsyth }
29737da2899SCharles.Forsyth if (tkt->propagate == BoolT) {
29837da2899SCharles.Forsyth if ((tk->flag & Tksetwidth) == 0)
29937da2899SCharles.Forsyth tk->req.width = tktmaxwid(tkt->start.next);
30037da2899SCharles.Forsyth if ((tk->flag & Tksetheight) == 0)
30137da2899SCharles.Forsyth tk->req.height = tkt->end.orig.y;
30237da2899SCharles.Forsyth }
30337da2899SCharles.Forsyth
30437da2899SCharles.Forsyth e = tkaddchild(t, tk, &names);
30537da2899SCharles.Forsyth tkfreename(names);
30637da2899SCharles.Forsyth if(e != nil)
30737da2899SCharles.Forsyth goto err;
30837da2899SCharles.Forsyth tk->name->link = nil;
30937da2899SCharles.Forsyth
31037da2899SCharles.Forsyth return tkvalue(ret, "%s", tk->name->name);
31137da2899SCharles.Forsyth
31237da2899SCharles.Forsyth err:
31337da2899SCharles.Forsyth /* XXX it's possible there's a memory leak here */
31437da2899SCharles.Forsyth tkfreeobj(tk);
31537da2899SCharles.Forsyth return e;
31637da2899SCharles.Forsyth }
31737da2899SCharles.Forsyth
31837da2899SCharles.Forsyth /*
31937da2899SCharles.Forsyth * There are four coordinate systems of interest:
32037da2899SCharles.Forsyth * S - screen coordinate system (i.e. top left corner of
32137da2899SCharles.Forsyth * inferno screen is (0,0) in S space.)
32237da2899SCharles.Forsyth * I - image coordinate system (i.e. top left corner of
32337da2899SCharles.Forsyth * tkimageof(this widget) is (0,0) in I space.)
32437da2899SCharles.Forsyth * T - text coordinate system (i.e., top left of first line
32537da2899SCharles.Forsyth * is at (0,0) in T space.)
32637da2899SCharles.Forsyth * V - view coordinate system (i.e., top left of visible
32737da2899SCharles.Forsyth * portion of widget is at (0,0) in V space.)
32837da2899SCharles.Forsyth *
32937da2899SCharles.Forsyth * A point P in the four systems (Ps, Pi, Pt, Pv) satisfies:
33037da2899SCharles.Forsyth * Pt = Ps - deltast
33137da2899SCharles.Forsyth * Pv = Ps - deltasv
33237da2899SCharles.Forsyth * Pv = Pi - deltaiv
33337da2899SCharles.Forsyth * (where deltast is vector from S origin to T origin;
33437da2899SCharles.Forsyth * deltasv is vector from S origin to V origin;
33537da2899SCharles.Forsyth * deltaiv is vector from I origin to V origin)
33637da2899SCharles.Forsyth *
33737da2899SCharles.Forsyth * We keep deltatv, deltasv, and deltaiv in tkt.
33837da2899SCharles.Forsyth * Deltatv is updated by scrolling.
33937da2899SCharles.Forsyth * Deltasv is updated by geom changes:
34037da2899SCharles.Forsyth * tkposn(tk)+ipad/2
34137da2899SCharles.Forsyth * Deltaiv is affected by geom changes and the call to the draw function:
34237da2899SCharles.Forsyth * tk->act+orig+ipad/2+(bw,bw) (orig is the parameter to tkdrawtext),
34337da2899SCharles.Forsyth *
34437da2899SCharles.Forsyth * We can derive
34537da2899SCharles.Forsyth * Ps = Pt + deltast
34637da2899SCharles.Forsyth * = Pt + deltasv - deltatv
34737da2899SCharles.Forsyth *
34837da2899SCharles.Forsyth * Pv = Pt - deltatv
34937da2899SCharles.Forsyth *
35037da2899SCharles.Forsyth * Here are various coordinates in the text widget according
35137da2899SCharles.Forsyth * to which coordinate system they use:
35237da2899SCharles.Forsyth *
35337da2899SCharles.Forsyth * S - Mouse coordinates (coming in to tktextevent);
35437da2899SCharles.Forsyth * the deltasv parameter to tkdrawtext;
35537da2899SCharles.Forsyth * coords in tkt->image, where drawing is done to
35637da2899SCharles.Forsyth * (to get same bit-alignment as screen, for fast transfer)
35737da2899SCharles.Forsyth * T - orig in TkTlines
35837da2899SCharles.Forsyth * V - %x,%y delivered via binds to TkText or its tags
35937da2899SCharles.Forsyth
36037da2899SCharles.Forsyth * Note deltasv changes underneath us, so is calculated on the fly
36137da2899SCharles.Forsyth * when it needs to be (in tktextevent).
36237da2899SCharles.Forsyth *
36337da2899SCharles.Forsyth */
36437da2899SCharles.Forsyth static void
tktsetdeltas(Tk * tk,Point orig)36537da2899SCharles.Forsyth tktsetdeltas(Tk *tk, Point orig)
36637da2899SCharles.Forsyth {
36737da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
36837da2899SCharles.Forsyth
36937da2899SCharles.Forsyth tkt->deltaiv.x = orig.x + tk->act.x + tk->ipad.x/2 + tk->borderwidth;
37037da2899SCharles.Forsyth tkt->deltaiv.y = orig.y + tk->act.y + tk->ipad.y/2 + tk->borderwidth;
37137da2899SCharles.Forsyth }
37237da2899SCharles.Forsyth
37337da2899SCharles.Forsyth static Point
tktrelpos(Tk * sub)37437da2899SCharles.Forsyth tktrelpos(Tk *sub)
37537da2899SCharles.Forsyth {
37637da2899SCharles.Forsyth Tk *tk;
37737da2899SCharles.Forsyth TkTindex ix;
37837da2899SCharles.Forsyth Rectangle r;
37937da2899SCharles.Forsyth Point ans;
38037da2899SCharles.Forsyth
38137da2899SCharles.Forsyth tk = sub->parent;
38237da2899SCharles.Forsyth if(tk == nil)
38337da2899SCharles.Forsyth return ZP;
38437da2899SCharles.Forsyth
38537da2899SCharles.Forsyth if(tktfindsubitem(sub, &ix)) {
38637da2899SCharles.Forsyth r = tktbbox(tk, &ix);
38737da2899SCharles.Forsyth ans.x = r.min.x;
38837da2899SCharles.Forsyth ans.y = r.min.y;
38937da2899SCharles.Forsyth return r.min;
39037da2899SCharles.Forsyth }
39137da2899SCharles.Forsyth return ZP;
39237da2899SCharles.Forsyth }
39337da2899SCharles.Forsyth
39437da2899SCharles.Forsyth static void
tktreplclipr(Image * dst,Rectangle r)39537da2899SCharles.Forsyth tktreplclipr(Image *dst, Rectangle r)
39637da2899SCharles.Forsyth {
39737da2899SCharles.Forsyth int locked;
39837da2899SCharles.Forsyth
39937da2899SCharles.Forsyth locked = lockdisplay(dst->display);
40037da2899SCharles.Forsyth replclipr(dst, 0, r);
40137da2899SCharles.Forsyth if(locked)
40237da2899SCharles.Forsyth unlockdisplay(dst->display);
40337da2899SCharles.Forsyth }
40437da2899SCharles.Forsyth
40537da2899SCharles.Forsyth char*
tkdrawtext(Tk * tk,Point orig)40637da2899SCharles.Forsyth tkdrawtext(Tk *tk, Point orig)
40737da2899SCharles.Forsyth {
40837da2899SCharles.Forsyth int vh;
40937da2899SCharles.Forsyth Image *dst;
41037da2899SCharles.Forsyth TkText *tkt;
41137da2899SCharles.Forsyth TkTline *l, *lend;
41237da2899SCharles.Forsyth Point p, deltait;
41337da2899SCharles.Forsyth Rectangle oclipr;
41437da2899SCharles.Forsyth int reldone = 1;
41537da2899SCharles.Forsyth char *e;
41637da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
41737da2899SCharles.Forsyth dst = tkimageof(tk);
41837da2899SCharles.Forsyth if (dst == nil)
41937da2899SCharles.Forsyth return nil;
42037da2899SCharles.Forsyth tkt->image = dst;
42137da2899SCharles.Forsyth tktsetdeltas(tk, orig);
42237da2899SCharles.Forsyth tkt->tflag |= TkTdrawn|TkTdlocked;
42337da2899SCharles.Forsyth oclipr = dst->clipr;
42437da2899SCharles.Forsyth tktsetclip(tk);
42537da2899SCharles.Forsyth
42637da2899SCharles.Forsyth if(tk->flag&Tkrefresh) {
42737da2899SCharles.Forsyth reldone = 0;
42837da2899SCharles.Forsyth tktnotdrawn(tk, 0, tkt->end.orig.y, 1);
42937da2899SCharles.Forsyth }
43037da2899SCharles.Forsyth tk->flag &= ~Tkrefresh;
43137da2899SCharles.Forsyth
43237da2899SCharles.Forsyth deltait = subpt(tkt->deltaiv, tkt->deltatv);
43337da2899SCharles.Forsyth vh = tk->act.height - tk->ipad.y/2;
43437da2899SCharles.Forsyth lend = &tkt->end;
43537da2899SCharles.Forsyth for(l = tkt->start.next; l != lend; l = l->next) {
43637da2899SCharles.Forsyth if(l->orig.y+l->height < tkt->deltatv.y)
43737da2899SCharles.Forsyth continue;
43837da2899SCharles.Forsyth if(l->orig.y > tkt->deltatv.y + vh)
43937da2899SCharles.Forsyth break;
44037da2899SCharles.Forsyth if(!(l->flags&TkTdrawn)) {
44137da2899SCharles.Forsyth e = tktdrawline(dst, tk, l, deltait);
44237da2899SCharles.Forsyth if(e != nil)
44337da2899SCharles.Forsyth return e;
44437da2899SCharles.Forsyth }
44537da2899SCharles.Forsyth }
44637da2899SCharles.Forsyth
44737da2899SCharles.Forsyth tktreplclipr(dst, oclipr);
44837da2899SCharles.Forsyth if(!reldone) {
44937da2899SCharles.Forsyth p.x = orig.x + tk->act.x;
45037da2899SCharles.Forsyth p.y = orig.y + tk->act.y;
45137da2899SCharles.Forsyth tkdrawrelief(dst, tk, p, TkCbackgnd, tk->relief);
45237da2899SCharles.Forsyth }
45337da2899SCharles.Forsyth tkt->tflag &= ~TkTdlocked;
45437da2899SCharles.Forsyth
45537da2899SCharles.Forsyth return nil;
45637da2899SCharles.Forsyth }
45737da2899SCharles.Forsyth
45837da2899SCharles.Forsyth /*
45937da2899SCharles.Forsyth * Set the clipping rectangle of the destination image to the
46037da2899SCharles.Forsyth * intersection of the current clipping rectangle and the area inside
46137da2899SCharles.Forsyth * the text widget that needs to be redrawn.
46237da2899SCharles.Forsyth * The caller should save the old one and restore it later.
46337da2899SCharles.Forsyth */
46437da2899SCharles.Forsyth static void
tktsetclip(Tk * tk)46537da2899SCharles.Forsyth tktsetclip(Tk *tk)
46637da2899SCharles.Forsyth {
46737da2899SCharles.Forsyth Rectangle r;
46837da2899SCharles.Forsyth Image *dst;
46937da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
47037da2899SCharles.Forsyth
47137da2899SCharles.Forsyth dst = tkt->image;
47237da2899SCharles.Forsyth r.min = tkt->deltaiv;
47337da2899SCharles.Forsyth r.max.x = r.min.x + tk->act.width - tk->ipad.x / 2;
47437da2899SCharles.Forsyth r.max.y = r.min.y + tk->act.height - tk->ipad.y / 2;
47537da2899SCharles.Forsyth
47637da2899SCharles.Forsyth if(!rectclip(&r, dst->clipr))
47737da2899SCharles.Forsyth r.max = r.min;
47837da2899SCharles.Forsyth tktreplclipr(dst, r);
47937da2899SCharles.Forsyth }
48037da2899SCharles.Forsyth
48137da2899SCharles.Forsyth static char*
tktdrawline(Image * i,Tk * tk,TkTline * l,Point deltait)48237da2899SCharles.Forsyth tktdrawline(Image *i, Tk *tk, TkTline *l, Point deltait)
48337da2899SCharles.Forsyth {
48437da2899SCharles.Forsyth Tk *sub;
48537da2899SCharles.Forsyth Font *f;
48637da2899SCharles.Forsyth Image *bg;
48737da2899SCharles.Forsyth Point p, q;
48837da2899SCharles.Forsyth Rectangle r;
48937da2899SCharles.Forsyth TkText *tkt;
49037da2899SCharles.Forsyth TkTitem *it, *z;
49137da2899SCharles.Forsyth int bevtop, bevbot;
49237da2899SCharles.Forsyth TkEnv *e, *et, *env;
49337da2899SCharles.Forsyth int *opts;
49437da2899SCharles.Forsyth int o, bd, ul, ov, h, w, la, lh, cursorx, join;
49537da2899SCharles.Forsyth char *err;
49637da2899SCharles.Forsyth
49737da2899SCharles.Forsyth env = mallocz(sizeof(TkEnv), 0);
49837da2899SCharles.Forsyth if(env == nil)
49937da2899SCharles.Forsyth return TkNomem;
50037da2899SCharles.Forsyth opts = mallocz(TkTnumopts*sizeof(int), 0);
50137da2899SCharles.Forsyth if(opts == nil) {
50237da2899SCharles.Forsyth free(env);
50337da2899SCharles.Forsyth return TkNomem;
50437da2899SCharles.Forsyth }
50537da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
50637da2899SCharles.Forsyth e = tk->env;
50737da2899SCharles.Forsyth et = env;
50837da2899SCharles.Forsyth et->top = e->top;
50937da2899SCharles.Forsyth f = e->font;
51037da2899SCharles.Forsyth
51137da2899SCharles.Forsyth /* l->orig is in T space, p is in I space */
51237da2899SCharles.Forsyth la = l->ascent;
51337da2899SCharles.Forsyth lh = l->height;
51437da2899SCharles.Forsyth p = addpt(l->orig, deltait);
51537da2899SCharles.Forsyth p.y += la;
51637da2899SCharles.Forsyth /* if(tktdbg){print("drawline, p=(%d,%d), f->a=%d, f->h=%d\n", p.x, p.y, f->ascent, f->height); tktprintline(l);} */
51737da2899SCharles.Forsyth cursorx = -1000;
51837da2899SCharles.Forsyth join = 0;
51937da2899SCharles.Forsyth for(it = l->items; it != nil; it = it->next) {
52037da2899SCharles.Forsyth bg = tkgc(e, TkCbackgnd);
52137da2899SCharles.Forsyth if(tktanytags(it)) {
52237da2899SCharles.Forsyth tkttagopts(tk, it, opts, env, nil, 1);
52337da2899SCharles.Forsyth if(e->colors[TkCbackgnd] != et->colors[TkCbackgnd]) {
52437da2899SCharles.Forsyth bg = tkgc(et, TkCbackgnd);
52537da2899SCharles.Forsyth r.min = p;
52637da2899SCharles.Forsyth r.min.y -= la;
52737da2899SCharles.Forsyth r.max.x = r.min.x + it->width;
52837da2899SCharles.Forsyth r.max.y = r.min.y + lh;
52937da2899SCharles.Forsyth draw(i, r, bg, nil, ZP);
53037da2899SCharles.Forsyth }
53137da2899SCharles.Forsyth o = opts[TkTrelief];
53237da2899SCharles.Forsyth bd = opts[TkTborderwidth];
53337da2899SCharles.Forsyth if((o == TKsunken || o == TKraised) && bd > 0) {
53437da2899SCharles.Forsyth /* fit relief inside item bounding box */
53537da2899SCharles.Forsyth
53637da2899SCharles.Forsyth q.x = p.x;
53737da2899SCharles.Forsyth q.y = p.y - la;
53837da2899SCharles.Forsyth if(it->width < 2*bd)
53937da2899SCharles.Forsyth bd = it->width / 2;
54037da2899SCharles.Forsyth if(lh < 2*bd)
54137da2899SCharles.Forsyth bd = lh / 2;
54237da2899SCharles.Forsyth w = it->width - 2*bd;
54337da2899SCharles.Forsyth h = lh - 2*bd;
54437da2899SCharles.Forsyth if(o == TKraised) {
54537da2899SCharles.Forsyth bevtop = TkLightshade;
54637da2899SCharles.Forsyth bevbot = TkDarkshade;
54737da2899SCharles.Forsyth }
54837da2899SCharles.Forsyth else {
54937da2899SCharles.Forsyth bevtop = TkDarkshade;
55037da2899SCharles.Forsyth bevbot = TkLightshade;
55137da2899SCharles.Forsyth }
55237da2899SCharles.Forsyth
55337da2899SCharles.Forsyth tkbevel(i, q, w, h, bd,
55437da2899SCharles.Forsyth tkgc(et, TkCbackgnd+bevtop), tkgc(et, TkCbackgnd+bevbot));
55537da2899SCharles.Forsyth
55637da2899SCharles.Forsyth /* join relief between adjacent items if tags match */
55737da2899SCharles.Forsyth if(join) {
55837da2899SCharles.Forsyth r.min.x = q.x;
55937da2899SCharles.Forsyth r.max.x = q.x + bd;
56037da2899SCharles.Forsyth r.min.y = q.y + bd;
56137da2899SCharles.Forsyth r.max.y = r.min.y + h;
56237da2899SCharles.Forsyth draw(i, r, bg, nil, ZP);
56337da2899SCharles.Forsyth r.min.y = r.max.y;
56437da2899SCharles.Forsyth r.max.y = r.min.y + bd;
56537da2899SCharles.Forsyth draw(i, r, tkgc(et, TkCbackgnd+bevbot), nil, ZP);
56637da2899SCharles.Forsyth }
56737da2899SCharles.Forsyth for(z = it->next; z != nil && z->kind == TkTmark; )
56837da2899SCharles.Forsyth z = z->next;
56937da2899SCharles.Forsyth if(z != nil && tktsametags(z, it)) {
57037da2899SCharles.Forsyth r.min.x = q.x + bd + w;
57137da2899SCharles.Forsyth r.max.x = r.min.x + bd;
57237da2899SCharles.Forsyth r.min.y = q.y;
57337da2899SCharles.Forsyth r.max.y = q.y + bd;
57437da2899SCharles.Forsyth draw(i, r, tkgc(et, TkCbackgnd+bevtop), nil, ZP);
57537da2899SCharles.Forsyth r.min.y = r.max.y;
57637da2899SCharles.Forsyth r.max.y = r.min.y + h;
57737da2899SCharles.Forsyth draw(i, r, bg, nil, ZP);
57837da2899SCharles.Forsyth join = 1;
57937da2899SCharles.Forsyth }
58037da2899SCharles.Forsyth else
58137da2899SCharles.Forsyth join = 0;
58237da2899SCharles.Forsyth }
58337da2899SCharles.Forsyth o = opts[TkToffset];
58437da2899SCharles.Forsyth ul = opts[TkTunderline];
58537da2899SCharles.Forsyth ov = opts[TkToverstrike];
58637da2899SCharles.Forsyth }
58737da2899SCharles.Forsyth else {
58837da2899SCharles.Forsyth et->font = f;
58937da2899SCharles.Forsyth et->colors[TkCforegnd] = e->colors[TkCforegnd];
59037da2899SCharles.Forsyth o = 0;
59137da2899SCharles.Forsyth ul = 0;
59237da2899SCharles.Forsyth ov = 0;
59337da2899SCharles.Forsyth }
59437da2899SCharles.Forsyth
59537da2899SCharles.Forsyth switch(it->kind) {
59637da2899SCharles.Forsyth case TkTascii:
59737da2899SCharles.Forsyth case TkTrune:
59837da2899SCharles.Forsyth q.x = p.x;
59937da2899SCharles.Forsyth q.y = p.y - env->font->ascent - o;
60037da2899SCharles.Forsyth /*if(tktdbg)print("q=(%d,%d)\n", q.x, q.y);*/
60137da2899SCharles.Forsyth string(i, q, tkgc(et, TkCforegnd), q, env->font, it->istring);
60237da2899SCharles.Forsyth if(ov == BoolT) {
60337da2899SCharles.Forsyth r.min.x = q.x;
60437da2899SCharles.Forsyth r.max.x = r.min.x + it->width;
60537da2899SCharles.Forsyth r.min.y = q.y + 2*env->font->ascent/3;
60637da2899SCharles.Forsyth r.max.y = r.min.y + 2;
60737da2899SCharles.Forsyth draw(i, r, tkgc(et, TkCforegnd), nil, ZP);
60837da2899SCharles.Forsyth }
60937da2899SCharles.Forsyth if(ul == BoolT) {
61037da2899SCharles.Forsyth r.min.x = q.x;
61137da2899SCharles.Forsyth r.max.x = r.min.x + it->width;
61237da2899SCharles.Forsyth r.max.y = p.y - la + lh;
61337da2899SCharles.Forsyth r.min.y = r.max.y - 2;
61437da2899SCharles.Forsyth draw(i, r, tkgc(et, TkCforegnd), nil, ZP);
61537da2899SCharles.Forsyth }
61637da2899SCharles.Forsyth break;
61737da2899SCharles.Forsyth case TkTmark:
61837da2899SCharles.Forsyth if((it->imark != nil)
61937da2899SCharles.Forsyth && strcmp(it->imark->name, "insert") == 0) {
62037da2899SCharles.Forsyth cursorx = p.x - 1;
62137da2899SCharles.Forsyth }
62237da2899SCharles.Forsyth break;
62337da2899SCharles.Forsyth case TkTwin:
62437da2899SCharles.Forsyth sub = it->iwin->sub;
62537da2899SCharles.Forsyth if(sub != nil) {
62637da2899SCharles.Forsyth int dirty;
62737da2899SCharles.Forsyth sub->flag |= Tkrefresh;
62837da2899SCharles.Forsyth sub->dirty = tkrect(sub, 1);
62937da2899SCharles.Forsyth err = tkdrawslaves(sub, p, &dirty);
63037da2899SCharles.Forsyth if(err != nil) {
63137da2899SCharles.Forsyth free(opts);
63237da2899SCharles.Forsyth free(env);
63337da2899SCharles.Forsyth return err;
63437da2899SCharles.Forsyth }
63537da2899SCharles.Forsyth }
63637da2899SCharles.Forsyth break;
63737da2899SCharles.Forsyth }
63837da2899SCharles.Forsyth p.x += it->width;
63937da2899SCharles.Forsyth }
64037da2899SCharles.Forsyth l->flags |= TkTdrawn;
64137da2899SCharles.Forsyth
64237da2899SCharles.Forsyth /* do cursor last, so not overwritten by later items */
64337da2899SCharles.Forsyth if(cursorx != -1000 && tkt->inswidth > 0) {
64437da2899SCharles.Forsyth r.min.x = cursorx;
64537da2899SCharles.Forsyth r.min.y = p.y - la;
64637da2899SCharles.Forsyth r.max.x = r.min.x + tkt->inswidth;
64737da2899SCharles.Forsyth r.max.y = r.min.y + lh;
64837da2899SCharles.Forsyth r = rectsubpt(r, deltait);
64937da2899SCharles.Forsyth if (!eqrect(tkt->cur_rec, r))
65037da2899SCharles.Forsyth blinkreset(tk);
65137da2899SCharles.Forsyth tkt->cur_rec = r;
65237da2899SCharles.Forsyth if(tkt->cur_flag)
65337da2899SCharles.Forsyth tktextcursordraw(tk, TkCforegnd);
65437da2899SCharles.Forsyth }
65537da2899SCharles.Forsyth
65637da2899SCharles.Forsyth free(opts);
65737da2899SCharles.Forsyth free(env);
65837da2899SCharles.Forsyth return nil;
65937da2899SCharles.Forsyth }
66037da2899SCharles.Forsyth
66137da2899SCharles.Forsyth static void
tktextcursordraw(Tk * tk,int color)66237da2899SCharles.Forsyth tktextcursordraw(Tk *tk, int color)
66337da2899SCharles.Forsyth {
66437da2899SCharles.Forsyth Rectangle r;
66537da2899SCharles.Forsyth TkText *tkt;
66637da2899SCharles.Forsyth Image *i;
66737da2899SCharles.Forsyth
66837da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
66937da2899SCharles.Forsyth
67037da2899SCharles.Forsyth r = rectaddpt(tkt->cur_rec, subpt(tkt->deltaiv, tkt->deltatv));
67137da2899SCharles.Forsyth
67237da2899SCharles.Forsyth /* check the cursor with widget boundary */
67337da2899SCharles.Forsyth /* do nothing if entire cursor outside widget boundary */
67437da2899SCharles.Forsyth if( ! ( r.max.x < tkt->deltaiv.x ||
67537da2899SCharles.Forsyth r.min.x > tkt->deltaiv.x + tk->act.width ||
67637da2899SCharles.Forsyth r.max.y < tkt->deltaiv.y ||
67737da2899SCharles.Forsyth r.min.y > tkt->deltaiv.y + tk->act.height)) {
67837da2899SCharles.Forsyth
67937da2899SCharles.Forsyth /* clip rectangle if extends beyond widget boundary */
68037da2899SCharles.Forsyth if (r.min.x < tkt->deltaiv.x)
68137da2899SCharles.Forsyth r.min.x = tkt->deltaiv.x;
68237da2899SCharles.Forsyth if (r.max.x > tkt->deltaiv.x + tk->act.width)
68337da2899SCharles.Forsyth r.max.x = tkt->deltaiv.x + tk->act.width;
68437da2899SCharles.Forsyth if (r.min.y < tkt->deltaiv.y)
68537da2899SCharles.Forsyth r.min.y = tkt->deltaiv.y;
68637da2899SCharles.Forsyth if (r.max.y > tkt->deltaiv.y + tk->act.height)
68737da2899SCharles.Forsyth r.max.y = tkt->deltaiv.y + tk->act.height;
68837da2899SCharles.Forsyth i = tkimageof(tk);
68937da2899SCharles.Forsyth if (i != nil)
69037da2899SCharles.Forsyth draw(i, r, tkgc(tk->env, color), nil, ZP);
69137da2899SCharles.Forsyth }
69237da2899SCharles.Forsyth }
69337da2899SCharles.Forsyth
69437da2899SCharles.Forsyth static void
blinkreset(Tk * tk)69537da2899SCharles.Forsyth blinkreset(Tk *tk)
69637da2899SCharles.Forsyth {
69737da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
69837da2899SCharles.Forsyth if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
69937da2899SCharles.Forsyth return;
70037da2899SCharles.Forsyth tkt->cur_flag = 1;
70137da2899SCharles.Forsyth tkblinkreset(tk);
70237da2899SCharles.Forsyth }
70337da2899SCharles.Forsyth
70437da2899SCharles.Forsyth static void
showcaret(Tk * tk,int on)70537da2899SCharles.Forsyth showcaret(Tk *tk, int on)
70637da2899SCharles.Forsyth {
70737da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
70837da2899SCharles.Forsyth TkTline *l, *lend;
70937da2899SCharles.Forsyth TkTitem *it;
71037da2899SCharles.Forsyth
71137da2899SCharles.Forsyth tkt->cur_flag = on;
71237da2899SCharles.Forsyth lend = &tkt->end;
71337da2899SCharles.Forsyth for(l = tkt->start.next; l != lend; l = l->next) {
71437da2899SCharles.Forsyth for (it = l->items; it != nil; it = it->next) {
71537da2899SCharles.Forsyth if (it->kind == TkTmark && it->imark != nil &&
71637da2899SCharles.Forsyth strcmp(it->imark->name, "insert") == 0) {
71737da2899SCharles.Forsyth if (on) {
71837da2899SCharles.Forsyth tktextcursordraw(tk, TkCforegnd);
71937da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
72037da2899SCharles.Forsyth } else
72137da2899SCharles.Forsyth tktnotdrawn(tk, l->orig.y, l->orig.y+l->height, 0);
72237da2899SCharles.Forsyth tkdirty(tk);
72337da2899SCharles.Forsyth return;
72437da2899SCharles.Forsyth }
72537da2899SCharles.Forsyth }
72637da2899SCharles.Forsyth }
72737da2899SCharles.Forsyth }
72837da2899SCharles.Forsyth
72937da2899SCharles.Forsyth char*
tktextcursor(Tk * tk,char * arg,char ** ret)73037da2899SCharles.Forsyth tktextcursor(Tk *tk, char* arg, char **ret)
73137da2899SCharles.Forsyth {
73237da2899SCharles.Forsyth int on = 0;
73337da2899SCharles.Forsyth USED(ret);
73437da2899SCharles.Forsyth
73537da2899SCharles.Forsyth if (tk->flag&Tkdisabled)
73637da2899SCharles.Forsyth return nil;
73737da2899SCharles.Forsyth
73837da2899SCharles.Forsyth if(strcmp(arg, " insert") == 0) {
73937da2899SCharles.Forsyth tkblink(tk, showcaret);
74037da2899SCharles.Forsyth on = 1;
74137da2899SCharles.Forsyth }
74237da2899SCharles.Forsyth else
74337da2899SCharles.Forsyth tkblink(nil, nil);
74437da2899SCharles.Forsyth
74537da2899SCharles.Forsyth showcaret(tk, on);
74637da2899SCharles.Forsyth return nil;
74737da2899SCharles.Forsyth }
74837da2899SCharles.Forsyth
74937da2899SCharles.Forsyth /*
75037da2899SCharles.Forsyth * Insert string s just before ins, but don't worry about geometry values.
75137da2899SCharles.Forsyth * Don't worry about doing wrapping correctly, but break long strings
75237da2899SCharles.Forsyth * into pieces to avoid bad behavior in the wrapping code of tktfixgeom.
75337da2899SCharles.Forsyth * If tagit != 0, use its tags, else use the intersection of tags of
75437da2899SCharles.Forsyth * non cont or mark elements just before and just after insertion point.
75537da2899SCharles.Forsyth * (At beginning and end of widget, just use the tags of one adjacent item).
75637da2899SCharles.Forsyth * Keep *ins up-to-date.
75737da2899SCharles.Forsyth */
75837da2899SCharles.Forsyth char*
tktinsert(Tk * tk,TkTindex * ins,char * s,TkTitem * tagit)75937da2899SCharles.Forsyth tktinsert(Tk *tk, TkTindex *ins, char *s, TkTitem *tagit)
76037da2899SCharles.Forsyth {
76137da2899SCharles.Forsyth int c, n, nextra, nmax, atend, atbeg;
76237da2899SCharles.Forsyth char *e, *p;
76337da2899SCharles.Forsyth Rune r;
76437da2899SCharles.Forsyth TkTindex iprev, inext;
76537da2899SCharles.Forsyth TkTitem *i, *utagit;
76637da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
76737da2899SCharles.Forsyth
76837da2899SCharles.Forsyth e = tktsplititem(ins);
76937da2899SCharles.Forsyth if(e != nil)
77037da2899SCharles.Forsyth return e;
77137da2899SCharles.Forsyth
77237da2899SCharles.Forsyth /* if no tags give, use intersection of previous and next char tags */
77337da2899SCharles.Forsyth
77437da2899SCharles.Forsyth nextra = 0;
77537da2899SCharles.Forsyth n = tk->env->wzero;
77637da2899SCharles.Forsyth if(n <= 0)
77737da2899SCharles.Forsyth n = 8;
77837da2899SCharles.Forsyth nmax = tk->act.width - tk->ipad.x;
77937da2899SCharles.Forsyth if(nmax <= 0) {
78037da2899SCharles.Forsyth if (tkt->propagate != BoolT || (tk->flag & Tksetwidth))
78137da2899SCharles.Forsyth nmax = tk->req.width;
78237da2899SCharles.Forsyth if(nmax <= 0)
78337da2899SCharles.Forsyth nmax = 60*n;
78437da2899SCharles.Forsyth }
78537da2899SCharles.Forsyth nmax = (nmax + n - 1) / n;
78637da2899SCharles.Forsyth utagit = nil;
78737da2899SCharles.Forsyth if(tagit == nil) {
78837da2899SCharles.Forsyth inext = *ins;
78937da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, &inext);
79037da2899SCharles.Forsyth atend = (inext.item->next == nil && inext.line->next == &tkt->end);
79137da2899SCharles.Forsyth if(atend || tktanytags(inext.item)) {
79237da2899SCharles.Forsyth iprev = *ins;
79337da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharback, &iprev);
79437da2899SCharles.Forsyth atbeg = (iprev.line->prev == &tkt->start && iprev.line->items == iprev.item);
79537da2899SCharles.Forsyth if(atbeg || tktanytags(iprev.item)) {
79637da2899SCharles.Forsyth nextra = 0;
79737da2899SCharles.Forsyth if(!atend)
79837da2899SCharles.Forsyth nextra = inext.item->tagextra;
79937da2899SCharles.Forsyth if(!atbeg && iprev.item->tagextra > nextra)
80037da2899SCharles.Forsyth nextra = iprev.item->tagextra;
80137da2899SCharles.Forsyth e = tktnewitem(TkTascii, nextra, &utagit);
80237da2899SCharles.Forsyth if(e != nil)
80337da2899SCharles.Forsyth return e;
80437da2899SCharles.Forsyth if(!atend) {
80537da2899SCharles.Forsyth tkttagcomb(utagit, inext.item, 1);
80637da2899SCharles.Forsyth if(!atbeg)
80737da2899SCharles.Forsyth tkttagcomb(utagit, iprev.item, 0);
80837da2899SCharles.Forsyth }
80937da2899SCharles.Forsyth else if(!atbeg)
81037da2899SCharles.Forsyth tkttagcomb(utagit, iprev.item, 1);
81137da2899SCharles.Forsyth tagit = utagit;
81237da2899SCharles.Forsyth }
81337da2899SCharles.Forsyth }
81437da2899SCharles.Forsyth }
81537da2899SCharles.Forsyth else
81637da2899SCharles.Forsyth nextra = tagit->tagextra;
81737da2899SCharles.Forsyth
81837da2899SCharles.Forsyth while((c = *s) != '\0') {
81937da2899SCharles.Forsyth e = tktnewitem(TkTascii, nextra, &i);
82037da2899SCharles.Forsyth if(e != nil) {
82137da2899SCharles.Forsyth if(utagit != nil)
82237da2899SCharles.Forsyth free(utagit);
82337da2899SCharles.Forsyth return e;
82437da2899SCharles.Forsyth }
82537da2899SCharles.Forsyth
82637da2899SCharles.Forsyth if(tagit != nil)
82737da2899SCharles.Forsyth tkttagcomb(i, tagit, 1);
82837da2899SCharles.Forsyth
82937da2899SCharles.Forsyth if(c == '\n') {
83037da2899SCharles.Forsyth i->kind = TkTnewline;
83137da2899SCharles.Forsyth tkt->nlines++;
83237da2899SCharles.Forsyth s++;
83337da2899SCharles.Forsyth }
83437da2899SCharles.Forsyth else
83537da2899SCharles.Forsyth if(c == '\t') {
83637da2899SCharles.Forsyth i->kind = TkTtab;
83737da2899SCharles.Forsyth s++;
83837da2899SCharles.Forsyth }
83937da2899SCharles.Forsyth else {
84037da2899SCharles.Forsyth p = s;
84137da2899SCharles.Forsyth n = 0;
84237da2899SCharles.Forsyth i->kind = TkTascii;
84337da2899SCharles.Forsyth while(c != '\0' && c != '\n' && c != '\t' && n < nmax){
84437da2899SCharles.Forsyth s += chartorune(&r, s);
84537da2899SCharles.Forsyth c = *s;
84637da2899SCharles.Forsyth n++;
84737da2899SCharles.Forsyth }
84837da2899SCharles.Forsyth /*
84937da2899SCharles.Forsyth * if more bytes than runes, then it's not all ascii, so create a TkTrune item
85037da2899SCharles.Forsyth */
85137da2899SCharles.Forsyth if(s - p > n)
85237da2899SCharles.Forsyth i->kind = TkTrune;
85337da2899SCharles.Forsyth n = s - p;
85437da2899SCharles.Forsyth i->istring = malloc(n+1);
85537da2899SCharles.Forsyth if(i->istring == nil) {
85637da2899SCharles.Forsyth tktfreeitems(tkt, i, 1);
85737da2899SCharles.Forsyth if(utagit != nil)
85837da2899SCharles.Forsyth free(utagit);
85937da2899SCharles.Forsyth return TkNomem;
86037da2899SCharles.Forsyth }
86137da2899SCharles.Forsyth memmove(i->istring, p, n);
86237da2899SCharles.Forsyth i->istring[n] = '\0';
86337da2899SCharles.Forsyth }
86437da2899SCharles.Forsyth e = tktiteminsert(tkt, ins, i);
86537da2899SCharles.Forsyth if(e != nil) {
86637da2899SCharles.Forsyth if(utagit != nil)
86737da2899SCharles.Forsyth free(utagit);
86837da2899SCharles.Forsyth tktfreeitems(tkt, i, 1);
86937da2899SCharles.Forsyth return e;
87037da2899SCharles.Forsyth }
87137da2899SCharles.Forsyth }
87237da2899SCharles.Forsyth
87337da2899SCharles.Forsyth if(utagit != nil)
87437da2899SCharles.Forsyth free(utagit);
87537da2899SCharles.Forsyth return nil;
87637da2899SCharles.Forsyth }
87737da2899SCharles.Forsyth
87837da2899SCharles.Forsyth void
tktextsize(Tk * tk,int dogeom)87937da2899SCharles.Forsyth tktextsize(Tk *tk, int dogeom)
88037da2899SCharles.Forsyth {
88137da2899SCharles.Forsyth TkText *tkt;
88237da2899SCharles.Forsyth TkGeom g;
88337da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
88437da2899SCharles.Forsyth if (tkt->propagate == BoolT) {
88537da2899SCharles.Forsyth g = tk->req;
88637da2899SCharles.Forsyth if ((tk->flag & Tksetwidth) == 0)
88737da2899SCharles.Forsyth tk->req.width = tktmaxwid(tkt->start.next);
88837da2899SCharles.Forsyth if ((tk->flag & Tksetheight) == 0)
88937da2899SCharles.Forsyth tk->req.height = tkt->end.orig.y;
89037da2899SCharles.Forsyth if (dogeom)
89137da2899SCharles.Forsyth tkgeomchg(tk, &g, tk->borderwidth);
89237da2899SCharles.Forsyth }
89337da2899SCharles.Forsyth }
89437da2899SCharles.Forsyth
89537da2899SCharles.Forsyth static int
maximum(int a,int b)89637da2899SCharles.Forsyth maximum(int a, int b)
89737da2899SCharles.Forsyth {
89837da2899SCharles.Forsyth if (a > b)
89937da2899SCharles.Forsyth return a;
90037da2899SCharles.Forsyth return b;
90137da2899SCharles.Forsyth }
90237da2899SCharles.Forsyth
90337da2899SCharles.Forsyth /*
90437da2899SCharles.Forsyth * For lines l1->next, ..., l2, fix up the geometry
90537da2899SCharles.Forsyth * elements of constituent TkTlines and TkTitems.
90637da2899SCharles.Forsyth * This involves doing proper line wrapping, and calculating item
90737da2899SCharles.Forsyth * widths and positions.
90837da2899SCharles.Forsyth * Also, merge any adjacent TkTascii/TkTrune items with the same tags.
90937da2899SCharles.Forsyth * Finally, bump the y component of lines l2->next, ... end.
91037da2899SCharles.Forsyth * l2 should not be tkt->end.
91137da2899SCharles.Forsyth *
91237da2899SCharles.Forsyth * if finalwidth is 0, we're trying to work out what the
91337da2899SCharles.Forsyth * width and height should be. if propagation is off,
91437da2899SCharles.Forsyth * it's irrelevant; otherwise it must assume that
91537da2899SCharles.Forsyth * its desired width will be fulfilled, as the packer
91637da2899SCharles.Forsyth * doesn't iterate...
91737da2899SCharles.Forsyth *
91837da2899SCharles.Forsyth * N.B. this function rearranges lines, merges and splits items.
91937da2899SCharles.Forsyth * this means that in general the item and line pointed to
92037da2899SCharles.Forsyth * by any index might have been freed after tktfixgeom
92137da2899SCharles.Forsyth * has been called.
92237da2899SCharles.Forsyth */
92337da2899SCharles.Forsyth char*
tktfixgeom(Tk * tk,TkTline * l1,TkTline * l2,int finalwidth)92437da2899SCharles.Forsyth tktfixgeom(Tk *tk, TkTline *l1, TkTline *l2, int finalwidth)
92537da2899SCharles.Forsyth {
92637da2899SCharles.Forsyth int x, y, a, wa, h, w, o, n, j, sp3, xleft, xright, winw, oa, oh, lh;
92737da2899SCharles.Forsyth int wrapmode, just, needsplit;
92837da2899SCharles.Forsyth char *e, *s;
92937da2899SCharles.Forsyth TkText *tkt;
93037da2899SCharles.Forsyth Tk *sub;
93137da2899SCharles.Forsyth TkTitem *i, *it, *ilast, *iprev;
93237da2899SCharles.Forsyth TkTindex ix, ixprev, ixw;
93337da2899SCharles.Forsyth TkTline *l, *lafter;
93437da2899SCharles.Forsyth Interval oldi, hole, rest, newrest;
93537da2899SCharles.Forsyth TkEnv *env;
93637da2899SCharles.Forsyth Font *f;
93737da2899SCharles.Forsyth int *opts;
93837da2899SCharles.Forsyth TkTtabstop *tb;
93937da2899SCharles.Forsyth
94037da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
94137da2899SCharles.Forsyth
94237da2899SCharles.Forsyth if(tktdbg)
94337da2899SCharles.Forsyth tktcheck(tkt, "tktfixgeom");
94437da2899SCharles.Forsyth
94537da2899SCharles.Forsyth if (!finalwidth && tkt->propagate == BoolT) {
94637da2899SCharles.Forsyth if ((tk->flag & Tksetwidth) == 0)
94737da2899SCharles.Forsyth winw = 1000000;
94837da2899SCharles.Forsyth else
94937da2899SCharles.Forsyth winw = tk->req.width;
95037da2899SCharles.Forsyth } else {
95137da2899SCharles.Forsyth winw = tk->act.width - tk->ipad.x;
95237da2899SCharles.Forsyth if(winw <= 0)
95337da2899SCharles.Forsyth winw = tk->req.width;
95437da2899SCharles.Forsyth }
95537da2899SCharles.Forsyth if(winw < 0)
95637da2899SCharles.Forsyth return nil;
95737da2899SCharles.Forsyth
95837da2899SCharles.Forsyth /*
95937da2899SCharles.Forsyth * Make lafter be the first line after l2 that comes after a newline
96037da2899SCharles.Forsyth * (so that wrap correction cannot affect it)
96137da2899SCharles.Forsyth */
96237da2899SCharles.Forsyth lafter = l2->next;
96337da2899SCharles.Forsyth if(tktdbg && lafter == nil) {
96437da2899SCharles.Forsyth print("tktfixgeom: botch 1\n");
96537da2899SCharles.Forsyth return nil;
96637da2899SCharles.Forsyth }
96737da2899SCharles.Forsyth while((lafter->flags & TkTfirst) == 0 && lafter != &tkt->end)
96837da2899SCharles.Forsyth lafter = lafter->next;
96937da2899SCharles.Forsyth
97037da2899SCharles.Forsyth
97137da2899SCharles.Forsyth y = l1->orig.y + l1->height + tktpostspace(tk, l1);
97237da2899SCharles.Forsyth
97337da2899SCharles.Forsyth oldi.lo = y;
97437da2899SCharles.Forsyth oldi.hi = lafter->orig.y;
97537da2899SCharles.Forsyth rest.lo = oldi.hi;
97637da2899SCharles.Forsyth rest.hi = rest.lo + 1000; /* get background after end, too */
97737da2899SCharles.Forsyth
97837da2899SCharles.Forsyth opts = mallocz(TkTnumopts*sizeof(int), 0);
97937da2899SCharles.Forsyth if(opts == nil)
98037da2899SCharles.Forsyth return TkNomem;
98137da2899SCharles.Forsyth env = mallocz(sizeof(TkEnv), 0);
98237da2899SCharles.Forsyth if(env == nil) {
98337da2899SCharles.Forsyth free(opts);
98437da2899SCharles.Forsyth return TkNomem;
98537da2899SCharles.Forsyth }
98637da2899SCharles.Forsyth
98737da2899SCharles.Forsyth for(l = l1->next; l != lafter; l = l->next) {
98837da2899SCharles.Forsyth if(tktdbg && l == nil) {
98937da2899SCharles.Forsyth print("tktfixgeom: botch 2\n");
99037da2899SCharles.Forsyth free(opts);
99137da2899SCharles.Forsyth free(env);
99237da2899SCharles.Forsyth return nil;
99337da2899SCharles.Forsyth }
99437da2899SCharles.Forsyth
99537da2899SCharles.Forsyth l->flags &= ~TkTdrawn;
99637da2899SCharles.Forsyth
99737da2899SCharles.Forsyth /* some spacing depends on tags of first non-mark on display line */
99837da2899SCharles.Forsyth iprev = nil;
99937da2899SCharles.Forsyth for(i = l->items; i->kind == TkTmark; ) {
100037da2899SCharles.Forsyth iprev = i;
100137da2899SCharles.Forsyth i = i->next;
100237da2899SCharles.Forsyth }
100337da2899SCharles.Forsyth tkttagopts(tk, i, opts, env, &tb, 1);
100437da2899SCharles.Forsyth
100537da2899SCharles.Forsyth if(l->flags&TkTfirst) {
100637da2899SCharles.Forsyth xleft = opts[TkTlmargin1];
100737da2899SCharles.Forsyth y += opts[TkTspacing1];
100837da2899SCharles.Forsyth }
100937da2899SCharles.Forsyth else {
101037da2899SCharles.Forsyth xleft = opts[TkTlmargin2];
101137da2899SCharles.Forsyth y += opts[TkTspacing2];
101237da2899SCharles.Forsyth }
101337da2899SCharles.Forsyth sp3 = opts[TkTspacing3];
101437da2899SCharles.Forsyth just = opts[TkTjustify];
101537da2899SCharles.Forsyth
101637da2899SCharles.Forsyth wrapmode = opts[TkTwrap];
101737da2899SCharles.Forsyth f = env->font;
101837da2899SCharles.Forsyth h = f->height;
101937da2899SCharles.Forsyth lh = opts[TkTlineheight];
102037da2899SCharles.Forsyth a = f->ascent;
102137da2899SCharles.Forsyth x = xleft;
102237da2899SCharles.Forsyth xright = winw - opts[TkTrmargin];
102337da2899SCharles.Forsyth if(xright < xleft)
102437da2899SCharles.Forsyth xright = xleft;
102537da2899SCharles.Forsyth
102637da2899SCharles.Forsyth /*
102737da2899SCharles.Forsyth * perform line wrapping and calculate h (height) and a (ascent)
102837da2899SCharles.Forsyth * for the current line
102937da2899SCharles.Forsyth */
103037da2899SCharles.Forsyth for(; i != nil; iprev = i, i = i->next) {
103137da2899SCharles.Forsyth again:
103237da2899SCharles.Forsyth if(i->kind == TkTmark)
103337da2899SCharles.Forsyth continue;
103437da2899SCharles.Forsyth if(i->kind == TkTnewline)
103537da2899SCharles.Forsyth break;
103637da2899SCharles.Forsyth if(i->kind == TkTcontline) {
103737da2899SCharles.Forsyth /*
103837da2899SCharles.Forsyth * See if some of following line fits on this one.
103937da2899SCharles.Forsyth * First, ensure that following line isn't empty.
104037da2899SCharles.Forsyth */
104137da2899SCharles.Forsyth it = l->next->items;
104237da2899SCharles.Forsyth while(it->kind == TkTmark)
104337da2899SCharles.Forsyth it = it->next;
104437da2899SCharles.Forsyth
104537da2899SCharles.Forsyth if(it->kind == TkTnewline || it->kind == TkTcontline) {
104637da2899SCharles.Forsyth /* next line is empty; join it to this one by removing i */
104737da2899SCharles.Forsyth ix.item = i;
104837da2899SCharles.Forsyth ix.line = l;
104937da2899SCharles.Forsyth ix.pos = 0;
105037da2899SCharles.Forsyth tktremitem(tkt, &ix);
105137da2899SCharles.Forsyth it = l->next->items;
105237da2899SCharles.Forsyth if(iprev == nil)
105337da2899SCharles.Forsyth i = l->items;
105437da2899SCharles.Forsyth else
105537da2899SCharles.Forsyth i = iprev->next;
105637da2899SCharles.Forsyth goto again;
105737da2899SCharles.Forsyth }
105837da2899SCharles.Forsyth
105937da2899SCharles.Forsyth n = xright - x;
106037da2899SCharles.Forsyth if(n <= 0)
106137da2899SCharles.Forsyth break;
106237da2899SCharles.Forsyth ixprev.line = l;
106337da2899SCharles.Forsyth ixprev.item = i;
106437da2899SCharles.Forsyth ixprev.pos = 0;
106537da2899SCharles.Forsyth ix = ixprev;
106637da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &ix);
106737da2899SCharles.Forsyth if(wrapmode == Tkwrapword)
106837da2899SCharles.Forsyth tktadjustind(tkt, TkTbywrapend, &ix);
106937da2899SCharles.Forsyth if(wrapmode != Tkwrapnone && tktwidbetween(tk, x, &ixprev, &ix) > n)
107037da2899SCharles.Forsyth break;
107137da2899SCharles.Forsyth /* move one item up from next line and try again */
107237da2899SCharles.Forsyth it = l->next->items;
107337da2899SCharles.Forsyth if(tktdbg && (it == nil || it->kind == TkTnewline || it->kind == TkTcontline)) {
107437da2899SCharles.Forsyth print("tktfixgeom: botch 3\n");
107537da2899SCharles.Forsyth free(opts);
107637da2899SCharles.Forsyth free(env);
107737da2899SCharles.Forsyth return nil;
107837da2899SCharles.Forsyth }
107937da2899SCharles.Forsyth if(iprev == nil)
108037da2899SCharles.Forsyth l->items = it;
108137da2899SCharles.Forsyth else
108237da2899SCharles.Forsyth iprev->next = it;
108337da2899SCharles.Forsyth l->next->items = it->next;
108437da2899SCharles.Forsyth it->next = i;
108537da2899SCharles.Forsyth i = it;
108637da2899SCharles.Forsyth goto again;
108737da2899SCharles.Forsyth }
108837da2899SCharles.Forsyth
108937da2899SCharles.Forsyth oa = a;
109037da2899SCharles.Forsyth oh = h;
109137da2899SCharles.Forsyth if(!tktanytags(i)) {
109237da2899SCharles.Forsyth env->font = tk->env->font;
109337da2899SCharles.Forsyth o = 0;
109437da2899SCharles.Forsyth }
109537da2899SCharles.Forsyth else {
109637da2899SCharles.Forsyth tkttagopts(tk, i, opts, env, nil, 1);
109737da2899SCharles.Forsyth o = opts[TkToffset];
109837da2899SCharles.Forsyth }
109937da2899SCharles.Forsyth if((o != 0 || env->font != f) && i->kind != TkTwin) {
110037da2899SCharles.Forsyth /* check ascent of current item */
110137da2899SCharles.Forsyth n = o+env->font->ascent;
110237da2899SCharles.Forsyth if(n > a) {
110337da2899SCharles.Forsyth a = n;
110437da2899SCharles.Forsyth h += (a - oa);
110537da2899SCharles.Forsyth }
110637da2899SCharles.Forsyth /* check descent of current item */
110737da2899SCharles.Forsyth n = (env->font->height - env->font->ascent) - o;
110837da2899SCharles.Forsyth if(n > h-a)
110937da2899SCharles.Forsyth h = a + n;
111037da2899SCharles.Forsyth }
111137da2899SCharles.Forsyth if(i->kind == TkTwin && i->iwin->sub != nil) {
111237da2899SCharles.Forsyth sub = i->iwin->sub;
111337da2899SCharles.Forsyth n = 2 * i->iwin->pady + sub->act.height +
111437da2899SCharles.Forsyth 2 * sub->borderwidth;
111537da2899SCharles.Forsyth switch(i->iwin->align) {
111637da2899SCharles.Forsyth case Tktop:
111737da2899SCharles.Forsyth case Tkbottom:
111837da2899SCharles.Forsyth if(n > h)
111937da2899SCharles.Forsyth h = n;
112037da2899SCharles.Forsyth break;
112137da2899SCharles.Forsyth case Tkcenter:
112237da2899SCharles.Forsyth if(n/2 > a)
112337da2899SCharles.Forsyth a = n/2;
112437da2899SCharles.Forsyth if(n/2 > h-a)
112537da2899SCharles.Forsyth h = a + n/2;
112637da2899SCharles.Forsyth break;
112737da2899SCharles.Forsyth case Tkbaseline:
112837da2899SCharles.Forsyth wa = i->iwin->ascent;
112937da2899SCharles.Forsyth if (wa == -1)
113037da2899SCharles.Forsyth wa = n;
113137da2899SCharles.Forsyth h = maximum(a, wa) + maximum(h - a, n - wa);
113237da2899SCharles.Forsyth a = maximum(a, wa);
113337da2899SCharles.Forsyth break;
113437da2899SCharles.Forsyth }
113537da2899SCharles.Forsyth }
113637da2899SCharles.Forsyth
113737da2899SCharles.Forsyth w = tktdispwidth(tk, tb, i, env->font, x, 0, -1);
113837da2899SCharles.Forsyth n = x + w - xright;
113937da2899SCharles.Forsyth if(n > 0 && wrapmode != Tkwrapnone) {
114037da2899SCharles.Forsyth /* find shortest suffix that can be removed to fit item */
114137da2899SCharles.Forsyth j = tktposcount(i) - 1;
114237da2899SCharles.Forsyth while(j > 0 && tktdispwidth(tk, tb, i, env->font, x, j, -1) < n)
114337da2899SCharles.Forsyth j--;
114437da2899SCharles.Forsyth /* put at least one item on a line before splitting */
114537da2899SCharles.Forsyth if(j == 0 && x == xleft) {
114637da2899SCharles.Forsyth if(tktposcount(i) == 1)
114737da2899SCharles.Forsyth goto Nosplit;
114837da2899SCharles.Forsyth j = 1;
114937da2899SCharles.Forsyth }
115037da2899SCharles.Forsyth ix.line = l;
115137da2899SCharles.Forsyth ix.item = i;
115237da2899SCharles.Forsyth ix.pos = j;
115337da2899SCharles.Forsyth if(wrapmode == Tkwrapword) {
115437da2899SCharles.Forsyth /* trim the item at the first word at or before the shortest suffix */
115537da2899SCharles.Forsyth /* TO DO: convert any resulting trailing white space to zero width */
115637da2899SCharles.Forsyth ixw = ix;
115737da2899SCharles.Forsyth if(tktisbreak(tktindrune(&ixw))) {
115837da2899SCharles.Forsyth /* at break character, find end of word preceding it */
115937da2899SCharles.Forsyth while(tktisbreak(tktindrune(&ixw))){
116037da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, &ixw) ||
116137da2899SCharles.Forsyth ixw.line != l || ixw.item == l->items && ixw.pos == 0)
116237da2899SCharles.Forsyth goto Wrapchar; /* no suitable point, degrade to char wrap */
116337da2899SCharles.Forsyth }
116437da2899SCharles.Forsyth ix = ixw;
116537da2899SCharles.Forsyth }
116637da2899SCharles.Forsyth /* now find start of word */
116737da2899SCharles.Forsyth tktadjustind(tkt, TkTbywrapstart, &ixw);
116837da2899SCharles.Forsyth if(ixw.line == l && (ixw.item != l->items || ixw.pos > 0)){
116937da2899SCharles.Forsyth /* it will leave something on the line, so reasonable to split here */
117037da2899SCharles.Forsyth ix = ixw;
117137da2899SCharles.Forsyth }
117237da2899SCharles.Forsyth /* otherwise degrade to char wrap */
117337da2899SCharles.Forsyth }
117437da2899SCharles.Forsyth Wrapchar:
117537da2899SCharles.Forsyth if(ix.pos > 0) {
117637da2899SCharles.Forsyth needsplit = 1;
117737da2899SCharles.Forsyth e = tktsplititem(&ix);
117837da2899SCharles.Forsyth if(e != nil) {
117937da2899SCharles.Forsyth free(opts);
118037da2899SCharles.Forsyth free(env);
118137da2899SCharles.Forsyth return e;
118237da2899SCharles.Forsyth }
118337da2899SCharles.Forsyth }
118437da2899SCharles.Forsyth else
118537da2899SCharles.Forsyth needsplit = 0;
118637da2899SCharles.Forsyth
118737da2899SCharles.Forsyth e = tktnewitem(TkTcontline, 0, &it);
118837da2899SCharles.Forsyth if(e != nil) {
118937da2899SCharles.Forsyth free(opts);
119037da2899SCharles.Forsyth free(env);
119137da2899SCharles.Forsyth return e;
119237da2899SCharles.Forsyth }
119337da2899SCharles.Forsyth e = tktiteminsert(tkt, &ix, it);
119437da2899SCharles.Forsyth if(e != nil) {
119537da2899SCharles.Forsyth tktfreeitems(tkt, it, 1);
119637da2899SCharles.Forsyth free(opts);
119737da2899SCharles.Forsyth free(env);
119837da2899SCharles.Forsyth return e;
119937da2899SCharles.Forsyth }
120037da2899SCharles.Forsyth
120137da2899SCharles.Forsyth l = l->prev; /* work on part of line up to split */
120237da2899SCharles.Forsyth
120337da2899SCharles.Forsyth if(needsplit) {
120437da2899SCharles.Forsyth /* have to calculate width of pre-split part */
120537da2899SCharles.Forsyth ixprev = ix;
120637da2899SCharles.Forsyth if(tktadjustind(tkt, TkTbyitemback, &ixprev) &&
120737da2899SCharles.Forsyth tktadjustind(tkt, TkTbyitemback, &ixprev)) {
120837da2899SCharles.Forsyth w = tktdispwidth(tk, tb, ixprev.item, nil, x, 0, -1);
120937da2899SCharles.Forsyth ixprev.item->width = w;
121037da2899SCharles.Forsyth x += w;
121137da2899SCharles.Forsyth }
121237da2899SCharles.Forsyth }
121337da2899SCharles.Forsyth else {
121437da2899SCharles.Forsyth h = oh;
121537da2899SCharles.Forsyth a = oa;
121637da2899SCharles.Forsyth }
121737da2899SCharles.Forsyth break;
121837da2899SCharles.Forsyth }
121937da2899SCharles.Forsyth else {
122037da2899SCharles.Forsyth Nosplit:
122137da2899SCharles.Forsyth i->width =w;
122237da2899SCharles.Forsyth x += w;
122337da2899SCharles.Forsyth }
122437da2899SCharles.Forsyth }
122537da2899SCharles.Forsyth if (a > h)
122637da2899SCharles.Forsyth h = a;
122737da2899SCharles.Forsyth if (lh == 0)
122837da2899SCharles.Forsyth lh = f->height;
122937da2899SCharles.Forsyth if (lh > h) {
123037da2899SCharles.Forsyth a += (lh - h) / 2;
123137da2899SCharles.Forsyth h = lh;
123237da2899SCharles.Forsyth }
123337da2899SCharles.Forsyth
123437da2899SCharles.Forsyth /*
123537da2899SCharles.Forsyth * Now line l is broken correctly and has correct item widths/line height/ascent.
123637da2899SCharles.Forsyth * Merge adjacent TkTascii/TkTrune items with same tags.
123737da2899SCharles.Forsyth * Also, set act{x,y} of embedded widgets to offset from
123837da2899SCharles.Forsyth * left of item box at baseline.
123937da2899SCharles.Forsyth */
124037da2899SCharles.Forsyth for(i = l->items; i->next != nil; i = i->next) {
124137da2899SCharles.Forsyth it = i->next;
124237da2899SCharles.Forsyth if( (i->kind == TkTascii || i->kind == TkTrune)
124337da2899SCharles.Forsyth &&
124437da2899SCharles.Forsyth i->kind == it->kind
124537da2899SCharles.Forsyth &&
124637da2899SCharles.Forsyth tktsametags(i, it)) {
124737da2899SCharles.Forsyth n = strlen(i->istring);
124837da2899SCharles.Forsyth j = strlen(it->istring);
124937da2899SCharles.Forsyth s = realloc(i->istring, n + j + 1);
125037da2899SCharles.Forsyth if(s == nil) {
125137da2899SCharles.Forsyth free(opts);
125237da2899SCharles.Forsyth free(env);
125337da2899SCharles.Forsyth return TkNomem;
125437da2899SCharles.Forsyth }
125537da2899SCharles.Forsyth i->istring = s;
125637da2899SCharles.Forsyth memmove(i->istring+n, it->istring, j+1);
125737da2899SCharles.Forsyth i->width += it->width;
125837da2899SCharles.Forsyth i->next = it->next;
125937da2899SCharles.Forsyth it->next = nil;
126037da2899SCharles.Forsyth tktfreeitems(tkt, it, 1);
126137da2899SCharles.Forsyth }
126237da2899SCharles.Forsyth else if(i->kind == TkTwin && i->iwin->sub != nil) {
126337da2899SCharles.Forsyth sub = i->iwin->sub;
126437da2899SCharles.Forsyth n = sub->act.height + 2 * sub->borderwidth;
126537da2899SCharles.Forsyth o = i->iwin->pady;
126637da2899SCharles.Forsyth sub->act.x = i->iwin->padx;
126737da2899SCharles.Forsyth /*
126837da2899SCharles.Forsyth * sub->act.y is y-origin of widget relative to baseline.
126937da2899SCharles.Forsyth */
127037da2899SCharles.Forsyth switch(i->iwin->align) {
127137da2899SCharles.Forsyth case Tktop:
127237da2899SCharles.Forsyth sub->act.y = o - a;
127337da2899SCharles.Forsyth break;
127437da2899SCharles.Forsyth case Tkbottom:
127537da2899SCharles.Forsyth sub->act.y = h - (o + n) - a;
127637da2899SCharles.Forsyth break;
127737da2899SCharles.Forsyth case Tkcenter:
127837da2899SCharles.Forsyth sub->act.y = (h - n) / 2 - a;
127937da2899SCharles.Forsyth break;
128037da2899SCharles.Forsyth case Tkbaseline:
128137da2899SCharles.Forsyth wa = i->iwin->ascent;
128237da2899SCharles.Forsyth if (wa == -1)
128337da2899SCharles.Forsyth wa = n;
128437da2899SCharles.Forsyth sub->act.y = -wa;
128537da2899SCharles.Forsyth break;
128637da2899SCharles.Forsyth }
128737da2899SCharles.Forsyth }
128837da2899SCharles.Forsyth }
128937da2899SCharles.Forsyth
129037da2899SCharles.Forsyth l->width = x - xleft;
129137da2899SCharles.Forsyth
129237da2899SCharles.Forsyth /* justification bug: wrong if line has tabs */
129337da2899SCharles.Forsyth l->orig.x = xleft;
129437da2899SCharles.Forsyth n = xright - x;
129537da2899SCharles.Forsyth if(n > 0) {
129637da2899SCharles.Forsyth if(just == Tkright)
129737da2899SCharles.Forsyth l->orig.x += n;
129837da2899SCharles.Forsyth else
129937da2899SCharles.Forsyth if(just == Tkcenter)
130037da2899SCharles.Forsyth l->orig.x += n/2;
130137da2899SCharles.Forsyth }
130237da2899SCharles.Forsyth
130337da2899SCharles.Forsyth /* give newline or contline width up to right margin */
130437da2899SCharles.Forsyth ilast = tktlastitem(l->items);
130537da2899SCharles.Forsyth ilast->width = xright - l->width;
130637da2899SCharles.Forsyth if(ilast->width < 0)
130737da2899SCharles.Forsyth ilast->width = 0;
130837da2899SCharles.Forsyth
130937da2899SCharles.Forsyth l->orig.y = y;
131037da2899SCharles.Forsyth l->height = h;
131137da2899SCharles.Forsyth l->ascent = a;
131237da2899SCharles.Forsyth y += h;
131337da2899SCharles.Forsyth if(l->flags&TkTlast)
131437da2899SCharles.Forsyth y += sp3;
131537da2899SCharles.Forsyth }
131637da2899SCharles.Forsyth free(opts);
131737da2899SCharles.Forsyth free(env);
131837da2899SCharles.Forsyth
131937da2899SCharles.Forsyth tktdrawbg(tk, oldi.lo, oldi.hi, 0);
132037da2899SCharles.Forsyth
132137da2899SCharles.Forsyth y += tktprespace(tk, l);
132237da2899SCharles.Forsyth newrest.lo = y;
132337da2899SCharles.Forsyth newrest.hi = y + rest.hi - rest.lo;
132437da2899SCharles.Forsyth
132537da2899SCharles.Forsyth hole = tkttranslate(tk, newrest, rest.lo);
132637da2899SCharles.Forsyth
132737da2899SCharles.Forsyth tktdrawbg(tk, hole.lo, hole.hi, 0);
132837da2899SCharles.Forsyth
132937da2899SCharles.Forsyth if(l != &tkt->end) {
133037da2899SCharles.Forsyth while(l != &tkt->end) {
133137da2899SCharles.Forsyth oh = l->next->orig.y - l->orig.y;
133237da2899SCharles.Forsyth l->orig.y = y;
133337da2899SCharles.Forsyth if(y + oh > hole.lo && y < hole.hi) {
133437da2899SCharles.Forsyth l->flags &= ~TkTdrawn;
133537da2899SCharles.Forsyth }
133637da2899SCharles.Forsyth y += oh;
133737da2899SCharles.Forsyth l = l->next;
133837da2899SCharles.Forsyth }
133937da2899SCharles.Forsyth }
134037da2899SCharles.Forsyth tkt->end.orig.y = tkt->end.prev->orig.y + tkt->end.prev->height;
134137da2899SCharles.Forsyth
134237da2899SCharles.Forsyth if(tkt->deltatv.y > tkt->end.orig.y)
134337da2899SCharles.Forsyth tkt->deltatv.y = tkt->end.prev->orig.y;
134437da2899SCharles.Forsyth
134537da2899SCharles.Forsyth
134637da2899SCharles.Forsyth e = tktsetscroll(tk, Tkvertical);
134737da2899SCharles.Forsyth if(e != nil)
134837da2899SCharles.Forsyth return e;
134937da2899SCharles.Forsyth e = tktsetscroll(tk, Tkhorizontal);
135037da2899SCharles.Forsyth if(e != nil)
135137da2899SCharles.Forsyth return e;
135237da2899SCharles.Forsyth
135337da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
135437da2899SCharles.Forsyth if(tktdbg)
135537da2899SCharles.Forsyth tktcheck(tkt, "tktfixgeom end");
135637da2899SCharles.Forsyth return nil;
135737da2899SCharles.Forsyth }
135837da2899SCharles.Forsyth
135937da2899SCharles.Forsyth static int
tktpostspace(Tk * tk,TkTline * l)136037da2899SCharles.Forsyth tktpostspace(Tk *tk, TkTline *l)
136137da2899SCharles.Forsyth {
136237da2899SCharles.Forsyth int ans;
136337da2899SCharles.Forsyth TkTitem *i;
136437da2899SCharles.Forsyth TkEnv env;
136537da2899SCharles.Forsyth int *opts;
136637da2899SCharles.Forsyth
136737da2899SCharles.Forsyth opts = mallocz(TkTnumopts*sizeof(int), 0);
136837da2899SCharles.Forsyth if(opts == nil)
136937da2899SCharles.Forsyth return 0;
137037da2899SCharles.Forsyth ans = 0;
137137da2899SCharles.Forsyth if(l->items != nil && (l->flags&TkTlast)) {
137237da2899SCharles.Forsyth for(i = l->items; i->kind == TkTmark; )
137337da2899SCharles.Forsyth i = i->next;
137437da2899SCharles.Forsyth tkttagopts(tk, i, opts, &env, nil, 1);
137537da2899SCharles.Forsyth ans = opts[TkTspacing3];
137637da2899SCharles.Forsyth }
137737da2899SCharles.Forsyth free(opts);
137837da2899SCharles.Forsyth return ans;
137937da2899SCharles.Forsyth }
138037da2899SCharles.Forsyth
138137da2899SCharles.Forsyth static int
tktprespace(Tk * tk,TkTline * l)138237da2899SCharles.Forsyth tktprespace(Tk *tk, TkTline *l)
138337da2899SCharles.Forsyth {
138437da2899SCharles.Forsyth int ans;
138537da2899SCharles.Forsyth TkTitem *i;
138637da2899SCharles.Forsyth TkEnv env;
138737da2899SCharles.Forsyth int *opts;
138837da2899SCharles.Forsyth
138937da2899SCharles.Forsyth opts = mallocz(TkTnumopts*sizeof(int), 0);
139037da2899SCharles.Forsyth if(opts == nil)
139137da2899SCharles.Forsyth return 0;
139237da2899SCharles.Forsyth
139337da2899SCharles.Forsyth ans = 0;
139437da2899SCharles.Forsyth if(l->items != nil) {
139537da2899SCharles.Forsyth for(i = l->items; i->kind == TkTmark; )
139637da2899SCharles.Forsyth i = i->next;
139737da2899SCharles.Forsyth tkttagopts(tk, i, opts, &env, nil, 1);
139837da2899SCharles.Forsyth if(l->flags&TkTfirst)
139937da2899SCharles.Forsyth ans = opts[TkTspacing1];
140037da2899SCharles.Forsyth else
140137da2899SCharles.Forsyth ans = opts[TkTspacing2];
140237da2899SCharles.Forsyth }
140337da2899SCharles.Forsyth free(opts);
140437da2899SCharles.Forsyth return ans;
140537da2899SCharles.Forsyth }
140637da2899SCharles.Forsyth
140737da2899SCharles.Forsyth static int
tktwidbetween(Tk * tk,int x,TkTindex * i1,TkTindex * i2)140837da2899SCharles.Forsyth tktwidbetween(Tk *tk, int x, TkTindex *i1, TkTindex *i2)
140937da2899SCharles.Forsyth {
141037da2899SCharles.Forsyth int d, w, n;
141137da2899SCharles.Forsyth TkTindex ix;
141237da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
141337da2899SCharles.Forsyth
141437da2899SCharles.Forsyth w = 0;
141537da2899SCharles.Forsyth ix = *i1;
141637da2899SCharles.Forsyth while(ix.item != i2->item) {
141737da2899SCharles.Forsyth /* probably wrong w.r.t tag tabs */
141837da2899SCharles.Forsyth d = tktdispwidth(tk, nil, ix.item, nil, x, ix.pos, -1);
141937da2899SCharles.Forsyth w += d;
142037da2899SCharles.Forsyth x += d;
142137da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, &ix)) {
142237da2899SCharles.Forsyth if(tktdbg)
142337da2899SCharles.Forsyth print("tktwidbetween botch\n");
142437da2899SCharles.Forsyth break;
142537da2899SCharles.Forsyth }
142637da2899SCharles.Forsyth }
142737da2899SCharles.Forsyth n = i2->pos - ix.pos;
142837da2899SCharles.Forsyth if(n > 0)
142937da2899SCharles.Forsyth /* probably wrong w.r.t tag tabs */
143037da2899SCharles.Forsyth w += tktdispwidth(tk, nil, ix.item, nil, x, ix.pos, i2->pos-ix.pos);
143137da2899SCharles.Forsyth return w;
143237da2899SCharles.Forsyth }
143337da2899SCharles.Forsyth
143437da2899SCharles.Forsyth static Interval
tktvclip(Interval i,int vh)143537da2899SCharles.Forsyth tktvclip(Interval i, int vh)
143637da2899SCharles.Forsyth {
143737da2899SCharles.Forsyth if(i.lo < 0)
143837da2899SCharles.Forsyth i.lo = 0;
143937da2899SCharles.Forsyth if(i.hi > vh)
144037da2899SCharles.Forsyth i.hi = vh;
144137da2899SCharles.Forsyth return i;
144237da2899SCharles.Forsyth }
144337da2899SCharles.Forsyth
144437da2899SCharles.Forsyth /*
144537da2899SCharles.Forsyth * Do translation of any part of interval that appears on screen
144637da2899SCharles.Forsyth * starting at srcy to its new position, dsti.
144737da2899SCharles.Forsyth * Return y-range of the hole left in the image (either because
144837da2899SCharles.Forsyth * the src bits were out of the V window, or because the src bits
144937da2899SCharles.Forsyth * vacated an area of the V window).
145037da2899SCharles.Forsyth * The coordinates passed in and out are in T space.
145137da2899SCharles.Forsyth */
145237da2899SCharles.Forsyth static Interval
tkttranslate(Tk * tk,Interval dsti,int srcy)145337da2899SCharles.Forsyth tkttranslate(Tk *tk, Interval dsti, int srcy)
145437da2899SCharles.Forsyth {
145537da2899SCharles.Forsyth int vh, vw, dvty, locked;
145637da2899SCharles.Forsyth TkText *tkt;
145737da2899SCharles.Forsyth Image *i;
145837da2899SCharles.Forsyth Interval hole, vdst, vsrc;
145937da2899SCharles.Forsyth Point src;
146037da2899SCharles.Forsyth Rectangle dst;
146137da2899SCharles.Forsyth Display *d;
146237da2899SCharles.Forsyth
146337da2899SCharles.Forsyth hole.hi = 0;
146437da2899SCharles.Forsyth hole.lo = 0;
146537da2899SCharles.Forsyth
146637da2899SCharles.Forsyth
146737da2899SCharles.Forsyth /*
146837da2899SCharles.Forsyth * If we are embedded in a text widget, we need to come in through
146937da2899SCharles.Forsyth * the tkdrawtext routine, to ensure our clipr is set properly, so we
147037da2899SCharles.Forsyth * just punt in that case.
147137da2899SCharles.Forsyth * XXX is just checking parent good enough. what if we're in
147237da2899SCharles.Forsyth * a frame in a text widget?
147337da2899SCharles.Forsyth * BUG!
147437da2899SCharles.Forsyth
147537da2899SCharles.Forsyth * if(tk->parent != nil && tk->parent->type == TKtext) {
147637da2899SCharles.Forsyth * tk->flag |= Tkrefresh;
147737da2899SCharles.Forsyth * return hole;
147837da2899SCharles.Forsyth * }
147937da2899SCharles.Forsyth */
148037da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
148137da2899SCharles.Forsyth dvty = tkt->deltatv.y;
148237da2899SCharles.Forsyth i = tkt->image;
148337da2899SCharles.Forsyth
148437da2899SCharles.Forsyth vw = tk->act.width - tk->ipad.x;
148537da2899SCharles.Forsyth vh = tk->act.height - tk->ipad.y;
148637da2899SCharles.Forsyth
148737da2899SCharles.Forsyth /* convert to V space */
148837da2899SCharles.Forsyth vdst.lo = dsti.lo - dvty;
148937da2899SCharles.Forsyth vdst.hi = dsti.hi - dvty;
149037da2899SCharles.Forsyth vsrc.lo = srcy - dvty;
149137da2899SCharles.Forsyth vsrc.hi = vsrc.lo + dsti.hi - dsti.lo;
149237da2899SCharles.Forsyth if(vsrc.lo == vsrc.hi || vsrc.lo == vdst.lo)
149337da2899SCharles.Forsyth return hole;
149437da2899SCharles.Forsyth else if(vsrc.hi <= 0 || vsrc.lo >= vh)
149537da2899SCharles.Forsyth hole = tktvclip(vdst, vh);
149637da2899SCharles.Forsyth else if(vdst.hi <= 0 || vdst.lo >= vh)
149737da2899SCharles.Forsyth hole = tktvclip(vsrc, vh);
149837da2899SCharles.Forsyth else if(i != nil) {
149937da2899SCharles.Forsyth src.x = 0;
150037da2899SCharles.Forsyth src.y = vsrc.lo;
150137da2899SCharles.Forsyth if(vdst.lo > vsrc.lo) { /* see earlier text lines */
150237da2899SCharles.Forsyth if(vsrc.lo < 0) {
150337da2899SCharles.Forsyth src.y = 0;
150437da2899SCharles.Forsyth vdst.lo -= vsrc.lo;
150537da2899SCharles.Forsyth }
150637da2899SCharles.Forsyth if(vdst.hi > vh)
150737da2899SCharles.Forsyth vdst.hi = vh;
150837da2899SCharles.Forsyth hole.lo = src.y;
150937da2899SCharles.Forsyth hole.hi = vdst.lo;
151037da2899SCharles.Forsyth }
151137da2899SCharles.Forsyth else { /* see later text lines */
151237da2899SCharles.Forsyth if(vsrc.hi > vh)
151337da2899SCharles.Forsyth vdst.hi -= (vsrc.hi - vh);
151437da2899SCharles.Forsyth if(vdst.lo < 0){
151537da2899SCharles.Forsyth src.y -= vdst.lo;
151637da2899SCharles.Forsyth vdst.lo = 0;
151737da2899SCharles.Forsyth }
151837da2899SCharles.Forsyth hole.lo = vdst.hi;
151937da2899SCharles.Forsyth hole.hi = src.y + (vdst.hi - vdst.lo);
152037da2899SCharles.Forsyth }
152137da2899SCharles.Forsyth if(vdst.hi > vdst.lo && (tkt->tflag&TkTdrawn)) {
152237da2899SCharles.Forsyth src = addpt(src, tkt->deltaiv);
152337da2899SCharles.Forsyth dst = rectaddpt(Rect(0, vdst.lo, vw, vdst.hi), tkt->deltaiv);
152437da2899SCharles.Forsyth d = tk->env->top->display;
152537da2899SCharles.Forsyth locked = 0;
152637da2899SCharles.Forsyth if(!(tkt->tflag&TkTdlocked))
152737da2899SCharles.Forsyth locked = lockdisplay(d);
152837da2899SCharles.Forsyth i = tkimageof(tk);
152937da2899SCharles.Forsyth tkt->image = i;
153037da2899SCharles.Forsyth if(i != nil)
153137da2899SCharles.Forsyth draw(i, dst, i, nil, src);
153237da2899SCharles.Forsyth if(locked)
153337da2899SCharles.Forsyth unlockdisplay(d);
153437da2899SCharles.Forsyth }
153537da2899SCharles.Forsyth }
153637da2899SCharles.Forsyth hole.lo += dvty;
153737da2899SCharles.Forsyth hole.hi += dvty;
153837da2899SCharles.Forsyth return hole;
153937da2899SCharles.Forsyth }
154037da2899SCharles.Forsyth
154137da2899SCharles.Forsyth /*
154237da2899SCharles.Forsyth * mark lines from firsty to lasty as not drawn.
154337da2899SCharles.Forsyth * firsty and lasty are in T space
154437da2899SCharles.Forsyth */
154537da2899SCharles.Forsyth static void
tktnotdrawn(Tk * tk,int firsty,int lasty,int all)154637da2899SCharles.Forsyth tktnotdrawn(Tk *tk, int firsty, int lasty, int all)
154737da2899SCharles.Forsyth {
154837da2899SCharles.Forsyth TkTline *lend, *l;
154937da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
155037da2899SCharles.Forsyth if(firsty >= lasty && !all)
155137da2899SCharles.Forsyth return;
155237da2899SCharles.Forsyth lend = &tkt->end;
155337da2899SCharles.Forsyth for(l = tkt->start.next; l != lend; l = l->next) {
155437da2899SCharles.Forsyth if(l->orig.y+l->height <= firsty)
155537da2899SCharles.Forsyth continue;
155637da2899SCharles.Forsyth if(l->orig.y >= lasty)
155737da2899SCharles.Forsyth break;
155837da2899SCharles.Forsyth l->flags &= ~TkTdrawn;
155937da2899SCharles.Forsyth if (firsty > l->orig.y)
156037da2899SCharles.Forsyth firsty = l->orig.y;
156137da2899SCharles.Forsyth if (lasty < l->orig.y+l->height)
156237da2899SCharles.Forsyth lasty = l->orig.y+l->height;
156337da2899SCharles.Forsyth }
156437da2899SCharles.Forsyth tktdrawbg(tk, firsty, lasty, all);
156537da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
156637da2899SCharles.Forsyth }
156737da2899SCharles.Forsyth
156837da2899SCharles.Forsyth /*
156937da2899SCharles.Forsyth * firsty and lasty are in T space
157037da2899SCharles.Forsyth */
157137da2899SCharles.Forsyth static void
tktdrawbg(Tk * tk,int firsty,int lasty,int all)157237da2899SCharles.Forsyth tktdrawbg(Tk *tk, int firsty, int lasty, int all)
157337da2899SCharles.Forsyth {
157437da2899SCharles.Forsyth int vw, vh, locked;
157537da2899SCharles.Forsyth Rectangle r;
157637da2899SCharles.Forsyth Image *i;
157737da2899SCharles.Forsyth Display *d;
157837da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
157937da2899SCharles.Forsyth
158037da2899SCharles.Forsyth if(tk->env->top->root->flag & Tksuspended){
158137da2899SCharles.Forsyth tk->flag |= Tkrefresh;
158237da2899SCharles.Forsyth return;
158337da2899SCharles.Forsyth }
158437da2899SCharles.Forsyth /*
158537da2899SCharles.Forsyth * If we are embedded in a text widget, we need to come in through
158637da2899SCharles.Forsyth * the tkdrawtext routine, to ensure our clipr is set properly, so we
158737da2899SCharles.Forsyth * just punt in that case.
158837da2899SCharles.Forsyth * BUG!
158937da2899SCharles.Forsyth * if(tk->parent != nil && tk->parent->type == TKtext) {
159037da2899SCharles.Forsyth * tk->flag |= Tkrefresh;
159137da2899SCharles.Forsyth * return;
159237da2899SCharles.Forsyth * }
159337da2899SCharles.Forsyth */
159437da2899SCharles.Forsyth vw = tk->act.width - tk->ipad.x;
159537da2899SCharles.Forsyth vh = tk->act.height - tk->ipad.y;
159637da2899SCharles.Forsyth if(all) {
159737da2899SCharles.Forsyth /* whole background is to be drawn, not just until last line */
159837da2899SCharles.Forsyth firsty = 0;
159937da2899SCharles.Forsyth lasty = 100000;
160037da2899SCharles.Forsyth }
160137da2899SCharles.Forsyth if(firsty >= lasty)
160237da2899SCharles.Forsyth return;
160337da2899SCharles.Forsyth firsty -= tkt->deltatv.y;
160437da2899SCharles.Forsyth lasty -= tkt->deltatv.y;
160537da2899SCharles.Forsyth if(firsty < 0)
160637da2899SCharles.Forsyth firsty = 0;
160737da2899SCharles.Forsyth if(lasty > vh)
160837da2899SCharles.Forsyth lasty = vh;
160937da2899SCharles.Forsyth r = rectaddpt(Rect(0, firsty, vw, lasty), tkt->deltaiv);
161037da2899SCharles.Forsyth if(r.min.y < r.max.y && (tkt->tflag&TkTdrawn)) {
161137da2899SCharles.Forsyth d = tk->env->top->display;
161237da2899SCharles.Forsyth locked = 0;
161337da2899SCharles.Forsyth if(!(tkt->tflag&TkTdlocked))
161437da2899SCharles.Forsyth locked = lockdisplay(d);
161537da2899SCharles.Forsyth i = tkimageof(tk);
161637da2899SCharles.Forsyth tkt->image = i;
161737da2899SCharles.Forsyth if(i != nil)
161837da2899SCharles.Forsyth draw(i, r, tkgc(tk->env, TkCbackgnd), nil, ZP);
161937da2899SCharles.Forsyth if(locked)
162037da2899SCharles.Forsyth unlockdisplay(d);
162137da2899SCharles.Forsyth }
162237da2899SCharles.Forsyth }
162337da2899SCharles.Forsyth
162437da2899SCharles.Forsyth static void
tktfixscroll(Tk * tk,Point odeltatv)162537da2899SCharles.Forsyth tktfixscroll(Tk *tk, Point odeltatv)
162637da2899SCharles.Forsyth {
162737da2899SCharles.Forsyth int lasty;
162837da2899SCharles.Forsyth Interval oi, hole;
162937da2899SCharles.Forsyth Rectangle oclipr;
163037da2899SCharles.Forsyth Image *dst;
163137da2899SCharles.Forsyth Point ndeltatv;
163237da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
163337da2899SCharles.Forsyth
163437da2899SCharles.Forsyth ndeltatv = tkt->deltatv;
163537da2899SCharles.Forsyth
163637da2899SCharles.Forsyth if(eqpt(odeltatv, ndeltatv))
163737da2899SCharles.Forsyth return;
163837da2899SCharles.Forsyth
163937da2899SCharles.Forsyth /* set clipr to avoid spilling outside (in case didn't come in through draw) */
164037da2899SCharles.Forsyth dst = tkimageof(tk);
164137da2899SCharles.Forsyth if(dst != nil) {
164237da2899SCharles.Forsyth tkt->image = dst;
164337da2899SCharles.Forsyth oclipr = dst->clipr;
164437da2899SCharles.Forsyth tktsetclip(tk);
164537da2899SCharles.Forsyth }
164637da2899SCharles.Forsyth
164737da2899SCharles.Forsyth lasty = tkt->end.orig.y;
164837da2899SCharles.Forsyth if(odeltatv.x != ndeltatv.x)
164937da2899SCharles.Forsyth tktnotdrawn(tk, ndeltatv.y, lasty, 0);
165037da2899SCharles.Forsyth else {
165137da2899SCharles.Forsyth oi.lo = odeltatv.y;
165237da2899SCharles.Forsyth oi.hi = lasty;
165337da2899SCharles.Forsyth hole = tkttranslate(tk, oi, ndeltatv.y);
165437da2899SCharles.Forsyth tktnotdrawn(tk, hole.lo, hole.hi, 0);
165537da2899SCharles.Forsyth }
165637da2899SCharles.Forsyth if(dst != nil)
165737da2899SCharles.Forsyth tktreplclipr(dst, oclipr);
165837da2899SCharles.Forsyth }
165937da2899SCharles.Forsyth
166037da2899SCharles.Forsyth void
tktextgeom(Tk * tk)166137da2899SCharles.Forsyth tktextgeom(Tk *tk)
166237da2899SCharles.Forsyth {
166337da2899SCharles.Forsyth TkTindex ix;
166437da2899SCharles.Forsyth Rectangle oclipr;
166537da2899SCharles.Forsyth Image *dst;
166637da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
166737da2899SCharles.Forsyth char buf[20], *p;
166837da2899SCharles.Forsyth
166937da2899SCharles.Forsyth tkt->tflag &= ~TkTdrawn;
167037da2899SCharles.Forsyth tktsetdeltas(tk, ZP);
167137da2899SCharles.Forsyth /* find index of current top-left, so can see it again */
167237da2899SCharles.Forsyth tktxyind(tk, 0, 0, &ix);
167337da2899SCharles.Forsyth /* make sure scroll bar is redrawn */
167437da2899SCharles.Forsyth tkt->scrolltop[Tkvertical] = -1;
167537da2899SCharles.Forsyth tkt->scrolltop[Tkhorizontal] = -1;
167637da2899SCharles.Forsyth tkt->scrollbot[Tkvertical] = -1;
167737da2899SCharles.Forsyth tkt->scrollbot[Tkhorizontal] = -1;
167837da2899SCharles.Forsyth
167937da2899SCharles.Forsyth /* set clipr to avoid spilling outside (didn't come in through draw) */
168037da2899SCharles.Forsyth dst = tkimageof(tk);
168137da2899SCharles.Forsyth if(dst != nil) {
168237da2899SCharles.Forsyth tkt->image = dst;
168337da2899SCharles.Forsyth oclipr = dst->clipr;
168437da2899SCharles.Forsyth tktsetclip(tk);
168537da2899SCharles.Forsyth }
168637da2899SCharles.Forsyth
168737da2899SCharles.Forsyth /*
168837da2899SCharles.Forsyth * have to save index in a reusable format, as
168937da2899SCharles.Forsyth * tktfixgeom can free everything that ix points to.
169037da2899SCharles.Forsyth */
169137da2899SCharles.Forsyth snprint(buf, sizeof(buf), "%d.%d", tktlinenum(tkt, &ix), tktlinepos(tkt, &ix));
169237da2899SCharles.Forsyth tktfixgeom(tk, &tkt->start, tkt->end.prev, 1);
169337da2899SCharles.Forsyth p = buf;
169437da2899SCharles.Forsyth tktindparse(tk, &p, &ix); /* restore index to something close to original value */
169537da2899SCharles.Forsyth tktsee(tk, &ix, 1);
169637da2899SCharles.Forsyth
169737da2899SCharles.Forsyth if(dst != nil)
169837da2899SCharles.Forsyth tktreplclipr(dst, oclipr);
169937da2899SCharles.Forsyth }
170037da2899SCharles.Forsyth
170137da2899SCharles.Forsyth static char*
tktsetscroll(Tk * tk,int orient)170237da2899SCharles.Forsyth tktsetscroll(Tk *tk, int orient)
170337da2899SCharles.Forsyth {
170437da2899SCharles.Forsyth TkText *tkt;
170537da2899SCharles.Forsyth TkTline *l;
170637da2899SCharles.Forsyth int ntot, nmin, nmax, top, bot, vw, vh;
170737da2899SCharles.Forsyth char *val, *cmd, *v, *e, *s;
170837da2899SCharles.Forsyth
170937da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
171037da2899SCharles.Forsyth
171137da2899SCharles.Forsyth s = (orient == Tkvertical)? tkt->yscroll : tkt->xscroll;
171237da2899SCharles.Forsyth if(s == nil)
171337da2899SCharles.Forsyth return nil;
171437da2899SCharles.Forsyth
171537da2899SCharles.Forsyth vw = tk->act.width - tk->ipad.x;
171637da2899SCharles.Forsyth vh = tk->act.height - tk->ipad.y;
171737da2899SCharles.Forsyth
171837da2899SCharles.Forsyth if(orient == Tkvertical) {
171937da2899SCharles.Forsyth l = tkt->end.prev;
172037da2899SCharles.Forsyth ntot = l->orig.y + l->height;
172137da2899SCharles.Forsyth nmin = tkt->deltatv.y;
172237da2899SCharles.Forsyth if(vh <= 0)
172337da2899SCharles.Forsyth nmax = nmin;
172437da2899SCharles.Forsyth else
172537da2899SCharles.Forsyth nmax = nmin + vh;
172637da2899SCharles.Forsyth }
172737da2899SCharles.Forsyth else {
172837da2899SCharles.Forsyth ntot = tktmaxwid(tkt->start.next);
172937da2899SCharles.Forsyth nmin = tkt->deltatv.x;
173037da2899SCharles.Forsyth if(vw <= 0)
173137da2899SCharles.Forsyth nmax = nmin;
173237da2899SCharles.Forsyth else
173337da2899SCharles.Forsyth nmax = nmin + vw;
173437da2899SCharles.Forsyth }
173537da2899SCharles.Forsyth
173637da2899SCharles.Forsyth if(ntot == 0) {
173737da2899SCharles.Forsyth top = 0;
173837da2899SCharles.Forsyth bot = TKI2F(1);
173937da2899SCharles.Forsyth }
174037da2899SCharles.Forsyth else {
174137da2899SCharles.Forsyth if(ntot < nmax)
174237da2899SCharles.Forsyth ntot = nmax;
174337da2899SCharles.Forsyth top = TKI2F(nmin)/ntot;
174437da2899SCharles.Forsyth bot = TKI2F(nmax)/ntot;
174537da2899SCharles.Forsyth }
174637da2899SCharles.Forsyth
174737da2899SCharles.Forsyth if(tkt->scrolltop[orient] == top && tkt->scrollbot[orient] == bot)
174837da2899SCharles.Forsyth return nil;
174937da2899SCharles.Forsyth
175037da2899SCharles.Forsyth tkt->scrolltop[orient] = top;
175137da2899SCharles.Forsyth tkt->scrollbot[orient] = bot;
175237da2899SCharles.Forsyth
175337da2899SCharles.Forsyth val = mallocz(Tkminitem, 0);
175437da2899SCharles.Forsyth if(val == nil)
175537da2899SCharles.Forsyth return TkNomem;
175637da2899SCharles.Forsyth cmd = mallocz(Tkmaxitem, 0);
175737da2899SCharles.Forsyth if(cmd == nil) {
175837da2899SCharles.Forsyth free(val);
175937da2899SCharles.Forsyth return TkNomem;
176037da2899SCharles.Forsyth }
176137da2899SCharles.Forsyth
176237da2899SCharles.Forsyth v = tkfprint(val, top);
176337da2899SCharles.Forsyth *v++ = ' ';
176437da2899SCharles.Forsyth tkfprint(v, bot);
176537da2899SCharles.Forsyth snprint(cmd, Tkmaxitem, "%s %s", s, val);
176637da2899SCharles.Forsyth e = tkexec(tk->env->top, cmd, nil);
176737da2899SCharles.Forsyth free(cmd);
176837da2899SCharles.Forsyth free(val);
176937da2899SCharles.Forsyth return e;
177037da2899SCharles.Forsyth }
177137da2899SCharles.Forsyth
177237da2899SCharles.Forsyth static char*
tktview(Tk * tk,char * arg,char ** val,int nl,int * posn,int max,int orient)177337da2899SCharles.Forsyth tktview(Tk *tk, char *arg, char **val, int nl, int *posn, int max, int orient)
177437da2899SCharles.Forsyth {
177537da2899SCharles.Forsyth int top, bot, amount, n;
177637da2899SCharles.Forsyth char buf[Tkminitem], *v, *e;
177737da2899SCharles.Forsyth
177837da2899SCharles.Forsyth if(*arg == '\0') {
177937da2899SCharles.Forsyth if ( max == 0 ) {
178037da2899SCharles.Forsyth top = 0;
178137da2899SCharles.Forsyth bot = TKI2F(1);
178237da2899SCharles.Forsyth }
178337da2899SCharles.Forsyth else {
178437da2899SCharles.Forsyth top = TKI2F(*posn)/max;
178537da2899SCharles.Forsyth bot = TKI2F(*posn+nl)/max;
178637da2899SCharles.Forsyth if (bot > TKI2F(1))
178737da2899SCharles.Forsyth bot = TKI2F(1);
178837da2899SCharles.Forsyth }
178937da2899SCharles.Forsyth v = tkfprint(buf, top);
179037da2899SCharles.Forsyth *v++ = ' ';
179137da2899SCharles.Forsyth tkfprint(v, bot);
179237da2899SCharles.Forsyth return tkvalue(val, "%s", buf);
179337da2899SCharles.Forsyth }
179437da2899SCharles.Forsyth
179537da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
179637da2899SCharles.Forsyth if(strcmp(buf, "moveto") == 0) {
179737da2899SCharles.Forsyth e = tkfracword(tk->env->top, &arg, &top, nil);
179837da2899SCharles.Forsyth if (e != nil)
179937da2899SCharles.Forsyth return e;
180037da2899SCharles.Forsyth *posn = TKF2I(top*max);
180137da2899SCharles.Forsyth }
180237da2899SCharles.Forsyth else
180337da2899SCharles.Forsyth if(strcmp(buf, "scroll") == 0) {
18046e425a9dSCharles.Forsyth e = tkfracword(tk->env->top, &arg, &amount, nil);
18056e425a9dSCharles.Forsyth if(e != nil)
18066e425a9dSCharles.Forsyth return e;
180737da2899SCharles.Forsyth arg = tkskip(arg, " \t");
180837da2899SCharles.Forsyth if(*arg == 'p') /* Pages */
180937da2899SCharles.Forsyth amount *= nl;
181037da2899SCharles.Forsyth else /* Lines or Characters */
181137da2899SCharles.Forsyth if(orient == Tkvertical) {
181237da2899SCharles.Forsyth /* XXX needs improvement */
181337da2899SCharles.Forsyth amount *= tk->env->font->height;
181437da2899SCharles.Forsyth }
181537da2899SCharles.Forsyth else
181637da2899SCharles.Forsyth amount *= tk->env->wzero;
18176e425a9dSCharles.Forsyth amount = TKF2I(amount);
181837da2899SCharles.Forsyth n = *posn + amount;
181937da2899SCharles.Forsyth if(n < 0)
182037da2899SCharles.Forsyth n = 0;
182137da2899SCharles.Forsyth if(n > max)
182237da2899SCharles.Forsyth n = max;
182337da2899SCharles.Forsyth *posn = n;
182437da2899SCharles.Forsyth }
182537da2899SCharles.Forsyth else
182637da2899SCharles.Forsyth return TkBadcm;
182737da2899SCharles.Forsyth
182837da2899SCharles.Forsyth bot = max - (nl * 3 / 4);
182937da2899SCharles.Forsyth if(*posn > bot)
183037da2899SCharles.Forsyth *posn = bot;
183137da2899SCharles.Forsyth if(*posn < 0)
183237da2899SCharles.Forsyth *posn = 0;
183337da2899SCharles.Forsyth
183437da2899SCharles.Forsyth return nil;
183537da2899SCharles.Forsyth }
183637da2899SCharles.Forsyth
183737da2899SCharles.Forsyth static void
tktclearsel(Tk * tk)183837da2899SCharles.Forsyth tktclearsel(Tk *tk)
183937da2899SCharles.Forsyth {
184037da2899SCharles.Forsyth TkTindex ibeg, iend;
184137da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
184237da2899SCharles.Forsyth
184337da2899SCharles.Forsyth if(tkt->selfirst == nil)
184437da2899SCharles.Forsyth return;
184537da2899SCharles.Forsyth tktitemind(tkt->selfirst, &ibeg);
184637da2899SCharles.Forsyth tktitemind(tkt->sellast, &iend);
184737da2899SCharles.Forsyth
184837da2899SCharles.Forsyth tkttagchange(tk, TkTselid, &ibeg, &iend, 0);
184937da2899SCharles.Forsyth }
185037da2899SCharles.Forsyth
185137da2899SCharles.Forsyth static int
tktgetsel(Tk * tk,TkTindex * i1,TkTindex * i2)185237da2899SCharles.Forsyth tktgetsel(Tk *tk, TkTindex *i1, TkTindex *i2)
185337da2899SCharles.Forsyth {
185437da2899SCharles.Forsyth TkText *tkt =TKobj(TkText, tk);
185537da2899SCharles.Forsyth
185637da2899SCharles.Forsyth if(tkt->selfirst == nil)
185737da2899SCharles.Forsyth return 0;
185837da2899SCharles.Forsyth tktitemind(tkt->selfirst, i1);
185937da2899SCharles.Forsyth tktitemind(tkt->sellast, i2);
186037da2899SCharles.Forsyth return 1;
186137da2899SCharles.Forsyth }
186237da2899SCharles.Forsyth
186337da2899SCharles.Forsyth /*
186437da2899SCharles.Forsyth * Adjust tkt->deltatv so that indexed character is visible.
186537da2899SCharles.Forsyth * - if seetop is true, make indexed char be at top of window
186637da2899SCharles.Forsyth * - if it is already visible, do nothing.
186737da2899SCharles.Forsyth * - if it is > 1/2 screenful off edge of screen, center it
186837da2899SCharles.Forsyth * else put it at bottom or top (whichever is nearer)
186937da2899SCharles.Forsyth * - if first line is visible, put it at top
187037da2899SCharles.Forsyth * - if last line is visible, allow one blank line at bottom
187137da2899SCharles.Forsyth *
187237da2899SCharles.Forsyth * BUG: should handle x visibility too
187337da2899SCharles.Forsyth */
187437da2899SCharles.Forsyth static void
tktsee(Tk * tk,TkTindex * ixp,int seetop)187537da2899SCharles.Forsyth tktsee(Tk *tk, TkTindex *ixp, int seetop)
187637da2899SCharles.Forsyth {
187737da2899SCharles.Forsyth int ycur, ynext, deltatvy, adjy, h;
187837da2899SCharles.Forsyth Point p, odeltatv;
187937da2899SCharles.Forsyth Rectangle bbox;
188037da2899SCharles.Forsyth TkTline *l, *el;
188137da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
188237da2899SCharles.Forsyth TkTindex ix;
188337da2899SCharles.Forsyth
188437da2899SCharles.Forsyth ix = *ixp;
188537da2899SCharles.Forsyth deltatvy = tkt->deltatv.y;
188637da2899SCharles.Forsyth odeltatv = tkt->deltatv;
188737da2899SCharles.Forsyth h = tk->act.height;
188837da2899SCharles.Forsyth
188937da2899SCharles.Forsyth /* find p (in T space): top left of indexed line */
189037da2899SCharles.Forsyth l = ix.line;
189137da2899SCharles.Forsyth p = l->orig;
189237da2899SCharles.Forsyth
189337da2899SCharles.Forsyth /* ycur, ynext in V space */
189437da2899SCharles.Forsyth ycur = p.y - deltatvy;
189537da2899SCharles.Forsyth ynext = ycur + l->height;
189637da2899SCharles.Forsyth adjy = 0;
189737da2899SCharles.Forsyth
189837da2899SCharles.Forsyth /* quantize h to line boundaries (works if single font) */
189937da2899SCharles.Forsyth if ( l->height )
190037da2899SCharles.Forsyth h -= h%l->height;
190137da2899SCharles.Forsyth
190237da2899SCharles.Forsyth if(seetop) {
190337da2899SCharles.Forsyth deltatvy = p.y;
190437da2899SCharles.Forsyth adjy = 1;
190537da2899SCharles.Forsyth }
190637da2899SCharles.Forsyth else
190737da2899SCharles.Forsyth if(ycur < 0 || ynext >= h) {
190837da2899SCharles.Forsyth adjy = 1;
190937da2899SCharles.Forsyth
191037da2899SCharles.Forsyth if(ycur < -h/2 || ycur > 3*h/2)
191137da2899SCharles.Forsyth deltatvy = p.y - h/2;
191237da2899SCharles.Forsyth else if(ycur < 0)
191337da2899SCharles.Forsyth deltatvy = p.y;
191437da2899SCharles.Forsyth else
191537da2899SCharles.Forsyth deltatvy = p.y - h + l->height;
191637da2899SCharles.Forsyth
191737da2899SCharles.Forsyth el = tkt->end.prev;
191837da2899SCharles.Forsyth if(el != nil && el->orig.y - deltatvy < h)
191937da2899SCharles.Forsyth deltatvy = tkt->end.orig.y - (h * 3 / 4);
192037da2899SCharles.Forsyth
192137da2899SCharles.Forsyth if(p.y - deltatvy < 0)
192237da2899SCharles.Forsyth deltatvy = p.y;
192337da2899SCharles.Forsyth if(deltatvy < 0)
192437da2899SCharles.Forsyth deltatvy = 0;
192537da2899SCharles.Forsyth }
192637da2899SCharles.Forsyth if(adjy) {
192737da2899SCharles.Forsyth tkt->deltatv.y = deltatvy;
192837da2899SCharles.Forsyth tktsetscroll(tk, Tkvertical); /* XXX - Tad: err ignored */
192937da2899SCharles.Forsyth tktfixscroll(tk, odeltatv);
193037da2899SCharles.Forsyth }
193137da2899SCharles.Forsyth while (ix.item->kind == TkTmark)
193237da2899SCharles.Forsyth ix.item = ix.item->next;
193337da2899SCharles.Forsyth bbox = tktbbox(tk, &ix);
193437da2899SCharles.Forsyth /* make sure that cursor at the end gets shown */
193537da2899SCharles.Forsyth tksee(tk, bbox, Pt(bbox.min.x, (bbox.min.y + bbox.max.y) / 2));
193637da2899SCharles.Forsyth }
193737da2899SCharles.Forsyth
193837da2899SCharles.Forsyth static int
tktcmatch(int c1,int c2,int nocase)193937da2899SCharles.Forsyth tktcmatch(int c1, int c2, int nocase)
194037da2899SCharles.Forsyth {
194137da2899SCharles.Forsyth if(nocase) {
194237da2899SCharles.Forsyth if(c1 >= 'a' && c1 <= 'z')
194337da2899SCharles.Forsyth c1 -= 'a' - 'A';
194437da2899SCharles.Forsyth if(c2 >= 'a' && c2 <= 'z')
194537da2899SCharles.Forsyth c2 -= 'a' - 'A';
194637da2899SCharles.Forsyth }
194737da2899SCharles.Forsyth return (c1 == c2);
194837da2899SCharles.Forsyth }
194937da2899SCharles.Forsyth
195037da2899SCharles.Forsyth /*
195137da2899SCharles.Forsyth * Return 1 if tag with id m1 ends before tag with id m2,
195237da2899SCharles.Forsyth * starting at the item after that indexed in ix (but don't
195337da2899SCharles.Forsyth * modify ix).
195437da2899SCharles.Forsyth */
195537da2899SCharles.Forsyth static int
tagendsbefore(TkText * tkt,TkTindex * ix,int m1,int m2)195637da2899SCharles.Forsyth tagendsbefore(TkText *tkt, TkTindex *ix, int m1, int m2)
195737da2899SCharles.Forsyth {
195837da2899SCharles.Forsyth int s1, s2;
195937da2899SCharles.Forsyth TkTindex ix1;
196037da2899SCharles.Forsyth TkTitem *i;
196137da2899SCharles.Forsyth
196237da2899SCharles.Forsyth ix1 = *ix;
196337da2899SCharles.Forsyth while(tktadjustind(tkt, TkTbyitem, &ix1)) {
196437da2899SCharles.Forsyth i = ix1.item;
196537da2899SCharles.Forsyth if(i->kind == TkTwin || i->kind == TkTcontline || i->kind == TkTmark)
196637da2899SCharles.Forsyth continue;
196737da2899SCharles.Forsyth s1 = tkttagset(i, m1);
196837da2899SCharles.Forsyth s2 = tkttagset(i, m2);
196937da2899SCharles.Forsyth if(!s1)
197037da2899SCharles.Forsyth return s2;
197137da2899SCharles.Forsyth else if(!s2)
197237da2899SCharles.Forsyth return 0;
197337da2899SCharles.Forsyth }
197437da2899SCharles.Forsyth return 0;
197537da2899SCharles.Forsyth }
197637da2899SCharles.Forsyth
197737da2899SCharles.Forsyth static int
tktsgmltags(TkText * tkt,Fmt * fmt,TkTitem * iprev,TkTitem * i,TkTindex * ix,int * stack,int * pnstack,int * tmpstack)197837da2899SCharles.Forsyth tktsgmltags(TkText *tkt, Fmt *fmt, TkTitem *iprev, TkTitem *i, TkTindex *ix, int *stack, int *pnstack, int *tmpstack)
197937da2899SCharles.Forsyth {
198037da2899SCharles.Forsyth int nprev, n, m, r, k, j, ii, onstack, nt;
198137da2899SCharles.Forsyth
198237da2899SCharles.Forsyth nprev = 0;
198337da2899SCharles.Forsyth if(iprev != nil && (iprev->tags[0] != 0 || iprev->tagextra > 0))
198437da2899SCharles.Forsyth nprev = 32*(iprev->tagextra + 1);
198537da2899SCharles.Forsyth n = 0;
198637da2899SCharles.Forsyth if(i != nil && (i->tags[0] != 0 || i->tagextra > 0))
198737da2899SCharles.Forsyth n = 32*(i->tagextra + 1);
198837da2899SCharles.Forsyth nt = 0;
198937da2899SCharles.Forsyth if(n > 0) {
199037da2899SCharles.Forsyth /* find tags which open here */
199137da2899SCharles.Forsyth for(m = 0; m < n; m++)
199237da2899SCharles.Forsyth if(tkttagset(i, m) && (iprev == nil || !tkttagset(iprev, m)))
199337da2899SCharles.Forsyth tmpstack[nt++] = m;
199437da2899SCharles.Forsyth }
199537da2899SCharles.Forsyth if(nprev > 0) {
199637da2899SCharles.Forsyth /*
199737da2899SCharles.Forsyth * Find lowest tag in stack that ends before any tag beginning here.
199837da2899SCharles.Forsyth * We have to emit end tags all the way down to there, then add
199937da2899SCharles.Forsyth * back the ones that haven't actually ended here, together with ones
200037da2899SCharles.Forsyth * that start here, and sort all of the added ones so that tags that
200137da2899SCharles.Forsyth * end later are lower in the stack.
200237da2899SCharles.Forsyth */
200337da2899SCharles.Forsyth ii = *pnstack;
200437da2899SCharles.Forsyth for(k = *pnstack - 1; k >=0; k--) {
200537da2899SCharles.Forsyth m = stack[k];
200637da2899SCharles.Forsyth if(i == nil || !tkttagset(i, m))
200737da2899SCharles.Forsyth ii = k;
200837da2899SCharles.Forsyth else
200937da2899SCharles.Forsyth for(j = 0; j < nt; j++)
201037da2899SCharles.Forsyth if(tagendsbefore(tkt, ix, m, tmpstack[j]))
201137da2899SCharles.Forsyth ii = k;
201237da2899SCharles.Forsyth }
201337da2899SCharles.Forsyth for(k = *pnstack - 1; k >= ii; k--) {
201437da2899SCharles.Forsyth m = stack[k];
201537da2899SCharles.Forsyth r = fmtprint(fmt, "</%s>", tkttagname(tkt, m));
201637da2899SCharles.Forsyth if(r < 0)
201737da2899SCharles.Forsyth return r;
201837da2899SCharles.Forsyth /* add m back to starting tags if m didn't actually end here */
201937da2899SCharles.Forsyth if(i != nil && tkttagset(i, m))
202037da2899SCharles.Forsyth tmpstack[nt++] = m;
202137da2899SCharles.Forsyth }
202237da2899SCharles.Forsyth *pnstack = ii;
202337da2899SCharles.Forsyth }
202437da2899SCharles.Forsyth if(nt > 0) {
202537da2899SCharles.Forsyth /* add tags which open or reopen here */
202637da2899SCharles.Forsyth onstack = *pnstack;
202737da2899SCharles.Forsyth k = onstack;
202837da2899SCharles.Forsyth for(j = 0; j < nt; j++)
202937da2899SCharles.Forsyth stack[k++] = tmpstack[j];
203037da2899SCharles.Forsyth *pnstack = k;
203137da2899SCharles.Forsyth if(k - onstack > 1) {
203237da2899SCharles.Forsyth /* sort new stack entries so tags that end later are lower in stack */
203337da2899SCharles.Forsyth for(ii = k-2; ii>= onstack; ii--) {
203437da2899SCharles.Forsyth m = stack[ii];
203537da2899SCharles.Forsyth for(j = ii+1; j < k && tagendsbefore(tkt, ix, m, stack[j]); j++) {
203637da2899SCharles.Forsyth stack[j-1] = stack[j];
203737da2899SCharles.Forsyth }
203837da2899SCharles.Forsyth stack[j-1] = m;
203937da2899SCharles.Forsyth }
204037da2899SCharles.Forsyth }
204137da2899SCharles.Forsyth for(j = onstack; j < k; j++) {
204237da2899SCharles.Forsyth r = fmtprint(fmt, "<%s>", tkttagname(tkt, stack[j]));
204337da2899SCharles.Forsyth if(r < 0)
204437da2899SCharles.Forsyth return r;
204537da2899SCharles.Forsyth }
204637da2899SCharles.Forsyth }
204737da2899SCharles.Forsyth return 0;
204837da2899SCharles.Forsyth }
204937da2899SCharles.Forsyth
205037da2899SCharles.Forsyth /*
205137da2899SCharles.Forsyth * In 'sgml' format, just print text (no special treatment of
205237da2899SCharles.Forsyth * special characters, except that < turns into <)
205337da2899SCharles.Forsyth * interspersed with things like <Bold> and </Bold>
205437da2899SCharles.Forsyth * (where Bold is a tag name).
205537da2899SCharles.Forsyth * Make sure that the tag pairs nest properly.
205637da2899SCharles.Forsyth */
205737da2899SCharles.Forsyth static char*
tktget(TkText * tkt,TkTindex * ix1,TkTindex * ix2,int sgml,char ** val)205837da2899SCharles.Forsyth tktget(TkText *tkt, TkTindex *ix1, TkTindex *ix2, int sgml, char **val)
205937da2899SCharles.Forsyth {
206037da2899SCharles.Forsyth int n, m, i, bychar, nstack;
206137da2899SCharles.Forsyth int *stack, *tmpstack;
206237da2899SCharles.Forsyth char *s;
206337da2899SCharles.Forsyth TkTitem *iprev;
206437da2899SCharles.Forsyth Tk *sub;
206537da2899SCharles.Forsyth Fmt fmt;
206637da2899SCharles.Forsyth char *buf;
206737da2899SCharles.Forsyth
206837da2899SCharles.Forsyth if(!tktindbefore(ix1, ix2))
206937da2899SCharles.Forsyth return nil;
207037da2899SCharles.Forsyth
207137da2899SCharles.Forsyth stack = nil;
207237da2899SCharles.Forsyth tmpstack = nil;
207337da2899SCharles.Forsyth
207437da2899SCharles.Forsyth iprev = nil;
207537da2899SCharles.Forsyth fmtstrinit(&fmt);
207637da2899SCharles.Forsyth buf = mallocz(100, 0);
207737da2899SCharles.Forsyth if(buf == nil)
207837da2899SCharles.Forsyth return TkNomem;
207937da2899SCharles.Forsyth if(sgml) {
208037da2899SCharles.Forsyth stack = malloc((tkt->nexttag+1)*sizeof(int));
208137da2899SCharles.Forsyth tmpstack = malloc((tkt->nexttag+1)*sizeof(int));
208237da2899SCharles.Forsyth if(stack == nil || tmpstack == nil)
208337da2899SCharles.Forsyth goto nomemret;
208437da2899SCharles.Forsyth nstack = 0;
208537da2899SCharles.Forsyth }
208637da2899SCharles.Forsyth for(;;) {
208737da2899SCharles.Forsyth if(ix1->item == ix2->item && ix1->pos == ix2->pos)
208837da2899SCharles.Forsyth break;
208937da2899SCharles.Forsyth s = nil;
209037da2899SCharles.Forsyth bychar = 0;
209137da2899SCharles.Forsyth m = 1;
209237da2899SCharles.Forsyth switch(ix1->item->kind) {
209337da2899SCharles.Forsyth case TkTrune:
209437da2899SCharles.Forsyth s = ix1->item->istring;
209537da2899SCharles.Forsyth s += tktutfpos(s, ix1->pos);
209637da2899SCharles.Forsyth if(ix1->item == ix2->item) {
209737da2899SCharles.Forsyth m = ix2->pos - ix1->pos;
209837da2899SCharles.Forsyth bychar = 1;
209937da2899SCharles.Forsyth }
210037da2899SCharles.Forsyth break;
210137da2899SCharles.Forsyth case TkTascii:
210237da2899SCharles.Forsyth s = ix1->item->istring + ix1->pos;
210337da2899SCharles.Forsyth if(ix1->item == ix2->item) {
210437da2899SCharles.Forsyth m = ix2->pos - ix1->pos;
210537da2899SCharles.Forsyth bychar = 1;
210637da2899SCharles.Forsyth }
210737da2899SCharles.Forsyth else {
210837da2899SCharles.Forsyth m = strlen(s);
210937da2899SCharles.Forsyth if(sgml && memchr(s, '<', m) != nil)
211037da2899SCharles.Forsyth bychar = 1;
211137da2899SCharles.Forsyth }
211237da2899SCharles.Forsyth break;
211337da2899SCharles.Forsyth case TkTtab:
211437da2899SCharles.Forsyth s = "\t";
211537da2899SCharles.Forsyth break;
211637da2899SCharles.Forsyth case TkTnewline:
211737da2899SCharles.Forsyth s = "\n";
211837da2899SCharles.Forsyth break;
211937da2899SCharles.Forsyth case TkTwin:
212037da2899SCharles.Forsyth sub = ix1->item->iwin->sub;
212137da2899SCharles.Forsyth if(sgml && sub != nil && sub->name != nil) {
212237da2899SCharles.Forsyth snprint(buf, 100, "<Window %s>", sub->name->name);
212337da2899SCharles.Forsyth s = buf;
212437da2899SCharles.Forsyth }
212537da2899SCharles.Forsyth }
212637da2899SCharles.Forsyth if(s != nil) {
212737da2899SCharles.Forsyth if(sgml) {
212837da2899SCharles.Forsyth n = tktsgmltags(tkt, &fmt, iprev, ix1->item, ix1, stack, &nstack, tmpstack);
212937da2899SCharles.Forsyth if(n < 0)
213037da2899SCharles.Forsyth goto nomemret;
213137da2899SCharles.Forsyth }
213237da2899SCharles.Forsyth if(bychar) {
213337da2899SCharles.Forsyth if (ix1->item->kind == TkTrune)
213437da2899SCharles.Forsyth n = fmtprint(&fmt, "%.*s", m, s);
213537da2899SCharles.Forsyth else {
213637da2899SCharles.Forsyth n = 0;
213737da2899SCharles.Forsyth for(i = 0; i < m && n >= 0; i++) {
213837da2899SCharles.Forsyth if(s[i] == '<')
213937da2899SCharles.Forsyth n = fmtprint(&fmt, "<");
214037da2899SCharles.Forsyth else
214137da2899SCharles.Forsyth n = fmtprint(&fmt, "%c", s[i]);
214237da2899SCharles.Forsyth }
214337da2899SCharles.Forsyth }
214437da2899SCharles.Forsyth }
214537da2899SCharles.Forsyth else
214637da2899SCharles.Forsyth n = fmtprint(&fmt, "%s", s);
214737da2899SCharles.Forsyth if(n < 0)
214837da2899SCharles.Forsyth goto nomemret;
214937da2899SCharles.Forsyth iprev = ix1->item;
215037da2899SCharles.Forsyth }
215137da2899SCharles.Forsyth if(ix1->item == ix2->item)
215237da2899SCharles.Forsyth break;
215337da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, ix1)) {
215437da2899SCharles.Forsyth if(tktdbg)
215537da2899SCharles.Forsyth print("tktextget botch\n");
215637da2899SCharles.Forsyth break;
215737da2899SCharles.Forsyth }
215837da2899SCharles.Forsyth }
215937da2899SCharles.Forsyth if(sgml) {
216037da2899SCharles.Forsyth n = tktsgmltags(tkt, &fmt, iprev, nil, nil, stack, &nstack, tmpstack);
216137da2899SCharles.Forsyth if(n < 0)
216237da2899SCharles.Forsyth goto nomemret;
216337da2899SCharles.Forsyth }
216437da2899SCharles.Forsyth
216537da2899SCharles.Forsyth *val = fmtstrflush(&fmt);
216637da2899SCharles.Forsyth free(buf);
216737da2899SCharles.Forsyth return nil;
216837da2899SCharles.Forsyth
216937da2899SCharles.Forsyth nomemret:
217037da2899SCharles.Forsyth free(buf);
217137da2899SCharles.Forsyth if(stack != nil)
217237da2899SCharles.Forsyth free(stack);
217337da2899SCharles.Forsyth if(tmpstack != nil)
217437da2899SCharles.Forsyth free(tmpstack);
217537da2899SCharles.Forsyth return TkNomem;
217637da2899SCharles.Forsyth }
217737da2899SCharles.Forsyth
217837da2899SCharles.Forsyth /* Widget Commands (+ means implemented)
217937da2899SCharles.Forsyth +bbox
218037da2899SCharles.Forsyth +cget
218137da2899SCharles.Forsyth +compare
218237da2899SCharles.Forsyth +configure
218337da2899SCharles.Forsyth +debug
218437da2899SCharles.Forsyth +delete
218537da2899SCharles.Forsyth +dlineinfo
218637da2899SCharles.Forsyth +dump
218737da2899SCharles.Forsyth +get
218837da2899SCharles.Forsyth +index
218937da2899SCharles.Forsyth +insert
219037da2899SCharles.Forsyth +mark
219137da2899SCharles.Forsyth +scan
219237da2899SCharles.Forsyth +search
219337da2899SCharles.Forsyth +see
219437da2899SCharles.Forsyth +tag
219537da2899SCharles.Forsyth +window
219637da2899SCharles.Forsyth +xview
219737da2899SCharles.Forsyth +yview
219837da2899SCharles.Forsyth */
219937da2899SCharles.Forsyth
220037da2899SCharles.Forsyth static int
220137da2899SCharles.Forsyth tktviewrectclip(Rectangle *r, Rectangle b);
220237da2899SCharles.Forsyth
220337da2899SCharles.Forsyth static char*
tktextbbox(Tk * tk,char * arg,char ** val)220437da2899SCharles.Forsyth tktextbbox(Tk *tk, char *arg, char **val)
220537da2899SCharles.Forsyth {
220637da2899SCharles.Forsyth char *e;
220737da2899SCharles.Forsyth int noclip, w, h;
220837da2899SCharles.Forsyth Rectangle r, rview;
220937da2899SCharles.Forsyth TkTindex ix;
221037da2899SCharles.Forsyth TkText *tkt;
221137da2899SCharles.Forsyth char buf[Tkmaxitem];
221237da2899SCharles.Forsyth
221337da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix);
221437da2899SCharles.Forsyth if(e != nil)
221537da2899SCharles.Forsyth return e;
221637da2899SCharles.Forsyth
221737da2899SCharles.Forsyth noclip = 0;
221837da2899SCharles.Forsyth if(*arg != '\0') {
221937da2899SCharles.Forsyth /* extension to tk4.0:
222037da2899SCharles.Forsyth * "noclip" means don't clip to viewable area
222137da2899SCharles.Forsyth * "all" means give unclipped bbox of entire contents
222237da2899SCharles.Forsyth */
222337da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
222437da2899SCharles.Forsyth if(strcmp(buf, "noclip") == 0)
222537da2899SCharles.Forsyth noclip = 1;
222637da2899SCharles.Forsyth else
222737da2899SCharles.Forsyth if(strcmp(buf, "all") == 0) {
222837da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
222937da2899SCharles.Forsyth w = tktmaxwid(tkt->start.next);
223037da2899SCharles.Forsyth h = tkt->end.orig.y;
223137da2899SCharles.Forsyth return tkvalue(val, "0 0 %d %d", w, h);
223237da2899SCharles.Forsyth }
223337da2899SCharles.Forsyth }
223437da2899SCharles.Forsyth
223537da2899SCharles.Forsyth /*
223637da2899SCharles.Forsyth * skip marks; bbox applies to characters only.
223737da2899SCharles.Forsyth * it's not defined what happens when bbox is applied to a newline char,
223837da2899SCharles.Forsyth * so we'll just let the default case sort that out.
223937da2899SCharles.Forsyth */
224037da2899SCharles.Forsyth while (ix.item->kind == TkTmark)
224137da2899SCharles.Forsyth ix.item = ix.item->next;
224237da2899SCharles.Forsyth r = tktbbox(tk, &ix);
224337da2899SCharles.Forsyth
224437da2899SCharles.Forsyth rview.min.x = 0;
224537da2899SCharles.Forsyth rview.min.y = 0;
224637da2899SCharles.Forsyth rview.max.x = tk->act.width - tk->ipad.x;
224737da2899SCharles.Forsyth rview.max.y = tk->act.height - tk->ipad.y;
224837da2899SCharles.Forsyth if(noclip || tktviewrectclip(&r, rview))
224937da2899SCharles.Forsyth return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y,
225037da2899SCharles.Forsyth r.max.x-r.min.x, r.max.y-r.min.y);
225137da2899SCharles.Forsyth return nil;
225237da2899SCharles.Forsyth }
225337da2899SCharles.Forsyth
225437da2899SCharles.Forsyth /*
225537da2899SCharles.Forsyth * a supplemented rectclip, as ((0, 1), (0,1)) does not intersect ((0, 0), (5, 5))
225637da2899SCharles.Forsyth * but for our purposes, we want it to. it's a hack.
225737da2899SCharles.Forsyth */
225837da2899SCharles.Forsyth static int
tktviewrectclip(Rectangle * rp,Rectangle b)225937da2899SCharles.Forsyth tktviewrectclip(Rectangle *rp, Rectangle b)
226037da2899SCharles.Forsyth {
226137da2899SCharles.Forsyth Rectangle *bp = &b;
226237da2899SCharles.Forsyth if((rp->min.x<bp->max.x &&
226337da2899SCharles.Forsyth (bp->min.x<rp->max.x || (rp->max.x == b.min.x
226437da2899SCharles.Forsyth && rp->min.x == b.min.x)) &&
226537da2899SCharles.Forsyth rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0)
226637da2899SCharles.Forsyth return 0;
226737da2899SCharles.Forsyth /* They must overlap */
226837da2899SCharles.Forsyth if(rp->min.x < bp->min.x)
226937da2899SCharles.Forsyth rp->min.x = bp->min.x;
227037da2899SCharles.Forsyth if(rp->min.y < bp->min.y)
227137da2899SCharles.Forsyth rp->min.y = bp->min.y;
227237da2899SCharles.Forsyth if(rp->max.x > bp->max.x)
227337da2899SCharles.Forsyth rp->max.x = bp->max.x;
227437da2899SCharles.Forsyth if(rp->max.y > bp->max.y)
227537da2899SCharles.Forsyth rp->max.y = bp->max.y;
227637da2899SCharles.Forsyth return 1;
227737da2899SCharles.Forsyth }
227837da2899SCharles.Forsyth
227937da2899SCharles.Forsyth static Point
scr2local(Tk * tk,Point p)228037da2899SCharles.Forsyth scr2local(Tk *tk, Point p)
228137da2899SCharles.Forsyth {
228237da2899SCharles.Forsyth p = subpt(p, tkposn(tk));
228337da2899SCharles.Forsyth p.x -= tk->borderwidth;
228437da2899SCharles.Forsyth p.y -= tk->borderwidth;
228537da2899SCharles.Forsyth return p;
228637da2899SCharles.Forsyth }
228737da2899SCharles.Forsyth
228837da2899SCharles.Forsyth static char*
tktextbutton1(Tk * tk,char * arg,char ** val)228937da2899SCharles.Forsyth tktextbutton1(Tk *tk, char *arg, char **val)
229037da2899SCharles.Forsyth {
229137da2899SCharles.Forsyth char *e;
229237da2899SCharles.Forsyth Point p;
229337da2899SCharles.Forsyth TkCtxt *c;
229437da2899SCharles.Forsyth TkTindex ix;
229537da2899SCharles.Forsyth TkTmarkinfo *mi;
229637da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
229737da2899SCharles.Forsyth
229837da2899SCharles.Forsyth USED(val);
229937da2899SCharles.Forsyth
230037da2899SCharles.Forsyth e = tkxyparse(tk, &arg, &p);
230137da2899SCharles.Forsyth if(e != nil)
230237da2899SCharles.Forsyth return e;
230337da2899SCharles.Forsyth tkt->track = p;
230437da2899SCharles.Forsyth p = scr2local(tk, p);
230537da2899SCharles.Forsyth
230637da2899SCharles.Forsyth tktxyind(tk, p.x, p.y, &ix);
230737da2899SCharles.Forsyth tkt->tflag &= ~TkTjustfoc;
230837da2899SCharles.Forsyth c = tk->env->top->ctxt;
230937da2899SCharles.Forsyth if(!(tk->flag&Tkdisabled) && c->tkkeygrab != tk
231037da2899SCharles.Forsyth && (tk->name != nil) && ix.item->kind != TkTwin) {
231137da2899SCharles.Forsyth tkfocus(tk->env->top, tk->name->name, nil);
231237da2899SCharles.Forsyth tkt->tflag |= TkTjustfoc;
231337da2899SCharles.Forsyth return nil;
231437da2899SCharles.Forsyth }
231537da2899SCharles.Forsyth
231637da2899SCharles.Forsyth mi = tktfindmark(tkt->marks, "insert");
231737da2899SCharles.Forsyth if(tktdbg && !mi) {
231837da2899SCharles.Forsyth print("tktextbutton1: botch\n");
231937da2899SCharles.Forsyth return nil;
232037da2899SCharles.Forsyth }
232137da2899SCharles.Forsyth tktmarkmove(tk, mi, &ix);
232237da2899SCharles.Forsyth
232337da2899SCharles.Forsyth tktclearsel(tk);
232437da2899SCharles.Forsyth tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
232537da2899SCharles.Forsyth return nil;
232637da2899SCharles.Forsyth }
232737da2899SCharles.Forsyth
232837da2899SCharles.Forsyth static char*
tktextbutton1r(Tk * tk,char * arg,char ** val)232937da2899SCharles.Forsyth tktextbutton1r(Tk *tk, char *arg, char **val)
233037da2899SCharles.Forsyth {
233137da2899SCharles.Forsyth TkText *tkt;
233237da2899SCharles.Forsyth
233337da2899SCharles.Forsyth USED(arg);
233437da2899SCharles.Forsyth USED(val);
233537da2899SCharles.Forsyth
233637da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
233737da2899SCharles.Forsyth tkt->tflag &= ~TkTnodrag;
233837da2899SCharles.Forsyth tkcancelrepeat(tk);
233937da2899SCharles.Forsyth return nil;
234037da2899SCharles.Forsyth }
234137da2899SCharles.Forsyth
234237da2899SCharles.Forsyth static char*
tktextcget(Tk * tk,char * arg,char ** val)234337da2899SCharles.Forsyth tktextcget(Tk *tk, char *arg, char **val)
234437da2899SCharles.Forsyth {
234537da2899SCharles.Forsyth TkText *tkt;
234637da2899SCharles.Forsyth TkOptab tko[3];
234737da2899SCharles.Forsyth
234837da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
234937da2899SCharles.Forsyth tko[0].ptr = tk;
235037da2899SCharles.Forsyth tko[0].optab = tkgeneric;
235137da2899SCharles.Forsyth tko[1].ptr = tkt;
235237da2899SCharles.Forsyth tko[1].optab = textopts;
235337da2899SCharles.Forsyth tko[2].ptr = nil;
235437da2899SCharles.Forsyth
235537da2899SCharles.Forsyth return tkgencget(tko, arg, val, tk->env->top);
235637da2899SCharles.Forsyth }
235737da2899SCharles.Forsyth
235837da2899SCharles.Forsyth static char*
tktextcompare(Tk * tk,char * arg,char ** val)235937da2899SCharles.Forsyth tktextcompare(Tk *tk, char *arg, char **val)
236037da2899SCharles.Forsyth {
236137da2899SCharles.Forsyth int op;
236237da2899SCharles.Forsyth char *e;
236337da2899SCharles.Forsyth TkTindex i1, i2;
236437da2899SCharles.Forsyth TkText *tkt;
236537da2899SCharles.Forsyth TkStab *s;
236637da2899SCharles.Forsyth char *buf;
236737da2899SCharles.Forsyth
236837da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
236937da2899SCharles.Forsyth
237037da2899SCharles.Forsyth e = tktindparse(tk, &arg, &i1);
237137da2899SCharles.Forsyth if(e != nil)
237237da2899SCharles.Forsyth return e;
237337da2899SCharles.Forsyth
237437da2899SCharles.Forsyth if(*arg == '\0')
237537da2899SCharles.Forsyth return TkBadcm;
237637da2899SCharles.Forsyth
237737da2899SCharles.Forsyth buf = mallocz(Tkmaxitem, 0);
237837da2899SCharles.Forsyth if(buf == nil)
237937da2899SCharles.Forsyth return TkNomem;
238037da2899SCharles.Forsyth
238137da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
238237da2899SCharles.Forsyth
238337da2899SCharles.Forsyth op = -1;
238437da2899SCharles.Forsyth for(s = tkcompare; s->val; s++)
238537da2899SCharles.Forsyth if(strcmp(s->val, buf) == 0) {
238637da2899SCharles.Forsyth op = s->con;
238737da2899SCharles.Forsyth break;
238837da2899SCharles.Forsyth }
238937da2899SCharles.Forsyth if(op == -1) {
239037da2899SCharles.Forsyth free(buf);
239137da2899SCharles.Forsyth return TkBadcm;
239237da2899SCharles.Forsyth }
239337da2899SCharles.Forsyth
239437da2899SCharles.Forsyth e = tktindparse(tk, &arg, &i2);
239537da2899SCharles.Forsyth if(e != nil) {
239637da2899SCharles.Forsyth free(buf);
239737da2899SCharles.Forsyth return e;
239837da2899SCharles.Forsyth }
239937da2899SCharles.Forsyth
240037da2899SCharles.Forsyth e = tkvalue(val, tktindcompare(tkt, &i1, op, &i2)? "1" : "0");
240137da2899SCharles.Forsyth free(buf);
240237da2899SCharles.Forsyth return e;
240337da2899SCharles.Forsyth }
240437da2899SCharles.Forsyth
240537da2899SCharles.Forsyth static char*
tktextconfigure(Tk * tk,char * arg,char ** val)240637da2899SCharles.Forsyth tktextconfigure(Tk *tk, char *arg, char **val)
240737da2899SCharles.Forsyth {
240837da2899SCharles.Forsyth char *e;
240937da2899SCharles.Forsyth TkGeom g;
241037da2899SCharles.Forsyth int bd;
241137da2899SCharles.Forsyth TkText *tkt;
241237da2899SCharles.Forsyth TkOptab tko[3];
241337da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
241437da2899SCharles.Forsyth tko[0].ptr = tk;
241537da2899SCharles.Forsyth tko[0].optab = tkgeneric;
241637da2899SCharles.Forsyth tko[1].ptr = tkt;
241737da2899SCharles.Forsyth tko[1].optab = textopts;
241837da2899SCharles.Forsyth tko[2].ptr = nil;
241937da2899SCharles.Forsyth
242037da2899SCharles.Forsyth if(*arg == '\0')
242137da2899SCharles.Forsyth return tkconflist(tko, val);
242237da2899SCharles.Forsyth
242337da2899SCharles.Forsyth g = tk->req;
242437da2899SCharles.Forsyth bd = tk->borderwidth;
242537da2899SCharles.Forsyth
242637da2899SCharles.Forsyth e = tkparse(tk->env->top, arg, tko, nil);
242737da2899SCharles.Forsyth tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
242837da2899SCharles.Forsyth if (tkt->propagate != BoolT) {
242937da2899SCharles.Forsyth if ((tk->flag & Tksetwidth) == 0)
243037da2899SCharles.Forsyth tk->req.width = tk->env->wzero*Textwidth;
243137da2899SCharles.Forsyth if ((tk->flag & Tksetheight) == 0)
243237da2899SCharles.Forsyth tk->req.height = tk->env->font->height*Textheight;
243337da2899SCharles.Forsyth }
243437da2899SCharles.Forsyth /* note: tkgeomchg() may also call tktfixgeom() via tktextgeom() */
243537da2899SCharles.Forsyth tktfixgeom(tk, &tkt->start, tkt->end.prev, 0);
243637da2899SCharles.Forsyth tktextsize(tk, 0);
243737da2899SCharles.Forsyth tkgeomchg(tk, &g, bd);
243837da2899SCharles.Forsyth tktnotdrawn(tk, 0, tkt->end.orig.y, 1);
243937da2899SCharles.Forsyth
244037da2899SCharles.Forsyth return e;
244137da2899SCharles.Forsyth }
244237da2899SCharles.Forsyth
244337da2899SCharles.Forsyth static char*
tktextdebug(Tk * tk,char * arg,char ** val)244437da2899SCharles.Forsyth tktextdebug(Tk *tk, char *arg, char **val)
244537da2899SCharles.Forsyth {
244637da2899SCharles.Forsyth char buf[Tkmaxitem];
244737da2899SCharles.Forsyth
244837da2899SCharles.Forsyth tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
244937da2899SCharles.Forsyth if(*buf == '\0')
245037da2899SCharles.Forsyth return tkvalue(val, "%s", tktdbg? "on" : "off");
245137da2899SCharles.Forsyth else {
245237da2899SCharles.Forsyth tktdbg = (strcmp(buf, "1") == 0 || strcmp(buf, "yes") == 0);
245337da2899SCharles.Forsyth if(tktdbg) {
245437da2899SCharles.Forsyth tktprinttext(TKobj(TkText, tk));
245537da2899SCharles.Forsyth }
245637da2899SCharles.Forsyth return nil;
245737da2899SCharles.Forsyth }
245837da2899SCharles.Forsyth }
245937da2899SCharles.Forsyth
246037da2899SCharles.Forsyth static char*
tktextdelete(Tk * tk,char * arg,char ** val)246137da2899SCharles.Forsyth tktextdelete(Tk *tk, char *arg, char **val)
246237da2899SCharles.Forsyth {
246337da2899SCharles.Forsyth int sameit;
246437da2899SCharles.Forsyth char *e;
246537da2899SCharles.Forsyth TkTindex i1, i2, ip, isee;
246637da2899SCharles.Forsyth TkTline *lmin;
246737da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
246837da2899SCharles.Forsyth char buf[20], *p;
246937da2899SCharles.Forsyth
247037da2899SCharles.Forsyth USED(val);
247137da2899SCharles.Forsyth
247237da2899SCharles.Forsyth e = tktindparse(tk, &arg, &i1);
247337da2899SCharles.Forsyth if(e != nil)
247437da2899SCharles.Forsyth return e;
247537da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, &i1);
247637da2899SCharles.Forsyth
247737da2899SCharles.Forsyth e = tktsplititem(&i1);
247837da2899SCharles.Forsyth if(e != nil)
247937da2899SCharles.Forsyth return e;
248037da2899SCharles.Forsyth
248137da2899SCharles.Forsyth if(*arg != '\0') {
248237da2899SCharles.Forsyth e = tktindparse(tk, &arg, &i2);
248337da2899SCharles.Forsyth if(e != nil)
248437da2899SCharles.Forsyth return e;
248537da2899SCharles.Forsyth }
248637da2899SCharles.Forsyth else {
248737da2899SCharles.Forsyth i2 = i1;
248837da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &i2);
248937da2899SCharles.Forsyth }
249037da2899SCharles.Forsyth if(tktindcompare(tkt, &i1, TkGte, &i2))
249137da2899SCharles.Forsyth return nil;
249237da2899SCharles.Forsyth
249337da2899SCharles.Forsyth sameit = (i1.item == i2.item);
249437da2899SCharles.Forsyth
249537da2899SCharles.Forsyth /* save possible fixup see place */
249637da2899SCharles.Forsyth isee.line = nil;
249737da2899SCharles.Forsyth if(i2.line->orig.y + i2.line->height < tkt->deltatv.y) {
249837da2899SCharles.Forsyth /* delete completely precedes view */
249937da2899SCharles.Forsyth tktxyind(tk, 0, 0, &isee);
250037da2899SCharles.Forsyth }
250137da2899SCharles.Forsyth
250237da2899SCharles.Forsyth e = tktsplititem(&i2);
250337da2899SCharles.Forsyth if(e != nil)
250437da2899SCharles.Forsyth return e;
250537da2899SCharles.Forsyth
250637da2899SCharles.Forsyth if(sameit) {
250737da2899SCharles.Forsyth /* after split, i1 should be in previous item to i2 */
250837da2899SCharles.Forsyth ip = i2;
250937da2899SCharles.Forsyth tktadjustind(tkt, TkTbyitemback, &ip);
251037da2899SCharles.Forsyth i1.item = ip.item;
251137da2899SCharles.Forsyth }
251237da2899SCharles.Forsyth
251337da2899SCharles.Forsyth lmin = tktprevwrapline(tk, i1.line);
251437da2899SCharles.Forsyth while(i1.item != i2.item) {
251537da2899SCharles.Forsyth if(i1.item->kind != TkTmark)
251637da2899SCharles.Forsyth tktremitem(tkt, &i1);
251737da2899SCharles.Forsyth /* tktremitem moves i1 to next item */
251837da2899SCharles.Forsyth else {
251937da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, &i1)) {
252037da2899SCharles.Forsyth if(tktdbg)
252137da2899SCharles.Forsyth print("tktextdelete botch\n");
252237da2899SCharles.Forsyth break;
252337da2899SCharles.Forsyth }
252437da2899SCharles.Forsyth }
252537da2899SCharles.Forsyth }
252637da2899SCharles.Forsyth
252737da2899SCharles.Forsyth /*
252837da2899SCharles.Forsyth * guard against invalidation of index by tktfixgeom
252937da2899SCharles.Forsyth */
253037da2899SCharles.Forsyth if (isee.line != nil)
253137da2899SCharles.Forsyth snprint(buf, sizeof(buf), "%d.%d", tktlinenum(tkt, &isee), tktlinepos(tkt, &isee));
253237da2899SCharles.Forsyth
253337da2899SCharles.Forsyth tktfixgeom(tk, lmin, i1.line, 0);
253437da2899SCharles.Forsyth tktextsize(tk, 1);
253537da2899SCharles.Forsyth if(isee.line != nil) {
253637da2899SCharles.Forsyth p = buf;
253737da2899SCharles.Forsyth tktindparse(tk, &p, &isee);
253837da2899SCharles.Forsyth tktsee(tk, &isee, 1);
253937da2899SCharles.Forsyth }
254037da2899SCharles.Forsyth return nil;
254137da2899SCharles.Forsyth }
254237da2899SCharles.Forsyth
254337da2899SCharles.Forsyth static char*
tktextsee(Tk * tk,char * arg,char ** val)254437da2899SCharles.Forsyth tktextsee(Tk *tk, char *arg, char **val)
254537da2899SCharles.Forsyth {
254637da2899SCharles.Forsyth char *e;
254737da2899SCharles.Forsyth TkTindex ix;
254837da2899SCharles.Forsyth
254937da2899SCharles.Forsyth USED(val);
255037da2899SCharles.Forsyth
255137da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix);
255237da2899SCharles.Forsyth if(e != nil)
255337da2899SCharles.Forsyth return e;
255437da2899SCharles.Forsyth
255537da2899SCharles.Forsyth tktsee(tk, &ix, 0);
255637da2899SCharles.Forsyth return nil;
255737da2899SCharles.Forsyth }
255837da2899SCharles.Forsyth
255937da2899SCharles.Forsyth static char*
tktextdelins(Tk * tk,char * arg,char ** val)256037da2899SCharles.Forsyth tktextdelins(Tk *tk, char *arg, char **val)
256137da2899SCharles.Forsyth {
256237da2899SCharles.Forsyth int m, c, skipping, wordc, n;
256337da2899SCharles.Forsyth TkTindex ix, ix2;
256437da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
256537da2899SCharles.Forsyth char buf[30];
256637da2899SCharles.Forsyth
256737da2899SCharles.Forsyth USED(val);
256837da2899SCharles.Forsyth
256937da2899SCharles.Forsyth if(tk->flag&Tkdisabled)
257037da2899SCharles.Forsyth return nil;
257137da2899SCharles.Forsyth
257237da2899SCharles.Forsyth if(tktgetsel(tk, &ix, &ix2))
257337da2899SCharles.Forsyth tktextdelete(tk, "sel.first sel.last", nil);
257437da2899SCharles.Forsyth else {
257537da2899SCharles.Forsyth while(*arg == ' ')
257637da2899SCharles.Forsyth arg++;
257737da2899SCharles.Forsyth if(*arg == '-') {
257837da2899SCharles.Forsyth m = arg[1];
257937da2899SCharles.Forsyth if(m == 'c')
258037da2899SCharles.Forsyth n = 1;
258137da2899SCharles.Forsyth else {
258237da2899SCharles.Forsyth /* delete prev word (m=='w') or prev line (m=='l') */
258337da2899SCharles.Forsyth if(!tktmarkind(tk, "insert", &ix))
258437da2899SCharles.Forsyth return nil;
258537da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, &ix))
258637da2899SCharles.Forsyth return nil;
258737da2899SCharles.Forsyth n = 1;
258837da2899SCharles.Forsyth /* ^W skips back over nonwordchars, then takes maximal seq of wordchars */
258937da2899SCharles.Forsyth skipping = 1;
259037da2899SCharles.Forsyth for(;;) {
259137da2899SCharles.Forsyth c = tktindrune(&ix);
259237da2899SCharles.Forsyth if(c == '\n') {
259337da2899SCharles.Forsyth /* special case: always delete at least one char */
259437da2899SCharles.Forsyth if(n > 1)
259537da2899SCharles.Forsyth n--;
259637da2899SCharles.Forsyth break;
259737da2899SCharles.Forsyth }
259837da2899SCharles.Forsyth if(m == 'w') {
259937da2899SCharles.Forsyth wordc = tkiswordchar(c);
260037da2899SCharles.Forsyth if(wordc && skipping)
260137da2899SCharles.Forsyth skipping = 0;
260237da2899SCharles.Forsyth else if(!wordc && !skipping) {
260337da2899SCharles.Forsyth n--;
260437da2899SCharles.Forsyth break;
260537da2899SCharles.Forsyth }
260637da2899SCharles.Forsyth }
260737da2899SCharles.Forsyth if(tktadjustind(tkt, TkTbycharback, &ix))
260837da2899SCharles.Forsyth n++;
260937da2899SCharles.Forsyth else
261037da2899SCharles.Forsyth break;
261137da2899SCharles.Forsyth }
261237da2899SCharles.Forsyth }
261337da2899SCharles.Forsyth sprint(buf, "insert-%dc insert", n);
261437da2899SCharles.Forsyth tktextdelete(tk, buf, nil);
261537da2899SCharles.Forsyth }
2616*3a78c580Sforsyth else if(arg[0] == '+' && arg[1] == 'l')
2617*3a78c580Sforsyth tktextdelete(tk, "insert {insert lineend}", nil);
261837da2899SCharles.Forsyth else
261937da2899SCharles.Forsyth tktextdelete(tk, "insert", nil);
262037da2899SCharles.Forsyth tktextsee(tk, "insert", nil);
262137da2899SCharles.Forsyth }
262237da2899SCharles.Forsyth return nil;
262337da2899SCharles.Forsyth }
262437da2899SCharles.Forsyth
262537da2899SCharles.Forsyth static char*
tktextdlineinfo(Tk * tk,char * arg,char ** val)262637da2899SCharles.Forsyth tktextdlineinfo(Tk *tk, char *arg, char **val)
262737da2899SCharles.Forsyth {
262837da2899SCharles.Forsyth char *e;
262937da2899SCharles.Forsyth TkTindex ix;
263037da2899SCharles.Forsyth TkTline *l;
263137da2899SCharles.Forsyth Point p;
263237da2899SCharles.Forsyth int vh;
263337da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
263437da2899SCharles.Forsyth
263537da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix);
263637da2899SCharles.Forsyth if(e != nil)
263737da2899SCharles.Forsyth return e;
263837da2899SCharles.Forsyth
263937da2899SCharles.Forsyth l = ix.line;
264037da2899SCharles.Forsyth vh = tk->act.height;
264137da2899SCharles.Forsyth
264237da2899SCharles.Forsyth /* get p in V space */
264337da2899SCharles.Forsyth p = subpt(l->orig, tkt->deltatv);
264437da2899SCharles.Forsyth if(p.y+l->height < 0 || p.y >= vh)
264537da2899SCharles.Forsyth return nil;
264637da2899SCharles.Forsyth
264737da2899SCharles.Forsyth return tkvalue(val, "%d %d %d %d %d",
264837da2899SCharles.Forsyth p.x, p.y, l->width, l->height, l->ascent);
264937da2899SCharles.Forsyth }
265037da2899SCharles.Forsyth
265137da2899SCharles.Forsyth static char*
tktextdump(Tk * tk,char * arg,char ** val)265237da2899SCharles.Forsyth tktextdump(Tk *tk, char *arg, char **val)
265337da2899SCharles.Forsyth {
265437da2899SCharles.Forsyth TkTline *l;
265537da2899SCharles.Forsyth TkTitem *i;
265637da2899SCharles.Forsyth Fmt fmt;
265737da2899SCharles.Forsyth TkText *tkt;
265837da2899SCharles.Forsyth TkDump tkdump;
265937da2899SCharles.Forsyth TkOptab tko[2];
266037da2899SCharles.Forsyth TkTtaginfo *ti;
266137da2899SCharles.Forsyth TkName *names, *n;
266237da2899SCharles.Forsyth char *e, *win, *p;
266337da2899SCharles.Forsyth TkTindex ix1, ix2;
266437da2899SCharles.Forsyth int r, j, numitems;
266537da2899SCharles.Forsyth ulong fg, bg;
266637da2899SCharles.Forsyth
266737da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
266837da2899SCharles.Forsyth
266937da2899SCharles.Forsyth
267037da2899SCharles.Forsyth tkdump.sgml = 0;
267137da2899SCharles.Forsyth tkdump.metrics = 0;
267237da2899SCharles.Forsyth
267337da2899SCharles.Forsyth tko[0].ptr = &tkdump;
267437da2899SCharles.Forsyth tko[0].optab = dumpopts;
267537da2899SCharles.Forsyth tko[1].ptr = nil;
267637da2899SCharles.Forsyth names = nil;
267737da2899SCharles.Forsyth e = tkparse(tk->env->top, arg, tko, &names);
267837da2899SCharles.Forsyth if(e != nil)
267937da2899SCharles.Forsyth return e;
268037da2899SCharles.Forsyth
268137da2899SCharles.Forsyth if(names != nil) { /* supplied indices */
268237da2899SCharles.Forsyth p = names->name;
268337da2899SCharles.Forsyth e = tktindparse(tk, &p, &ix1);
268437da2899SCharles.Forsyth if(e != nil) {
268537da2899SCharles.Forsyth tkfreename(names);
268637da2899SCharles.Forsyth return e;
268737da2899SCharles.Forsyth }
268837da2899SCharles.Forsyth n = names->link;
268937da2899SCharles.Forsyth if(n != nil) {
269037da2899SCharles.Forsyth p = n->name;
269137da2899SCharles.Forsyth e = tktindparse(tk, &p, &ix2);
269237da2899SCharles.Forsyth if(e != nil) {
269337da2899SCharles.Forsyth tkfreename(names);
269437da2899SCharles.Forsyth return e;
269537da2899SCharles.Forsyth }
269637da2899SCharles.Forsyth }
269737da2899SCharles.Forsyth else {
269837da2899SCharles.Forsyth ix2 = ix1;
269937da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &ix2);
270037da2899SCharles.Forsyth }
270137da2899SCharles.Forsyth tkfreename(names);
270237da2899SCharles.Forsyth if(!tktindbefore(&ix1, &ix2))
270337da2899SCharles.Forsyth return nil;
270437da2899SCharles.Forsyth }
270537da2899SCharles.Forsyth else
270637da2899SCharles.Forsyth return TkBadix;
270737da2899SCharles.Forsyth
270837da2899SCharles.Forsyth if(tkdump.metrics != 0) {
270937da2899SCharles.Forsyth fmtstrinit(&fmt);
271037da2899SCharles.Forsyth if(fmtprint(&fmt, "%%Fonts\n") < 0)
271137da2899SCharles.Forsyth return TkNomem;
271237da2899SCharles.Forsyth for(ti=tkt->tags; ti != nil; ti=ti->next) {
271337da2899SCharles.Forsyth if(ti->env == nil || ti->env->font == nil)
271437da2899SCharles.Forsyth continue;
271537da2899SCharles.Forsyth if(fmtprint(&fmt, "%d::%s\n", ti->id,ti->env->font->name) < 0)
271637da2899SCharles.Forsyth return TkNomem;
271737da2899SCharles.Forsyth }
271837da2899SCharles.Forsyth if(fmtprint(&fmt, "-1::%s\n%%Colors\n", tk->env->font->name) < 0)
271937da2899SCharles.Forsyth return TkNomem;
272037da2899SCharles.Forsyth for(ti=tkt->tags; ti != nil; ti=ti->next) {
272137da2899SCharles.Forsyth if(ti->env == nil)
272237da2899SCharles.Forsyth continue;
272337da2899SCharles.Forsyth bg = ti->env->colors[TkCbackgnd];
272437da2899SCharles.Forsyth fg = ti->env->colors[TkCforegnd];
272537da2899SCharles.Forsyth if(bg == tk->env->colors[TkCbackgnd] &&
272637da2899SCharles.Forsyth fg == ti->env->colors[TkCforegnd])
272737da2899SCharles.Forsyth continue;
272837da2899SCharles.Forsyth r = fmtprint(&fmt,"%d::#%.8lux\n", ti->id, bg);
272937da2899SCharles.Forsyth if(r < 0)
273037da2899SCharles.Forsyth return TkNomem;
273137da2899SCharles.Forsyth r = fmtprint(&fmt,"%d::#%.8lux\n", ti->id, fg);
273237da2899SCharles.Forsyth if(r < 0)
273337da2899SCharles.Forsyth return TkNomem;
273437da2899SCharles.Forsyth }
273537da2899SCharles.Forsyth if(fmtprint(&fmt, "%%Lines\n") < 0)
273637da2899SCharles.Forsyth return TkNomem;
273737da2899SCharles.Forsyth
273837da2899SCharles.Forsyth /*
273937da2899SCharles.Forsyth * In 'metrics' format lines are recorded in the following way:
274037da2899SCharles.Forsyth * xorig yorig wd ht as [data]
274137da2899SCharles.Forsyth * where data is of the form:
274237da2899SCharles.Forsyth * CodeWidth{tags} data
274337da2899SCharles.Forsyth * For Example;
274437da2899SCharles.Forsyth * A200{200000} Hello World!
274537da2899SCharles.Forsyth * denotes an A(scii) contiguous string of 200 pixels with
274637da2899SCharles.Forsyth * bit 20 set in its tags which corresponds to some font.
274737da2899SCharles.Forsyth *
274837da2899SCharles.Forsyth */
274937da2899SCharles.Forsyth if(ix2.line->items != ix2.item)
275037da2899SCharles.Forsyth ix2.line = ix2.line->next;
275137da2899SCharles.Forsyth for(l = ix1.line; l != ix2.line; l = l->next) {
275237da2899SCharles.Forsyth numitems = 0;
275337da2899SCharles.Forsyth for(i = l->items; i != nil; i = i->next) {
275437da2899SCharles.Forsyth if(i->kind != TkTmark)
275537da2899SCharles.Forsyth numitems++;
275637da2899SCharles.Forsyth }
275737da2899SCharles.Forsyth r = fmtprint(&fmt, "%d %d %d %d %d %d ",
275837da2899SCharles.Forsyth l->orig.x, l->orig.y, l->width, l->height, l->ascent,numitems);
275937da2899SCharles.Forsyth if(r < 0)
276037da2899SCharles.Forsyth return TkNomem;
276137da2899SCharles.Forsyth for(i = l->items; i != nil; i = i->next) {
276237da2899SCharles.Forsyth switch(i->kind) {
276337da2899SCharles.Forsyth case TkTascii:
276437da2899SCharles.Forsyth case TkTrune:
276537da2899SCharles.Forsyth r = i->kind == TkTascii ? 'A' : 'R';
276637da2899SCharles.Forsyth if(fmtprint(&fmt,"[%c%d{", r, i->width) < 0)
276737da2899SCharles.Forsyth return TkNomem;
276837da2899SCharles.Forsyth if(i->tags !=0 || i->tagextra !=0) {
276937da2899SCharles.Forsyth if(fmtprint(&fmt,"%lux", i->tags[0]) < 0)
277037da2899SCharles.Forsyth return TkNomem;
277137da2899SCharles.Forsyth for(j=0; j < i->tagextra; j++)
277237da2899SCharles.Forsyth if(fmtprint(&fmt,"::%lux", i->tags[j+1]) < 0)
277337da2899SCharles.Forsyth return TkNomem;
277437da2899SCharles.Forsyth }
277537da2899SCharles.Forsyth /* XXX string should be quoted to avoid embedded ']'s */
277637da2899SCharles.Forsyth if(fmtprint(&fmt,"}%s]", i->istring) < 0)
277737da2899SCharles.Forsyth return TkNomem;
277837da2899SCharles.Forsyth break;
277937da2899SCharles.Forsyth case TkTnewline:
278037da2899SCharles.Forsyth case TkTcontline:
278137da2899SCharles.Forsyth r = i->kind == TkTnewline ? 'N' : 'C';
278237da2899SCharles.Forsyth if(fmtprint(&fmt, "[%c]", r) < 0)
278337da2899SCharles.Forsyth return TkNomem;
278437da2899SCharles.Forsyth break;
278537da2899SCharles.Forsyth case TkTtab:
278637da2899SCharles.Forsyth if(fmtprint(&fmt,"[T%d]",i->width) < 0)
278737da2899SCharles.Forsyth return TkNomem;
278837da2899SCharles.Forsyth break;
278937da2899SCharles.Forsyth case TkTwin:
279037da2899SCharles.Forsyth win = "<null>";
279137da2899SCharles.Forsyth if(i->iwin->sub != nil)
279237da2899SCharles.Forsyth win = i->iwin->sub->name->name;
279337da2899SCharles.Forsyth if(fmtprint(&fmt,"[W%d %s]",i->width, win) < 0)
279437da2899SCharles.Forsyth return TkNomem;
279537da2899SCharles.Forsyth break;
279637da2899SCharles.Forsyth }
279737da2899SCharles.Forsyth if(fmtprint(&fmt, " ") < 0)
279837da2899SCharles.Forsyth return TkNomem;
279937da2899SCharles.Forsyth
280037da2899SCharles.Forsyth }
280137da2899SCharles.Forsyth if(fmtprint(&fmt, "\n") < 0)
280237da2899SCharles.Forsyth return TkNomem;
280337da2899SCharles.Forsyth *val = fmtstrflush(&fmt);
280437da2899SCharles.Forsyth if(*val == nil)
280537da2899SCharles.Forsyth return TkNomem;
280637da2899SCharles.Forsyth }
280737da2899SCharles.Forsyth }
280837da2899SCharles.Forsyth else
280937da2899SCharles.Forsyth return tktget(tkt, &ix1, &ix2, tkdump.sgml, val);
281037da2899SCharles.Forsyth
281137da2899SCharles.Forsyth return nil;
281237da2899SCharles.Forsyth }
281337da2899SCharles.Forsyth
281437da2899SCharles.Forsyth
281537da2899SCharles.Forsyth static char*
tktextget(Tk * tk,char * arg,char ** val)281637da2899SCharles.Forsyth tktextget(Tk *tk, char *arg, char **val)
281737da2899SCharles.Forsyth {
281837da2899SCharles.Forsyth char *e;
281937da2899SCharles.Forsyth TkTindex ix1, ix2;
282037da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
282137da2899SCharles.Forsyth
282237da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix1);
282337da2899SCharles.Forsyth if(e != nil)
282437da2899SCharles.Forsyth return e;
282537da2899SCharles.Forsyth
282637da2899SCharles.Forsyth if(*arg != '\0') {
282737da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix2);
282837da2899SCharles.Forsyth if(e != nil)
282937da2899SCharles.Forsyth return e;
283037da2899SCharles.Forsyth }
283137da2899SCharles.Forsyth else {
283237da2899SCharles.Forsyth ix2 = ix1;
283337da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &ix2);
283437da2899SCharles.Forsyth }
283537da2899SCharles.Forsyth return tktget(tkt, &ix1, &ix2, 0, val);
283637da2899SCharles.Forsyth }
283737da2899SCharles.Forsyth
283837da2899SCharles.Forsyth static char*
tktextindex(Tk * tk,char * arg,char ** val)283937da2899SCharles.Forsyth tktextindex(Tk *tk, char *arg, char **val)
284037da2899SCharles.Forsyth {
284137da2899SCharles.Forsyth char *e;
284237da2899SCharles.Forsyth TkTindex ix;
284337da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
284437da2899SCharles.Forsyth
284537da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix);
284637da2899SCharles.Forsyth if(e != nil)
284737da2899SCharles.Forsyth return e;
284837da2899SCharles.Forsyth return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix), tktlinepos(tkt, &ix));
284937da2899SCharles.Forsyth }
285037da2899SCharles.Forsyth
285137da2899SCharles.Forsyth static char*
tktextinsert(Tk * tk,char * arg,char ** val)285237da2899SCharles.Forsyth tktextinsert(Tk *tk, char *arg, char **val)
285337da2899SCharles.Forsyth {
285437da2899SCharles.Forsyth int n;
285537da2899SCharles.Forsyth char *e, *p, *pe;
285637da2899SCharles.Forsyth TkTindex ins, pins;
285737da2899SCharles.Forsyth TkTtaginfo *ti;
285837da2899SCharles.Forsyth TkText *tkt;
285937da2899SCharles.Forsyth TkTline *lmin;
286037da2899SCharles.Forsyth TkTop *top;
286137da2899SCharles.Forsyth TkTitem *tagit;
286237da2899SCharles.Forsyth char *tbuf, *buf;
286337da2899SCharles.Forsyth
286437da2899SCharles.Forsyth USED(val);
286537da2899SCharles.Forsyth
286637da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
286737da2899SCharles.Forsyth top = tk->env->top;
286837da2899SCharles.Forsyth
286937da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ins);
287037da2899SCharles.Forsyth if(e != nil)
287137da2899SCharles.Forsyth return e;
287237da2899SCharles.Forsyth
287337da2899SCharles.Forsyth if(ins.item->kind == TkTmark) {
287437da2899SCharles.Forsyth if(ins.item->imark->gravity == Tkleft) {
287537da2899SCharles.Forsyth while(ins.item->kind == TkTmark && ins.item->imark->gravity == Tkleft)
287637da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, &ins)) {
287737da2899SCharles.Forsyth if(tktdbg)
287837da2899SCharles.Forsyth print("tktextinsert botch\n");
287937da2899SCharles.Forsyth break;
288037da2899SCharles.Forsyth }
288137da2899SCharles.Forsyth }
288237da2899SCharles.Forsyth else {
288337da2899SCharles.Forsyth for(;;) {
288437da2899SCharles.Forsyth pins = ins;
288537da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitemback, &pins))
288637da2899SCharles.Forsyth break;
288737da2899SCharles.Forsyth if(pins.item->kind == TkTmark && pins.item->imark->gravity == Tkright)
288837da2899SCharles.Forsyth ins = pins;
288937da2899SCharles.Forsyth else
289037da2899SCharles.Forsyth break;
289137da2899SCharles.Forsyth }
289237da2899SCharles.Forsyth }
289337da2899SCharles.Forsyth }
289437da2899SCharles.Forsyth
289537da2899SCharles.Forsyth lmin = tktprevwrapline(tk, ins.line);
289637da2899SCharles.Forsyth
289737da2899SCharles.Forsyth n = strlen(arg) + 1;
289837da2899SCharles.Forsyth if(n < Tkmaxitem)
289937da2899SCharles.Forsyth n = Tkmaxitem;
290037da2899SCharles.Forsyth tbuf = malloc(n);
290137da2899SCharles.Forsyth if(tbuf == nil)
290237da2899SCharles.Forsyth return TkNomem;
290337da2899SCharles.Forsyth buf = mallocz(Tkmaxitem, 0);
290437da2899SCharles.Forsyth if(buf == nil) {
290537da2899SCharles.Forsyth free(tbuf);
290637da2899SCharles.Forsyth return TkNomem;
290737da2899SCharles.Forsyth }
290837da2899SCharles.Forsyth
290937da2899SCharles.Forsyth tagit = nil;
291037da2899SCharles.Forsyth
291137da2899SCharles.Forsyth while(*arg != '\0') {
291237da2899SCharles.Forsyth arg = tkword(top, arg, tbuf, tbuf+n, nil);
291337da2899SCharles.Forsyth if(*arg != '\0') {
291437da2899SCharles.Forsyth /* tag list spec -- add some slop to tagextra for added tags */
291537da2899SCharles.Forsyth e = tktnewitem(TkTascii, (tkt->nexttag-1)/32 + 1, &tagit);
291637da2899SCharles.Forsyth if(e != nil) {
291737da2899SCharles.Forsyth free(tbuf);
291837da2899SCharles.Forsyth free(buf);
291937da2899SCharles.Forsyth return e;
292037da2899SCharles.Forsyth }
292137da2899SCharles.Forsyth arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
292237da2899SCharles.Forsyth p = buf;
292337da2899SCharles.Forsyth while(*p) {
292437da2899SCharles.Forsyth while(*p == ' ') {
292537da2899SCharles.Forsyth p++;
292637da2899SCharles.Forsyth }
292737da2899SCharles.Forsyth if(*p == '\0')
292837da2899SCharles.Forsyth break;
292937da2899SCharles.Forsyth pe = strchr(p, ' ');
293037da2899SCharles.Forsyth if(pe != nil)
293137da2899SCharles.Forsyth *pe = '\0';
293237da2899SCharles.Forsyth ti = tktfindtag(tkt->tags, p);
293337da2899SCharles.Forsyth if(ti == nil) {
293437da2899SCharles.Forsyth e = tktaddtaginfo(tk, p, &ti);
293537da2899SCharles.Forsyth if(e != nil) {
293637da2899SCharles.Forsyth if(tagit != nil)
293737da2899SCharles.Forsyth free(tagit);
293837da2899SCharles.Forsyth free(tbuf);
293937da2899SCharles.Forsyth free(buf);
294037da2899SCharles.Forsyth return e;
294137da2899SCharles.Forsyth }
294237da2899SCharles.Forsyth }
294337da2899SCharles.Forsyth tkttagbit(tagit, ti->id, 1);
294437da2899SCharles.Forsyth if(pe == nil)
294537da2899SCharles.Forsyth break;
294637da2899SCharles.Forsyth else
294737da2899SCharles.Forsyth p = pe+1;
294837da2899SCharles.Forsyth }
294937da2899SCharles.Forsyth }
295037da2899SCharles.Forsyth e = tktinsert(tk, &ins, tbuf, tagit);
295137da2899SCharles.Forsyth if(tagit != nil) {
295237da2899SCharles.Forsyth free(tagit);
295337da2899SCharles.Forsyth tagit = nil;
295437da2899SCharles.Forsyth }
295537da2899SCharles.Forsyth if(e != nil) {
295637da2899SCharles.Forsyth free(tbuf);
295737da2899SCharles.Forsyth free(buf);
295837da2899SCharles.Forsyth return e;
295937da2899SCharles.Forsyth }
296037da2899SCharles.Forsyth }
296137da2899SCharles.Forsyth
296237da2899SCharles.Forsyth tktfixgeom(tk, lmin, ins.line, 0);
296337da2899SCharles.Forsyth tktextsize(tk, 1);
296437da2899SCharles.Forsyth
296537da2899SCharles.Forsyth free(tbuf);
296637da2899SCharles.Forsyth free(buf);
296737da2899SCharles.Forsyth
296837da2899SCharles.Forsyth return nil;
296937da2899SCharles.Forsyth }
297037da2899SCharles.Forsyth
297137da2899SCharles.Forsyth static char*
tktextinserti(Tk * tk,char * arg,char ** val)297237da2899SCharles.Forsyth tktextinserti(Tk *tk, char *arg, char **val)
297337da2899SCharles.Forsyth {
297437da2899SCharles.Forsyth int n;
297537da2899SCharles.Forsyth TkTline *lmin;
297637da2899SCharles.Forsyth TkTindex ix, is1, is2;
297737da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
297837da2899SCharles.Forsyth char *tbuf, *buf;
297937da2899SCharles.Forsyth
298037da2899SCharles.Forsyth USED(val);
298137da2899SCharles.Forsyth
298237da2899SCharles.Forsyth if(tk->flag&Tkdisabled)
298337da2899SCharles.Forsyth return nil;
298437da2899SCharles.Forsyth
298537da2899SCharles.Forsyth buf = mallocz(Tkmaxitem, 0);
298637da2899SCharles.Forsyth if(buf == nil)
298737da2899SCharles.Forsyth return TkNomem;
298837da2899SCharles.Forsyth
298937da2899SCharles.Forsyth tbuf = nil;
299037da2899SCharles.Forsyth n = strlen(arg) + 1;
299137da2899SCharles.Forsyth if(n < Tkmaxitem)
299237da2899SCharles.Forsyth tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
299337da2899SCharles.Forsyth else {
299437da2899SCharles.Forsyth tbuf = malloc(n);
299537da2899SCharles.Forsyth if(tbuf == nil) {
299637da2899SCharles.Forsyth free(buf);
299737da2899SCharles.Forsyth return TkNomem;
299837da2899SCharles.Forsyth }
299937da2899SCharles.Forsyth tkword(tk->env->top, arg, tbuf, buf+n, nil);
300037da2899SCharles.Forsyth }
300137da2899SCharles.Forsyth if(*buf == '\0')
300237da2899SCharles.Forsyth goto Ret;
300337da2899SCharles.Forsyth if(!tktmarkind(tk, "insert", &ix)) {
300437da2899SCharles.Forsyth print("tktextinserti: botch\n");
300537da2899SCharles.Forsyth goto Ret;
300637da2899SCharles.Forsyth }
300737da2899SCharles.Forsyth if(tktgetsel(tk, &is1, &is2)) {
300837da2899SCharles.Forsyth if(tktindcompare(tkt, &is1, TkLte, &ix) &&
300937da2899SCharles.Forsyth tktindcompare(tkt, &is2, TkGte, &ix)) {
301037da2899SCharles.Forsyth tktextdelete(tk, "sel.first sel.last", nil);
301137da2899SCharles.Forsyth /* delete might have changed ix item */
301237da2899SCharles.Forsyth tktmarkind(tk, "insert", &ix);
301337da2899SCharles.Forsyth }
301437da2899SCharles.Forsyth }
301537da2899SCharles.Forsyth
301637da2899SCharles.Forsyth lmin = tktprevwrapline(tk, ix.line);
301737da2899SCharles.Forsyth tktinsert(tk, &ix, tbuf==nil ? buf : tbuf, 0);
301837da2899SCharles.Forsyth tktfixgeom(tk, lmin, ix.line, 0);
301937da2899SCharles.Forsyth if(tktmarkind(tk, "insert", &ix)) /* index doesn't remain valid after fixgeom */
302037da2899SCharles.Forsyth tktsee(tk, &ix, 0);
302137da2899SCharles.Forsyth tktextsize(tk, 1);
302237da2899SCharles.Forsyth Ret:
302337da2899SCharles.Forsyth if(tbuf != nil)
302437da2899SCharles.Forsyth free(tbuf);
302537da2899SCharles.Forsyth free(buf);
302637da2899SCharles.Forsyth return nil;
302737da2899SCharles.Forsyth }
302837da2899SCharles.Forsyth
302937da2899SCharles.Forsyth static char*
tktextmark(Tk * tk,char * arg,char ** val)303037da2899SCharles.Forsyth tktextmark(Tk *tk, char *arg, char **val)
303137da2899SCharles.Forsyth {
303237da2899SCharles.Forsyth char *buf;
303337da2899SCharles.Forsyth TkCmdtab *cmd;
303437da2899SCharles.Forsyth
303537da2899SCharles.Forsyth buf = mallocz(Tkmaxitem, 0);
303637da2899SCharles.Forsyth if(buf == nil)
303737da2899SCharles.Forsyth return TkNomem;
303837da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
303937da2899SCharles.Forsyth for(cmd = tktmarkcmd; cmd->name != nil; cmd++) {
304037da2899SCharles.Forsyth if(strcmp(cmd->name, buf) == 0) {
304137da2899SCharles.Forsyth free(buf);
304237da2899SCharles.Forsyth return cmd->fn(tk, arg, val);
304337da2899SCharles.Forsyth }
304437da2899SCharles.Forsyth }
304537da2899SCharles.Forsyth free(buf);
304637da2899SCharles.Forsyth return TkBadcm;
304737da2899SCharles.Forsyth }
304837da2899SCharles.Forsyth
304937da2899SCharles.Forsyth static char*
tktextscan(Tk * tk,char * arg,char ** val)305037da2899SCharles.Forsyth tktextscan(Tk *tk, char *arg, char **val)
305137da2899SCharles.Forsyth {
305237da2899SCharles.Forsyth char *e;
305337da2899SCharles.Forsyth int mark, x, y, xmax, ymax, vh, vw;
305437da2899SCharles.Forsyth Point p, odeltatv;
305537da2899SCharles.Forsyth char buf[Tkmaxitem];
305637da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
305737da2899SCharles.Forsyth
305837da2899SCharles.Forsyth USED(val);
305937da2899SCharles.Forsyth
306037da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
306137da2899SCharles.Forsyth
306237da2899SCharles.Forsyth if(strcmp(buf, "mark") == 0)
306337da2899SCharles.Forsyth mark = 1;
306437da2899SCharles.Forsyth else
306537da2899SCharles.Forsyth if(strcmp(buf, "dragto") == 0)
306637da2899SCharles.Forsyth mark = 0;
306737da2899SCharles.Forsyth else
306837da2899SCharles.Forsyth return TkBadcm;
306937da2899SCharles.Forsyth
307037da2899SCharles.Forsyth e = tkxyparse(tk, &arg, &p);
307137da2899SCharles.Forsyth if(e != nil)
307237da2899SCharles.Forsyth return e;
307337da2899SCharles.Forsyth
307437da2899SCharles.Forsyth if(mark)
307537da2899SCharles.Forsyth tkt->track = p;
307637da2899SCharles.Forsyth else {
307737da2899SCharles.Forsyth odeltatv = tkt->deltatv;
307837da2899SCharles.Forsyth vw = tk->act.width - tk->ipad.x;
307937da2899SCharles.Forsyth vh = tk->act.height - tk->ipad.y;
308037da2899SCharles.Forsyth ymax = tkt->end.prev->orig.y + tkt->end.prev->height - vh;
308137da2899SCharles.Forsyth y = tkt->deltatv.y -10*(p.y - tkt->track.y);
308237da2899SCharles.Forsyth if(y > ymax)
308337da2899SCharles.Forsyth y = ymax;
308437da2899SCharles.Forsyth if(y < 0)
308537da2899SCharles.Forsyth y = 0;
308637da2899SCharles.Forsyth tkt->deltatv.y = y;
308737da2899SCharles.Forsyth e = tktsetscroll(tk, Tkvertical);
308837da2899SCharles.Forsyth if(e != nil)
308937da2899SCharles.Forsyth return e;
309037da2899SCharles.Forsyth if(tkt->opts[TkTwrap] == Tkwrapnone) {
309137da2899SCharles.Forsyth xmax = tktmaxwid(tkt->start.next) - vw;
309237da2899SCharles.Forsyth x = tkt->deltatv.x - 10*(p.x - tkt->track.x);
309337da2899SCharles.Forsyth if(x > xmax)
309437da2899SCharles.Forsyth x = xmax;
309537da2899SCharles.Forsyth if(x < 0)
309637da2899SCharles.Forsyth x = 0;
309737da2899SCharles.Forsyth tkt->deltatv.x = x;
309837da2899SCharles.Forsyth e = tktsetscroll(tk, Tkhorizontal);
309937da2899SCharles.Forsyth if(e != nil)
310037da2899SCharles.Forsyth return e;
310137da2899SCharles.Forsyth }
310237da2899SCharles.Forsyth tktfixscroll(tk, odeltatv);
310337da2899SCharles.Forsyth tkt->track = p;
310437da2899SCharles.Forsyth }
310537da2899SCharles.Forsyth
310637da2899SCharles.Forsyth return nil;
310737da2899SCharles.Forsyth }
310837da2899SCharles.Forsyth
310937da2899SCharles.Forsyth static char*
tktextscrollpages(Tk * tk,char * arg,char ** val)311037da2899SCharles.Forsyth tktextscrollpages(Tk *tk, char *arg, char **val)
311137da2899SCharles.Forsyth {
311237da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
311337da2899SCharles.Forsyth
311437da2899SCharles.Forsyth USED(tkt);
311537da2899SCharles.Forsyth USED(arg);
311637da2899SCharles.Forsyth USED(val);
311737da2899SCharles.Forsyth return nil;
311837da2899SCharles.Forsyth }
311937da2899SCharles.Forsyth
312037da2899SCharles.Forsyth static char*
tktextsearch(Tk * tk,char * arg,char ** val)312137da2899SCharles.Forsyth tktextsearch(Tk *tk, char *arg, char **val)
312237da2899SCharles.Forsyth {
312337da2899SCharles.Forsyth int i, n;
312437da2899SCharles.Forsyth Rune r;
312537da2899SCharles.Forsyth char *e, *s;
312637da2899SCharles.Forsyth int wrap, fwd, nocase;
312737da2899SCharles.Forsyth TkText *tkt;
312837da2899SCharles.Forsyth TkTindex ix1, ix2, ixstart, ixend, tx;
312937da2899SCharles.Forsyth char buf[Tkmaxitem];
313037da2899SCharles.Forsyth
313137da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
313237da2899SCharles.Forsyth
313337da2899SCharles.Forsyth fwd = 1;
313437da2899SCharles.Forsyth nocase = 0;
313537da2899SCharles.Forsyth
313637da2899SCharles.Forsyth while(*arg != '\0') {
313737da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
313837da2899SCharles.Forsyth if(*buf != '-')
313937da2899SCharles.Forsyth break;
314037da2899SCharles.Forsyth if(strcmp(buf, "-backwards") == 0)
314137da2899SCharles.Forsyth fwd = 0;
314237da2899SCharles.Forsyth else if(strcmp(buf, "-nocase") == 0)
314337da2899SCharles.Forsyth nocase = 1;
314437da2899SCharles.Forsyth else if(strcmp(buf, "--") == 0) {
314537da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
314637da2899SCharles.Forsyth break;
314737da2899SCharles.Forsyth }
314837da2899SCharles.Forsyth }
314937da2899SCharles.Forsyth
315037da2899SCharles.Forsyth tktstartind(tkt, &ixstart);
315137da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, &ixstart);
315237da2899SCharles.Forsyth tktendind(tkt, &ixend);
315337da2899SCharles.Forsyth
315437da2899SCharles.Forsyth if(*arg == '\0')
315537da2899SCharles.Forsyth return TkOparg;
315637da2899SCharles.Forsyth
315737da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix1);
315837da2899SCharles.Forsyth if(e != nil)
315937da2899SCharles.Forsyth return e;
316037da2899SCharles.Forsyth tktadjustind(tkt, fwd? TkTbycharstart : TkTbycharback, &ix1);
316137da2899SCharles.Forsyth
316237da2899SCharles.Forsyth if(*arg != '\0') {
316337da2899SCharles.Forsyth wrap = 0;
316437da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix2);
316537da2899SCharles.Forsyth if(e != nil)
316637da2899SCharles.Forsyth return e;
316737da2899SCharles.Forsyth if(!fwd)
316837da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharback, &ix2);
316937da2899SCharles.Forsyth }
317037da2899SCharles.Forsyth else {
317137da2899SCharles.Forsyth wrap = 1;
317237da2899SCharles.Forsyth if(fwd) {
317337da2899SCharles.Forsyth if(tktindcompare(tkt, &ix1, TkEq, &ixstart))
317437da2899SCharles.Forsyth ix2 = ixend;
317537da2899SCharles.Forsyth else {
317637da2899SCharles.Forsyth ix2 = ix1;
317737da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharback, &ix2);
317837da2899SCharles.Forsyth }
317937da2899SCharles.Forsyth }
318037da2899SCharles.Forsyth else {
318137da2899SCharles.Forsyth if(tktindcompare(tkt, &ix1, TkEq, &ixend))
318237da2899SCharles.Forsyth ix2 = ixstart;
318337da2899SCharles.Forsyth else {
318437da2899SCharles.Forsyth ix2 = ix1;
318537da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &ix2);
318637da2899SCharles.Forsyth }
318737da2899SCharles.Forsyth }
318837da2899SCharles.Forsyth }
318937da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, &ix2);
319037da2899SCharles.Forsyth if(tktindcompare(tkt, &ix1, TkEq, &ix2))
319137da2899SCharles.Forsyth return nil;
319237da2899SCharles.Forsyth
319337da2899SCharles.Forsyth if(*buf == '\0')
319437da2899SCharles.Forsyth return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix1), tktlinepos(tkt, &ix1));
319537da2899SCharles.Forsyth
319637da2899SCharles.Forsyth while(!(ix1.item == ix2.item && ix1.pos == ix2.pos)) {
319737da2899SCharles.Forsyth tx = ix1;
319837da2899SCharles.Forsyth for(i = 0; buf[i] != '\0'; i++) {
319937da2899SCharles.Forsyth switch(tx.item->kind) {
320037da2899SCharles.Forsyth case TkTascii:
320137da2899SCharles.Forsyth if(!tktcmatch(tx.item->istring[tx.pos], buf[i], nocase))
320237da2899SCharles.Forsyth goto nomatch;
320337da2899SCharles.Forsyth break;
320437da2899SCharles.Forsyth case TkTrune:
320537da2899SCharles.Forsyth s = tx.item->istring;
320637da2899SCharles.Forsyth s += tktutfpos(s, tx.pos);
320737da2899SCharles.Forsyth n = chartorune(&r, s);
320837da2899SCharles.Forsyth if(strncmp(s, buf+i, n) != 0)
320937da2899SCharles.Forsyth goto nomatch;
321037da2899SCharles.Forsyth i += n-1;
321137da2899SCharles.Forsyth break;
321237da2899SCharles.Forsyth case TkTtab:
321337da2899SCharles.Forsyth if(buf[i] != '\t')
321437da2899SCharles.Forsyth goto nomatch;
321537da2899SCharles.Forsyth break;
321637da2899SCharles.Forsyth case TkTnewline:
321737da2899SCharles.Forsyth if(buf[i] != '\n')
321837da2899SCharles.Forsyth goto nomatch;
321937da2899SCharles.Forsyth break;
322037da2899SCharles.Forsyth default:
322137da2899SCharles.Forsyth goto nomatch;
322237da2899SCharles.Forsyth }
322337da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &tx);
322437da2899SCharles.Forsyth }
322537da2899SCharles.Forsyth return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix1), tktlinepos(tkt, &ix1));
322637da2899SCharles.Forsyth nomatch:
322737da2899SCharles.Forsyth if(fwd) {
322837da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbychar, &ix1)) {
322937da2899SCharles.Forsyth if(!wrap)
323037da2899SCharles.Forsyth break;
323137da2899SCharles.Forsyth ix1 = ixstart;
323237da2899SCharles.Forsyth }
323337da2899SCharles.Forsyth }
323437da2899SCharles.Forsyth else {
323537da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, &ix1)) {
323637da2899SCharles.Forsyth if(!wrap)
323737da2899SCharles.Forsyth break;
323837da2899SCharles.Forsyth ix1 = ixend;
323937da2899SCharles.Forsyth }
324037da2899SCharles.Forsyth }
324137da2899SCharles.Forsyth }
324237da2899SCharles.Forsyth
324337da2899SCharles.Forsyth return nil;
324437da2899SCharles.Forsyth }
324537da2899SCharles.Forsyth
324637da2899SCharles.Forsyth char*
tktextselection(Tk * tk,char * arg,char ** val)324737da2899SCharles.Forsyth tktextselection(Tk *tk, char *arg, char **val)
324837da2899SCharles.Forsyth {
324937da2899SCharles.Forsyth USED(val);
325037da2899SCharles.Forsyth if (strcmp(arg, " clear") == 0) {
325137da2899SCharles.Forsyth tktclearsel(tk);
325237da2899SCharles.Forsyth return nil;
325337da2899SCharles.Forsyth }
325437da2899SCharles.Forsyth else
325537da2899SCharles.Forsyth return TkBadcm;
325637da2899SCharles.Forsyth }
325737da2899SCharles.Forsyth
325837da2899SCharles.Forsyth static void
doselectto(Tk * tk,Point p,int dbl)325937da2899SCharles.Forsyth doselectto(Tk *tk, Point p, int dbl)
326037da2899SCharles.Forsyth {
326137da2899SCharles.Forsyth int halfway;
326237da2899SCharles.Forsyth TkTindex cur, insert, first, last;
326337da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
326437da2899SCharles.Forsyth tktclearsel(tk);
326537da2899SCharles.Forsyth
326637da2899SCharles.Forsyth halfway = tktxyind(tk, p.x, p.y, &cur);
326737da2899SCharles.Forsyth
326837da2899SCharles.Forsyth if(!dbl) {
326937da2899SCharles.Forsyth if(!tktmarkind(tk, "insert", &insert))
327037da2899SCharles.Forsyth insert = cur;
327137da2899SCharles.Forsyth
327237da2899SCharles.Forsyth if(tktindcompare(tkt, &cur, TkLt, &insert)) {
327337da2899SCharles.Forsyth first = cur;
327437da2899SCharles.Forsyth last = insert;
327537da2899SCharles.Forsyth }
327637da2899SCharles.Forsyth else {
327737da2899SCharles.Forsyth first = insert;
327837da2899SCharles.Forsyth last = cur;
327937da2899SCharles.Forsyth if(halfway)
328037da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, &last);
328137da2899SCharles.Forsyth if(last.line == &tkt->end)
328237da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharback, &last);
328337da2899SCharles.Forsyth if(tktindcompare(tkt, &first, TkGte, &last))
328437da2899SCharles.Forsyth return;
328537da2899SCharles.Forsyth cur = last;
328637da2899SCharles.Forsyth }
328737da2899SCharles.Forsyth tktsee(tk, &cur, 0);
328837da2899SCharles.Forsyth }
328937da2899SCharles.Forsyth else {
329037da2899SCharles.Forsyth first = cur;
329137da2899SCharles.Forsyth last = cur;
329237da2899SCharles.Forsyth tktdoubleclick(tkt, &first, &last);
329337da2899SCharles.Forsyth }
329437da2899SCharles.Forsyth
329537da2899SCharles.Forsyth tkttagchange(tk, TkTselid, &first, &last, 1);
329637da2899SCharles.Forsyth }
329737da2899SCharles.Forsyth
329837da2899SCharles.Forsyth static void
autoselect(Tk * tk,void * v,int cancelled)329937da2899SCharles.Forsyth autoselect(Tk *tk, void *v, int cancelled)
330037da2899SCharles.Forsyth {
330137da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
330237da2899SCharles.Forsyth Rectangle hitr;
330337da2899SCharles.Forsyth Point p;
330437da2899SCharles.Forsyth USED(v);
330537da2899SCharles.Forsyth
330637da2899SCharles.Forsyth if (cancelled)
330737da2899SCharles.Forsyth return;
330837da2899SCharles.Forsyth
330937da2899SCharles.Forsyth p = scr2local(tk, tkt->track);
331037da2899SCharles.Forsyth if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
331137da2899SCharles.Forsyth return;
331237da2899SCharles.Forsyth doselectto(tk, p, 0);
331337da2899SCharles.Forsyth tkdirty(tk);
331437da2899SCharles.Forsyth tkupdate(tk->env->top);
331537da2899SCharles.Forsyth }
331637da2899SCharles.Forsyth
331737da2899SCharles.Forsyth static char*
tktextselectto(Tk * tk,char * arg,char ** val)331837da2899SCharles.Forsyth tktextselectto(Tk *tk, char *arg, char **val)
331937da2899SCharles.Forsyth {
332037da2899SCharles.Forsyth int dbl;
332137da2899SCharles.Forsyth char *e;
332237da2899SCharles.Forsyth Point p;
332337da2899SCharles.Forsyth Rectangle hitr;
332437da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
332537da2899SCharles.Forsyth
332637da2899SCharles.Forsyth USED(val);
332737da2899SCharles.Forsyth
332837da2899SCharles.Forsyth if(tkt->tflag & (TkTjustfoc|TkTnodrag))
332937da2899SCharles.Forsyth return nil;
333037da2899SCharles.Forsyth
333137da2899SCharles.Forsyth e = tkxyparse(tk, &arg, &p);
333237da2899SCharles.Forsyth if(e != nil)
333337da2899SCharles.Forsyth return e;
333437da2899SCharles.Forsyth tkt->track = p;
333537da2899SCharles.Forsyth p = scr2local(tk, p);
333637da2899SCharles.Forsyth
333737da2899SCharles.Forsyth arg = tkskip(arg, " ");
333837da2899SCharles.Forsyth if(*arg == 'd') {
333937da2899SCharles.Forsyth tkcancelrepeat(tk);
334037da2899SCharles.Forsyth dbl = 1;
334137da2899SCharles.Forsyth tkt->tflag |= TkTnodrag;
334237da2899SCharles.Forsyth } else {
334337da2899SCharles.Forsyth dbl = 0;
334437da2899SCharles.Forsyth if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
334537da2899SCharles.Forsyth return nil;
334637da2899SCharles.Forsyth }
334737da2899SCharles.Forsyth doselectto(tk, p, dbl);
334837da2899SCharles.Forsyth return nil;
334937da2899SCharles.Forsyth }
335037da2899SCharles.Forsyth
335137da2899SCharles.Forsyth static char tktleft1[] = "{[(<";
335237da2899SCharles.Forsyth static char tktright1[] = "}])>";
335337da2899SCharles.Forsyth static char tktleft2[] = "\n";
335437da2899SCharles.Forsyth static char tktleft3[] = "\'\"`";
335537da2899SCharles.Forsyth
335637da2899SCharles.Forsyth static char *tktleft[] = {tktleft1, tktleft2, tktleft3, nil};
335737da2899SCharles.Forsyth static char *tktright[] = {tktright1, tktleft2, tktleft3, nil};
335837da2899SCharles.Forsyth
335937da2899SCharles.Forsyth static void
tktdoubleclick(TkText * tkt,TkTindex * first,TkTindex * last)336037da2899SCharles.Forsyth tktdoubleclick(TkText *tkt, TkTindex *first, TkTindex *last)
336137da2899SCharles.Forsyth {
336237da2899SCharles.Forsyth int c, i;
336337da2899SCharles.Forsyth TkTindex ix, ix2;
336437da2899SCharles.Forsyth char *r, *l, *p;
336537da2899SCharles.Forsyth
336637da2899SCharles.Forsyth for(i = 0; tktleft[i] != nil; i++) {
336737da2899SCharles.Forsyth ix = *first;
336837da2899SCharles.Forsyth l = tktleft[i];
336937da2899SCharles.Forsyth r = tktright[i];
337037da2899SCharles.Forsyth /* try matching character to left, looking right */
337137da2899SCharles.Forsyth ix2 = ix;
337237da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, &ix2))
337337da2899SCharles.Forsyth c = '\n';
337437da2899SCharles.Forsyth else
337537da2899SCharles.Forsyth c = tktindrune(&ix2);
337637da2899SCharles.Forsyth p = strchr(l, c);
337737da2899SCharles.Forsyth if(p != nil) {
337837da2899SCharles.Forsyth if(tktclickmatch(tkt, c, r[p-l], 1, &ix)) {
337937da2899SCharles.Forsyth *last = ix;
338037da2899SCharles.Forsyth if(c != '\n')
338137da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharback, last);
338237da2899SCharles.Forsyth }
338337da2899SCharles.Forsyth return;
338437da2899SCharles.Forsyth }
338537da2899SCharles.Forsyth /* try matching character to right, looking left */
338637da2899SCharles.Forsyth c = tktindrune(&ix);
338737da2899SCharles.Forsyth p = strchr(r, c);
338837da2899SCharles.Forsyth if(p != nil) {
338937da2899SCharles.Forsyth if(tktclickmatch(tkt, c, l[p-r], -1, &ix)) {
339037da2899SCharles.Forsyth *last = *first;
339137da2899SCharles.Forsyth if(c == '\n')
339237da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, last);
339337da2899SCharles.Forsyth *first = ix;
339437da2899SCharles.Forsyth if(!(c=='\n' && ix.line == tkt->start.next && ix.item == ix.line->items))
339537da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, first);
339637da2899SCharles.Forsyth }
339737da2899SCharles.Forsyth return;
339837da2899SCharles.Forsyth }
339937da2899SCharles.Forsyth }
340037da2899SCharles.Forsyth /* try filling out word to right */
340137da2899SCharles.Forsyth while(tkiswordchar(tktindrune(last))) {
340237da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbychar, last))
340337da2899SCharles.Forsyth break;
340437da2899SCharles.Forsyth }
340537da2899SCharles.Forsyth /* try filling out word to left */
340637da2899SCharles.Forsyth for(;;) {
340737da2899SCharles.Forsyth ix = *first;
340837da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, &ix))
340937da2899SCharles.Forsyth break;
341037da2899SCharles.Forsyth if(!tkiswordchar(tktindrune(&ix)))
341137da2899SCharles.Forsyth break;
341237da2899SCharles.Forsyth *first = ix;
341337da2899SCharles.Forsyth }
341437da2899SCharles.Forsyth }
341537da2899SCharles.Forsyth
341637da2899SCharles.Forsyth static int
tktclickmatch(TkText * tkt,int cl,int cr,int dir,TkTindex * ix)341737da2899SCharles.Forsyth tktclickmatch(TkText *tkt, int cl, int cr, int dir, TkTindex *ix)
341837da2899SCharles.Forsyth {
341937da2899SCharles.Forsyth int c, nest, atend;
342037da2899SCharles.Forsyth
342137da2899SCharles.Forsyth nest = 1;
342237da2899SCharles.Forsyth atend = 0;
342337da2899SCharles.Forsyth for(;;) {
342437da2899SCharles.Forsyth if(dir > 0) {
342537da2899SCharles.Forsyth if(atend)
342637da2899SCharles.Forsyth break;
342737da2899SCharles.Forsyth c = tktindrune(ix);
342837da2899SCharles.Forsyth atend = !tktadjustind(tkt, TkTbychar, ix);
342937da2899SCharles.Forsyth } else {
343037da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, ix))
343137da2899SCharles.Forsyth break;
343237da2899SCharles.Forsyth c = tktindrune(ix);
343337da2899SCharles.Forsyth }
343437da2899SCharles.Forsyth if(c == cr){
343537da2899SCharles.Forsyth if(--nest==0)
343637da2899SCharles.Forsyth return 1;
343737da2899SCharles.Forsyth }else if(c == cl)
343837da2899SCharles.Forsyth nest++;
343937da2899SCharles.Forsyth }
344037da2899SCharles.Forsyth return cl=='\n' && nest==1;
344137da2899SCharles.Forsyth }
344237da2899SCharles.Forsyth
344337da2899SCharles.Forsyth /*
344437da2899SCharles.Forsyth * return the line before line l, unless word wrap is on,
344537da2899SCharles.Forsyth * (for the first word of line l), in which case return the last non-empty line before that.
344637da2899SCharles.Forsyth * tktgeom might then combine the end of that line with the start of the insertion
344737da2899SCharles.Forsyth * (unless there is a newline in the way).
344837da2899SCharles.Forsyth */
344937da2899SCharles.Forsyth TkTline*
tktprevwrapline(Tk * tk,TkTline * l)345037da2899SCharles.Forsyth tktprevwrapline(Tk *tk, TkTline *l)
345137da2899SCharles.Forsyth {
345237da2899SCharles.Forsyth TkTitem *i;
345337da2899SCharles.Forsyth int *opts, wrapmode;
345437da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
345537da2899SCharles.Forsyth TkEnv env;
345637da2899SCharles.Forsyth
345737da2899SCharles.Forsyth if(l == nil)
345837da2899SCharles.Forsyth return nil;
345937da2899SCharles.Forsyth /* some spacing depends on tags of first non-mark on display line */
346037da2899SCharles.Forsyth for(i = l->items; i != nil; i = i->next)
346137da2899SCharles.Forsyth if(i->kind != TkTmark && i->kind != TkTcontline)
346237da2899SCharles.Forsyth break;
346337da2899SCharles.Forsyth if(i == nil || i->kind == TkTnewline) /* can't use !tkanytags(i) because it doesn't check env */
346437da2899SCharles.Forsyth return l->prev;
346537da2899SCharles.Forsyth opts = mallocz(TkTnumopts*sizeof(int), 0);
346637da2899SCharles.Forsyth if(opts == nil)
346737da2899SCharles.Forsyth return l->prev; /* in worst case gets word wrap wrong */
346837da2899SCharles.Forsyth tkttagopts(tk, i, opts, &env, nil, 1);
346937da2899SCharles.Forsyth wrapmode = opts[TkTwrap];
347037da2899SCharles.Forsyth free(opts);
347137da2899SCharles.Forsyth if(wrapmode != Tkwrapword)
347237da2899SCharles.Forsyth return l->prev;
347337da2899SCharles.Forsyth if(l->prev != &tkt->start)
347437da2899SCharles.Forsyth l = l->prev; /* having been processed by tktgeom, shouldn't have extraneous marks etc */
347537da2899SCharles.Forsyth return l->prev;
347637da2899SCharles.Forsyth }
347737da2899SCharles.Forsyth
347837da2899SCharles.Forsyth static char*
tktextsetcursor(Tk * tk,char * arg,char ** val)347937da2899SCharles.Forsyth tktextsetcursor(Tk *tk, char *arg, char **val)
348037da2899SCharles.Forsyth {
348137da2899SCharles.Forsyth char *e;
348237da2899SCharles.Forsyth TkTindex ix;
348337da2899SCharles.Forsyth TkTmarkinfo *mi;
348437da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
348537da2899SCharles.Forsyth
348637da2899SCharles.Forsyth USED(val);
348737da2899SCharles.Forsyth
348837da2899SCharles.Forsyth /* do clearsel here, because it can change indices */
348937da2899SCharles.Forsyth tktclearsel(tk);
349037da2899SCharles.Forsyth
349137da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix);
349237da2899SCharles.Forsyth if(e != nil)
349337da2899SCharles.Forsyth return e;
349437da2899SCharles.Forsyth
349537da2899SCharles.Forsyth mi = tktfindmark(tkt->marks, "insert");
349637da2899SCharles.Forsyth if(tktdbg && mi == nil) {
349737da2899SCharles.Forsyth print("tktextsetcursor: botch\n");
349837da2899SCharles.Forsyth return nil;
349937da2899SCharles.Forsyth }
350037da2899SCharles.Forsyth tktmarkmove(tk, mi, &ix);
350137da2899SCharles.Forsyth tktsee(tk, &ix, 0);
350237da2899SCharles.Forsyth return nil;
350337da2899SCharles.Forsyth }
350437da2899SCharles.Forsyth
350537da2899SCharles.Forsyth static char*
tktexttag(Tk * tk,char * arg,char ** val)350637da2899SCharles.Forsyth tktexttag(Tk *tk, char *arg, char **val)
350737da2899SCharles.Forsyth {
350837da2899SCharles.Forsyth char *buf;
350937da2899SCharles.Forsyth TkCmdtab *cmd;
351037da2899SCharles.Forsyth
351137da2899SCharles.Forsyth buf = mallocz(Tkmaxitem, 0);
351237da2899SCharles.Forsyth if(buf == nil)
351337da2899SCharles.Forsyth return TkNomem;
351437da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
351537da2899SCharles.Forsyth for(cmd = tkttagcmd; cmd->name != nil; cmd++) {
351637da2899SCharles.Forsyth if(strcmp(cmd->name, buf) == 0) {
351737da2899SCharles.Forsyth free(buf);
351837da2899SCharles.Forsyth return cmd->fn(tk, arg, val);
351937da2899SCharles.Forsyth }
352037da2899SCharles.Forsyth }
352137da2899SCharles.Forsyth free(buf);
352237da2899SCharles.Forsyth return TkBadcm;
352337da2899SCharles.Forsyth }
352437da2899SCharles.Forsyth
352537da2899SCharles.Forsyth static char*
tktextwindow(Tk * tk,char * arg,char ** val)352637da2899SCharles.Forsyth tktextwindow(Tk *tk, char *arg, char **val)
352737da2899SCharles.Forsyth {
352837da2899SCharles.Forsyth char buf[Tkmaxitem];
352937da2899SCharles.Forsyth TkCmdtab *cmd;
353037da2899SCharles.Forsyth
353137da2899SCharles.Forsyth arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
353237da2899SCharles.Forsyth for(cmd = tktwincmd; cmd->name != nil; cmd++) {
353337da2899SCharles.Forsyth if(strcmp(cmd->name, buf) == 0)
353437da2899SCharles.Forsyth return cmd->fn(tk, arg, val);
353537da2899SCharles.Forsyth }
353637da2899SCharles.Forsyth return TkBadcm;
353737da2899SCharles.Forsyth }
353837da2899SCharles.Forsyth
353937da2899SCharles.Forsyth static char*
tktextxview(Tk * tk,char * arg,char ** val)354037da2899SCharles.Forsyth tktextxview(Tk *tk, char *arg, char **val)
354137da2899SCharles.Forsyth {
354237da2899SCharles.Forsyth int ntot, vw;
354337da2899SCharles.Forsyth char *e;
354437da2899SCharles.Forsyth Point odeltatv;
354537da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
354637da2899SCharles.Forsyth
354737da2899SCharles.Forsyth odeltatv = tkt->deltatv;
354837da2899SCharles.Forsyth vw = tk->act.width - tk->ipad.x;
354937da2899SCharles.Forsyth ntot = tktmaxwid(tkt->start.next);
355037da2899SCharles.Forsyth if(ntot < tkt->deltatv.x +vw)
355137da2899SCharles.Forsyth ntot = tkt->deltatv.x + vw;
355237da2899SCharles.Forsyth e = tktview(tk, arg, val, vw, &tkt->deltatv.x, ntot, Tkhorizontal);
355337da2899SCharles.Forsyth if(e == nil) {
355437da2899SCharles.Forsyth e = tktsetscroll(tk, Tkhorizontal);
355537da2899SCharles.Forsyth if(e == nil)
355637da2899SCharles.Forsyth tktfixscroll(tk, odeltatv);
355737da2899SCharles.Forsyth }
355837da2899SCharles.Forsyth return e;
355937da2899SCharles.Forsyth }
356037da2899SCharles.Forsyth
356137da2899SCharles.Forsyth static int
istext(TkTline * l)356237da2899SCharles.Forsyth istext(TkTline *l)
356337da2899SCharles.Forsyth {
356437da2899SCharles.Forsyth TkTitem *i;
356537da2899SCharles.Forsyth
356637da2899SCharles.Forsyth for(i = l->items; i != nil; i = i->next)
356737da2899SCharles.Forsyth if(i->kind == TkTwin || i->kind == TkTmark)
356837da2899SCharles.Forsyth return 0;
356937da2899SCharles.Forsyth return 1;
357037da2899SCharles.Forsyth }
357137da2899SCharles.Forsyth
357237da2899SCharles.Forsyth static void
tkadjpage(Tk * tk,int ody,int * dy)357337da2899SCharles.Forsyth tkadjpage(Tk *tk, int ody, int *dy)
357437da2899SCharles.Forsyth {
357537da2899SCharles.Forsyth int y, a, b, d;
357637da2899SCharles.Forsyth TkTindex ix;
357737da2899SCharles.Forsyth TkTline *l;
357837da2899SCharles.Forsyth
357937da2899SCharles.Forsyth d = *dy-ody;
358037da2899SCharles.Forsyth y = d > 0 ? tk->act.height : 0;
358137da2899SCharles.Forsyth tktxyind(tk, 0, y-d, &ix);
358237da2899SCharles.Forsyth if((l = ix.line) != nil && istext(l)){
358337da2899SCharles.Forsyth a = l->orig.y;
358437da2899SCharles.Forsyth b = a+l->height;
358537da2899SCharles.Forsyth /* print("AP: %d %d %d (%d+%d)\n", a, ody+y, b, ody, y); */
358637da2899SCharles.Forsyth if(a+2 < ody+y && ody+y < b-2){ /* partially obscured line */
358737da2899SCharles.Forsyth if(d > 0)
358837da2899SCharles.Forsyth *dy -= ody+y-a;
358937da2899SCharles.Forsyth else
359037da2899SCharles.Forsyth *dy += b-ody;
359137da2899SCharles.Forsyth }
359237da2899SCharles.Forsyth }
359337da2899SCharles.Forsyth }
359437da2899SCharles.Forsyth
359537da2899SCharles.Forsyth static char*
tktextyview(Tk * tk,char * arg,char ** val)359637da2899SCharles.Forsyth tktextyview(Tk *tk, char *arg, char **val)
359737da2899SCharles.Forsyth {
359837da2899SCharles.Forsyth int ntot, vh, d;
359937da2899SCharles.Forsyth char *e;
360037da2899SCharles.Forsyth TkTline *l;
360137da2899SCharles.Forsyth Point odeltatv;
360237da2899SCharles.Forsyth TkTindex ix;
360337da2899SCharles.Forsyth TkText *tkt = TKobj(TkText, tk);
360437da2899SCharles.Forsyth char buf[Tkmaxitem], *v;
360537da2899SCharles.Forsyth
360637da2899SCharles.Forsyth if(*arg != '\0') {
360737da2899SCharles.Forsyth v = tkitem(buf, arg);
360837da2899SCharles.Forsyth if(strcmp(buf, "-pickplace") == 0)
360937da2899SCharles.Forsyth return tktextsee(tk,v, val);
361037da2899SCharles.Forsyth if(strcmp(buf, "moveto") != 0 && strcmp(buf, "scroll") != 0) {
361137da2899SCharles.Forsyth e = tktindparse(tk, &arg, &ix);
361237da2899SCharles.Forsyth if(e != nil)
361337da2899SCharles.Forsyth return e;
361437da2899SCharles.Forsyth tktsee(tk, &ix, 1);
361537da2899SCharles.Forsyth return nil;
361637da2899SCharles.Forsyth }
361737da2899SCharles.Forsyth }
361837da2899SCharles.Forsyth odeltatv = tkt->deltatv;
361937da2899SCharles.Forsyth vh = tk->act.height;
362037da2899SCharles.Forsyth l = tkt->end.prev;
362137da2899SCharles.Forsyth ntot = l->orig.y + l->height;
362237da2899SCharles.Forsyth // if(ntot < tkt->deltatv.y + vh)
362337da2899SCharles.Forsyth // ntot = tkt->deltatv.y + vh;
362437da2899SCharles.Forsyth e = tktview(tk, arg, val, vh, &tkt->deltatv.y, ntot, Tkvertical);
362537da2899SCharles.Forsyth d = tkt->deltatv.y-odeltatv.y;
362637da2899SCharles.Forsyth if(d == vh || d == -vh)
362737da2899SCharles.Forsyth tkadjpage(tk, odeltatv.y, &tkt->deltatv.y);
362837da2899SCharles.Forsyth if(e == nil) {
362937da2899SCharles.Forsyth e = tktsetscroll(tk, Tkvertical);
363037da2899SCharles.Forsyth if(e == nil)
363137da2899SCharles.Forsyth tktfixscroll(tk, odeltatv);
363237da2899SCharles.Forsyth }
363337da2899SCharles.Forsyth return e;
363437da2899SCharles.Forsyth }
363537da2899SCharles.Forsyth static void
tktextfocusorder(Tk * tk)363637da2899SCharles.Forsyth tktextfocusorder(Tk *tk)
363737da2899SCharles.Forsyth {
363837da2899SCharles.Forsyth TkTindex ix;
363937da2899SCharles.Forsyth TkText *t;
364037da2899SCharles.Forsyth Tk *isub;
364137da2899SCharles.Forsyth
364237da2899SCharles.Forsyth t = TKobj(TkText, tk);
364337da2899SCharles.Forsyth tktstartind(t, &ix);
364437da2899SCharles.Forsyth do {
364537da2899SCharles.Forsyth if(ix.item->kind == TkTwin) {
364637da2899SCharles.Forsyth isub = ix.item->iwin->sub;
364737da2899SCharles.Forsyth if(isub != nil)
364837da2899SCharles.Forsyth tkappendfocusorder(isub);
364937da2899SCharles.Forsyth }
365037da2899SCharles.Forsyth } while(tktadjustind(t, TkTbyitem, &ix));
365137da2899SCharles.Forsyth }
365237da2899SCharles.Forsyth
365337da2899SCharles.Forsyth TkCmdtab tktextcmd[] =
365437da2899SCharles.Forsyth {
365537da2899SCharles.Forsyth "bbox", tktextbbox,
365637da2899SCharles.Forsyth "cget", tktextcget,
365737da2899SCharles.Forsyth "compare", tktextcompare,
365837da2899SCharles.Forsyth "configure", tktextconfigure,
365937da2899SCharles.Forsyth "debug", tktextdebug,
366037da2899SCharles.Forsyth "delete", tktextdelete,
366137da2899SCharles.Forsyth "dlineinfo", tktextdlineinfo,
366237da2899SCharles.Forsyth "dump", tktextdump,
366337da2899SCharles.Forsyth "get", tktextget,
366437da2899SCharles.Forsyth "index", tktextindex,
366537da2899SCharles.Forsyth "insert", tktextinsert,
366637da2899SCharles.Forsyth "mark", tktextmark,
366737da2899SCharles.Forsyth "scan", tktextscan,
366837da2899SCharles.Forsyth "search", tktextsearch,
366937da2899SCharles.Forsyth "see", tktextsee,
367037da2899SCharles.Forsyth "selection", tktextselection,
367137da2899SCharles.Forsyth "tag", tktexttag,
367237da2899SCharles.Forsyth "window", tktextwindow,
367337da2899SCharles.Forsyth "xview", tktextxview,
367437da2899SCharles.Forsyth "yview", tktextyview,
367537da2899SCharles.Forsyth "tkTextButton1", tktextbutton1,
367637da2899SCharles.Forsyth "tkTextButton1R", tktextbutton1r,
367737da2899SCharles.Forsyth "tkTextDelIns", tktextdelins,
367837da2899SCharles.Forsyth "tkTextInsert", tktextinserti,
367937da2899SCharles.Forsyth "tkTextSelectTo", tktextselectto,
368037da2899SCharles.Forsyth "tkTextSetCursor", tktextsetcursor,
368137da2899SCharles.Forsyth "tkTextScrollPages", tktextscrollpages,
368237da2899SCharles.Forsyth "tkTextCursor", tktextcursor,
368337da2899SCharles.Forsyth nil
368437da2899SCharles.Forsyth };
368537da2899SCharles.Forsyth
368637da2899SCharles.Forsyth TkMethod textmethod = {
368737da2899SCharles.Forsyth "text",
368837da2899SCharles.Forsyth tktextcmd,
368937da2899SCharles.Forsyth tkfreetext,
369037da2899SCharles.Forsyth tkdrawtext,
369137da2899SCharles.Forsyth tktextgeom,
369237da2899SCharles.Forsyth nil,
369337da2899SCharles.Forsyth tktextfocusorder,
369437da2899SCharles.Forsyth tktdirty,
369537da2899SCharles.Forsyth tktrelpos,
369637da2899SCharles.Forsyth tktextevent,
369737da2899SCharles.Forsyth nil, /* XXX need to implement textsee */
3698c9c0d12eSforsyth tktinwindow,
3699c9c0d12eSforsyth nil,
3700c9c0d12eSforsyth tktxtforgetsub,
370137da2899SCharles.Forsyth };
3702