
#include <gtk/gtksignal.h>

#include <gtk/gtkdialog.h>

#include <gtk/gtkbox.h>
#include <gtk/gtktable.h>
#include <gtk/gtktogglebutton.h>

#include <string.h>

#include "gw_pannel.h"

enum {
  GW_PANNEL_SIGNAL,
  LAST_SIGNAL
};

static void gw_pannel_class_init          (Gw_pannelClass *klass);
static void gw_pannel_init                (Gw_pannel      *ttt);
static void gw_pannel_toggle              (GtkWidget *widget, Gw_pannel *ttt);

static guint gw_pannel_signals[LAST_SIGNAL] = { 0 };

GType gw_pannel_get_type (void)
{
  static GType ttt_type = 0;

  if (!ttt_type)
    {
      static const GTypeInfo ttt_info =
	{
	  sizeof (Gw_pannelClass),
	  NULL, /* base_init */
	  NULL, /* base_finalize */
	  (GClassInitFunc) gw_pannel_class_init,
	  NULL, /* class_finalize */
	  NULL, /* class_data */
	  sizeof (Gw_pannel),
	  0,
	  (GInstanceInitFunc) gw_pannel_init,
	};

      ttt_type = g_type_register_static (GTK_TYPE_DIALOG, "Gw_pannel", &ttt_info, 0);
    }

  return ttt_type;
}

static void
gw_pannel_class_init (Gw_pannelClass *klass)
{
  gw_pannel_signals[GW_PANNEL_SIGNAL] = g_signal_new ("gw_pannel",
					 G_TYPE_FROM_CLASS (klass),
	                                 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
	                                 G_STRUCT_OFFSET (Gw_pannelClass, gw_pannel),
                                         NULL, 
                                         NULL,                
					 g_cclosure_marshal_VOID__VOID,
                                         G_TYPE_NONE, 0);
}

/* Appelée par gw_pannel_new via g_object_new */
static void gw_pannel_init (Gw_pannel *ttt)
{
  gtk_dialog_set_has_separator ( GTK_DIALOG(ttt) , FALSE);
  gtk_window_set_modal ( GTK_WINDOW(ttt) ,TRUE);
}

/**
 *  gw_pannel_new creates a new pannel with "nrows" rows and "ncols" columns
 *  on drawable "win"
 *                
 */
GtkWidget* gw_pannel_new (char *title ,guint nrows ,guint ncols ,GdkDrawable *win)
{
  Gw_pannel *ttt;
  gint nrc;
  const GdkColor black = {0 ,0 ,0 ,0};
  const GdkColor white = {0xffffffff ,257*255 ,257*255 ,257*255};

  ttt = g_object_new (GW_PANNEL_TYPE, NULL);
  gtk_window_set_title (GTK_WINDOW (ttt) ,title);
  ttt->table = gtk_table_new (nrows ,ncols ,TRUE);
  gtk_table_resize (GTK_TABLE (ttt->table) ,nrows ,ncols );
  gtk_widget_show (ttt->table);
  gtk_box_pack_start_defaults (GTK_BOX(GTK_DIALOG(ttt)->vbox) ,ttt->table);

  ttt->nlignes 	  = nrows;
  ttt->ncolons 	  = ncols;
  ttt->nrc     	  = nrc = nrows * ncols;
  ttt->buttons 	  = g_malloc0 (nrc * sizeof(GtkWidget *));
  ttt->bg      	  = g_malloc0 (nrc * sizeof(GdkColor  *));
  ttt->depth      = 0;
  ttt->size_vary  = FALSE;
  ttt->bitmaps 	  = NULL;
  ttt->width      = NULL;
  ttt->height     = NULL;
  ttt->mask       = NULL;
  ttt->bg[0]      = gdk_color_copy (&white);
  ttt->fg         = gdk_color_copy (&black);
  ttt->with_num   = TRUE;
  ttt->row_first  = TRUE;
  ttt->active     = 0;
  ttt->win        = win;
  ttt->hide_on_click = TRUE;
  ttt->last       = -1;

  g_signal_connect (GTK_DIALOG(ttt) ,"delete-event" ,G_CALLBACK (gtk_widget_hide) ,NULL);

  return GTK_WIDGET (ttt);
}

/**
 *  Allows to transpose matrix.
 *  Defautls is line nb vary before column nb (i.e. row_first==TRUE)
 */
void gw_pannel_set_row_first (Gw_pannel *ttt ,gboolean row_first)
{
  ttt->row_first = row_first;
}

/**
 *  To change widget default (bg=white, fg=black)
 */
