/** File gg_frame.c
 *
 * Fonctions to create a frame widget and the widgets into.
 *
 */

#include <stdlib.h>
#include <string.h>

#include <gtk/gtk.h>

#include "globals.h"

#include "draw.h"
#include "graphs.h"
#include "utils.h"

#include "t1fonts.h"
#include "patterns.h"
#include "jbitmaps.h"
#include "mbitmaps.h"

#include "gw_list.h"
#include "gw_choice.h"
#include "gw_pannel.h"

#include "ge_protos.h"
#include "gg_protos.h"
#include "gg_gtkinc.h"

#include "gg_frame.h"

//35  provisoire
extern void    	    gg_set_int  (GtkWidget *w ,int val);
extern void    	    gg_set_dble (GtkWidget *w ,gdouble d);
extern int     	    gg_get_int  (GtkWidget *w);
extern gdouble 	    gg_get_dble (GtkWidget *w);
extern GdkDrawable *gg_get_win  (void);
extern gint 	    gg_get_depth (void);

extern GtkWidget *gg_main_window;
/* main window parameters */
static gint gg_wx ,gg_wy ,gg_ww ,gg_wh ,gg_depth;

extern GdkColor  gg_colors[MAXCOLORS];
extern GdkColor  bleuciel ,wheat;


static GtkWidget *pannel_button;

/**
 * The gg_frame_attach system. CAUTION tables are limited to xx dimension.
 */
static int n;
static int ii[2];
static int xx[2][80] ,yy[2][80];
static int stepcol = 1;          /* nb of table column use by gg_frame_attach */

static GtkWidget *w_box ,*w_label;
GtkWidget *gg_frame_n (gint un ,GtkWidget *parent ,gchar *label ,GdkColor *couleur ,int nx ,int ny);

/********** F R A M E  with  C O L O U R  B A C K G R O U N D ***********
 * If nx==0 , it is a Vbox
 * If ny==0 , it is a Hbox
 * Else, it is a table using the gg_frame_attach/ii/xx/yy  procedure
 */
GtkWidget *gg_frame (GtkWidget *parent ,gchar *label ,GdkColor *couleur ,int nx ,int ny)
{
  return gg_frame_n (0 ,parent ,label ,couleur ,nx ,ny);
}

void gg_frame_set_n (int un)
{
  n = un;
}

GtkWidget *gg_frame_n (gint un ,GtkWidget *parent ,gchar *label ,GdkColor *couleur ,int nx ,int ny)
{
  GtkWidget *retval;
  GtkWidget *fframe ,*fevent;
  int i ,j;

  n = un;

  /* un "event"  est necessaire pour pouvoir changer la couleur du fond */
  fevent = gtk_event_box_new ();
  if (couleur != NULL) {
    gtk_widget_modify_bg (GTK_WIDGET(fevent), GTK_STATE_NORMAL ,couleur);
  }
  gtk_box_pack_start (GTK_BOX (parent) ,fevent , TRUE , FALSE , 1);

  fframe = gtk_frame_new (label);
  gtk_container_add (GTK_CONTAINER (fevent) ,fframe);

  if (ny == 0) {
    retval = gtk_hbox_new (TRUE ,1);
  } else if (nx == 0) {
    retval = gtk_vbox_new (FALSE ,1);
  } else {
    retval = gtk_table_new (ny ,nx ,FALSE);
    gtk_table_set_row_spacings (GTK_TABLE (retval) ,1);
    gtk_table_set_col_spacings (GTK_TABLE (retval) ,1);
    ii[n] = 0;
    for (i=0; i<ny; i++) {
      for (j=0; j<nx; j++) {
	xx[n][ii[n]] = j;
	yy[n][ii[n]] = i;
	ii[n]++;
      }
    }
    ii[n] = 0;
  }
  gtk_container_add (GTK_CONTAINER (fframe) ,retval);
  gtk_widget_show_all (fevent);

  return (retval);
}

/**
 *  gg_frame_attach is called to pack a child into a frame
 */
void gg_frame_attach (GtkWidget *parent, GtkWidget *child)
{
  if (parent == NULL) {
    printf ("gg_frame_attach : parent==NULL\n");
    return;
  } else if (GTK_IS_BOX (parent)) {
    gtk_box_pack_start (GTK_BOX (parent) ,child , FALSE, TRUE, 1);
  } else if (GTK_IS_TABLE (parent)) {
    gtk_table_attach_defaults (GTK_TABLE (parent) ,child
			       ,xx[n][ii[n]] ,xx[n][ii[n]]+stepcol
			       ,yy[n][ii[n]] ,yy[n][ii[n]]+stepcol  );
    ii[n] += stepcol;
  } else if (GTK_IS_TOOLBAR (parent)) {
    gtk_toolbar_insert (GTK_TOOLBAR (parent) ,GTK_TOOL_ITEM(child) ,-1);
  }
}

/** Utilities to get current box or label 
 */
GtkWidget *gg_get_w_box (void)
{
  return w_box;
}
GtkWidget *gg_get_w_label (void)
{
  return w_label;
}


/********** I N I T I A L I Z A T I O N   F U N C T I O N ********/


static gg_OptionItem *settype_option_items;
static unsigned char *lin_bits[MAXLINESTYLES];

#define LINES_BM_HEIGHT 15
#define LINES_BM_WIDTH  64


