text.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <mouse.h>
  6. #include <keyboard.h>
  7. #include <control.h>
  8. static int debug = 0;
  9. typedef struct Text Text;
  10. struct Text
  11. {
  12. Control;
  13. int border;
  14. int topline;
  15. int scroll;
  16. int nvis;
  17. int lastbut;
  18. CFont *font;
  19. CImage *image;
  20. CImage *textcolor;
  21. CImage *bordercolor;
  22. CImage *selectcolor;
  23. CImage *selectingcolor;
  24. Rune **line;
  25. int selectmode; // Selsingle, Selmulti
  26. int selectstyle; // Seldown, Selup (use Selup only with Selsingle)
  27. uchar *selected;
  28. int nline;
  29. int warp;
  30. int align;
  31. int sel; // line nr of selection made by last button down
  32. int but; // last button down (still being hold)
  33. int offsel; // we are on selection
  34. };
  35. enum
  36. {
  37. Selsingle,
  38. Selmulti,
  39. Seldown,
  40. Selup,
  41. };
  42. enum{
  43. EAccumulate,
  44. EAdd,
  45. EAlign,
  46. EBorder,
  47. EBordercolor,
  48. EClear,
  49. EDelete,
  50. EFocus,
  51. EFont,
  52. EHide,
  53. EImage,
  54. ERect,
  55. EReplace,
  56. EReveal,
  57. EScroll,
  58. ESelect,
  59. ESelectcolor,
  60. ESelectingcolor,
  61. ESelectmode,
  62. ESelectstyle,
  63. EShow,
  64. ESize,
  65. ETextcolor,
  66. ETopline,
  67. EValue,
  68. EWarp,
  69. };
  70. static char *cmds[] = {
  71. [EAccumulate] = "accumulate",
  72. [EAdd] = "add",
  73. [EAlign] = "align",
  74. [EBorder] = "border",
  75. [EBordercolor] = "bordercolor",
  76. [EClear] = "clear",
  77. [EDelete] = "delete",
  78. [EFocus] = "focus",
  79. [EFont] = "font",
  80. [EHide] = "hide",
  81. [EImage] = "image",
  82. [ERect] = "rect",
  83. [EReplace] = "replace",
  84. [EReveal] = "reveal",
  85. [EScroll] = "scroll",
  86. [ESelect] = "select",
  87. [ESelectcolor] = "selectcolor",
  88. [ESelectingcolor] = "selectingcolor",
  89. [ESelectmode] = "selectmode",
  90. [ESelectstyle] = "selectstyle",
  91. [EShow] = "show",
  92. [ESize] = "size",
  93. [ETextcolor] = "textcolor",
  94. [ETopline] = "topline",
  95. [EValue] = "value",
  96. [EWarp] = "warp",
  97. nil
  98. };
  99. static void textshow(Text*);
  100. static void texttogglei(Text*, int);
  101. static int textline(Text*, Point);
  102. static int texttoggle(Text*, Point);
  103. static void
  104. textmouse(Control *c, Mouse *m)
  105. {
  106. Text *t;
  107. int sel;
  108. t = (Text*)c;
  109. if (debug) fprint(2, "textmouse %s t->lastbut %d; m->buttons %d\n", t->name, t->lastbut, m->buttons);
  110. if (t->warp >= 0)
  111. return;
  112. if ((t->selectstyle == Selup) && (m->buttons&7)) {
  113. sel = textline(t, m->xy);
  114. if (t->sel >= 0) {
  115. // if (debug) fprint(2, "textmouse Selup %q sel=%d t->sel=%d t->but=%d\n",
  116. // t->name, sel, t->sel, t->but);
  117. t->offsel = (sel == t->sel) ? 0 : 1;
  118. if ((sel == t->sel &&
  119. ((t->selected[t->sel] && !t->but) ||
  120. ((!t->selected[t->sel]) && t->but))) ||
  121. (sel != t->sel &&
  122. ((t->selected[t->sel] && t->but) ||
  123. ((!t->selected[t->sel]) && (!t->but))))) {
  124. texttogglei(t, t->sel);
  125. }
  126. }
  127. }
  128. if(t->lastbut != (m->buttons&7)){
  129. if(m->buttons & 7){
  130. sel = texttoggle(t, m->xy);
  131. if(sel >= 0) {
  132. if (t->selectstyle == Seldown) {
  133. chanprint(t->event, "%q: select %d %d",
  134. t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
  135. if (debug) fprint(2, "textmouse Seldown event %q: select %d %d\n",
  136. t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
  137. } else {
  138. if (debug) fprint(2, "textmouse Selup no event yet %q: select %d %d\n",
  139. t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
  140. t->sel = sel;
  141. t->but = t->selected[sel] ? (m->buttons & 7) : 0;
  142. }
  143. }
  144. } else if (t->selectstyle == Selup) {
  145. sel = textline(t, m->xy);
  146. t->offsel = 0;
  147. if ((sel >= 0) && (sel == t->sel)) {
  148. chanprint(t->event, "%q: select %d %d",
  149. t->name, sel, t->but);
  150. if (debug) fprint(2, "textmouse Selup event %q: select %d %d\n",
  151. t->name, sel, t->but);
  152. } else if (sel != t->sel) {
  153. if ((t->selected[t->sel] && t->but) ||
  154. ((!t->selected[t->sel]) && (!t->but))) {
  155. texttogglei(t, t->sel);
  156. } else {
  157. textshow(t);
  158. }
  159. if (debug) fprint(2, "textmouse Selup cancel %q: select %d %d\n",
  160. t->name, sel, t->but);
  161. }
  162. t->sel = -1;
  163. t->but = 0;
  164. }
  165. t->lastbut = m->buttons & 7;
  166. }
  167. }
  168. static void
  169. textfree(Control *c)
  170. {
  171. int i;
  172. Text *t;
  173. t = (Text*)c;
  174. _putctlfont(t->font);
  175. _putctlimage(t->image);
  176. _putctlimage(t->textcolor);
  177. _putctlimage(t->bordercolor);
  178. _putctlimage(t->selectcolor);
  179. _putctlimage(t->selectingcolor);
  180. for(i=0; i<t->nline; i++)
  181. free(t->line[i]);
  182. free(t->line);
  183. free(t->selected);
  184. }
  185. static void
  186. textshow(Text *t)
  187. {
  188. Rectangle r, tr;
  189. Point p;
  190. int i, ntext;
  191. Font *f;
  192. Rune *text;
  193. if (t->hidden)
  194. return;
  195. r = t->rect;
  196. f = t->font->font;
  197. draw(t->screen, r, t->image->image, nil, t->image->image->r.min);
  198. if(t->border > 0){
  199. border(t->screen, r, t->border, t->bordercolor->image, t->bordercolor->image->r.min);
  200. r = insetrect(r, t->border);
  201. }
  202. tr = r;
  203. t->nvis = Dy(r)/f->height;
  204. for(i=t->topline; i<t->nline && i<t->topline+t->nvis; i++){
  205. text = t->line[i];
  206. ntext = runestrlen(text);
  207. r.max.y = r.min.y+f->height;
  208. if(t->sel == i && t->offsel)
  209. draw(t->screen, r, t->selectingcolor->image, nil, ZP);
  210. else if(t->selected[i])
  211. draw(t->screen, r, t->selectcolor->image, nil, ZP);
  212. p = _ctlalignpoint(r,
  213. runestringnwidth(f, text, ntext),
  214. f->height, t->align);
  215. if(t->warp == i) {
  216. Point p2;
  217. p2.x = p.x + 0.5*runestringnwidth(f, text, ntext);
  218. p2.y = p.y + 0.5*f->height;
  219. moveto(t->controlset->mousectl, p2);
  220. t->warp = -1;
  221. }
  222. _string(t->screen, p, t->textcolor->image,
  223. ZP, f, nil, text, ntext, tr,
  224. nil, ZP, SoverD);
  225. r.min.y += f->height;
  226. }
  227. flushimage(display, 1);
  228. }
  229. static void
  230. textctl(Control *c, CParse *cp)
  231. {
  232. int cmd, i, n;
  233. Rectangle r;
  234. Text *t;
  235. Rune *rp;
  236. t = (Text*)c;
  237. cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
  238. switch(cmd){
  239. default:
  240. ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
  241. break;
  242. case EAlign:
  243. _ctlargcount(t, cp, 2);
  244. t->align = _ctlalignment(cp->args[1]);
  245. break;
  246. case EBorder:
  247. _ctlargcount(t, cp, 2);
  248. if(cp->iargs[1] < 0)
  249. ctlerror("%q: bad border: %c", t->name, cp->str);
  250. t->border = cp->iargs[1];
  251. break;
  252. case EBordercolor:
  253. _ctlargcount(t, cp, 2);
  254. _setctlimage(t, &t->bordercolor, cp->args[1]);
  255. break;
  256. case EClear:
  257. _ctlargcount(t, cp, 1);
  258. for(i=0; i<t->nline; i++)
  259. free(t->line[i]);
  260. free(t->line);
  261. free(t->selected);
  262. t->line = ctlmalloc(sizeof(Rune*));
  263. t->selected = ctlmalloc(1);
  264. t->nline = 0;
  265. textshow(t);
  266. break;
  267. case EDelete:
  268. _ctlargcount(t, cp, 2);
  269. i = cp->iargs[1];
  270. if(i<0 || i>=t->nline)
  271. ctlerror("%q: line number out of range: %s", t->name, cp->str);
  272. free(t->line[i]);
  273. memmove(t->line+i, t->line+i+1, (t->nline-(i+1))*sizeof(Rune*));
  274. memmove(t->selected+i, t->selected+i+1, t->nline-(i+1));
  275. t->nline--;
  276. textshow(t);
  277. break;
  278. case EFocus:
  279. break;
  280. case EFont:
  281. _ctlargcount(t, cp, 2);
  282. _setctlfont(t, &t->font, cp->args[1]);
  283. break;
  284. case EHide:
  285. _ctlargcount(t, cp, 1);
  286. t->hidden = 1;
  287. break;
  288. case EImage:
  289. _ctlargcount(t, cp, 2);
  290. _setctlimage(t, &t->image, cp->args[1]);
  291. break;
  292. case ERect:
  293. _ctlargcount(t, cp, 5);
  294. r.min.x = cp->iargs[1];
  295. r.min.y = cp->iargs[2];
  296. r.max.x = cp->iargs[3];
  297. r.max.y = cp->iargs[4];
  298. if(Dx(r)<=0 || Dy(r)<=0)
  299. ctlerror("%q: bad rectangle: %s", t->name, cp->str);
  300. t->rect = r;
  301. t->nvis = (Dy(r)-2*t->border)/t->font->font->height;
  302. break;
  303. case EReplace:
  304. _ctlargcount(t, cp, 3);
  305. i = cp->iargs[1];
  306. if(i<0 || i>=t->nline)
  307. ctlerror("%q: line number out of range: %s", t->name, cp->str);
  308. free(t->line[i]);
  309. t->line[i] = _ctlrunestr(cp->args[2]);
  310. textshow(t);
  311. break;
  312. case EReveal:
  313. _ctlargcount(t, cp, 1);
  314. t->hidden = 0;
  315. textshow(t);
  316. break;
  317. case EScroll:
  318. _ctlargcount(t, cp, 2);
  319. t->scroll = cp->iargs[1];
  320. break;
  321. case ESelect:
  322. if(cp->nargs!=2 && cp->nargs!=3)
  323. badselect:
  324. ctlerror("%q: bad select message: %s", t->name, cp->str);
  325. if(cp->nargs == 2){
  326. if(strcmp(cp->args[1], "all") == 0){
  327. memset(t->selected, 1, t->nline);
  328. break;
  329. }
  330. if(strcmp(cp->args[1], "none") == 0){
  331. memset(t->selected, 0, t->nline);
  332. break;
  333. }
  334. if(cp->args[1][0]<'0' && '9'<cp->args[1][0])
  335. goto badselect;
  336. texttogglei(t, cp->iargs[1]);
  337. break;
  338. }
  339. if(cp->iargs[1]<0 || cp->iargs[1]>=t->nline)
  340. ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
  341. if(t->selected[cp->iargs[1]] != (cp->iargs[2]!=0))
  342. texttogglei(t, cp->iargs[1]);
  343. break;
  344. case ESelectcolor:
  345. _ctlargcount(t, cp, 2);
  346. _setctlimage(t, &t->selectcolor, cp->args[1]);
  347. break;
  348. case ESelectmode:
  349. _ctlargcount(t, cp, 2);
  350. if(strcmp(cp->args[1], "single") == 0)
  351. t->selectmode = Selsingle;
  352. else if(strncmp(cp->args[1], "multi", 5) == 0)
  353. t->selectmode = Selmulti;
  354. break;
  355. case ESelectstyle:
  356. _ctlargcount(t, cp, 2);
  357. if(strcmp(cp->args[1], "down") == 0)
  358. t->selectstyle = Seldown;
  359. else if(strcmp(cp->args[1], "up") == 0)
  360. t->selectstyle = Selup;
  361. break;
  362. case EShow:
  363. _ctlargcount(t, cp, 1);
  364. textshow(t);
  365. break;
  366. case ESize:
  367. if (cp->nargs == 3)
  368. r.max = Pt(10000, 10000);
  369. else{
  370. _ctlargcount(t, cp, 5);
  371. r.max.x = cp->iargs[3];
  372. r.max.y = cp->iargs[4];
  373. }
  374. r.min.x = cp->iargs[1];
  375. r.min.y = cp->iargs[2];
  376. if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
  377. ctlerror("%q: bad sizes: %s", t->name, cp->str);
  378. t->size.min = r.min;
  379. t->size.max = r.max;
  380. break;
  381. case ETextcolor:
  382. _ctlargcount(t, cp, 2);
  383. _setctlimage(t, &t->textcolor, cp->args[1]);
  384. break;
  385. case ETopline:
  386. _ctlargcount(t, cp, 2);
  387. i = cp->iargs[1];
  388. if(i < 0)
  389. i = 0;
  390. if(i > t->nline)
  391. i = t->nline;
  392. if(t->topline != i){
  393. t->topline = i;
  394. textshow(t);
  395. }
  396. break;
  397. case EValue:
  398. /* set contents to single line */
  399. /* free existing text and fall through to add */
  400. for(i=0; i<t->nline; i++){
  401. free(t->line[i]);
  402. t->line[i] = nil;
  403. }
  404. t->nline = 0;
  405. t->topline = 0;
  406. /* fall through */
  407. case EAccumulate:
  408. case EAdd:
  409. switch (cp->nargs) {
  410. default:
  411. ctlerror("%q: wrong argument count in '%s'", t->name, cp->str);
  412. case 2:
  413. n = t->nline;
  414. break;
  415. case 3:
  416. n = cp->iargs[1];
  417. if(n<0 || n>t->nline)
  418. ctlerror("%q: line number out of range: %s", t->name, cp->str);
  419. break;
  420. }
  421. rp = _ctlrunestr(cp->args[cp->nargs-1]);
  422. t->line = ctlrealloc(t->line, (t->nline+1)*sizeof(Rune*));
  423. memmove(t->line+n+1, t->line+n, (t->nline-n)*sizeof(Rune*));
  424. t->line[n] = rp;
  425. t->selected = ctlrealloc(t->selected, t->nline+1);
  426. memmove(t->selected+n+1, t->selected+n, t->nline-n);
  427. t->selected[n] = (t->selectmode==Selmulti && cmd!=EAccumulate);
  428. t->nline++;
  429. if(t->scroll) {
  430. if(n > t->topline + (t->nvis - 1)){
  431. t->topline = n - (t->nvis - 1);
  432. if(t->topline < 0)
  433. t->topline = 0;
  434. }
  435. if(n < t->topline)
  436. t->topline = n;
  437. }
  438. if(cmd != EAccumulate)
  439. if(t->scroll || t->nline<=t->topline+t->nvis)
  440. textshow(t);
  441. break;
  442. case EWarp:
  443. _ctlargcount(t, cp, 2);
  444. i = cp->iargs[1];
  445. if(i <0 || i>=t->nline)
  446. ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
  447. if(i < t->topline || i >= t->topline+t->nvis){
  448. t->topline = i;
  449. }
  450. t->warp = cp->iargs[1];
  451. textshow(t);
  452. t->warp = -1;
  453. break;
  454. }
  455. }
  456. static void
  457. texttogglei(Text *t, int i)
  458. {
  459. int prev;
  460. if(t->selectmode == Selsingle){
  461. /* clear the others */
  462. prev = t->selected[i];
  463. memset(t->selected, 0, t->nline);
  464. t->selected[i] = prev;
  465. }
  466. t->selected[i] ^= 1;
  467. textshow(t);
  468. }
  469. static int
  470. textline(Text *t, Point p)
  471. {
  472. Rectangle r;
  473. int i;
  474. r = t->rect;
  475. if(t->border > 0)
  476. r = insetrect(r, t->border);
  477. if(!ptinrect(p, r))
  478. return -1;
  479. i = (p.y-r.min.y)/t->font->font->height;
  480. i += t->topline;
  481. if(i >= t->nline)
  482. return -1;
  483. return i;
  484. }
  485. static int
  486. texttoggle(Text *t, Point p)
  487. {
  488. int i;
  489. i = textline(t, p);
  490. if (i >= 0)
  491. texttogglei(t, i);
  492. return i;
  493. }
  494. Control*
  495. createtext(Controlset *cs, char *name)
  496. {
  497. Text *t;
  498. t = (Text*)_createctl(cs, "text", sizeof(Text), name);
  499. t->line = ctlmalloc(sizeof(Rune*));
  500. t->selected = ctlmalloc(1);
  501. t->nline = 0;
  502. t->image = _getctlimage("white");
  503. t->textcolor = _getctlimage("black");
  504. t->bordercolor = _getctlimage("black");
  505. t->selectcolor = _getctlimage("yellow");
  506. t->selectingcolor = _getctlimage("paleyellow");
  507. t->font = _getctlfont("font");
  508. t->selectmode = Selsingle;
  509. t->selectstyle = Selup; // Seldown;
  510. t->lastbut = 0;
  511. t->mouse = textmouse;
  512. t->ctl = textctl;
  513. t->exit = textfree;
  514. t->warp = -1;
  515. t->sel = -1;
  516. t->offsel = 0;
  517. t->but = 0;
  518. return (Control *)t;
  519. }