entry.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. typedef struct Entry Entry;
  9. struct Entry
  10. {
  11. Control;
  12. int border;
  13. CFont *font;
  14. CImage *image;
  15. CImage *textcolor;
  16. CImage *bordercolor;
  17. Rune *text;
  18. int ntext;
  19. int cursor;
  20. int align;
  21. int hasfocus;
  22. int lastbut;
  23. };
  24. enum{
  25. EAlign,
  26. EBorder,
  27. EBordercolor,
  28. EData,
  29. EFocus,
  30. EFont,
  31. EFormat,
  32. EHide,
  33. EImage,
  34. ERect,
  35. EReveal,
  36. EShow,
  37. ESize,
  38. ETextcolor,
  39. EValue,
  40. };
  41. static char *cmds[] = {
  42. [EAlign] = "align",
  43. [EBorder] = "border",
  44. [EBordercolor] = "bordercolor",
  45. [EData] = "data",
  46. [EFocus] = "focus",
  47. [EFont] = "font",
  48. [EFormat] = "format",
  49. [EHide] = "hide",
  50. [EImage] = "image",
  51. [ERect] = "rect",
  52. [EReveal] = "reveal",
  53. [EShow] = "show",
  54. [ESize] = "size",
  55. [ETextcolor] = "textcolor",
  56. [EValue] = "value",
  57. nil
  58. };
  59. static void
  60. entryfree(Control *c)
  61. {
  62. Entry *e;
  63. e = (Entry *)c;
  64. _putctlfont(e->font);
  65. _putctlimage(e->image);
  66. _putctlimage(e->textcolor);
  67. _putctlimage(e->bordercolor);
  68. free(e->text);
  69. }
  70. static Point
  71. entrypoint(Entry *e, int c)
  72. {
  73. Point p;
  74. Rectangle r;
  75. r = e->rect;
  76. if(e->border > 0)
  77. r = insetrect(r, e->border);
  78. p = _ctlalignpoint(r,
  79. runestringnwidth(e->font->font, e->text, e->ntext),
  80. e->font->font->height, e->align);
  81. if(c > e->ntext)
  82. c = e->ntext;
  83. p.x += runestringnwidth(e->font->font, e->text, c);
  84. return p;
  85. }
  86. static void
  87. entryshow(Entry *e)
  88. {
  89. Rectangle r, dr;
  90. Point p;
  91. if (e->hidden)
  92. return;
  93. r = e->rect;
  94. draw(e->screen, r, e->image->image, nil, e->image->image->r.min);
  95. if(e->border > 0){
  96. border(e->screen, r, e->border, e->bordercolor->image, e->bordercolor->image->r.min);
  97. dr = insetrect(r, e->border);
  98. }else
  99. dr = r;
  100. p = entrypoint(e, 0);
  101. _string(e->screen, p, e->textcolor->image,
  102. ZP, e->font->font, nil, e->text, e->ntext,
  103. dr, nil, ZP, SoverD);
  104. if(e->hasfocus){
  105. p = entrypoint(e, e->cursor);
  106. r.min = p;
  107. r.max.x = p.x+1;
  108. r.max.y = p.y+e->font->font->height;
  109. if(rectclip(&r, dr))
  110. draw(e->screen, r, e->textcolor->image, nil, ZP);
  111. }
  112. flushimage(display, 1);
  113. }
  114. static void
  115. entrysetpoint(Entry *e, Point cp)
  116. {
  117. Point p;
  118. int i;
  119. if(!ptinrect(cp, insetrect(e->rect, e->border)))
  120. return;
  121. p = entrypoint(e, 0);
  122. for(i=0; i<e->ntext; i++){
  123. p.x += runestringnwidth(e->font->font, e->text+i, 1);
  124. if(p.x > cp.x)
  125. break;
  126. }
  127. e->cursor = i;
  128. entryshow(e);
  129. }
  130. static void
  131. entrymouse(Control *c, Mouse *m)
  132. {
  133. Entry *e;
  134. e = (Entry*)c;
  135. if(m->buttons==1 && e->lastbut==0)
  136. entrysetpoint(e, m->xy);
  137. e->lastbut = m->buttons;
  138. }
  139. static void
  140. entryctl(Control *c, CParse *cp)
  141. {
  142. int cmd;
  143. Rectangle r;
  144. Entry *e;
  145. Rune *rp;
  146. e = (Entry*)c;
  147. cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
  148. switch(cmd){
  149. default:
  150. ctlerror("%q: unrecognized message '%s'", e->name, cp->str);
  151. break;
  152. case EAlign:
  153. _ctlargcount(e, cp, 2);
  154. e->align = _ctlalignment(cp->args[1]);
  155. break;
  156. case EBorder:
  157. _ctlargcount(e, cp, 2);
  158. if(cp->iargs[1] < 0)
  159. ctlerror("%q: bad border: %c", e->name, cp->str);
  160. e->border = cp->iargs[1];
  161. break;
  162. case EBordercolor:
  163. _ctlargcount(e, cp, 2);
  164. _setctlimage(e, &e->bordercolor, cp->args[1]);
  165. break;
  166. case EData:
  167. _ctlargcount(e, cp, 1);
  168. chanprint(e->data, "%S", e->text);
  169. break;
  170. case EFocus:
  171. _ctlargcount(e, cp, 2);
  172. e->hasfocus = cp->iargs[1];
  173. e->lastbut = 0;
  174. entryshow(e);
  175. break;
  176. case EFont:
  177. _ctlargcount(e, cp, 2);
  178. _setctlfont(e, &e->font, cp->args[1]);
  179. break;
  180. case EFormat:
  181. _ctlargcount(e, cp, 2);
  182. e->format = ctlstrdup(cp->args[1]);
  183. break;
  184. case EHide:
  185. _ctlargcount(e, cp, 1);
  186. e->hidden = 1;
  187. break;
  188. case EImage:
  189. _ctlargcount(e, cp, 2);
  190. _setctlimage(e, &e->image, cp->args[1]);
  191. break;
  192. case ERect:
  193. _ctlargcount(e, cp, 5);
  194. r.min.x = cp->iargs[1];
  195. r.min.y = cp->iargs[2];
  196. r.max.x = cp->iargs[3];
  197. r.max.y = cp->iargs[4];
  198. if(Dx(r)<=0 || Dy(r)<=0)
  199. ctlerror("%q: bad rectangle: %s", e->name, cp->str);
  200. e->rect = r;
  201. break;
  202. case EReveal:
  203. _ctlargcount(e, cp, 1);
  204. e->hidden = 0;
  205. entryshow(e);
  206. break;
  207. case EShow:
  208. _ctlargcount(e, cp, 1);
  209. entryshow(e);
  210. break;
  211. case ESize:
  212. if (cp->nargs == 3)
  213. r.max = Pt(0x7fffffff, 0x7fffffff);
  214. else{
  215. _ctlargcount(e, cp, 5);
  216. r.max.x = cp->iargs[3];
  217. r.max.y = cp->iargs[4];
  218. }
  219. r.min.x = cp->iargs[1];
  220. r.min.y = cp->iargs[2];
  221. 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)
  222. ctlerror("%q: bad sizes: %s", e->name, cp->str);
  223. e->size.min = r.min;
  224. e->size.max = r.max;
  225. break;
  226. case ETextcolor:
  227. _ctlargcount(e, cp, 2);
  228. _setctlimage(e, &e->textcolor, cp->args[1]);
  229. break;
  230. case EValue:
  231. _ctlargcount(e, cp, 2);
  232. rp = _ctlrunestr(cp->args[1]);
  233. if(runestrcmp(rp, e->text) != 0){
  234. free(e->text);
  235. e->text = rp;
  236. e->ntext = runestrlen(e->text);
  237. e->cursor = e->ntext;
  238. entryshow(e);
  239. }else
  240. free(rp);
  241. break;
  242. }
  243. }
  244. static void
  245. entrykey(Entry *e, Rune r)
  246. {
  247. Rune *s;
  248. int n;
  249. char *p;
  250. switch(r){
  251. default:
  252. e->text = ctlrealloc(e->text, (e->ntext+1+1)*sizeof(Rune));
  253. memmove(e->text+e->cursor+1, e->text+e->cursor,
  254. (e->ntext+1-e->cursor)*sizeof(Rune));
  255. e->text[e->cursor++] = r;
  256. e->ntext++;
  257. break;
  258. case L'\n': /* newline: return value */
  259. p = _ctlstrrune(e->text);
  260. chanprint(e->event, e->format, e->name, p);
  261. free(p);
  262. return;
  263. case L'\b':
  264. if(e->cursor > 0){
  265. memmove(e->text+e->cursor-1, e->text+e->cursor,
  266. (e->ntext+1-e->cursor)*sizeof(Rune));
  267. e->cursor--;
  268. e->ntext--;
  269. }
  270. break;
  271. case 0x15: /* control U: kill line */
  272. e->cursor = 0;
  273. e->ntext = 0;
  274. break;
  275. case 0x16: /* control V: paste (append snarf buffer) */
  276. s = _ctlgetsnarf();
  277. if(s != nil){
  278. n = runestrlen(s);
  279. e->text = ctlrealloc(e->text, (e->ntext+n+1)*sizeof(Rune));
  280. memmove(e->text+e->cursor+n, e->text+e->cursor,
  281. (e->ntext+1-e->cursor)*sizeof(Rune));
  282. memmove(e->text+e->cursor, s, n*sizeof(Rune));
  283. e->cursor += n;
  284. e->ntext += n;
  285. }
  286. break;
  287. }
  288. e->text[e->ntext] = L'\0';
  289. }
  290. static void
  291. entrykeys(Control *c, Rune *rp)
  292. {
  293. Entry *e;
  294. int i;
  295. e = (Entry *)c;
  296. for(i=0; rp[i]!=L'\0'; i++)
  297. entrykey(e, rp[i]);
  298. entryshow(e);
  299. }
  300. Control*
  301. createentry(Controlset *cs, char *name)
  302. {
  303. Entry *e;
  304. e = (Entry*) _createctl(cs, "entry", sizeof(Entry), name);
  305. e->text = ctlmalloc(sizeof(Rune));
  306. e->ntext = 0;
  307. e->image = _getctlimage("white");
  308. e->textcolor = _getctlimage("black");
  309. e->bordercolor = _getctlimage("black");
  310. e->font = _getctlfont("font");
  311. e->format = ctlstrdup("%q: value %q");
  312. e->border = 0;
  313. e->ctl = entryctl;
  314. e->mouse = entrymouse;
  315. e->key = entrykeys;
  316. e->exit = entryfree;
  317. return (Control *)e;
  318. }