entry.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. #include <lib9.h>
  2. #include <kernel.h>
  3. #include "draw.h"
  4. #include "keyboard.h"
  5. #include "tk.h"
  6. /* Widget Commands (+ means implemented)
  7. +bbox
  8. +cget
  9. +configure
  10. +delete
  11. +get
  12. +icursor
  13. +index
  14. scan
  15. +selection
  16. +xview
  17. +see
  18. */
  19. #define O(t, e) ((long)(&((t*)0)->e))
  20. #define CNTL(c) ((c)&0x1f)
  21. #define DEL 0x7f
  22. /* Layout constants */
  23. enum {
  24. Entrypady = 0,
  25. Entrypadx = 0,
  26. Inswidth = 2,
  27. Ecursoron = 1<<0,
  28. Ecenter = 1<<1,
  29. Eright = 1<<2,
  30. Eleft = 1<<3,
  31. Ewordsel = 1<<4,
  32. Ejustify = Ecenter|Eleft|Eright
  33. };
  34. static TkStab tkjust[] =
  35. {
  36. "left", Eleft,
  37. "right", Eright,
  38. "center", Ecenter,
  39. nil
  40. };
  41. static
  42. TkEbind b[] =
  43. {
  44. {TkKey, "%W delete sel.first sel.last; %W insert insert {%A};%W see insert"},
  45. {TkKey|CNTL('a'), "%W icursor 0;%W see insert;%W selection clear"},
  46. {TkKey|Home, "%W icursor 0;%W see insert;%W selection clear"},
  47. {TkKey|CNTL('d'), "%W delete insert; %W see insert"},
  48. {TkKey|CNTL('e'), "%W icursor end; %W see insert;%W selection clear"},
  49. {TkKey|End, "%W icursor end; %W see insert;%W selection clear"},
  50. {TkKey|CNTL('h'), "%W tkEntryBS;%W see insert"},
  51. {TkKey|CNTL('k'), "%W delete insert end;%W see insert"},
  52. {TkKey|CNTL('u'), "%W delete 0 end;%W see insert"},
  53. {TkKey|CNTL('w'), "%W delete sel.first sel.last; %W tkEntryBW;%W see insert"},
  54. {TkKey|DEL, "%W tkEntryBS 1;%W see insert"},
  55. {TkKey|CNTL('\\'), "%W selection clear"},
  56. {TkKey|CNTL('/'), "%W selection range 0 end"},
  57. {TkKey|Left, "%W icursor insert-1;%W selection clear;%W selection from insert;%W see insert"},
  58. {TkKey|Right, "%W icursor insert+1;%W selection clear;%W selection from insert;%W see insert"},
  59. {TkButton1P, "focus %W; %W tkEntryB1P %X"},
  60. {TkButton1P|TkMotion, "%W tkEntryB1M %X"},
  61. {TkButton1R, "%W tkEntryB1R"},
  62. {TkButton1P|TkDouble, "%W tkEntryB1P %X;%W selection word @%x"},
  63. {TkButton2P, "%W tkEntryB2P %x"},
  64. {TkButton2P|TkMotion, "%W xview scroll %x scr"},
  65. {TkFocusin, "%W tkEntryFocus in"},
  66. {TkFocusout, "%W tkEntryFocus out"},
  67. {TkKey|APP|'\t', ""},
  68. {TkKey|BackTab, ""},
  69. };
  70. typedef struct TkEntry TkEntry;
  71. struct TkEntry
  72. {
  73. Rune* text;
  74. int textlen;
  75. char* xscroll;
  76. char* show;
  77. int flag;
  78. int oldx;
  79. int icursor; /* index of insertion cursor */
  80. int anchor; /* selection anchor point */
  81. int sel0; /* index of start of selection */
  82. int sel1; /* index of end of selection */
  83. int x0; /* x-offset of visible area */
  84. /* derived values */
  85. int v0; /* index of first visible character */
  86. int v1; /* index of last visible character + 1 */
  87. int xlen; /* length of text in pixels*/
  88. int xv0; /* position of first visible character */
  89. int xsel0; /* position of start of selection */
  90. int xsel1; /* position of end of selection */
  91. int xicursor; /* position of insertion cursor */
  92. };
  93. static void blinkreset(Tk*);
  94. static
  95. TkOption opts[] =
  96. {
  97. "xscrollcommand", OPTtext, O(TkEntry, xscroll), nil,
  98. "justify", OPTstab, O(TkEntry, flag), tkjust,
  99. "show", OPTtext, O(TkEntry, show), nil,
  100. nil
  101. };
  102. static int
  103. xinset(Tk *tk)
  104. {
  105. return Entrypadx + tk->highlightwidth;
  106. }
  107. static int
  108. yinset(Tk *tk)
  109. {
  110. return Entrypady + tk->highlightwidth;
  111. }
  112. static void
  113. tksizeentry(Tk *tk)
  114. {
  115. if((tk->flag & Tksetwidth) == 0)
  116. tk->req.width = tk->env->wzero*25 + 2*xinset(tk) + Inswidth;
  117. if((tk->flag & Tksetheight) == 0)
  118. tk->req.height = tk->env->font->height+ 2*yinset(tk);
  119. }
  120. int
  121. entrytextwidth(Tk *tk, int n)
  122. {
  123. TkEntry *tke = TKobj(TkEntry, tk);
  124. Rune c;
  125. Font *f;
  126. f = tk->env->font;
  127. if (tke->show != nil) {
  128. chartorune(&c, tke->show);
  129. return n * runestringnwidth(f, &c, 1);
  130. }
  131. return runestringnwidth(f, tke->text, n);
  132. }
  133. static int
  134. x2index(Tk *tk, int x, int *xc)
  135. {
  136. TkEntry *tke = TKobj(TkEntry, tk);
  137. int t0, t1, r, q;
  138. t0 = 0;
  139. t1 = tke->textlen;
  140. while (t0 <= t1) {
  141. r = (t0 + t1) / 2;
  142. q = entrytextwidth(tk, r);
  143. if (q == x) {
  144. if (xc != nil)
  145. *xc = q;
  146. return r;
  147. }
  148. if (q < x)
  149. t0 = r + 1;
  150. else
  151. t1 = r - 1;
  152. }
  153. if (xc != nil)
  154. *xc = t1 > 0 ? entrytextwidth(tk, t1) : 0;
  155. if (t1 < 0)
  156. t1 = 0;
  157. return t1;
  158. }
  159. /*
  160. * recalculate derived values
  161. */
  162. static void
  163. recalcentry(Tk *tk)
  164. {
  165. TkEntry *tke = TKobj(TkEntry, tk);
  166. int x, avail, locked;
  167. locked = lockdisplay(tk->env->top->display);
  168. tke->xlen = entrytextwidth(tk, tke->textlen) + Inswidth;
  169. avail = tk->act.width - 2*xinset(tk);
  170. if (tke->xlen < avail) {
  171. switch(tke->flag & Ejustify) {
  172. default:
  173. tke->x0 = 0;
  174. break;
  175. case Eright:
  176. tke->x0 = -(avail - tke->xlen);
  177. break;
  178. case Ecenter:
  179. tke->x0 = -(avail - tke->xlen) / 2;
  180. break;
  181. }
  182. }
  183. tke->v0 = x2index(tk, tke->x0, &tke->xv0);
  184. tke->v1 = x2index(tk, tk->act.width + tke->x0, &x);
  185. /* perhaps include partial last character */
  186. if (tke->v1 < tke->textlen && x < avail + tke->x0)
  187. tke->v1++;
  188. tke->xsel0 = entrytextwidth(tk, tke->sel0);
  189. tke->xsel1 = entrytextwidth(tk, tke->sel1);
  190. tke->xicursor = entrytextwidth(tk, tke->icursor);
  191. if (locked)
  192. unlockdisplay(tk->env->top->display);
  193. }
  194. char*
  195. tkentry(TkTop *t, char *arg, char **ret)
  196. {
  197. Tk *tk;
  198. char *e;
  199. TkName *names;
  200. TkEntry *tke;
  201. TkOptab tko[3];
  202. tk = tknewobj(t, TKentry, sizeof(Tk)+sizeof(TkEntry));
  203. if(tk == nil)
  204. return TkNomem;
  205. tk->relief = TKsunken;
  206. tk->borderwidth = 1;
  207. tk->flag |= Tktakefocus;
  208. tk->highlightwidth = 1;
  209. tke = TKobj(TkEntry, tk);
  210. tko[0].ptr = tk;
  211. tko[0].optab = tkgeneric;
  212. tko[1].ptr = tke;
  213. tko[1].optab = opts;
  214. tko[2].ptr = nil;
  215. names = nil;
  216. e = tkparse(t, arg, tko, &names);
  217. if(e != nil) {
  218. tkfreeobj(tk);
  219. return e;
  220. }
  221. tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
  222. tksizeentry(tk);
  223. e = tkbindings(t, tk, b, nelem(b));
  224. if(e != nil) {
  225. tkfreeobj(tk);
  226. return e;
  227. }
  228. e = tkaddchild(t, tk, &names);
  229. tkfreename(names);
  230. if(e != nil) {
  231. tkfreeobj(tk);
  232. return e;
  233. }
  234. tk->name->link = nil;
  235. recalcentry(tk);
  236. return tkvalue(ret, "%s", tk->name->name);
  237. }
  238. static char*
  239. tkentrycget(Tk *tk, char *arg, char **val)
  240. {
  241. TkOptab tko[3];
  242. TkEntry *tke = TKobj(TkEntry, tk);
  243. tko[0].ptr = tk;
  244. tko[0].optab = tkgeneric;
  245. tko[1].ptr = tke;
  246. tko[1].optab = opts;
  247. tko[2].ptr = nil;
  248. return tkgencget(tko, arg, val, tk->env->top);
  249. }
  250. void
  251. tkfreeentry(Tk *tk)
  252. {
  253. TkEntry *tke = TKobj(TkEntry, tk);
  254. free(tke->xscroll);
  255. free(tke->text);
  256. free(tke->show);
  257. }
  258. static void
  259. tkentrytext(Image *i, Rectangle s, Tk *tk, TkEnv *env)
  260. {
  261. TkEntry *tke = TKobj(TkEntry, tk);
  262. Point dp;
  263. int s0, s1, xs0, xs1, j;
  264. Rectangle r;
  265. Rune showr, *text;
  266. dp = Pt(s.min.x - (tke->x0 - tke->xv0), s.min.y);
  267. if (tke->show) {
  268. chartorune(&showr, tke->show);
  269. text = mallocz(sizeof(Rune) * (tke->textlen+1), 0);
  270. if (text == nil)
  271. return;
  272. for (j = 0; j < tke->textlen; j++)
  273. text[j] = showr;
  274. } else
  275. text = tke->text;
  276. runestringn(i, dp, tkgc(env, TkCforegnd), dp, env->font,
  277. text+tke->v0, tke->v1-tke->v0);
  278. if (tke->sel0 < tke->v1 && tke->sel1 > tke->v0) {
  279. if (tke->sel0 < tke->v0) {
  280. s0 = tke->v0;
  281. xs0 = tke->xv0 - tke->x0;
  282. } else {
  283. s0 = tke->sel0;
  284. xs0 = tke->xsel0 - tke->x0;
  285. }
  286. if (tke->sel1 > tke->v1) {
  287. s1 = tke->v1;
  288. xs1 = s.max.x;
  289. } else {
  290. s1 = tke->sel1;
  291. xs1 = tke->xsel1 - tke->x0;
  292. }
  293. r = rectaddpt(Rect(xs0, 0, xs1, env->font->height), s.min);
  294. tktextsdraw(i, r, env, 1);
  295. runestringn(i, r.min, tkgc(env, TkCselectfgnd), r.min, env->font,
  296. text+s0, s1-s0);
  297. }
  298. if((tke->flag&Ecursoron) && tke->icursor >= tke->v0 && tke->icursor <= tke->v1) {
  299. r = Rect(
  300. tke->xicursor - tke->x0, 0,
  301. tke->xicursor - tke->x0 + Inswidth, env->font->height
  302. );
  303. draw(i, rectaddpt(r, s.min), tkgc(env, TkCforegnd), nil, ZP);
  304. }
  305. if (tke->show)
  306. free(text);
  307. }
  308. char*
  309. tkdrawentry(Tk *tk, Point orig)
  310. {
  311. Point p;
  312. TkEnv *env;
  313. Rectangle r, s;
  314. Image *i;
  315. int xp, yp;
  316. env = tk->env;
  317. r.min = ZP;
  318. r.max.x = tk->act.width + 2*tk->borderwidth;
  319. r.max.y = tk->act.height + 2*tk->borderwidth;
  320. i = tkitmp(env, r.max, TkCbackgnd);
  321. if(i == nil)
  322. return nil;
  323. xp = tk->borderwidth + xinset(tk);
  324. yp = tk->borderwidth + yinset(tk);
  325. s = r;
  326. s.min.x += xp;
  327. s.max.x -= xp;
  328. s.min.y += yp;
  329. s.max.y -= yp;
  330. tkentrytext(i, s, tk, env);
  331. tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
  332. if (tkhaskeyfocus(tk))
  333. tkbox(i, insetrect(r, tk->borderwidth), tk->highlightwidth, tkgc(tk->env, TkChighlightfgnd));
  334. p.x = tk->act.x + orig.x;
  335. p.y = tk->act.y + orig.y;
  336. r = rectaddpt(r, p);
  337. draw(tkimageof(tk), r, i, nil, ZP);
  338. return nil;
  339. }
  340. char*
  341. tkentrysh(Tk *tk)
  342. {
  343. TkEntry *tke = TKobj(TkEntry, tk);
  344. int dx, top, bot;
  345. char *val, *cmd, *v, *e;
  346. if(tke->xscroll == nil)
  347. return nil;
  348. bot = 0;
  349. top = Tkfpscalar;
  350. if(tke->text != 0 && tke->textlen != 0) {
  351. dx = tk->act.width - 2*xinset(tk);
  352. if (tke->xlen > dx) {
  353. bot = TKI2F(tke->x0) / tke->xlen;
  354. top = TKI2F(tke->x0 + dx) / tke->xlen;
  355. }
  356. }
  357. val = mallocz(Tkminitem, 0);
  358. if(val == nil)
  359. return TkNomem;
  360. v = tkfprint(val, bot);
  361. *v++ = ' ';
  362. tkfprint(v, top);
  363. cmd = mallocz(Tkminitem, 0);
  364. if(cmd == nil) {
  365. free(val);
  366. return TkNomem;
  367. }
  368. sprint(cmd, "%s %s", tke->xscroll, val);
  369. e = tkexec(tk->env->top, cmd, nil);
  370. free(cmd);
  371. free(val);
  372. return e;
  373. }
  374. void
  375. tkentrygeom(Tk *tk)
  376. {
  377. char *e;
  378. e = tkentrysh(tk);
  379. if ((e != nil) && /* XXX - Tad: should propagate not print */
  380. (tk->name != nil))
  381. print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
  382. recalcentry(tk);
  383. }
  384. static char*
  385. tkentryconf(Tk *tk, char *arg, char **val)
  386. {
  387. char *e;
  388. TkGeom g;
  389. int bd;
  390. TkOptab tko[3];
  391. TkEntry *tke = TKobj(TkEntry, tk);
  392. tko[0].ptr = tk;
  393. tko[0].optab = tkgeneric;
  394. tko[1].ptr = tke;
  395. tko[1].optab = opts;
  396. tko[2].ptr = nil;
  397. if(*arg == '\0')
  398. return tkconflist(tko, val);
  399. bd = tk->borderwidth;
  400. g = tk->req;
  401. e = tkparse(tk->env->top, arg, tko, nil);
  402. tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
  403. tksizeentry(tk);
  404. tkgeomchg(tk, &g, bd);
  405. recalcentry(tk);
  406. tk->dirty = tkrect(tk, 1);
  407. return e;
  408. }
  409. static char*
  410. tkentryparseindex(Tk *tk, char *buf, int *index)
  411. {
  412. TkEntry *tke = TKobj(TkEntry, tk);
  413. TkEnv *env;
  414. char *mod;
  415. int i, x, locked, modstart;
  416. modstart = 0;
  417. for(mod = buf; *mod != '\0'; mod++)
  418. if(*mod == '-' || *mod == '+') {
  419. modstart = *mod;
  420. *mod = '\0';
  421. break;
  422. }
  423. if(strcmp(buf, "end") == 0)
  424. i = tke->textlen;
  425. else
  426. if(strcmp(buf, "anchor") == 0)
  427. i = tke->anchor;
  428. else
  429. if(strcmp(buf, "insert") == 0)
  430. i = tke->icursor;
  431. else
  432. if(strcmp(buf, "sel.first") == 0)
  433. i = tke->sel0;
  434. else
  435. if(strcmp(buf, "sel.last") == 0)
  436. i = tke->sel1;
  437. else
  438. if(buf[0] >= '0' && buf[0] <= '9')
  439. i = atoi(buf);
  440. else
  441. if(buf[0] == '@') {
  442. x = atoi(buf+1) - xinset(tk);
  443. if(tke->textlen == 0) {
  444. *index = 0;
  445. return nil;
  446. }
  447. env = tk->env;
  448. locked = lockdisplay(env->top->display);
  449. i = x2index(tk, x + tke->x0, nil); /* XXX could possibly select nearest character? */
  450. if(locked)
  451. unlockdisplay(env->top->display);
  452. }
  453. else
  454. return TkBadix;
  455. if(i < 0 || i > tke->textlen)
  456. return TkBadix;
  457. if(modstart) {
  458. *mod = modstart;
  459. i += atoi(mod);
  460. if(i < 0)
  461. i = 0;
  462. if(i > tke->textlen)
  463. i = tke->textlen;
  464. }
  465. *index = i;
  466. return nil;
  467. }
  468. /*
  469. * return bounding box of character at index, in coords relative to
  470. * the top left position of the text.
  471. */
  472. static Rectangle
  473. tkentrybbox(Tk *tk, int index)
  474. {
  475. TkEntry *tke;
  476. TkEnv *env;
  477. Display *d;
  478. int x, cw, locked;
  479. Rectangle r;
  480. tke = TKobj(TkEntry, tk);
  481. env = tk->env;
  482. d = env->top->display;
  483. locked = lockdisplay(d);
  484. x = entrytextwidth(tk, index);
  485. if (index < tke->textlen)
  486. cw = entrytextwidth(tk, index+1) - x;
  487. else
  488. cw = Inswidth;
  489. if(locked)
  490. unlockdisplay(d);
  491. r.min.x = x;
  492. r.min.y = 0;
  493. r.max.x = x + cw;
  494. r.max.y = env->font->height;
  495. return r;
  496. }
  497. static void
  498. tkentrysee(Tk *tk, int index, int jump)
  499. {
  500. TkEntry *tke = TKobj(TkEntry, tk);
  501. int dx, margin;
  502. Rectangle r;
  503. r = tkentrybbox(tk, index);
  504. dx = tk->act.width - 2*xinset(tk);
  505. if (jump)
  506. margin = dx / 4;
  507. else
  508. margin = 0;
  509. if (r.min.x <= tke->x0 || r.max.x > tke->x0 + dx) {
  510. if (r.min.x <= tke->x0) {
  511. tke->x0 = r.min.x - margin;
  512. if (tke->x0 < 0)
  513. tke->x0 = 0;
  514. } else if (r.max.x >= tke->x0 + dx) {
  515. tke->x0 = r.max.x - dx + margin;
  516. if (tke->x0 > tke->xlen - dx)
  517. tke->x0 = tke->xlen - dx;
  518. }
  519. tk->dirty = tkrect(tk, 0);
  520. }
  521. r = rectaddpt(r, Pt(xinset(tk) - tke->x0, yinset(tk)));
  522. tksee(tk, r, r.min);
  523. }
  524. static char*
  525. tkentryseecmd(Tk *tk, char *arg, char **val)
  526. {
  527. int index;
  528. char *e, *buf;
  529. USED(val);
  530. buf = mallocz(Tkmaxitem, 0);
  531. if(buf == nil)
  532. return TkNomem;
  533. tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
  534. e = tkentryparseindex(tk, buf, &index);
  535. free(buf);
  536. if(e != nil)
  537. return e;
  538. tkentrysee(tk, index, 1);
  539. recalcentry(tk);
  540. return nil;
  541. }
  542. static char*
  543. tkentrybboxcmd(Tk *tk, char *arg, char **val)
  544. {
  545. TkEntry *tke = TKobj(TkEntry, tk);
  546. char *r, *buf;
  547. int index;
  548. Rectangle bbox;
  549. buf = mallocz(Tkmaxitem, 0);
  550. if(buf == nil)
  551. return TkNomem;
  552. tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
  553. r = tkentryparseindex(tk, buf, &index);
  554. free(buf);
  555. if(r != nil)
  556. return r;
  557. bbox = rectaddpt(tkentrybbox(tk, index), Pt(xinset(tk) - tke->x0, yinset(tk)));
  558. return tkvalue(val, "%d %d %d %d", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
  559. }
  560. static char*
  561. tkentryindex(Tk *tk, char *arg, char **val)
  562. {
  563. int index;
  564. char *r, *buf;
  565. buf = mallocz(Tkmaxitem, 0);
  566. if(buf == nil)
  567. return TkNomem;
  568. tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
  569. r = tkentryparseindex(tk, buf, &index);
  570. free(buf);
  571. if(r != nil)
  572. return r;
  573. return tkvalue(val, "%d", index);
  574. }
  575. static char*
  576. tkentryicursor(Tk *tk, char *arg, char **val)
  577. {
  578. TkEntry *tke = TKobj(TkEntry, tk);
  579. int index, locked;
  580. char *r, *buf;
  581. USED(val);
  582. buf = mallocz(Tkmaxitem, 0);
  583. if(buf == nil)
  584. return TkNomem;
  585. tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
  586. r = tkentryparseindex(tk, buf, &index);
  587. free(buf);
  588. if(r != nil)
  589. return r;
  590. tke->icursor = index;
  591. locked = lockdisplay(tk->env->top->display);
  592. tke->xicursor = entrytextwidth(tk, tke->icursor);
  593. if (locked)
  594. unlockdisplay(tk->env->top->display);
  595. blinkreset(tk);
  596. tk->dirty = tkrect(tk, 1);
  597. return nil;
  598. }
  599. static int
  600. adjustforins(int i, int n, int q)
  601. {
  602. if (i <= q)
  603. q += n;
  604. return q;
  605. }
  606. static int
  607. adjustfordel(int d0, int d1, int q)
  608. {
  609. if (d1 <= q)
  610. q -= d1 - d0;
  611. else if (d0 <= q && q <= d1)
  612. q = d0;
  613. return q;
  614. }
  615. static char*
  616. tkentryget(Tk *tk, char *arg, char **val)
  617. {
  618. TkTop *top;
  619. TkEntry *tke;
  620. int first, last;
  621. char *e, *buf;
  622. tke = TKobj(TkEntry, tk);
  623. if(tke->text == nil)
  624. return nil;
  625. arg = tkskip(arg, " \t");
  626. if(*arg == '\0')
  627. return tkvalue(val, "%.*S", tke->textlen, tke->text);
  628. top = tk->env->top;
  629. buf = mallocz(Tkmaxitem, 0);
  630. if(buf == nil)
  631. return TkNomem;
  632. arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
  633. e = tkentryparseindex(tk, buf, &first);
  634. if(e != nil) {
  635. free(buf);
  636. return e;
  637. }
  638. last = first+1;
  639. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  640. if(buf[0] != '\0') {
  641. e = tkentryparseindex(tk, buf, &last);
  642. if(e != nil) {
  643. free(buf);
  644. return e;
  645. }
  646. }
  647. free(buf);
  648. if(last <= first || tke->textlen == 0 || first == tke->textlen)
  649. return tkvalue(val, "%S", L"");
  650. return tkvalue(val, "%.*S", last-first, tke->text+first);
  651. }
  652. static char*
  653. tkentryinsert(Tk *tk, char *arg, char **val)
  654. {
  655. TkTop *top;
  656. TkEntry *tke;
  657. int ins, i, n, locked;
  658. char *e, *t, *text, *buf;
  659. Rune *etext;
  660. USED(val);
  661. tke = TKobj(TkEntry, tk);
  662. top = tk->env->top;
  663. buf = mallocz(Tkmaxitem, 0);
  664. if(buf == nil)
  665. return TkNomem;
  666. arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
  667. e = tkentryparseindex(tk, buf, &ins);
  668. free(buf);
  669. if(e != nil)
  670. return e;
  671. if(*arg == '\0')
  672. return nil;
  673. n = strlen(arg) + 1;
  674. if(n < Tkmaxitem)
  675. n = Tkmaxitem;
  676. text = malloc(n);
  677. if(text == nil)
  678. return TkNomem;
  679. tkword(top, arg, text, text+n, nil);
  680. n = utflen(text);
  681. etext = realloc(tke->text, (tke->textlen+n+1)*sizeof(Rune));
  682. if(etext == nil) {
  683. free(text);
  684. return TkNomem;
  685. }
  686. tke->text = etext;
  687. memmove(tke->text+ins+n, tke->text+ins, (tke->textlen-ins)*sizeof(Rune));
  688. t = text;
  689. for(i=0; i<n; i++)
  690. t += chartorune(tke->text+ins+i, t);
  691. free(text);
  692. tke->textlen += n;
  693. tke->sel0 = adjustforins(ins, n, tke->sel0);
  694. tke->sel1 = adjustforins(ins, n, tke->sel1);
  695. tke->icursor = adjustforins(ins, n, tke->icursor);
  696. tke->anchor = adjustforins(ins, n, tke->anchor);
  697. locked = lockdisplay(tk->env->top->display);
  698. if (ins < tke->v0)
  699. tke->x0 += entrytextwidth(tk, tke->v0 + n) + (tke->x0 - tke->xv0);
  700. if (locked)
  701. unlockdisplay(tk->env->top->display);
  702. recalcentry(tk);
  703. e = tkentrysh(tk);
  704. blinkreset(tk);
  705. tk->dirty = tkrect(tk, 1);
  706. return e;
  707. }
  708. static char*
  709. tkentrydelete(Tk *tk, char *arg, char **val)
  710. {
  711. TkTop *top;
  712. TkEntry *tke;
  713. int d0, d1, locked;
  714. char *e, *buf;
  715. Rune *text;
  716. USED(val);
  717. tke = TKobj(TkEntry, tk);
  718. top = tk->env->top;
  719. buf = mallocz(Tkmaxitem, 0);
  720. if(buf == nil)
  721. return TkNomem;
  722. arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
  723. e = tkentryparseindex(tk, buf, &d0);
  724. if(e != nil) {
  725. free(buf);
  726. return e;
  727. }
  728. d1 = d0+1;
  729. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  730. if(buf[0] != '\0') {
  731. e = tkentryparseindex(tk, buf, &d1);
  732. if(e != nil) {
  733. free(buf);
  734. return e;
  735. }
  736. }
  737. free(buf);
  738. if(d1 <= d0 || tke->textlen == 0 || d0 >= tke->textlen)
  739. return nil;
  740. memmove(tke->text+d0, tke->text+d1, (tke->textlen-d1)*sizeof(Rune));
  741. tke->textlen -= d1 - d0;
  742. text = realloc(tke->text, (tke->textlen+1) * sizeof(Rune));
  743. if (text != nil)
  744. tke->text = text;
  745. tke->sel0 = adjustfordel(d0, d1, tke->sel0);
  746. tke->sel1 = adjustfordel(d0, d1, tke->sel1);
  747. tke->icursor = adjustfordel(d0, d1, tke->icursor);
  748. tke->anchor = adjustfordel(d0, d1, tke->anchor);
  749. locked = lockdisplay(tk->env->top->display);
  750. if (d1 < tke->v0)
  751. tke->x0 = entrytextwidth(tk, tke->v0 - (d1 - d0)) + (tke->x0 - tke->xv0);
  752. else if (d0 < tke->v0)
  753. tke->x0 = entrytextwidth(tk, d0);
  754. if (locked)
  755. unlockdisplay(tk->env->top->display);
  756. recalcentry(tk);
  757. e = tkentrysh(tk);
  758. blinkreset(tk);
  759. tk->dirty = tkrect(tk, 1);
  760. return e;
  761. }
  762. /* Used for both backspace and DEL. If a selection exists, delete it.
  763. * Otherwise delete the character to the left(right) of the insertion
  764. * cursor, if any.
  765. */
  766. static char*
  767. tkentrybs(Tk *tk, char *arg, char **val)
  768. {
  769. TkEntry *tke = TKobj(TkEntry, tk);
  770. char *buf, *e;
  771. int ix;
  772. USED(val);
  773. USED(arg);
  774. if(tke->textlen == 0)
  775. return nil;
  776. if(tke->sel0 < tke->sel1)
  777. return tkentrydelete(tk, "sel.first sel.last", nil);
  778. buf = mallocz(Tkmaxitem, 0);
  779. if(buf == nil)
  780. return TkNomem;
  781. tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
  782. ix = -1;
  783. if(buf[0] != '\0') {
  784. e = tkentryparseindex(tk, buf, &ix);
  785. if(e != nil) {
  786. free(buf);
  787. return e;
  788. }
  789. }
  790. if(ix > -1) { /* DEL */
  791. if(tke->icursor >= tke->textlen) {
  792. free(buf);
  793. return nil;
  794. }
  795. }
  796. else { /* backspace */
  797. if(tke->icursor == 0) {
  798. free(buf);
  799. return nil;
  800. }
  801. tke->icursor--;
  802. }
  803. snprint(buf, Tkmaxitem, "%d", tke->icursor);
  804. e = tkentrydelete(tk, buf, nil);
  805. free(buf);
  806. return e;
  807. }
  808. static char*
  809. tkentrybw(Tk *tk, char *arg, char **val)
  810. {
  811. int start;
  812. Rune *text;
  813. TkEntry *tke;
  814. char buf[32];
  815. USED(val);
  816. USED(arg);
  817. tke = TKobj(TkEntry, tk);
  818. if(tke->textlen == 0 || tke->icursor == 0)
  819. return nil;
  820. text = tke->text;
  821. start = tke->icursor-1;
  822. while(start > 0 && !tkiswordchar(text[start]))
  823. --start;
  824. while(start > 0 && tkiswordchar(text[start-1]))
  825. --start;
  826. snprint(buf, sizeof(buf), "%d %d", start, tke->icursor);
  827. return tkentrydelete(tk, buf, nil);
  828. }
  829. char*
  830. tkentryselect(Tk *tk, char *arg, char **val)
  831. {
  832. TkTop *top;
  833. int start, from, to, locked;
  834. TkEntry *tke;
  835. char *e, *buf;
  836. buf = mallocz(Tkmaxitem, 0);
  837. if(buf == nil)
  838. return TkNomem;
  839. tke = TKobj(TkEntry, tk);
  840. top = tk->env->top;
  841. arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
  842. if(strcmp(buf, "clear") == 0) {
  843. tke->sel0 = 0;
  844. tke->sel1 = 0;
  845. }
  846. else
  847. if(strcmp(buf, "from") == 0) {
  848. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  849. e = tkentryparseindex(tk, buf, &tke->anchor);
  850. tke->flag &= ~Ewordsel;
  851. free(buf);
  852. return e;
  853. }
  854. else
  855. if(strcmp(buf, "to") == 0) {
  856. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  857. e = tkentryparseindex(tk, buf, &to);
  858. if(e != nil) {
  859. free(buf);
  860. return e;
  861. }
  862. if(to < tke->anchor) {
  863. if(tke->flag & Ewordsel)
  864. while(to > 0 && tkiswordchar(tke->text[to-1]))
  865. --to;
  866. tke->sel0 = to;
  867. tke->sel1 = tke->anchor;
  868. }
  869. else
  870. if(to >= tke->anchor) {
  871. if(tke->flag & Ewordsel)
  872. while(to < tke->textlen &&
  873. tkiswordchar(tke->text[to]))
  874. to++;
  875. tke->sel0 = tke->anchor;
  876. tke->sel1 = to;
  877. }
  878. tkentrysee(tk, to, 0);
  879. recalcentry(tk);
  880. }
  881. else
  882. if(strcmp(buf, "word") == 0) { /* inferno invention */
  883. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  884. e = tkentryparseindex(tk, buf, &start);
  885. if(e != nil) {
  886. free(buf);
  887. return e;
  888. }
  889. from = start;
  890. while(from > 0 && tkiswordchar(tke->text[from-1]))
  891. --from;
  892. to = start;
  893. while(to < tke->textlen && tkiswordchar(tke->text[to]))
  894. to++;
  895. tke->sel0 = from;
  896. tke->sel1 = to;
  897. tke->anchor = from;
  898. tke->icursor = from;
  899. tke->flag |= Ewordsel;
  900. locked = lockdisplay(tk->env->top->display);
  901. tke->xicursor = entrytextwidth(tk, tke->icursor);
  902. if (locked)
  903. unlockdisplay(tk->env->top->display);
  904. }
  905. else
  906. if(strcmp(buf, "present") == 0) {
  907. e = tkvalue(val, "%d", tke->sel1 > tke->sel0);
  908. free(buf);
  909. return e;
  910. }
  911. else
  912. if(strcmp(buf, "range") == 0) {
  913. arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
  914. e = tkentryparseindex(tk, buf, &from);
  915. if(e != nil) {
  916. free(buf);
  917. return e;
  918. }
  919. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  920. e = tkentryparseindex(tk, buf, &to);
  921. if(e != nil) {
  922. free(buf);
  923. return e;
  924. }
  925. tke->sel0 = from;
  926. tke->sel1 = to;
  927. if(to <= from) {
  928. tke->sel0 = 0;
  929. tke->sel1 = 0;
  930. }
  931. }
  932. else
  933. if(strcmp(buf, "adjust") == 0) {
  934. tkword(top, arg, buf, buf+Tkmaxitem, nil);
  935. e = tkentryparseindex(tk, buf, &to);
  936. if(e != nil) {
  937. free(buf);
  938. return e;
  939. }
  940. if(tke->sel0 == 0 && tke->sel1 == 0) {
  941. tke->sel0 = tke->anchor;
  942. tke->sel1 = to;
  943. }
  944. else {
  945. if(abs(tke->sel0-to) < abs(tke->sel1-to)) {
  946. tke->sel0 = to;
  947. tke->anchor = tke->sel1;
  948. }
  949. else {
  950. tke->sel1 = to;
  951. tke->anchor = tke->sel0;
  952. }
  953. }
  954. if(tke->sel0 > tke->sel1) {
  955. to = tke->sel0;
  956. tke->sel0 = tke->sel1;
  957. tke->sel1 = to;
  958. }
  959. }
  960. else {
  961. free(buf);
  962. return TkBadcm;
  963. }
  964. locked = lockdisplay(tk->env->top->display);
  965. tke->xsel0 = entrytextwidth(tk, tke->sel0);
  966. tke->xsel1 = entrytextwidth(tk, tke->sel1);
  967. if (locked)
  968. unlockdisplay(tk->env->top->display);
  969. tk->dirty = tkrect(tk, 1);
  970. free(buf);
  971. return nil;
  972. }
  973. static char*
  974. tkentryb2p(Tk *tk, char *arg, char **val)
  975. {
  976. TkEntry *tke;
  977. char *buf;
  978. USED(val);
  979. tke = TKobj(TkEntry, tk);
  980. buf = malloc(Tkmaxitem);
  981. if (buf == nil)
  982. return TkNomem;
  983. tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
  984. tke->oldx = atoi(buf);
  985. return nil;
  986. }
  987. static char*
  988. tkentryxview(Tk *tk, char *arg, char **val)
  989. {
  990. int locked;
  991. TkEnv *env;
  992. TkEntry *tke;
  993. char *buf, *v;
  994. int dx, top, bot, amount, ix, x;
  995. char *e;
  996. tke = TKobj(TkEntry, tk);
  997. env = tk->env;
  998. dx = tk->act.width - 2*xinset(tk);
  999. buf = mallocz(Tkmaxitem, 0);
  1000. if(buf == nil)
  1001. return TkNomem;
  1002. if(*arg == '\0') {
  1003. if (tke->textlen == 0 || tke->xlen < dx) {
  1004. bot = TKI2F(0);
  1005. top = TKI2F(1);
  1006. } else {
  1007. bot = TKI2F(tke->x0) / tke->xlen;
  1008. top = TKI2F(tke->x0 + dx) / tke->xlen;
  1009. }
  1010. v = tkfprint(buf, bot);
  1011. *v++ = ' ';
  1012. tkfprint(v, top);
  1013. e = tkvalue(val, "%s", buf);
  1014. free(buf);
  1015. return e;
  1016. }
  1017. arg = tkitem(buf, arg);
  1018. if(strcmp(buf, "moveto") == 0) {
  1019. e = tkfracword(env->top, &arg, &top, nil);
  1020. if (e != nil) {
  1021. free(buf);
  1022. return e;
  1023. }
  1024. tke->x0 = TKF2I(top*tke->xlen);
  1025. }
  1026. else
  1027. if(strcmp(buf, "scroll") == 0) {
  1028. arg = tkitem(buf, arg);
  1029. amount = atoi(buf);
  1030. if(*arg == 'p') /* Pages */
  1031. amount *= (9*tke->xlen)/10;
  1032. else
  1033. if(*arg == 's') { /* Inferno-ism, "scr", must be used in the context of button2p */
  1034. x = amount;
  1035. amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0);
  1036. tke->oldx = x;
  1037. }
  1038. tke->x0 += amount;
  1039. }
  1040. else {
  1041. e = tkentryparseindex(tk, buf, &ix);
  1042. if(e != nil) {
  1043. free(buf);
  1044. return e;
  1045. }
  1046. locked = lockdisplay(env->top->display);
  1047. tke->x0 = entrytextwidth(tk, ix);
  1048. if (locked)
  1049. unlockdisplay(env->top->display);
  1050. }
  1051. free(buf);
  1052. if (tke->x0 > tke->xlen - dx)
  1053. tke->x0 = tke->xlen - dx;
  1054. if (tke->x0 < 0)
  1055. tke->x0 = 0;
  1056. recalcentry(tk);
  1057. e = tkentrysh(tk);
  1058. blinkreset(tk);
  1059. tk->dirty = tkrect(tk, 1);
  1060. return e;
  1061. }
  1062. static void
  1063. autoselect(Tk *tk, void *v, int cancelled)
  1064. {
  1065. TkEntry *tke = TKobj(TkEntry, tk);
  1066. Rectangle hitr;
  1067. char buf[32];
  1068. Point p;
  1069. USED(v);
  1070. if (cancelled)
  1071. return;
  1072. p = tkscrn2local(tk, Pt(tke->oldx, 0));
  1073. p.y = 0;
  1074. if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
  1075. return;
  1076. snprint(buf, sizeof(buf), "to @%d", p.x);
  1077. tkentryselect(tk, buf, nil);
  1078. tkdirty(tk);
  1079. tkupdate(tk->env->top);
  1080. }
  1081. static char*
  1082. tkentryb1p(Tk *tk, char* arg, char **ret)
  1083. {
  1084. TkEntry *tke = TKobj(TkEntry, tk);
  1085. Point p;
  1086. int i, locked, x;
  1087. char buf[32], *e;
  1088. USED(ret);
  1089. x = atoi(arg);
  1090. p = tkscrn2local(tk, Pt(x, 0));
  1091. sprint(buf, "@%d", p.x);
  1092. e = tkentryparseindex(tk, buf, &i);
  1093. if (e != nil)
  1094. return e;
  1095. tke->sel0 = 0;
  1096. tke->sel1 = 0;
  1097. tke->icursor = i;
  1098. tke->anchor = i;
  1099. tke->flag &= ~Ewordsel;
  1100. locked = lockdisplay(tk->env->top->display);
  1101. tke->xsel0 = 0;
  1102. tke->xsel1 = 0;
  1103. tke->xicursor = entrytextwidth(tk, tke->icursor);
  1104. if (locked)
  1105. unlockdisplay(tk->env->top->display);
  1106. tke->oldx = x;
  1107. blinkreset(tk);
  1108. tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
  1109. tk->dirty = tkrect(tk, 0);
  1110. return nil;
  1111. }
  1112. static char*
  1113. tkentryb1m(Tk *tk, char* arg, char **ret)
  1114. {
  1115. TkEntry *tke = TKobj(TkEntry, tk);
  1116. Point p;
  1117. Rectangle hitr;
  1118. char buf[32];
  1119. USED(ret);
  1120. p.x = atoi(arg);
  1121. tke->oldx = p.x;
  1122. p = tkscrn2local(tk, p);
  1123. p.y = 0;
  1124. if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
  1125. return nil;
  1126. snprint(buf, sizeof(buf), "to @%d", p.x);
  1127. tkentryselect(tk, buf, nil);
  1128. return nil;
  1129. }
  1130. static char*
  1131. tkentryb1r(Tk *tk, char* arg, char **ret)
  1132. {
  1133. USED(tk);
  1134. USED(arg);
  1135. USED(ret);
  1136. tkcancelrepeat(tk);
  1137. return nil;
  1138. }
  1139. static void
  1140. blinkreset(Tk *tk)
  1141. {
  1142. TkEntry *e = TKobj(TkEntry, tk);
  1143. if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
  1144. return;
  1145. e->flag |= Ecursoron;
  1146. tkblinkreset(tk);
  1147. }
  1148. static void
  1149. showcaret(Tk *tk, int on)
  1150. {
  1151. TkEntry *e = TKobj(TkEntry, tk);
  1152. if (on)
  1153. e->flag |= Ecursoron;
  1154. else
  1155. e->flag &= ~Ecursoron;
  1156. tk->dirty = tkrect(tk, 0);
  1157. }
  1158. char*
  1159. tkentryfocus(Tk *tk, char* arg, char **ret)
  1160. {
  1161. int on = 0;
  1162. USED(ret);
  1163. if (tk->flag&Tkdisabled)
  1164. return nil;
  1165. if(strcmp(arg, " in") == 0) {
  1166. tkblink(tk, showcaret);
  1167. on = 1;
  1168. }
  1169. else
  1170. tkblink(nil, nil);
  1171. showcaret(tk, on);
  1172. return nil;
  1173. }
  1174. static
  1175. TkCmdtab tkentrycmd[] =
  1176. {
  1177. "cget", tkentrycget,
  1178. "configure", tkentryconf,
  1179. "delete", tkentrydelete,
  1180. "get", tkentryget,
  1181. "icursor", tkentryicursor,
  1182. "index", tkentryindex,
  1183. "insert", tkentryinsert,
  1184. "selection", tkentryselect,
  1185. "xview", tkentryxview,
  1186. "tkEntryBS", tkentrybs,
  1187. "tkEntryBW", tkentrybw,
  1188. "tkEntryB1P", tkentryb1p,
  1189. "tkEntryB1M", tkentryb1m,
  1190. "tkEntryB1R", tkentryb1r,
  1191. "tkEntryB2P", tkentryb2p,
  1192. "tkEntryFocus", tkentryfocus,
  1193. "bbox", tkentrybboxcmd,
  1194. "see", tkentryseecmd,
  1195. nil
  1196. };
  1197. TkMethod entrymethod = {
  1198. "entry",
  1199. tkentrycmd,
  1200. tkfreeentry,
  1201. tkdrawentry,
  1202. tkentrygeom
  1203. };