PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/lui5/buttonmatrix.c

https://github.com/drafnel/Vis5d
C | 465 lines | 304 code | 110 blank | 51 comment | 37 complexity | 612d2f7ef31d89be7b847cbfa6231ae5 MD5 | raw file
  1. /* buttonmatrix.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <X11/keysym.h>
  6. #include "lui.h"
  7. #define MIN(A,B) ( (A) < (B) ? (A) : (B) )
  8. /*
  9. * NOTES:
  10. * Each button in the matrix can have a different color. This unique
  11. * color is only used when the button is turned on. The X color for
  12. * the button is only allocated while the button is on to minimize
  13. * colormap allocations.
  14. */
  15. static void draw_button( LUI_BUTTON_MATRIX *bm, int item, int row, int col )
  16. {
  17. int x, y;
  18. int width, height;
  19. width = bm->bwidth;
  20. height = bm->bheight;
  21. x = col * width;
  22. y = row * height;
  23. if (bm->labels[item][col]) {
  24. int len;
  25. /* MJK 12.04.98 */
  26. /* 03Feb98 Phil McDonald use white on dark or blue-dominated colors */
  27. GC text_gc;
  28. text_gc = ((bm->color[item][col][0] < 0.6) &&
  29. (bm->color[item][col][1] < 0.6)) ? LUI_GC_white : LUI_GC_black;
  30. LUI_DrawFrame( bm->mainwindow, x, y, width-1, height-1, 1,
  31. !bm->state[item][col] );
  32. len = MIN( strlen(bm->labels[item][col]), bm->maxchars );
  33. if (bm->state[item][col]) {
  34. /* button is "on" */
  35. XSetForeground( LUI_Display, LUI_Gc, bm->pixel[item][col] );
  36. XFillRectangle( LUI_Display, bm->mainwindow, LUI_Gc,
  37. x+1, y+1, width-3, height-3 );
  38. XDrawString( LUI_Display, bm->mainwindow, text_gc,
  39. x+2, y+LUI_Font_yoff+1,
  40. bm->labels[item][col], len );
  41. /* MJK 12.04.98 */
  42. /* XDrawString( LUI_Display, bm->mainwindow, LUI_GC_black,
  43. x+2, y+LUI_Font_yoff+1,
  44. bm->labels[item][col], len );
  45. */
  46. }
  47. else {
  48. /* button is "off" */
  49. XFillRectangle( LUI_Display, bm->mainwindow, LUI_GC_gray,
  50. x+1, y+1, width-3, height-3 );
  51. XDrawString( LUI_Display, bm->mainwindow, LUI_GC_black,
  52. x+2, y+LUI_Font_yoff+1,
  53. bm->labels[item][col], len );
  54. }
  55. }
  56. else {
  57. /* empty button */
  58. XFillRectangle( LUI_Display, bm->mainwindow, LUI_GC_gray,
  59. x, y, width-1, height-1 );
  60. }
  61. XDrawLine( LUI_Display, bm->mainwindow, LUI_GC_black,
  62. x, y+height-1, x+width-1, y+height-1 );
  63. XDrawLine( LUI_Display, bm->mainwindow, LUI_GC_black,
  64. x+width-1, y, x+width-1, y+height-1 );
  65. }
  66. static void draw_matrix( LUI_BUTTON_MATRIX *bm )
  67. {
  68. int i, j;
  69. for (i=0;i<bm->viewrows;i++) {
  70. for (j=0;j<bm->columns;j++) {
  71. int item = i + bm->toprow;
  72. if (item<bm->rows) {
  73. draw_button( bm, item, i, j );
  74. }
  75. }
  76. }
  77. }
  78. static void set_scrollbar( LUI_BUTTON_MATRIX *bm )
  79. {
  80. double size, pos;
  81. if (bm->rows <= bm->viewrows) {
  82. size = 100.0;
  83. pos = 0.0;
  84. }
  85. else {
  86. size = 100.0 * (double) bm->viewrows / (double) bm->rows;
  87. pos = 100.0 * bm->toprow / (double) (bm->rows - bm->viewrows);
  88. }
  89. LUI_ScrollBarSet( bm->scrollbar, size, pos );
  90. }
  91. void LUI_ButtonMatrixRedraw( LUI_BUTTON_MATRIX *bm)
  92. {
  93. draw_matrix(bm);
  94. set_scrollbar(bm);
  95. }
  96. /*
  97. * Convert a window (x,y) coordinate into a button (row,column).
  98. */
  99. static void xy_to_rowcol( LUI_BUTTON_MATRIX *bm, int x, int y,
  100. int *row, int *col )
  101. {
  102. *row = y / bm->bheight + bm->toprow;
  103. *col = x / bm->bwidth;
  104. }
  105. static int matrix_event( LUI_BUTTON_MATRIX *bm, XEvent *event )
  106. {
  107. switch (event->type) {
  108. case Expose:
  109. draw_matrix( bm );
  110. break;
  111. case ButtonPress:
  112. if (bm->callback) {
  113. int row, col;
  114. xy_to_rowcol( bm, event->xbutton.x, event->xbutton.y, &row, &col );
  115. /*
  116. int row = event->xbutton.y / bm->bheight + bm->toprow;
  117. int col = event->xbutton.x / bm->bwidth;
  118. */
  119. if (row < bm->viewrows+bm->toprow) {
  120. if (bm->labels[row][col]) {
  121. (*bm->callback)( bm, row, col, event->xbutton.button );
  122. }
  123. }
  124. }
  125. break;
  126. case KeyPress:
  127. /* Scroll button matrix if too many to see all at once */
  128. if (bm->rows > bm->viewrows) {
  129. KeySym keysym;
  130. XComposeStatus compose;
  131. char buffer[100];
  132. XLookupString( &event->xkey, buffer, 100, &keysym, &compose );
  133. if (keysym==XK_Up && bm->toprow>0) {
  134. bm->toprow--;
  135. draw_matrix( bm );
  136. set_scrollbar( bm );
  137. }
  138. else if (keysym==XK_Down && bm->toprow < bm->rows - bm->viewrows) {
  139. bm->toprow++;
  140. draw_matrix( bm );
  141. set_scrollbar( bm );
  142. }
  143. }
  144. break;
  145. default:
  146. printf("Error in matrix_event: unexpected event\n");
  147. }
  148. return 1;
  149. }
  150. static int sb_event( LUI_SCROLLBAR *sb, float pos )
  151. {
  152. LUI_BUTTON_MATRIX *bm;
  153. int oldtop;
  154. bm = sb->userdata;
  155. oldtop = bm->toprow;
  156. bm->toprow = (int) (pos * (bm->rows - bm->viewrows) / 100.0);
  157. if (oldtop!=bm->toprow) {
  158. draw_matrix( bm );
  159. }
  160. return 1;
  161. }
  162. void LUI_ButtonMatrixDestroy( bm )
  163. LUI_BUTTON_MATRIX *bm;
  164. {
  165. int i, j;
  166. /* free the color allocations */
  167. for (i=0;i<bm->rows;i++) {
  168. for (j=0;j<bm->columns;j++) {
  169. if (bm->pixel[i][j]!=0) {
  170. LUI_FreeColor( bm->pixel[i][j] );
  171. }
  172. /* MJK 12.04.98 */
  173. /* 24Nov97 Phil McDonald */
  174. if (bm->labels[i][j]) free (bm->labels[i][j]);
  175. }
  176. }
  177. LUI_ScrollBarDestroy( bm->scrollbar );
  178. LUI_EventRemove( bm->mainwindow );
  179. XDestroyWindow( LUI_Display, bm->mainwindow );
  180. free( bm );
  181. }
  182. LUI_BUTTON_MATRIX *LUI_ButtonMatrixCreate( Window parent, int x, int y,
  183. int width, int height,
  184. int columns )
  185. {
  186. LUI_BUTTON_MATRIX *bm;
  187. int xx, yy;
  188. LUI_LayoutCheck( &x, &y, &width, &height );
  189. /* allocate struct w/ all fields zeroed */
  190. bm = (LUI_BUTTON_MATRIX *) calloc( 1, sizeof(LUI_BUTTON_MATRIX) );
  191. bm->scrollbar = LUI_ScrollBarCreate( parent, x, y, 16, height, 1 );
  192. LUI_UnlinkWidgetFromWindow( parent, bm->scrollbar );
  193. bm->scrollbar->userdata = bm;
  194. LUI_ScrollBarCallback( bm->scrollbar, sb_event );
  195. bm->mainwindow = XCreateSimpleWindow( LUI_Display, parent,
  196. x+18, y, width-18, height-2,
  197. 1, LUI_Color_black, LUI_Color_gray );
  198. {
  199. int nx = x+18, ny = y, nw = width-18, nh = height-2;
  200. LUI_LayoutCheck( &nx, &ny, &nw, &nh );
  201. }
  202. bm->x = x+18;
  203. bm->y = y;
  204. bm->width = width - 18;
  205. bm->height = height;
  206. bm->rows = 0;
  207. bm->columns = columns;
  208. bm->toprow = 0;
  209. bm->bwidth = bm->width / bm->columns;
  210. bm->bheight = LUI_Font_height + 4;
  211. bm->viewrows = height / bm->bheight;
  212. {
  213. static char str[] = "WWWWWWWWWWWWWW";
  214. int dir, ascent, descent;
  215. XCharStruct overall;
  216. bm->maxchars = 0;
  217. do {
  218. bm->maxchars++;
  219. XTextExtents( LUI_Font, str, bm->maxchars+1, &dir, &ascent,
  220. &descent, &overall );
  221. } while (overall.width < bm->bwidth-2);
  222. }
  223. bm->callback = NULL;
  224. LUI_AddWidgetToWindow( parent, bm, (LUI_FNCP) LUI_ButtonMatrixDestroy );
  225. LUI_EventAdd2( bm->mainwindow,
  226. ExposureMask | ButtonPressMask | KeyPressMask,
  227. (LUI_FNCP) matrix_event, bm );
  228. return bm;
  229. }
  230. /*
  231. * Add a new row of buttons to the button matrix.
  232. * Input: bm - which button matrix
  233. * labels - button labels for the row
  234. * reds, greens, blues - colors for each button in [0,1]
  235. */
  236. void LUI_ButtonMatrixAddRow( LUI_BUTTON_MATRIX *bm, char *labels[],
  237. float *reds, float *greens, float *blues )
  238. {
  239. int i;
  240. if (bm->rows==MAX_BM_ROWS) {
  241. printf("Error in LUI_ButtonMatrixAddRow: too many rows\n");
  242. return;
  243. }
  244. for (i=0;i<bm->columns;i++) {
  245. if (labels[i]) {
  246. bm->labels[bm->rows][i] = strdup( labels[i] );
  247. }
  248. else {
  249. bm->labels[bm->rows][i] = NULL;
  250. }
  251. bm->color[bm->rows][i][0] = reds[i];
  252. bm->color[bm->rows][i][1] = greens[i];
  253. bm->color[bm->rows][i][2] = blues[i];
  254. bm->pixel[bm->rows][i] = 0;
  255. bm->state[bm->rows][i] = 0;
  256. }
  257. bm->rows++;
  258. set_scrollbar( bm );
  259. draw_matrix( bm );
  260. }
  261. void LUI_ButtonMatrixChangeLabel( LUI_BUTTON_MATRIX *bm,
  262. int row, int column, char *label )
  263. {
  264. if (bm->labels[row][column]) {
  265. free( bm->labels[row][column] );
  266. }
  267. bm->labels[row][column] = strdup( label );
  268. draw_matrix( bm );
  269. }
  270. void LUI_ButtonMatrixCallback( LUI_BUTTON_MATRIX *bm, int (*callback)() )
  271. {
  272. bm->callback = callback;
  273. bm->context_index = context_index;
  274. }
  275. void LUI_ButtonMatrixSetState( LUI_BUTTON_MATRIX *bm, int row, int col,
  276. int state )
  277. {
  278. /* always free the button's color */
  279. if (bm->pixel[row][col]>0) {
  280. LUI_FreeColor( bm->pixel[row][col] );
  281. }
  282. bm->pixel[row][col] = 0;
  283. bm->state[row][col] = state;
  284. if (state) {
  285. /* Allocate the button's color */
  286. float r = bm->color[row][col][0];
  287. float g = bm->color[row][col][1];
  288. float b = bm->color[row][col][2];
  289. bm->pixel[row][col] = LUI_AllocateColor( r, g, b );
  290. }
  291. draw_button( bm, row, row-bm->toprow, col );
  292. }
  293. int LUI_ButtonMatrixGetState( LUI_BUTTON_MATRIX *bm, int row, int col )
  294. {
  295. return bm->state[row][col];
  296. }
  297. /*
  298. * Set the color of a matrix's button.
  299. */
  300. void LUI_ButtonMatrixSetColor( LUI_BUTTON_MATRIX *bm, int row, int col,
  301. double red, double green, double blue )
  302. {
  303. bm->color[row][col][0] = red;
  304. bm->color[row][col][1] = green;
  305. bm->color[row][col][2] = blue;
  306. if (bm->state[row][col]) {
  307. /* force redraw with new color */
  308. LUI_ButtonMatrixSetState( bm, row, col, 1 );
  309. }
  310. }
  311. /*
  312. * Scroll the button matrix so the last row is visible.
  313. */
  314. void LUI_ButtonMatrixShowBottom( bm )
  315. LUI_BUTTON_MATRIX *bm;
  316. {
  317. if (bm->viewrows < bm->rows) {
  318. bm->toprow = bm->rows - bm->viewrows;
  319. set_scrollbar(bm);
  320. draw_matrix(bm);
  321. }
  322. }
  323. /*
  324. * Change the size of a button matrix window.
  325. */
  326. void LUI_ButtonMatrixResize( bm, width, height )
  327. LUI_BUTTON_MATRIX *bm;
  328. int width, height;
  329. {
  330. XResizeWindow( LUI_Display, bm->mainwindow, width-18, height );
  331. bm->width = width - 10;
  332. bm->height = height;
  333. bm->bwidth = bm->width / bm->columns;
  334. bm->viewrows = height / bm->bheight;
  335. if (bm->rows <= bm->viewrows) {
  336. bm->toprow = 0;
  337. }
  338. else if (bm->toprow > bm->rows - bm->viewrows) {
  339. bm->toprow = bm->rows - bm->viewrows;
  340. }
  341. LUI_ScrollBarResize( bm->scrollbar, 16, height );
  342. set_scrollbar( bm );
  343. draw_matrix( bm );
  344. }
  345. /*
  346. * Delete all the rows in a button matrix, i.e. empty it.
  347. */
  348. void LUI_ButtonMatrixEmpty( bm )
  349. LUI_BUTTON_MATRIX *bm;
  350. {
  351. bm->rows = 0;
  352. bm->toprow = 0;
  353. set_scrollbar( bm );
  354. draw_matrix( bm );
  355. }