/* XBubble - dialog.c Copyright (C) 2002 Ivan Djelic This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "rgba.h" #include "controls.h" extern Display *display; extern Window root; extern Window win; extern int screen; extern int depth; extern GC dialog_gc; extern GC dialog_text_gc; extern GC menu_gc; extern GC selected_gc; extern XFontStruct *menu_font; void get_column_size( int nb_lines, char ** line, XFontStruct *xfont, int *width, int *height ) { int i, entry_width; *width = 0; *height = nb_lines*( xfont->ascent + xfont->descent ); for ( i = 0; i < nb_lines; i++ ) { entry_width = XTextWidth( xfont, line[i], strlen(line[i])); if ( entry_width > *width ) *width = entry_width; } } Window create_column( int x, int y, int nb_lines, char ** line, XFontStruct *xfont, unsigned long *pixel, double expand ) { int i; int tx; int ty; int text_x; int text_y; int msg_width; int width; int height; int font_height; Window box; Pixmap background; get_column_size( nb_lines, line, xfont, &width, &height ); font_height = xfont->descent + xfont->ascent; width *= expand; height *= expand; /* center text */ tx = x - width/2; ty = y - height/2; /* draw background pixmap */ background = XCreatePixmap( display, root, width, height, depth ); XSetTSOrigin( display, dialog_gc, -tx, -ty ); XFillRectangle( display, background, dialog_gc, 0, 0, width, height ); XSetFont( display, dialog_text_gc, xfont->fid ); for ( i = 0; i < nb_lines; i++ ) { msg_width = XTextWidth( xfont, line[i], strlen(line[i])); text_x = ( width - msg_width ) / 2; text_y = font_height*i*expand + xfont->ascent; XSetForeground( display, dialog_text_gc, pixel[i] ); XDrawString( display, background, dialog_text_gc, text_x, text_y, line[i], strlen(line[i]) ); } /* and create window */ box = XCreateSimpleWindow( display, win, tx, ty, width, height, 0, 0, 0 ); XSetWindowBackgroundPixmap( display, box, background ); XMapWindow( display, box ); XFreePixmap( display, background ); return box; } Window create_dialog( int x, int y, char * msg, XFontStruct *xfont, unsigned long pixel, int border_width, double expand ) { int tx; int ty; int text_x; int text_y; int width; int height; int msg_width; Window dialog; Pixmap background; msg_width = XTextWidth( xfont, msg, strlen(msg)); width = expand*msg_width; height = expand*( xfont->ascent + xfont->descent ); tx = x - width/2; ty = y - height/2; text_x = ( width - msg_width) / 2; text_y = ( height + xfont->ascent - xfont->descent ) / 2; /* draw background pixmap */ background = XCreatePixmap( display, root, width, height, depth ); XSetTSOrigin( display, dialog_gc, -tx-border_width, -ty-border_width ); XFillRectangle( display, background, dialog_gc, 0, 0, width, height ); XSetFont( display, dialog_text_gc, xfont->fid ); XSetForeground( display, dialog_text_gc, pixel ); XDrawString( display, background, dialog_text_gc, text_x, text_y, msg, strlen(msg) ); /* and create window */ dialog = XCreateSimpleWindow( display, win, tx, ty, width, height, border_width, pixel, 0 ); XSetWindowBackgroundPixmap( display, dialog, background ); XMapWindow( display, dialog ); XFreePixmap( display, background ); return dialog; } static void draw_menu_entry( Window menu_win, int win_width, char ** entries, int nb, int entry, GC gc, int horizontal ) { int tx; int ty; char * line = entries[entry]; if ( horizontal ) { tx = (entry+0.5)*win_width/nb - XTextWidth( menu_font,line,strlen(line))/2; ty = menu_font->ascent; } else { tx = ( win_width - XTextWidth( menu_font, line, strlen(line)) )/2; ty = entry*(menu_font->ascent + menu_font->descent) + menu_font->ascent; } XDrawString( display, menu_win, gc, tx, ty, line, strlen(line) ); } void get_menu_size( int nb, char ** entries, int *w, int *h, int horizontal ) { get_column_size( nb, entries, menu_font, w, h ); if ( horizontal ) { *w *= 2*nb; *h /= nb; } } void get_menu_choices( int nb_entries, char ** entries, int *x, int *y, int *selection, int nb_menus, int horizontal, int escapable ) { int i; int j; int width; int height; int confirmation; XEvent event, e; KeySym keysym; Window menu_win[2]; get_menu_size( nb_entries, entries, &width, &height, horizontal ); /* create menu windows */ for ( i = 0; i < nb_menus; i++ ) { menu_win[i] = XCreateSimpleWindow( display, win, x[i] - width/2, y[i] - height/2, width, height, 0,0,0); XSetWindowBackgroundPixmap( display, menu_win[i], ParentRelative ); XSelectInput( display, menu_win[i], ExposureMask | KeyPressMask ); XMapWindow( display, menu_win[i] ); } confirmation = 0; while ( ! confirmation ) { /* X event loop */ XNextEvent( display, &event); switch ( event.type ) { case Expose: for ( i = 0; i < nb_menus; i++ ) if ( event.xexpose.window == menu_win[i] ) { for ( j = 0; j < nb_entries; j++ ) if ( j == selection[i] ) draw_menu_entry( menu_win[i], width, entries, nb_entries, j, selected_gc, horizontal ); else draw_menu_entry( menu_win[i], width, entries, nb_entries, j, menu_gc, horizontal ); /* flush expose event queue */ while ( XCheckTypedWindowEvent( display, menu_win[i], Expose, &e )); } break; case KeyPress: keysym = XLookupKeysym( &event.xkey, 0); if ( nb_menus > 1 ) { /* player 1 */ if (( horizontal )? PLAYER1_LEFT(keysym) : PLAYER1_UP(keysym)) { draw_menu_entry( menu_win[1], width, entries, nb_entries, selection[1], menu_gc, horizontal ); selection[1] = ( selection[1] + nb_entries - 1 )% nb_entries; draw_menu_entry( menu_win[1], width, entries, nb_entries, selection[1], selected_gc, horizontal ); } if (( horizontal )? PLAYER1_RIGHT(keysym) : PLAYER1_DOWN(keysym)) { draw_menu_entry( menu_win[1], width, entries, nb_entries, selection[1], menu_gc, horizontal ); selection[1] = ( selection[1] + 1 )% nb_entries; draw_menu_entry( menu_win[1], width, entries, nb_entries, selection[1], selected_gc, horizontal ); } /* player 2 */ if (( horizontal )? PLAYER2_LEFT(keysym) : PLAYER2_UP(keysym)) { draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], menu_gc, horizontal ); selection[0] = ( selection[0] + nb_entries - 1 )% nb_entries; draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], selected_gc, horizontal ); } if (( horizontal )? PLAYER2_RIGHT(keysym) : PLAYER2_DOWN(keysym)) { draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], menu_gc, horizontal ); selection[0] = ( selection[0] + 1 )% nb_entries; draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], selected_gc, horizontal ); } } else { if (( horizontal )? PLAYER1_LEFT(keysym) : PLAYER1_UP(keysym)) { draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], menu_gc, horizontal ); selection[0] = ( selection[0] + nb_entries - 1 )% nb_entries; draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], selected_gc, horizontal ); } if (( horizontal )? PLAYER1_RIGHT(keysym) : PLAYER1_DOWN(keysym)) { draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], menu_gc, horizontal ); selection[0] = ( selection[0] + 1 )% nb_entries; draw_menu_entry( menu_win[0], width, entries, nb_entries, selection[0], selected_gc, horizontal ); } } if ( keysym == XK_Return || keysym == XK_space ) confirmation = 1; if (( escapable )&&( keysym == XK_Escape || keysym == XK_q )) { selection[0] = -1; confirmation = 1; } break; default: break; } } /* destroy windows */ for ( i = 0; i < nb_menus; i++ ) XDestroyWindow( display, menu_win[i] ); }