int gg_init_option_menus (void)
{
  int i, j, k, l, n;
  /* Compute lin_bits */
  gdk_window_get_geometry (gg_main_window->window
			   ,&gg_wx ,&gg_wy ,&gg_ww ,&gg_wh ,&gg_depth);
  n = number_of_linestyles ();
  for (i = 0; i < n; i++) {
    lin_bits[i] =
      xcalloc (LINES_BM_HEIGHT*LINES_BM_WIDTH/8/SIZEOF_CHAR, SIZEOF_CHAR);
    k = LINES_BM_WIDTH*(LINES_BM_HEIGHT/2);
    while (k < LINES_BM_WIDTH*(LINES_BM_HEIGHT/2 + 1)) {
      for (j = 0; j < dash_array_length[i]; j++) {
	for (l = 0; l < dash_array[i][j]; l++) {
	  if (k < LINES_BM_WIDTH*(LINES_BM_HEIGHT/2 + 1)) {
	    if (j % 2 == 0) {
	      /* black */
 	      lin_bits[i][k/8] |= 1 << k % 8;   // doit remplacer la ligne ci-dessus
	    }
	    k++;
	  }
	}
      }
    }
  }
  settype_option_items = xmalloc(NUMBER_OF_SETTYPES*sizeof(gg_OptionItem));
  if (settype_option_items == NULL) {
    errmsg("Malloc error in init_option_menus()");
    return RETURN_FAILURE;
  }
  for (i = 0; i < NUMBER_OF_SETTYPES; i++) {
    settype_option_items[i].value = i;
    settype_option_items[i].label = copy_string (NULL, set_types(i));
    lowtoupper (settype_option_items[i].label);
  }
  return RETURN_SUCCESS;
}

/********** C O N N E C T   F O R   I N S T A N T   U P D A T E **********/


/**
 *  After a call to gg_frame_connect, the widget created are automatically
 *  g_signal_connect'ed to CB, until CB == NULL
 *  The default must be to set  CB=NULL in order to refer to a known state.
 */
static void (*CB) (GtkWidget *w ,gpointer p) = NULL;
static gpointer pcb = NULL;

void gg_frame_connect (void (*fun) (GtkWidget *w ,gpointer p))
{
  CB = fun;
  pcb = NULL;
}

void gg_frame_connect_with_gpointer (void (*fun) (GtkWidget *w ,gpointer p)  ,gpointer p)
{
  CB = fun;
  pcb = p;
}


/********** Widgets to be attached into a frame ********/

GtkWidget *gg_vbox_new (GtkWidget *parent)
{
  w_box = gtk_vbox_new (FALSE, 2);
  gg_frame_attach (parent ,w_box); 
  return (w_box);
}

GtkWidget *gg_hbox_new (GtkWidget *parent)
{
  w_box = gtk_hbox_new (FALSE, 2);
  gg_frame_attach (parent ,w_box); 
  return (w_box);
}

/**
 * Use n columns of the table 
 */
GtkWidget *gg_hbox_n_new (GtkWidget *parent ,int n)
{
  w_box = gtk_hbox_new (FALSE, 2);
  stepcol = n;
  gg_frame_attach (parent ,w_box); 
  stepcol = 1;
  return (w_box);
}


GtkWidget *gg_angle_new (GtkWidget *parent, char *s)
{
  GtkWidget *retval;
  retval = gg_spin_new (parent ,s ,0.0 ,360.0 ,1.0);
  gg_set_dble (retval ,0.0);
  return retval;
}

/**
 *  Replace CreateButton        motifutils.c  911
 */
GtkWidget *gg_button_new (GtkWidget *parent, char *s)
{
    GtkWidget *w_but;
    w_but = gtk_button_new_with_label (s);
    gg_frame_attach (parent ,w_but);
    return (w_but);
}

/**
 * Create button including  callback action
 */
void gg_buttonA (GtkWidget *parent ,char *s
		,void (*func) (GtkWidget *w ,gpointer p)
		,gint action)
{
  GtkWidget *w_but;
  w_but = gtk_button_new_with_label (s);
  gg_frame_attach (parent ,w_but);
  g_signal_connect (w_but ,"clicked" ,G_CALLBACK (func) ,GINT_TO_POINTER (action) );
}


/**
 *  Create button with bitmap image, callback and tooltip.
 *         Assume square bitmap.
 *  Replace    CreateBitmapButton   motifutils.c  933
 */
GtkWidget *gg_buttonB (GtkWidget *parent ,int side ,int depth
		      ,const unsigned char *bits
		      ,void (*cb) (GtkWidget *w ,gpointer p)
		      ,gint action
		      ,const gchar *tip)
{
  GtkWidget *w_but;
  int i;
  unsigned char *bmask;
  gint nbits = side * side;
  GdkBitmap *mask;
  GdkPixmap *pixmap;
  GtkWidget *image;
  GdkDrawable *win;
  win = gg_get_win ();
  bmask = malloc (nbits * sizeof(char));
  for (i=0; i<nbits; i++) bmask[i] = 0xff;
  mask = gdk_bitmap_create_from_data (win ,(char *)bmask ,side ,side);
  free (bmask);
  pixmap = gdk_pixmap_create_from_data (win
					,(char *)bits
					,side ,side ,depth
					,&gg_colors[1] ,&gg_colors[0]);
  image = gtk_image_new_from_pixmap (pixmap ,mask);
  w_but = gtk_button_new ();
  gtk_button_set_image (GTK_BUTTON(w_but) ,image);
  gg_frame_attach (parent ,w_but);
  g_signal_connect (w_but ,"clicked" , G_CALLBACK (cb) ,GINT_TO_POINTER (action));
#ifdef WITH_TOOLTIPS
  gtk_widget_set_tooltip_text (w_but ,tip);
#endif
  return w_but;
}