void gw_pannel_set_default_colors (Gw_pannel *ttt ,GdkColor *bg ,GdkColor *fg)
{
  ttt->bg[0] = bg;
  ttt->fg    = fg;
}



gint gw_pannel_xy_to_n (Gw_pannel *ttt ,gint x ,gint y)
{
  gint n;

  if (ttt->row_first) {
    n = y + ttt->nlignes*x;
  } else {
    n = x +  ttt->ncolons*y;
  }
  return (n);
}


void gw_pannel_n_to_xy (Gw_pannel *ttt ,gint n ,gint *x ,gint *y)
{
  if (ttt->row_first) {
    *x = n / ttt->nlignes;
    *y = n % ttt->nlignes;
  } else {
    *y = n / ttt->ncolons;
    *x = n % ttt->ncolons;
  }
}

static void gw_pannel_toggle (GtkWidget *widget, Gw_pannel *ttt)
{
  gint n ,x ,y;

  for (n = 0; n < ttt->nrc; n++) {
    if (ttt->buttons[n] != NULL) {                      /* non valid glyph have no buttons */
      if (GTK_TOGGLE_BUTTON (ttt->buttons[n])->active) {
	g_signal_handlers_block_matched (G_OBJECT (ttt->buttons[n]), 
					 G_SIGNAL_MATCH_DATA,
					 0, 0, NULL, NULL, ttt);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[n]),
				      FALSE);
	g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[n]),
					   G_SIGNAL_MATCH_DATA,
					   0, 0, NULL, NULL, ttt);
	gw_pannel_n_to_xy (ttt ,n ,&x ,&y);
	ttt->x_clicked = x;
	ttt->y_clicked = y;
	// et on emet le signal pour utiliser le clic
	g_signal_emit (G_OBJECT (ttt), 
		       gw_pannel_signals[GW_PANNEL_SIGNAL], 0);
	if (ttt->hide_on_click) gtk_widget_hide (GTK_WIDGET(ttt));
	return;
      }
    }
  }
} 

/**
 *   Attach a button with a coloured background
 */
void gw_pannel_attach_color_button  (Gw_pannel *ttt ,GtkWidget *button
				     ,GdkColor *bg ,char *name
				     ,gint nx ,gint ny)
{
  char *buf;
  gint n ,ln;
  ln = strlen(name);
  buf = g_malloc ((ln+5) * sizeof(char));
  n = gw_pannel_xy_to_n (ttt ,nx ,ny);
  if (n >= ttt->nrc) {
    g_error ("gw_pannel_attach_color_button : pannel too small");
  }
  if (n > ttt->last) ttt->last = n;
  ttt->buttons[n] = button;
  gtk_table_attach_defaults (GTK_TABLE (ttt->table), button ,nx,nx+1 ,ny,ny+1);
  sprintf (buf ,"%d  %s" ,gw_pannel_xy_to_n (ttt ,nx ,ny) ,name);
  gtk_button_set_label (GTK_BUTTON(button) , buf);
  gtk_widget_modify_bg (GTK_WIDGET(button), GTK_STATE_NORMAL ,bg);
  ttt->bg[n] = bg;
  g_free (buf);
  g_signal_connect (G_OBJECT (button), "toggled",
		    G_CALLBACK (gw_pannel_toggle), (gpointer) ttt);
  gtk_widget_show (button);
}

/**
 *   Update a button with a coloured background
 */
void gw_pannel_update_color_button  (Gw_pannel *ttt ,gint n ,GdkColor *bg ,char *name)
{
  GtkWidget *button;
  if (n >= ttt->nrc) g_error ("gw_pannel_update_color_button: n out of range");
  button = ttt->buttons[n];
  if (button == NULL) {
    gint nx ,ny;
    gw_pannel_n_to_xy (ttt ,n ,&nx ,&ny);
    button = gtk_toggle_button_new ();
    gw_pannel_attach_color_button (ttt ,button ,bg ,name ,nx ,ny);
  } else {
    char *buf;
    gint ln = strlen(name);
    buf = g_malloc ((ln+5) * sizeof(char));
    sprintf (buf ,"%d  %s" ,n ,name);
    gtk_button_set_label (GTK_BUTTON(button) , buf);
    gtk_widget_modify_bg (GTK_WIDGET(button), GTK_STATE_NORMAL ,bg);
    ttt->bg[n] = bg;
    g_free (buf);
    gtk_widget_show (button);
  }
}




/**************** Bitmaps buttons ******************/

/**
 * depth is the screen depth
 * if size_vary=F: only the first element of arrays is allocated and used
 */
