/lui5/buttonmatrix.c
C | 465 lines | 304 code | 110 blank | 51 comment | 37 complexity | 612d2f7ef31d89be7b847cbfa6231ae5 MD5 | raw file
- /* buttonmatrix.c */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <X11/keysym.h>
- #include "lui.h"
- #define MIN(A,B) ( (A) < (B) ? (A) : (B) )
- /*
- * NOTES:
- * Each button in the matrix can have a different color. This unique
- * color is only used when the button is turned on. The X color for
- * the button is only allocated while the button is on to minimize
- * colormap allocations.
- */
- static void draw_button( LUI_BUTTON_MATRIX *bm, int item, int row, int col )
- {
- int x, y;
- int width, height;
- width = bm->bwidth;
- height = bm->bheight;
- x = col * width;
- y = row * height;
- if (bm->labels[item][col]) {
- int len;
- /* MJK 12.04.98 */
- /* 03Feb98 Phil McDonald use white on dark or blue-dominated colors */
- GC text_gc;
- text_gc = ((bm->color[item][col][0] < 0.6) &&
- (bm->color[item][col][1] < 0.6)) ? LUI_GC_white : LUI_GC_black;
- LUI_DrawFrame( bm->mainwindow, x, y, width-1, height-1, 1,
- !bm->state[item][col] );
- len = MIN( strlen(bm->labels[item][col]), bm->maxchars );
- if (bm->state[item][col]) {
- /* button is "on" */
- XSetForeground( LUI_Display, LUI_Gc, bm->pixel[item][col] );
- XFillRectangle( LUI_Display, bm->mainwindow, LUI_Gc,
- x+1, y+1, width-3, height-3 );
- XDrawString( LUI_Display, bm->mainwindow, text_gc,
- x+2, y+LUI_Font_yoff+1,
- bm->labels[item][col], len );
- /* MJK 12.04.98 */
- /* XDrawString( LUI_Display, bm->mainwindow, LUI_GC_black,
- x+2, y+LUI_Font_yoff+1,
- bm->labels[item][col], len );
- */
- }
- else {
- /* button is "off" */
- XFillRectangle( LUI_Display, bm->mainwindow, LUI_GC_gray,
- x+1, y+1, width-3, height-3 );
- XDrawString( LUI_Display, bm->mainwindow, LUI_GC_black,
- x+2, y+LUI_Font_yoff+1,
- bm->labels[item][col], len );
- }
- }
- else {
- /* empty button */
- XFillRectangle( LUI_Display, bm->mainwindow, LUI_GC_gray,
- x, y, width-1, height-1 );
- }
- XDrawLine( LUI_Display, bm->mainwindow, LUI_GC_black,
- x, y+height-1, x+width-1, y+height-1 );
- XDrawLine( LUI_Display, bm->mainwindow, LUI_GC_black,
- x+width-1, y, x+width-1, y+height-1 );
- }
- static void draw_matrix( LUI_BUTTON_MATRIX *bm )
- {
- int i, j;
- for (i=0;i<bm->viewrows;i++) {
- for (j=0;j<bm->columns;j++) {
- int item = i + bm->toprow;
- if (item<bm->rows) {
- draw_button( bm, item, i, j );
- }
- }
- }
- }
- static void set_scrollbar( LUI_BUTTON_MATRIX *bm )
- {
- double size, pos;
- if (bm->rows <= bm->viewrows) {
- size = 100.0;
- pos = 0.0;
- }
- else {
- size = 100.0 * (double) bm->viewrows / (double) bm->rows;
- pos = 100.0 * bm->toprow / (double) (bm->rows - bm->viewrows);
- }
- LUI_ScrollBarSet( bm->scrollbar, size, pos );
- }
- void LUI_ButtonMatrixRedraw( LUI_BUTTON_MATRIX *bm)
- {
- draw_matrix(bm);
- set_scrollbar(bm);
- }
- /*
- * Convert a window (x,y) coordinate into a button (row,column).
- */
- static void xy_to_rowcol( LUI_BUTTON_MATRIX *bm, int x, int y,
- int *row, int *col )
- {
- *row = y / bm->bheight + bm->toprow;
- *col = x / bm->bwidth;
- }
- static int matrix_event( LUI_BUTTON_MATRIX *bm, XEvent *event )
- {
- switch (event->type) {
- case Expose:
- draw_matrix( bm );
- break;
- case ButtonPress:
- if (bm->callback) {
- int row, col;
- xy_to_rowcol( bm, event->xbutton.x, event->xbutton.y, &row, &col );
- /*
- int row = event->xbutton.y / bm->bheight + bm->toprow;
- int col = event->xbutton.x / bm->bwidth;
- */
- if (row < bm->viewrows+bm->toprow) {
- if (bm->labels[row][col]) {
- (*bm->callback)( bm, row, col, event->xbutton.button );
- }
- }
- }
- break;
- case KeyPress:
- /* Scroll button matrix if too many to see all at once */
- if (bm->rows > bm->viewrows) {
- KeySym keysym;
- XComposeStatus compose;
- char buffer[100];
- XLookupString( &event->xkey, buffer, 100, &keysym, &compose );
- if (keysym==XK_Up && bm->toprow>0) {
- bm->toprow--;
- draw_matrix( bm );
- set_scrollbar( bm );
- }
- else if (keysym==XK_Down && bm->toprow < bm->rows - bm->viewrows) {
- bm->toprow++;
- draw_matrix( bm );
- set_scrollbar( bm );
- }
- }
- break;
- default:
- printf("Error in matrix_event: unexpected event\n");
- }
- return 1;
- }
- static int sb_event( LUI_SCROLLBAR *sb, float pos )
- {
- LUI_BUTTON_MATRIX *bm;
- int oldtop;
- bm = sb->userdata;
- oldtop = bm->toprow;
- bm->toprow = (int) (pos * (bm->rows - bm->viewrows) / 100.0);
- if (oldtop!=bm->toprow) {
- draw_matrix( bm );
- }
- return 1;
- }
- void LUI_ButtonMatrixDestroy( bm )
- LUI_BUTTON_MATRIX *bm;
- {
- int i, j;
- /* free the color allocations */
- for (i=0;i<bm->rows;i++) {
- for (j=0;j<bm->columns;j++) {
- if (bm->pixel[i][j]!=0) {
- LUI_FreeColor( bm->pixel[i][j] );
- }
- /* MJK 12.04.98 */
- /* 24Nov97 Phil McDonald */
- if (bm->labels[i][j]) free (bm->labels[i][j]);
- }
- }
- LUI_ScrollBarDestroy( bm->scrollbar );
- LUI_EventRemove( bm->mainwindow );
- XDestroyWindow( LUI_Display, bm->mainwindow );
- free( bm );
- }
- LUI_BUTTON_MATRIX *LUI_ButtonMatrixCreate( Window parent, int x, int y,
- int width, int height,
- int columns )
- {
- LUI_BUTTON_MATRIX *bm;
- int xx, yy;
- LUI_LayoutCheck( &x, &y, &width, &height );
- /* allocate struct w/ all fields zeroed */
- bm = (LUI_BUTTON_MATRIX *) calloc( 1, sizeof(LUI_BUTTON_MATRIX) );
- bm->scrollbar = LUI_ScrollBarCreate( parent, x, y, 16, height, 1 );
- LUI_UnlinkWidgetFromWindow( parent, bm->scrollbar );
- bm->scrollbar->userdata = bm;
- LUI_ScrollBarCallback( bm->scrollbar, sb_event );
- bm->mainwindow = XCreateSimpleWindow( LUI_Display, parent,
- x+18, y, width-18, height-2,
- 1, LUI_Color_black, LUI_Color_gray );
- {
- int nx = x+18, ny = y, nw = width-18, nh = height-2;
- LUI_LayoutCheck( &nx, &ny, &nw, &nh );
- }
- bm->x = x+18;
- bm->y = y;
- bm->width = width - 18;
- bm->height = height;
- bm->rows = 0;
- bm->columns = columns;
- bm->toprow = 0;
- bm->bwidth = bm->width / bm->columns;
- bm->bheight = LUI_Font_height + 4;
- bm->viewrows = height / bm->bheight;
- {
- static char str[] = "WWWWWWWWWWWWWW";
- int dir, ascent, descent;
- XCharStruct overall;
- bm->maxchars = 0;
- do {
- bm->maxchars++;
- XTextExtents( LUI_Font, str, bm->maxchars+1, &dir, &ascent,
- &descent, &overall );
- } while (overall.width < bm->bwidth-2);
- }
-
- bm->callback = NULL;
- LUI_AddWidgetToWindow( parent, bm, (LUI_FNCP) LUI_ButtonMatrixDestroy );
- LUI_EventAdd2( bm->mainwindow,
- ExposureMask | ButtonPressMask | KeyPressMask,
- (LUI_FNCP) matrix_event, bm );
- return bm;
- }
- /*
- * Add a new row of buttons to the button matrix.
- * Input: bm - which button matrix
- * labels - button labels for the row
- * reds, greens, blues - colors for each button in [0,1]
- */
- void LUI_ButtonMatrixAddRow( LUI_BUTTON_MATRIX *bm, char *labels[],
- float *reds, float *greens, float *blues )
- {
- int i;
- if (bm->rows==MAX_BM_ROWS) {
- printf("Error in LUI_ButtonMatrixAddRow: too many rows\n");
- return;
- }
- for (i=0;i<bm->columns;i++) {
- if (labels[i]) {
- bm->labels[bm->rows][i] = strdup( labels[i] );
- }
- else {
- bm->labels[bm->rows][i] = NULL;
- }
- bm->color[bm->rows][i][0] = reds[i];
- bm->color[bm->rows][i][1] = greens[i];
- bm->color[bm->rows][i][2] = blues[i];
- bm->pixel[bm->rows][i] = 0;
- bm->state[bm->rows][i] = 0;
- }
- bm->rows++;
- set_scrollbar( bm );
- draw_matrix( bm );
- }
- void LUI_ButtonMatrixChangeLabel( LUI_BUTTON_MATRIX *bm,
- int row, int column, char *label )
- {
- if (bm->labels[row][column]) {
- free( bm->labels[row][column] );
- }
- bm->labels[row][column] = strdup( label );
- draw_matrix( bm );
- }
- void LUI_ButtonMatrixCallback( LUI_BUTTON_MATRIX *bm, int (*callback)() )
- {
- bm->callback = callback;
- bm->context_index = context_index;
- }
- void LUI_ButtonMatrixSetState( LUI_BUTTON_MATRIX *bm, int row, int col,
- int state )
- {
- /* always free the button's color */
- if (bm->pixel[row][col]>0) {
- LUI_FreeColor( bm->pixel[row][col] );
- }
- bm->pixel[row][col] = 0;
- bm->state[row][col] = state;
- if (state) {
- /* Allocate the button's color */
- float r = bm->color[row][col][0];
- float g = bm->color[row][col][1];
- float b = bm->color[row][col][2];
- bm->pixel[row][col] = LUI_AllocateColor( r, g, b );
- }
- draw_button( bm, row, row-bm->toprow, col );
- }
- int LUI_ButtonMatrixGetState( LUI_BUTTON_MATRIX *bm, int row, int col )
- {
- return bm->state[row][col];
- }
- /*
- * Set the color of a matrix's button.
- */
- void LUI_ButtonMatrixSetColor( LUI_BUTTON_MATRIX *bm, int row, int col,
- double red, double green, double blue )
- {
- bm->color[row][col][0] = red;
- bm->color[row][col][1] = green;
- bm->color[row][col][2] = blue;
- if (bm->state[row][col]) {
- /* force redraw with new color */
- LUI_ButtonMatrixSetState( bm, row, col, 1 );
- }
- }
- /*
- * Scroll the button matrix so the last row is visible.
- */
- void LUI_ButtonMatrixShowBottom( bm )
- LUI_BUTTON_MATRIX *bm;
- {
- if (bm->viewrows < bm->rows) {
- bm->toprow = bm->rows - bm->viewrows;
- set_scrollbar(bm);
- draw_matrix(bm);
- }
- }
- /*
- * Change the size of a button matrix window.
- */
- void LUI_ButtonMatrixResize( bm, width, height )
- LUI_BUTTON_MATRIX *bm;
- int width, height;
- {
- XResizeWindow( LUI_Display, bm->mainwindow, width-18, height );
- bm->width = width - 10;
- bm->height = height;
- bm->bwidth = bm->width / bm->columns;
- bm->viewrows = height / bm->bheight;
- if (bm->rows <= bm->viewrows) {
- bm->toprow = 0;
- }
- else if (bm->toprow > bm->rows - bm->viewrows) {
- bm->toprow = bm->rows - bm->viewrows;
- }
- LUI_ScrollBarResize( bm->scrollbar, 16, height );
- set_scrollbar( bm );
- draw_matrix( bm );
- }
- /*
- * Delete all the rows in a button matrix, i.e. empty it.
- */
- void LUI_ButtonMatrixEmpty( bm )
- LUI_BUTTON_MATRIX *bm;
- {
- bm->rows = 0;
- bm->toprow = 0;
- set_scrollbar( bm );
- draw_matrix( bm );
- }