/**
 * Button with callback action and tooltip
 */
void gg_buttonT (GtkWidget *parent ,char *s
		 ,void (*func) (GtkWidget *w ,gpointer p)
		 ,gint action
		 ,const char *tip)
{
  GtkWidget *w_but;
  w_but = gtk_button_new_with_label (s);
  gg_frame_attach (parent ,w_but);
#ifdef WITH_TOOLTIPS
  gtk_widget_set_tooltip_text (w_but ,tip);
#endif
  g_signal_connect (w_but ,"clicked" ,G_CALLBACK (func) ,GINT_TO_POINTER (action) );
}


/**
 *  Replace  CreateCharSizeChoice     motifutils.c 2836
 */
GtkWidget *gg_charsize_new (GtkWidget *parent ,char *s)
{
  GtkWidget *retval;
  retval = gg_spin_new (parent ,s ,0.1 ,5.0 ,0.05);
  gg_set_dble (retval ,0.5);
  return retval;
}

/**
 *  Signal to use: "toggled"
 *  Callback: void fun (GtkToggleButton *w ,gpointer p)   : Run First
 */
GtkWidget *gg_check_new (GtkWidget *parent ,char *s)
{
  GtkWidget *w_but;
  w_but = gtk_check_button_new_with_label (s);
  gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (w_but) ,TRUE);
  gg_frame_attach (parent ,w_but);
  /* for instantaneous update */
  if (CB) g_signal_connect (w_but ,"toggled" ,G_CALLBACK (CB) ,pcb);
  return (w_but);
}

/**
 * Create check button including  callback action
 */
void gg_checkA (GtkWidget *parent ,char *s
		,void (*func) (GtkWidget *w ,gpointer p)
		,gint action)
{
  GtkWidget *w_but;
  w_but = gtk_check_button_new_with_label (s);
  gg_frame_attach (parent ,w_but);
  g_signal_connect (w_but ,"clicked" ,G_CALLBACK (func) ,GINT_TO_POINTER (action) );
}


/********* C O L O R   C H O I C E ***********/

/**
 *  Create the color pannel
 * Replace CreateColorChoice */

static GtkWidget *color_pannel  = NULL;
static int ncolor_option_items = 0;

GtkWidget *gg_color_new (GtkWidget *parent ,char *s)
{
  GtkWidget *choix;
  gint ncolors ,nrows ,nrow ,ncol ,i ,k;
  if (color_pannel == NULL) {
    ncolors = number_of_main_colors (); /* only COLOR_MAIN are displayed in the pannel */
    nrows = (ncolors-1)/4 + 1;
    color_pannel = gw_pannel_new ("Colors" ,nrows ,4 ,gg_get_win ());
    gw_pannel_set_row_first (GW_PANNEL (color_pannel) ,FALSE);
    for (i = 0, k = 0; i < number_of_colors(); i++) {
      if (get_colortype (i) == COLOR_MAIN)  {
	gw_pannel_n_to_xy (GW_PANNEL (color_pannel) ,i ,&ncol ,&nrow);
	pannel_button = gtk_toggle_button_new ();
	gw_pannel_attach_color_button (GW_PANNEL (color_pannel) ,pannel_button
				       ,&gg_colors[i] ,get_colorname(i) ,ncol ,nrow);
	k++;
      }
    }
    ncolor_option_items = ncolors;
  }
  choix = gw_choice_new (s ,GW_PANNEL(color_pannel) ,1);
  gtk_widget_show_all (choix);
  gg_frame_attach (parent ,choix);
  /* for instantaneous update */
  if (CB) g_signal_connect (choix ,"gw_choice" ,G_CALLBACK (CB) ,pcb);
  return (choix);
}


/*  Called by store_color via devupdatecmap  (i.e. gg_updatecmap) */
void gg_color_pannel_update (void)
{
  gint last;
  gint ncolors ,nrows ,nrows_old ,i ,k;
  if (!inwin) return;
  if (color_pannel != NULL) {
    ncolors = number_of_main_colors (); /* only COLOR_MAIN are displayed in the pannel */
    nrows = (ncolors-1)/4 + 1;
    last = GW_PANNEL (color_pannel)->last;
    nrows_old = last/4 + 1;
    if (nrows > nrows_old) {
      gw_pannel_resize (GW_PANNEL (color_pannel) ,nrows ,4);
    }
    /* devupdatecmap has no arg, thus allows only to update all the table
     * => we update all the pannel
     */
    for (i = 0 ,k = 0; i < number_of_colors(); i++) {
      if (get_colortype (i)  == COLOR_MAIN) {
	if (k > last) {
	  gw_pannel_update_color_button (GW_PANNEL (color_pannel) ,k ,&gg_colors[i] ,get_colorname(i));
	}
	k++;
      }
    }
    ncolor_option_items = k;
  }
}

/******** C O M B O  from an  A R R A Y **************/

/**
 * Creer une ComboBox à partir d'un tableau de chaines de caracteres
 *  Signal to use: "changed"
 */