void gw_pannel_set_bitmaps_defaults (Gw_pannel *ttt ,gint depth ,gboolean size_vary)
{
  gint ni;

  ttt->bitmaps 	 = g_malloc (ttt->nrc * sizeof(char **));
  ttt->depth     = depth;
  ttt->size_vary = size_vary;

  /* GTK bug 437281 (corrected in new versions of GTK) implies
   * to recreate bitmap image before each gtk_button_set_image,
   * thus to store bitmap with, height and mask
   */
  ni = size_vary ? ttt->nrc : 1;
  ttt->mask    = g_malloc (ni * sizeof(GdkBitmap *));
  ttt->width   = g_malloc (ni * sizeof(gint));
  ttt->height  = g_malloc (ni * sizeof(gint));
}

/**
 * use width, height and mask allocated by gw_pannel_set_bitmaps_defaults
 *     and stored by gw_pannel_bitmap_button_attach
 */
void gw_pannel_bitmap_button_set (Gw_pannel *ttt ,GtkWidget *button ,gint n)
{
  GdkPixmap *pixmap;
  GtkWidget *image;
  gint width ,height ,ni;
  ni = (ttt->size_vary) ? n : 0 ;

  if (ttt->mask[ni] == NULL) {
    g_error ("gw_pannel_bitmap_button_set called with mask=NULL");
  }
  if (ttt->buttons[n] != NULL) {
    width = ttt->width[ni];
    height = ttt->height[ni];
    pixmap = gdk_pixmap_create_from_data (ttt->win  //17 NULL
					  ,ttt->bitmaps[n]
					  ,width ,height
					  ,ttt->depth ,ttt->fg ,ttt->bg[0]);
    image = gtk_image_new_from_pixmap (pixmap ,ttt->mask[ni]);
    gtk_widget_show (image);
    gtk_button_set_image (GTK_BUTTON(button) ,image);  
    gtk_button_set_image_position (GTK_BUTTON(button) ,GTK_POS_RIGHT);
  }
}

void gw_pannel_bitmap_button_attach (Gw_pannel *ttt ,GtkWidget *button ,gint n
				     ,unsigned char *bitmap ,gint width ,gint height)
{
  char buf[5];
  gint x ,y ,nwh ,i;
  unsigned char *bmask;

  ttt->buttons[n] = button;
  gw_pannel_n_to_xy (ttt ,n ,&x ,&y);
  gtk_table_attach_defaults (GTK_TABLE (ttt->table), button ,x,x+1 ,y,y+1);
  if (ttt->with_num) {
    sprintf (buf ,"%d" ,n);
  } else {
    sprintf (buf ," ");
  }
  gtk_button_set_label (GTK_BUTTON(button) , buf);

  ttt->bitmaps[n] = (gchar *)bitmap;
  if (bitmap != NULL) {
    if (n == 0 || ttt->size_vary) {
      nwh = width * height;
      bmask = g_malloc (nwh * sizeof(unsigned char));
      for (i = 0; i < nwh; i++) bmask[i] = 0xff;
      ttt->mask[n]   = gdk_bitmap_create_from_data (NULL ,(char *)bmask ,width ,height);
      ttt->width[n]  = width;
      ttt->height[n] = height;
      g_free (bmask);
    }
    gw_pannel_bitmap_button_set (ttt ,button ,n);
    g_signal_connect (G_OBJECT (button), "toggled",
		      G_CALLBACK (gw_pannel_toggle), (gpointer) ttt);
  }
  gtk_widget_show (button);
}

void gw_pannel_numbering (Gw_pannel *ttt ,gboolean with_num)
{
  ttt->with_num = with_num;
}

void gw_pannel_hide_on_click (Gw_pannel *ttt ,gboolean hide_on_click)
{
  if (ttt != NULL) {
    ttt->hide_on_click = hide_on_click;
  }
}

void gw_pannel_resize (Gw_pannel *ttt ,guint nrows ,guint ncols)
{
  gint i ,nrc;
  gint nrc_old = ttt->nrc;
  gtk_table_resize (GTK_TABLE (ttt->table) ,nrows ,ncols);
  ttt->nlignes = nrows;
  ttt->ncolons = ncols;
  ttt->nrc     = nrc = nrows * ncols;
  if (nrc > nrc_old) {
    ttt->buttons = g_realloc (ttt->buttons ,nrc * sizeof(GtkWidget *));
    ttt->bg      = g_realloc (ttt->bg      ,nrc * sizeof(GdkColor  *));
    for (i = nrc_old; i < nrc; i++) {
      ttt->buttons[i] = NULL;
    }
  }
}

GtkWidget*  gw_pannel_button_get (Gw_pannel *ttt ,guint n)
{
  if (n < ttt->last) {
    return ttt->buttons[n];
  } else {
    return NULL;
  }
}
