textbutton.c 7.3 KB

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