static GtkWidget *gg_combo_array (int nb_item ,int nb_char ,char **items ,char *s ,GtkWidget **p ,int n)
{
  GtkWidget *w_combo;
  int i;
  w_box = gtk_hbox_new (FALSE, 3);
  w_label = gtk_label_new_with_mnemonic (s);
  gtk_box_pack_start (GTK_BOX (w_box), w_label, FALSE, TRUE, 0);
  w_combo = gtk_combo_box_new_text ();
  for (i=0; i<nb_item; i++) {
    gtk_combo_box_append_text (GTK_COMBO_BOX(w_combo) ,items[i]);
  }
  gtk_box_pack_start (GTK_BOX (w_box), w_combo, FALSE, TRUE, 1);
  gtk_combo_box_set_active  (GTK_COMBO_BOX(w_combo) ,n);
  /* for instantaneous update */
  if (CB) g_signal_connect (w_combo ,"changed" ,G_CALLBACK (CB) ,pcb);
  *p = w_combo;
  return (w_box);
}

/**
 *  Creer une ComboBox  dont les items sont donnés par la fonction "fun"
 *  Create a GtkComboBox with at most "*nb_item" items. The string is
 *  given by "fun" and default setting is "active"
 *  Signal to use: "changed"
 */
GtkWidget *gg_combo_fun (GtkWidget *parent ,char *s ,int *nb_item ,char*(*fun) (int i),int active)
{
  GtkWidget *w_combo;
  int i;
  w_box = gtk_hbox_new (FALSE, 3);
  w_label = gtk_label_new_with_mnemonic (s);
  gtk_box_pack_start (GTK_BOX (w_box), w_label, FALSE, TRUE, 0);
  w_combo = gtk_combo_box_new_text ();
  for (i=0; i<*nb_item; i++) {
    if (strlen( fun(i) ) > 0) {
      gtk_combo_box_append_text (GTK_COMBO_BOX(w_combo) ,fun(i));
    } else {
      break;
    }
  }
  gtk_box_pack_start (GTK_BOX (w_box), w_combo, FALSE, TRUE, 1);
  gtk_combo_box_set_active  (GTK_COMBO_BOX(w_combo) ,active);
  gg_frame_attach (parent ,w_box);
  /* for instantaneous update */
  if (CB) g_signal_connect (w_combo ,"changed" ,G_CALLBACK (CB) ,pcb);
  return w_combo;
}

GtkWidget *gg_combo_fun2 (GtkWidget *parent ,char *s ,int *nb_item ,char*(*fun) (int i) ,int active)
{
  GtkWidget *w_combo;
  int i;
  w_label = gtk_label_new_with_mnemonic (s);
  gg_frame_attach (parent ,w_label);
  w_combo = gtk_combo_box_new_text ();
  for (i=0; i<*nb_item; i++) {
    if (strlen( fun(i) ) > 0) {
      gtk_combo_box_append_text (GTK_COMBO_BOX(w_combo) ,fun(i));
    } else {
      break;
    }
  }
  gtk_combo_box_set_active  (GTK_COMBO_BOX(w_combo) ,active);
  gg_frame_attach (parent ,w_combo);
  /* for instantaneous update */
  if (CB) g_signal_connect (w_combo ,"changed" ,G_CALLBACK (CB) ,pcb);
  return w_combo;
}


/**
 *   gg_combo_new
 *   Replace  CreatePanelChoice motifutils.c 2615
 *   use "changed" signal
 */
GtkWidget *gg_combo_new (GtkWidget *parent, char *labelstr, int nchoices,...)
{
  va_list var;
  int i ,lsu ,maxlsu;
  char **items ,*s;
  GtkWidget *w_combo;
  nchoices--;
  items = malloc (nchoices * sizeof(char *));
  maxlsu = 0;
  va_start(var, nchoices);
  for (i=0; i<nchoices; i++) {
    s = va_arg (var, char *);
    lsu = strlen (s) + 1;
    if (maxlsu < lsu) maxlsu = lsu;
    items[i] = malloc (lsu * sizeof(char) );
    strcpy (items[i] ,s);
  }
  va_end(var);
  w_box = gg_combo_array (nchoices ,maxlsu ,items ,labelstr ,&w_combo ,0);
  for (i=0; i<nchoices; i++) free (items[i]);
  free (items);
  gg_frame_attach (parent ,w_box);
  return (w_combo);
}

/************ E N T R Y  with  L A B E L ****************
 *  Replace CreateTextItem2   Caution arg 2 and 3 swapped   motifutils.c 3245
 */
GtkWidget *gg_entry_new (GtkWidget *parent ,char *s ,int len)
{
  GtkWidget *w_entry;
  w_box   = gtk_hbox_new (FALSE, 2);
  w_label = gtk_label_new (s);
  w_entry = gtk_entry_new ();
  gtk_entry_set_width_chars (GTK_ENTRY (w_entry) ,len);
  gtk_box_pack_start 	    (GTK_BOX   (w_box) ,w_label , FALSE, TRUE, 1);
  gtk_box_pack_start 	    (GTK_BOX   (w_box) ,w_entry , FALSE, TRUE, 1);
  gtk_widget_show_all (w_box);
  gg_frame_attach (parent ,w_box);
  if (CB) g_signal_connect (w_entry ,"activate" ,G_CALLBACK (CB) ,NULL);
  return (w_entry);
}

/**
 *  Replace  CreateFontChoice    motifutils.c 1283
 */
