/*
  XBubble - dialog.c

  Copyright (C) 2002  Ivan Djelic <ivan@savannah.gnu.org>
  
  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 <string.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

#include "rgba.h"
#include "controls.h"
#include "dialog.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, const 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, const 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, const 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,
			     const char ** entries, 
			     int nb,
			     int entry,
			     GC gc,
			     int horizontal ) {
  int tx;
  int ty;
  const 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, const 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,
		       const 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] );
}
