menu.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <draw.h>
  12. #include <thread.h>
  13. #include <mouse.h>
  14. #include <keyboard.h>
  15. #include <control.h>
  16. typedef struct Menu0 Menu0; /* Menu is taken by mouse.h */
  17. struct Menu0
  18. {
  19. Control Control;
  20. CImage *image;
  21. CImage *bordercolor;
  22. CImage *textcolor;
  23. CImage *selectcolor;
  24. CImage *selecttextcolor;
  25. CFont *font;
  26. char **line;
  27. int nline;
  28. int border;
  29. int align;
  30. Image *window;
  31. int visible; /* state of menu */
  32. int selection; /* currently selected line; -1 == none */
  33. int prevsel; /* previous selection */
  34. int lastbut; /* previous state of mouse button */
  35. };
  36. enum{
  37. EAdd,
  38. EAlign,
  39. EBorder,
  40. EBordercolor,
  41. EFocus,
  42. EFont,
  43. EFormat,
  44. EHide,
  45. EImage,
  46. ERect,
  47. EReveal,
  48. ESelectcolor,
  49. ESelecttextcolor,
  50. EShow,
  51. ESize,
  52. ETextcolor,
  53. EWindow,
  54. };
  55. static char *cmds[] = {
  56. [EAdd] = "add",
  57. [EAlign] = "align",
  58. [EBorder] = "border",
  59. [EBordercolor] = "bordercolor",
  60. [EFocus] = "focus",
  61. [EFont] = "font",
  62. [EFormat] = "format",
  63. [EHide] = "hide",
  64. [EImage] = "image",
  65. [ERect] = "rect",
  66. [EReveal] = "reveal",
  67. [ESelectcolor] = "selectcolor",
  68. [ESelecttextcolor] = "selecttextcolor",
  69. [EShow] = "show",
  70. [ESize] = "size",
  71. [ETextcolor] = "textcolor",
  72. [EWindow] = "window",
  73. nil
  74. };
  75. static void menushow(Menu0*);
  76. static void menuhide(Menu0*);
  77. static void
  78. menufree(Control *c)
  79. {
  80. Menu0 *m;
  81. m = (Menu0*)c;
  82. _putctlfont(m->font);
  83. _putctlimage(m->image);
  84. _putctlimage(m->textcolor);
  85. _putctlimage(m->bordercolor);
  86. _putctlimage(m->selectcolor);
  87. _putctlimage(m->selecttextcolor);
  88. }
  89. static void
  90. menushow(Menu0 *m)
  91. {
  92. Rectangle r, clipr;
  93. int i, dx, dy, w;
  94. Font *f;
  95. Point p, q;
  96. Image *im, *c;
  97. if(m->Control.hidden || m->window == nil)
  98. return;
  99. m->visible = 1;
  100. f = m->font->font;
  101. draw(m->window, m->Control.rect, m->image->image, nil, m->image->image->r.min);
  102. if(m->border > 0)
  103. border(m->window, m->Control.rect, m->border, m->bordercolor->image, ZP);
  104. /* text goes here */
  105. dx = 0;
  106. for(i=0; i<m->nline; i++){
  107. w = stringwidth(f, m->line[i]);
  108. if(dx < w)
  109. dx = w;
  110. }
  111. dy = m->nline*f->height;
  112. clipr = insetrect(m->Control.rect, m->border);
  113. p = _ctlalignpoint(clipr, dx, dy, m->align);
  114. im = m->textcolor->image;
  115. // if(m->pressed)
  116. // im = m->pressedtextcolor->image;
  117. for(i=0; i<m->nline; i++){
  118. r.min = p;
  119. r.max.x = p.x+dx;
  120. r.max.y = p.y+f->height;
  121. c = im;
  122. if(i == m->selection){
  123. draw(m->window, r, m->selectcolor->image, nil, ZP);
  124. c = m->selecttextcolor->image;
  125. }
  126. q = _ctlalignpoint(r, stringwidth(f, m->line[i]), f->height, m->align%3);
  127. _string(m->window, q, c,
  128. ZP, f, m->line[i], nil, strlen(m->line[i]),
  129. clipr, nil, ZP, SoverD);
  130. p.y += f->height;
  131. }
  132. // if(m->pressed)
  133. // draw(m->Control.screen, m->Control.rect, m->lighm->image, m->mask->image, m->mask->image->r.min);
  134. flushimage(display, 1);
  135. }
  136. static Point
  137. menusize(Menu0 *m)
  138. {
  139. int x, y;
  140. int i;
  141. Point p;
  142. Font *f;
  143. x = 0;
  144. y = 0;
  145. f = m->font->font;
  146. for(i=0; i<m->nline; i++){
  147. p = stringsize(f, m->line[i]);
  148. if(p.x > x)
  149. x = p.x;
  150. y += f->height;
  151. }
  152. return Pt(x+2*m->border, y+2*m->border);
  153. }
  154. static void
  155. menuhide(Menu0 *m)
  156. {
  157. freeimage(m->window);
  158. m->window = nil;
  159. m->Control.rect.max.y = m->Control.rect.min.y; /* go to zero size */
  160. m->lastbut = 0;
  161. m->visible = 0;
  162. if(m->selection >= 0)
  163. m->prevsel = m->selection;
  164. m->selection = -1;
  165. _ctlfocus(&m->Control, 0);
  166. }
  167. static void
  168. menutrack(Control *c, Mouse *ms)
  169. {
  170. Rectangle r;
  171. int s;
  172. Menu0 *m;
  173. m = (Menu0*)c;
  174. if(m->window == nil)
  175. return;
  176. if(m->lastbut && ms->buttons==0){ /* menu was released */
  177. chanprint(m->Control.event, "%q: value %d", m->Control.name, m->selection);
  178. menuhide(m);
  179. return;
  180. }
  181. m->lastbut = ms->buttons;
  182. r = insetrect(m->Control.rect, m->border);
  183. if(!ptinrect(ms->xy, r))
  184. s = -1;
  185. else{
  186. s = (ms->xy.y - r.min.y)/m->font->font->height;
  187. if(s < 0 || s >= m->nline)
  188. s = -1;
  189. }
  190. if(m->visible== 0 || s!=m->selection){
  191. m->selection = s;
  192. menushow(m);
  193. }
  194. }
  195. static void
  196. menuctl(Control *c, CParse *cp)
  197. {
  198. int up, cmd, h;
  199. Rectangle r;
  200. Menu0 *m;
  201. Point diag;
  202. m = (Menu0*)c;
  203. cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
  204. switch(cmd){
  205. default:
  206. ctlerror("%q: unrecognized message '%s'", m->Control.name, cp->str);
  207. break;
  208. case EAdd:
  209. _ctlargcount(&m->Control, cp, 2);
  210. m->line = ctlrealloc(m->line, (m->nline+1)*sizeof(char*));
  211. m->line[m->nline++] = ctlstrdup(cp->args[1]);
  212. menushow(m);
  213. break;
  214. case EAlign:
  215. _ctlargcount(&m->Control, cp, 2);
  216. m->align = _ctlalignment(cp->args[1]);
  217. menushow(m);
  218. break;
  219. case EBorder:
  220. _ctlargcount(&m->Control, cp, 2);
  221. m->border = cp->iargs[1];
  222. menushow(m);
  223. break;
  224. case EBordercolor:
  225. _ctlargcount(&m->Control, cp, 2);
  226. _setctlimage(&m->Control, &m->bordercolor, cp->args[1]);
  227. menushow(m);
  228. break;
  229. case EFocus:
  230. _ctlargcount(&m->Control, cp, 2);
  231. if(atoi(cp->args[1]) == 0)
  232. menuhide(m);
  233. break;
  234. case EFont:
  235. _ctlargcount(&m->Control, cp, 2);
  236. _setctlfont(&m->Control, &m->font, cp->args[1]);
  237. break;
  238. case EFormat:
  239. _ctlargcount(&m->Control, cp, 2);
  240. m->Control.format = ctlstrdup(cp->args[1]);
  241. break;
  242. case EHide:
  243. _ctlargcount(&m->Control, cp, 1);
  244. m->Control.hidden = 1;
  245. break;
  246. case EImage:
  247. _ctlargcount(&m->Control, cp, 2);
  248. _setctlimage(&m->Control, &m->image, cp->args[1]);
  249. menushow(m);
  250. break;
  251. case ERect:
  252. _ctlargcount(&m->Control, cp, 5);
  253. r.min.x = cp->iargs[1];
  254. r.min.y = cp->iargs[2];
  255. r.max.x = cp->iargs[3];
  256. r.max.y = cp->iargs[4];
  257. if(Dx(r)<0 || Dy(r)<0)
  258. ctlerror("%q: bad rectangle: %s", m->Control.name, cp->str);
  259. m->Control.rect = r;
  260. menushow(m);
  261. break;
  262. case EReveal:
  263. _ctlargcount(&m->Control, cp, 1);
  264. m->Control.hidden = 0;
  265. menushow(m);
  266. break;
  267. case ESelectcolor:
  268. _ctlargcount(&m->Control, cp, 2);
  269. _setctlimage(&m->Control, &m->selectcolor, cp->args[1]);
  270. menushow(m);
  271. break;
  272. case ESelecttextcolor:
  273. _ctlargcount(&m->Control, cp, 2);
  274. _setctlimage(&m->Control, &m->selecttextcolor, cp->args[1]);
  275. menushow(m);
  276. break;
  277. case EShow:
  278. _ctlargcount(&m->Control, cp, 1);
  279. menushow(m);
  280. break;
  281. case ESize:
  282. if (cp->nargs == 3)
  283. r.max = Pt(0x7fffffff, 0x7fffffff);
  284. else{
  285. _ctlargcount(&m->Control, cp, 5);
  286. r.max.x = cp->iargs[3];
  287. r.max.y = cp->iargs[4];
  288. }
  289. r.min.x = cp->iargs[1];
  290. r.min.y = cp->iargs[2];
  291. 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)
  292. ctlerror("%q: bad sizes: %s", m->Control.name, cp->str);
  293. m->Control.size.min = r.min;
  294. m->Control.size.max = r.max;
  295. break;
  296. case ETextcolor:
  297. _ctlargcount(&m->Control, cp, 2);
  298. _setctlimage(&m->Control, &m->textcolor, cp->args[1]);
  299. menushow(m);
  300. break;
  301. case EWindow:
  302. /* no args == toggle; otherwise 0 or 1 for state of window */
  303. if(cp->nargs >= 2)
  304. up = cp->iargs[1];
  305. else
  306. up = (m->window == nil);
  307. if(!up){ /* take window down */
  308. if(m->window)
  309. menuhide(m);
  310. break;
  311. }
  312. if(m->window != nil)
  313. break;
  314. diag = menusize(m);
  315. m->Control.rect.max.x = m->Control.rect.min.x + diag.x;
  316. m->Control.rect.max.y = m->Control.rect.min.y + diag.y;
  317. m->window = allocwindow(_screen, m->Control.rect, Refbackup, DWhite);
  318. if(m->window == nil)
  319. m->window = m->Control.screen;
  320. up = m->prevsel;
  321. if(up<0 || up>=m->nline)
  322. up = 0;
  323. m->selection = up;
  324. menushow(m);
  325. h = m->font->font->height;
  326. moveto(m->Control.controlset->mousectl,
  327. Pt(m->Control.rect.min.x+Dx(m->Control.rect)/2, m->Control.rect.min.y+up*h+h/2));
  328. // _ctlfocus(m, 1);
  329. break;
  330. }
  331. }
  332. Control*
  333. createmenu(Controlset *cs, char *name)
  334. {
  335. Menu0 *m;
  336. m = (Menu0*)_createctl(cs, "menu", sizeof(Menu0), name);
  337. m->font = _getctlfont("font");
  338. m->image = _getctlimage("white");
  339. m->textcolor = _getctlimage("black");
  340. m->selectcolor = _getctlimage("yellow");
  341. m->selecttextcolor = _getctlimage("black");
  342. m->bordercolor = _getctlimage("black");
  343. m->Control.format = ctlstrdup("%q: value %d");
  344. m->border = 0;
  345. m->align = Aupperleft;
  346. m->visible = 0;
  347. m->window = nil;
  348. m->lastbut = 0;
  349. m->selection = -1;
  350. m->Control.mouse = menutrack;
  351. m->Control.ctl = menuctl;
  352. m->Control.exit = menufree;
  353. return (Control *)m;
  354. }