GtkWidget *gg_font_new (GtkWidget *parent ,char *s)
{
  int nfonts = number_of_fonts();
  GtkWidget *w_combo;
  w_combo = gg_combo_fun (parent ,s ,&nfonts ,get_fontalias ,0);
  /* note that gg_frame_attach is already called by gg_combo_fun */
  gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (w_combo) ,4);
  return (w_combo);
}

/************ E N T R Y  with  F O N T  T O O L ****************/

static void gg_font_tool_item_CB (GtkMenuItem *item ,gpointer p)
{
  GtkWidget *entry = GTK_WIDGET (p);
  gg_fontwin_set_cur_entry (entry);
  gg_fontwin_create (NULL ,NULL);
}

static void gg_add_font_tool_item (GtkEntry *entry ,GtkMenu *menu ,gpointer p)
{
  GtkWidget *sep ,*new_item;
  sep = gtk_separator_menu_item_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu) ,sep);
  gtk_widget_show (sep);
  new_item = gtk_menu_item_new_with_label ("Use font tool");
  gtk_menu_shell_append (GTK_MENU_SHELL (menu) ,new_item);
  gtk_widget_show (new_item);
  g_signal_connect (new_item ,"activate" ,G_CALLBACK (gg_font_tool_item_CB) ,p);
}

/**
 *  Entry with Font Tool added to mouse button3 menu
 */
GtkWidget *gg_string_new (GtkWidget *parent ,char *s ,int len)
{
  GtkWidget *w_entry = gg_entry_new (parent ,s ,len);
  g_signal_connect (w_entry ,"populate-popup" ,G_CALLBACK (gg_add_font_tool_item) ,w_entry);
  return w_entry;
}



/********* F O R M A T   C H O I C E ***********/

static GtkWidget *format_pannel = NULL;
static gg_OptionItem fmt_option_items[32] =
{
    {FORMAT_DECIMAL,        "Decimal"              },
    {FORMAT_EXPONENTIAL,    "Exponential"          },
    {FORMAT_GENERAL,        "General"              },
    {FORMAT_POWER,          "Power"                },
    {FORMAT_SCIENTIFIC,     "Scientific"           },
    {FORMAT_ENGINEERING,    "Engineering"          },
    {FORMAT_COMPUTING,      "Computing (K,M,G,...)"},
    {FORMAT_DDMMYY,         "DD-MM-YY"             },
    {FORMAT_MMDDYY,         "MM-DD-YY"             },
    {FORMAT_YYMMDD,         "YY-MM-DD"             },
    {FORMAT_MMYY,           "MM-YY"                },
    {FORMAT_MMDD,           "MM-DD"                },
    {FORMAT_MONTHDAY,       "Month-DD"             },
    {FORMAT_DAYMONTH,       "DD-Month"             },
    {FORMAT_MONTHS,         "Month (abrev.)"       },
    {FORMAT_MONTHSY,        "Month (abrev.)-YY"    },
    {FORMAT_MONTHL,         "Month"                },
    {FORMAT_DAYOFWEEKS,     "Day of week (abrev.)" },
    {FORMAT_DAYOFWEEKL,     "Day of week"          },
    {FORMAT_DAYOFYEAR,      "Day of year"          },
    {FORMAT_HMS,            "HH:MM:SS"             },
    {FORMAT_MMDDHMS,        "MM-DD HH:MM:SS"       },
    {FORMAT_MMDDYYHMS,      "MM-DD-YY HH:MM:SS"    },
    {FORMAT_YYMMDDHMS,      "YY-MM-DD HH:MM:SS"    },
    {FORMAT_DEGREESLON,     "Degrees (lon)"        },
    {FORMAT_DEGREESMMLON,   "DD MM' (lon)"         },
    {FORMAT_DEGREESMMSSLON, "DD MM' SS.s\" (lon)"  },
    {FORMAT_MMSSLON,        "MM' SS.s\" (lon)"     },
    {FORMAT_DEGREESLAT,     "Degrees (lat)"        },
    {FORMAT_DEGREESMMLAT,   "DD MM' (lat)"         },
    {FORMAT_DEGREESMMSSLAT, "DD MM' SS.s\" (lat)"  },
    {FORMAT_MMSSLAT,        "MM' SS.s\" (lat)"     }
};
/**
 *  Replace CreateFormatChoice    motifutils.c 2735
 */
GtkWidget *gg_format_new (GtkWidget *parent ,char *s)
{
  GtkWidget *choix;
  gint i ,j ,k;
  if (format_pannel == NULL) {
    format_pannel = gw_pannel_new ("Formats" ,8 ,4 ,gg_get_win ());
    k = 0;
    for (i=0; i<4; i++) {
      for (j=0; j<8; j++) {
  	pannel_button = gtk_toggle_button_new ();
  	gw_pannel_attach_color_button (GW_PANNEL(format_pannel) ,pannel_button
  				       ,&wheat ,fmt_option_items[k].label ,i ,j);
  	k++;
      }
    }
  }
  choix = gw_choice_new (s ,GW_PANNEL(format_pannel) ,1);
  gtk_widget_show_all (choix);
  gg_frame_attach (parent ,choix);
  /* for instantaneous update */
  if (CB) g_signal_connect (choix ,"gw_choice" ,G_CALLBACK (CB) ,pcb);
  return (choix);
}

GtkWidget *gg_label_new (GtkWidget *parent, char *s)
{
  GtkWidget *w_label;
  w_label = gtk_label_new (s);
  gg_frame_attach (parent ,w_label);
  return (w_label);
}

/*************** J U S T I F I C A T I O N    C H O I C E ****************/

static GtkWidget *just_pannel = NULL;
static unsigned char *just_bits[12] = {
  j_lm_o_bits,
  j_cm_o_bits,
  j_rm_o_bits,
  j_lb_b_bits,
  j_cb_b_bits,
  j_rb_b_bits,
  j_lm_b_bits,
  j_cm_b_bits,
  j_rm_b_bits,
  j_lt_b_bits,
  j_ct_b_bits,
  j_rt_b_bits
};

/**
 *   Replace   CreateJustChoice    motifutils.c 1323
 */
GtkWidget *gg_just_new (GtkWidget *parent ,char *s)
{
  GtkWidget *choix;
  if (just_pannel == NULL) {
    just_pannel = gg_pannelB ("Justification" ,3 ,4
					 ,just_bits ,JBITMAP_WIDTH ,JBITMAP_HEIGHT
					 ,TRUE);
  }
  choix = gw_choice_new (s ,GW_PANNEL(just_pannel) ,1);
  gtk_widget_show_all (choix);
  gg_frame_attach (parent ,choix);
  gw_choice_set (GW_CHOICE (choix) ,0);
  /* for instantaneous update */
  if (CB) g_signal_connect (choix ,"gw_choice" ,G_CALLBACK (CB) ,pcb);
  return (choix);
}

/*************** L I N E   S T Y L E   C H O I C E ****************/

static GtkWidget *linestyle_pannel = NULL;
/**
 *  Replace  CreateLineStyleChoice    motifutils.c 1295
 *      and  CreateBitmapOptionChoice motifutils.c 309
 */
GtkWidget *gg_lines_new (GtkWidget *parent ,char *s)
{
  GtkWidget *choix;
  if (linestyle_pannel == NULL) {
    linestyle_pannel = gg_pannelB ("Style" ,MAXLINESTYLES ,1
				   ,lin_bits ,LINES_BM_WIDTH ,LINES_BM_HEIGHT
				   ,TRUE);
  }
  choix = gw_choice_new (s ,GW_PANNEL(linestyle_pannel) ,1);
  gtk_widget_show_all (choix);
  gg_frame_attach (parent ,choix);
  /* for instantaneous update */
  if (CB) g_signal_connect (choix ,"gw_choice" ,G_CALLBACK (CB) ,pcb);
  return (choix);
}


/*************** O R D E R    C H O I C E ****************/

static GtkWidget *order_pannel = NULL;
static unsigned char *order_bits[8] = {
  m_hv_lr_tb_bits
  ,m_hv_lr_bt_bits
  ,m_hv_rl_tb_bits
  ,m_hv_rl_bt_bits
  ,m_vh_lr_tb_bits
  ,m_vh_lr_bt_bits
  ,m_vh_rl_tb_bits
  ,m_vh_rl_bt_bits };

GtkWidget *gg_order_new (GtkWidget *parent ,char *s)
{
  GtkWidget *choix;
  if (order_pannel == NULL) {
    order_pannel = gg_pannelB ("Order" ,4 ,2
					  ,order_bits ,MBITMAP_WIDTH ,MBITMAP_HEIGHT
					  ,TRUE);
  }
  choix = gw_choice_new (s ,GW_PANNEL(order_pannel) ,1);
  gtk_widget_show_all (choix);
  gg_frame_attach (parent ,choix);
  /* for instantaneous update */
  if (CB) g_signal_connect (choix ,"gw_choice" ,G_CALLBACK (CB) ,pcb);
  return (choix);
}

/*************** B I T M A P   P A N N E L  ****************/

/**
 *   "nrows" and "ncols" are the number of buttons rows and columns
 *   "width" and "height" arrays for the size  of images
 *                        (all images have the same size)
 *
 * Replace CreateBitmapOptionChoice motifutils.c   309
 *
 *
 */
GtkWidget *gg_pannelB (gchar *s ,gint nrows ,gint ncols
				  ,unsigned char **bits ,int width ,int height
				  ,gboolean with_num
				  )
{
  int n;
  GtkWidget *pannel ,*pannel_button;
  GdkDrawable *win = gg_get_win ();
  gint gg_depth    = gg_get_depth ();
  pannel 	   = gw_pannel_new (s ,nrows ,ncols ,win);
  gw_pannel_set_bitmaps_defaults (GW_PANNEL (pannel) ,gg_depth ,FALSE);
  gw_pannel_numbering            (GW_PANNEL (pannel) ,with_num);
  /* create the elements in pannel */
  for (n = 0; n < nrows*ncols; n++) {
    pannel_button = gtk_toggle_button_new ();
    gw_pannel_bitmap_button_attach (GW_PANNEL (pannel) ,pannel_button ,n
				    ,bits[n]   ,width ,height);
  }
  return (pannel);
}

/*************** P A T T E R N    C H O I C E ****************/

static GtkWidget *pattern_pannel = NULL;
/**
 *  Replace  CreatePatternChoice    motifutils.c 1286
 *  Signal to use: "gw_choice"
 */
GtkWidget *gg_pattern_new (GtkWidget *parent ,char *label)
{
  GtkWidget *choix;
  if (pattern_pannel == NULL) {
    pattern_pannel = gg_pannelB ("Patterns" ,8 ,6 ,pat_bits ,16 ,16 ,TRUE);
  }
  choix = gw_choice_new (label ,GW_PANNEL(pattern_pannel) ,1);
  gtk_widget_show_all (choix);
  gg_frame_attach (parent ,choix);
  /* for instantaneous update */
  if (CB) g_signal_connect (choix ,"gw_choice" ,G_CALLBACK (CB) ,pcb);
  return (choix);
}




/********** S P I N    B U T T O N ************
 *
 *  Replace   CreateSpinChoice    motifutils.c 680
 *  Signal to use: "value-changed"
 *  Callback: void fun (GtkSpinButton *w ,gpointer p)
 */
GtkWidget *gg_spin_new (GtkWidget *parent ,char *s ,double min ,double max ,double incr)
{
  GtkWidget  *spin;
  w_box   = gtk_hbox_new (FALSE ,2);
  w_label = gtk_label_new (s);
  spin 	  = gtk_spin_button_new_with_range (min ,max ,incr);
  gtk_box_pack_start (GTK_BOX (w_box) ,w_label ,FALSE ,TRUE ,0);
  gtk_box_pack_start (GTK_BOX (w_box) ,spin ,FALSE ,TRUE ,1);
  gg_frame_attach (parent ,w_box);
  /* for instantaneous update */
  if (CB) g_signal_connect (spin ,"value-changed" ,G_CALLBACK (CB) ,pcb);
  g_signal_connect 	   (spin ,"value-changed" ,G_CALLBACK (gg_spin_time_store_CB) ,NULL);
  return (spin);
}

/**
 *  Replace CreateScale        motifutils.c 2777
 *  Signal to use: "value-changed"
 */
GtkWidget *gg_scale_new (GtkWidget *parent ,char *s  ,double min ,double max ,double delta)
{
  GtkWidget *scale;
  w_box     = gtk_vbox_new (FALSE ,2);
  w_label   = gtk_label_new (s);
  scale     = gtk_hscale_new_with_range (min ,max ,delta);
  gtk_box_pack_start (GTK_BOX (w_box) ,scale ,FALSE ,TRUE ,1);
  gtk_box_pack_start (GTK_BOX (w_box) ,w_label   ,FALSE ,TRUE ,0);
  gg_frame_attach (parent ,w_box);
  /* for instantaneous update */
  if (CB) g_signal_connect (scale ,"value-changed" ,G_CALLBACK (CB) ,pcb);
  return (scale);
}


GtkWidget *gg_layer_new (GtkWidget *parent ,char *s)
{
  return gg_spin_new  (parent ,s ,1.0 ,(double) (LAYER_MAX-1) ,1.0);
}

/************** D O U B L E    S P I N ****************/

void gg_spin2d (GtkWidget *parent ,spin2Struct *sp2
		,gdouble xmin ,gdouble xmax ,gdouble dx)
{
  sp2->box    = gtk_hbox_new (TRUE ,2);
  sp2->label1 = gtk_label_new (sp2->s1);
  sp2->label2 = gtk_label_new (sp2->s2);
  sp2->spin1  = gtk_spin_button_new_with_range (xmin ,xmax ,dx);
  sp2->spin2  = gtk_spin_button_new_with_range (xmin ,xmax ,dx);
  gtk_box_pack_end (GTK_BOX (sp2->box) ,sp2->spin2  ,FALSE ,FALSE ,0);
  gtk_box_pack_end (GTK_BOX (sp2->box) ,sp2->label2 ,FALSE ,FALSE ,1);
  gtk_box_pack_end (GTK_BOX (sp2->box) ,sp2->spin1  ,FALSE ,FALSE ,0);
  gtk_box_pack_end (GTK_BOX (sp2->box) ,sp2->label1 ,FALSE ,FALSE ,1);
  gtk_box_pack_end (GTK_BOX (parent)   ,sp2->box    ,TRUE  ,TRUE  ,1);
  if (CB) {
    g_signal_connect (sp2->spin1 ,"value-changed" ,G_CALLBACK (CB) ,pcb);
    g_signal_connect (sp2->spin2 ,"value-changed" ,G_CALLBACK (CB) ,pcb);
  }
  g_signal_connect (sp2->spin1 ,"value-changed" ,G_CALLBACK (gg_spin_time_store_CB) ,NULL);
  g_signal_connect (sp2->spin2 ,"value-changed" ,G_CALLBACK (gg_spin_time_store_CB) ,NULL);

}

void gg_spin2d_set (spin2Struct *sp2
		    ,gchar *s1 ,gdouble x1
		    ,gchar *s2 ,gdouble x2)
{
  gtk_label_set_text (GTK_LABEL (sp2->label1) ,s1);
  gg_set_dble (sp2->spin1  ,x1);
  if (s2 != NULL) {
    gtk_widget_show (sp2->label2);
    gtk_widget_show (sp2->spin2);
    gtk_label_set_text (GTK_LABEL (sp2->label2) ,s2);
    gg_set_dble (sp2->spin2  ,x2);
  } else {
    gtk_widget_hide (sp2->label2);
    gtk_widget_hide (sp2->spin2);
  }
}
void gg_spin2i_set (spin2Struct *sp2
		    ,gchar *s1 ,int x1
		    ,gchar *s2 ,int x2)
{
  gtk_label_set_text (GTK_LABEL (sp2->label1) ,s1);
  gg_set_int (sp2->spin1  ,x1);
  if (s2 != NULL) {
    gtk_label_set_text (GTK_LABEL (sp2->label2) ,s2);
    gg_set_int (sp2->spin2  ,x2);
  }
}

/******* D O U B L E   S P I N  with  M E N U 3   M A N A G E M E N T *******/

//044b Voir gg_fontwin_create et gg_add_font_tool_item

static GtkWidget *spine_win = NULL;
static GtkWidget *vb ,*fr;
static GtkSpinButton *w_s;
static GtkWidget *w_min ,*w_max ,*w_step ,*w_value;

static void 	  gg_spine_win_AC_CB  (GtkWidget *w ,gint reponse);
static GtkWidget *gg_spine_win_create (GtkWidget *w ,gpointer p);
static void	  gg_spine_win_update (GtkSpinButton *w);


static gdouble min ,max ,step ,page ,value;

static void gg_spine_tool_item_CB (GtkMenuItem *item ,gpointer p)
{
  GtkSpinButton *w_s = GTK_SPIN_BUTTON (p);
  gg_spine_win_create (NULL ,p);
  gg_spine_win_update (w_s);
}

static void gg_add_spine_tool_item (GtkEntry *entry ,GtkMenu *menu ,gpointer p)
{
  GtkWidget *sep ,*new_item;
  sep = gtk_separator_menu_item_new ();
  gtk_menu_shell_append (GTK_MENU_SHELL (menu) ,sep);
  gtk_widget_show (sep);
  new_item = gtk_menu_item_new_with_label ("Manage spin button");
  gtk_menu_shell_append (GTK_MENU_SHELL (menu) ,new_item);
  gtk_widget_show (new_item);
  g_signal_connect (new_item ,"activate" ,G_CALLBACK (gg_spine_tool_item_CB) ,p);
}

void gg_spin2e (GtkWidget *parent ,spin2Struct *sp2
		,gdouble xmin ,gdouble xmax ,gdouble dx)
{
  gg_spin2d (parent ,sp2 ,xmin ,xmax ,dx);
  g_signal_connect (GTK_ENTRY (sp2->spin1) ,"populate-popup" ,G_CALLBACK (gg_add_spine_tool_item) ,sp2->spin1);
  g_signal_connect (GTK_ENTRY (sp2->spin2) ,"populate-popup" ,G_CALLBACK (gg_add_spine_tool_item) ,sp2->spin2);

}

GtkWidget *gg_spine_win_create (GtkWidget *w ,gpointer p)
{
  if (spine_win == NULL) {
    spine_win = gtk_dialog_new_with_buttons ("Manage spin button" ,NULL
					    ,GTK_DIALOG_DESTROY_WITH_PARENT
					    ,"Accept"          ,GTK_RESPONSE_ACCEPT
					    ,GTK_STOCK_CLOSE   ,GTK_RESPONSE_CLOSE
					    ,NULL); 
    vb = GTK_DIALOG (spine_win)->vbox;
    g_signal_connect (spine_win ,"delete-event" ,G_CALLBACK (gtk_widget_hide) 	 ,NULL);
    g_signal_connect (spine_win ,"response"     ,G_CALLBACK (gg_spine_win_AC_CB) ,NULL);
    gtk_window_set_modal (GTK_WINDOW (spine_win) ,TRUE);
    fr = gg_frame (vb ,"Spin button configuration" ,&wheat ,0 ,1);
    w_min   = gg_entry_new (fr ,"Min:"   ,15);
    w_max   = gg_entry_new (fr ,"Max:"   ,15);
    w_step  = gg_entry_new (fr ,"Step:"  ,15);
    w_value = gg_entry_new (fr ,"Value:" ,15);
  }
  gtk_widget_show_all (spine_win);
  return spine_win;
}

void gg_spine_win_update (GtkSpinButton *w)
{
  char buf[16];
  w_s = w;
  gtk_spin_button_get_range 	 (w_s ,&min ,&max);
  gtk_spin_button_get_increments (w_s ,&step ,&page);
  gg_setstr_d (w_min  ,"%g" ,min  ,buf);
  gg_setstr_d (w_max  ,"%g" ,max  ,buf);
  gg_setstr_d (w_step ,"%g" ,step ,buf);
  value = gtk_spin_button_get_value (w_s);
  gg_setstr_d (w_value ,"%g" ,value ,buf);

}

static void  gg_spine_win_AC_CB	(GtkWidget *w ,gint reponse)
{
  if (reponse == GTK_RESPONSE_ACCEPT) {
    if (gg_evalexpr (w_min  ,&min) == RETURN_FAILURE) {
      errmsg ("enable to evaluate Min");
      return;
    }
    if (gg_evalexpr (w_max  ,&max) == RETURN_FAILURE) {
      errmsg ("enable to evaluate Max");
      return;
    }
    if (gg_evalexpr (w_step  ,&step) == RETURN_FAILURE) {
      errmsg ("enable to evaluate Step");
      return;
    }
    if (gg_evalexpr (w_value  ,&value) == RETURN_FAILURE) {
      errmsg ("enable to evaluate Value");
      return;
    }
    gtk_spin_button_set_range 	   (w_s ,min  ,max);
    gtk_spin_button_set_increments (w_s ,step ,page);
    gtk_spin_button_set_value      (w_s ,value);

  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_destroy (spine_win);
    spine_win = NULL;
  }
}
