/**
 *  File ge_axe.c :  Axes menus
 *
 *  Replace tickwin.c
 *   Home page: http://plasma-gate.weizmann.ac.il/Grace/
 *   Copyright (c) 1991-1995 Paul J Turner, Portland, OR
 *   Copyright (c) 1996-2003 Grace Development Team
 *   Copyright (c) 2010 P. Vincent.    See GNU GPL ../LICENCE
 */

/* with SCALE_DEGREES, only the display is in degrees,
 * the internal data remains in radians
 * In "special tab" the first column remains in radians
 */


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

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

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

#include "gg_gutil.h"
#include "gg_gtkinc.h"
#include "gg_protos.h"

#include "t1fonts.h"

#include "ge_protos.h"

#include "ge_tree.h"
#include "ng_objects.h"
#include "wu.h"

static gint specticks_width = 320 ,specticks_height = 300;

extern GdkColor  bleuciel ,wheat;

extern void nn_cmd_axis (int gno ,int axisno
			 ,tickmarks *old ,world *w_old ,QDobject *oobj 
			 ,int all ,int undo_on);
extern int  niceprec (double x0 ,double x1);

extern Ge_tree *get_getree (void);

static GtkWidget *titre_item = NULL;


#define cg get_cg()

#define W(nom) if(gg_get_int(nom.u))

/************************************************************/
static int menu_finalized 	= FALSE;
static int block_instant_update = FALSE;

static int curaxis    = -1;
static int hide_minor = FALSE;

static void ge_axis_scale_CB 	    (GtkWidget *w ,gpointer p);
static void ge_axis_set_CB   	    (GtkWidget *w ,gpointer p);
static void ge_axislabelplace_CB    (GtkWidget *w ,gpointer p);
static void ge_tickslabelplace_CB   (GtkWidget *w ,gpointer p);
static void ge_axis_t_spec_CB 	    (GtkWidget *w ,gpointer p);
static void ge_axis_t_spec_major_CB (GtkWidget *w ,gpointer p);
static void ge_axis_nticks_CB 	    (GtkWidget *w ,gpointer p);
static void ge_axis_hide_minor_CB   (GtkWidget *w ,gpointer p);

static GtkWidget *ge_axes_u_new (void);
static void ge_axes_u_AAC_CB (GtkWidget *widget ,gint reponse);

static GtkWidget *vbox = NULL;

/**************************************************************/
/*  Widgets for tickmarks struct  elements (see defines.h 593) */
/**************************************************************/
static Wu zero;
//33 QDobject  label;
static Wu label_x1 ,label_y1;  // axislabelspec_para  axislabelspec_perp
static Wu label_color;
static Wu label_font;
static Wu label_charsize;
static Wu label_layout;
static Wu label_place;
static Wu label_op;
static Wu t_drawbar;
static Wu t_drawbarcolor;
static Wu t_drawbarlines;
static Wu t_drawbarlinew;
static Wu offsx ,offsy;
static Wu t_flag;
static Wu t_autonum;
static Wu t_spec;
static Wu t_round;
static Wu tmajor;
static Wu nminor;
static Wu nticks;
static GtkWidget *w_hide_minor;
static Wu t_inout;
static Wu t_op;
static Wu props_size;       /* tlen        */
static Wu props_color;      /* tgridcol	   */
static Wu props_linew;      /* tgridlinew  */
static Wu props_lines;      /* tgridlines  */
static Wu props_gridflag;   /* tgrid	   */
static Wu mprops_size;      /* tmlen	   */
static Wu mprops_color;     /* tmgridcol   */
static Wu mprops_linew;     /* tmgridlinew */
static Wu mprops_lines;     /* tmgridlines */
static Wu mprops_gridflag;  /* tmgrid	   */
static Wu tl_flag;          /* tlonoff	   */
static Wu tl_angle;         /* tlangle	   */
static Wu tl_format;        /* tlform	   */
static Wu tl_prec;          /* tlprec	   */
static Wu tl_formula;       /* tlformula   */
static Wu tl_skip;          /* tlskip	   */
static Wu tl_staggered;     /* tlstagger   */
static Wu tl_starttype;     /* tlstarttype */
static Wu tl_stoptype;      /* tlstoptype  */
static GtkWidget *tl_start; /* tlstart	   */
static GtkWidget *tl_stop;  /* tlstop	   */
static Wu tl_op;            /* ticklop	   */
static Wu tl_gaptype;       /* tlgaptype   */
static Wu tl_gap_para; 	    /* ,tl_gap_x;  */
static Wu tl_gap_perp; 	    /* ,tl_gap_y;  */
static Wu tl_font;          /* tlfont	   */
static Wu tl_charsize;      /* tlcharsize  */
static Wu tl_color;         /* tlcolor	   */
static Wu tl_appstr;        /* tlappstr	   */
static Wu tl_prestr;        /* tlprestr    */
/**************************************************************/
/*  Widgets for QDobject struct  elements (see defines.h 483) */
static Wu layer;
/**************************************************************/

typedef struct {
  GtkWidget *box;
  GtkWidget *major;
  GtkWidget *label;
  GtkWidget *loc;
} WSpec;
  
static WSpec wspec[MAX_TICKS];

/* Notebook */
static GtkWidget *w_notebook;         /* axes_notb  */
/* tab Widgets for the notebook */
static GtkWidget *w_tab_main;         /* axes_main       */
static GtkWidget *w_tab_axis_label;   /* axes_label	 */
static GtkWidget *w_tab_ticks_label;  /* axes_ticklabel	 */
static GtkWidget *w_tab_ticks_marks;  /* axes_tickmark	 */
static GtkWidget *w_tab_special;      /* axes_special    */


static Wu axis_hidden      ,axis_edit;
static Wu axis_world_start ,axis_world_stop;
static Wu axis_scale       ,axis_invert;
static GtkWidget *w_specrc;
static Wu axis_applyto;
static GtkWidget *w_blank;

static gint current_page = -1;
static gulong handler_id;

void ge_axis_page_block (void)
{
  g_signal_handler_block (w_notebook ,handler_id);
}
void ge_axis_page_unblock (void)
{
  g_signal_handler_unblock (w_notebook ,handler_id);
}
static void ge_axis_store_page_CB (GtkNotebook     *notebook,
 				    GtkNotebookPage *page,
 				    guint            page_num,
 				    gpointer         user_data)
{
  if (current_page >= 0) current_page = page_num;
}

static int cur_max_ticks = 0;
static int ge_axis_spec_ticks_max (GtkWidget *parent ,int n)
{
  int i;
  GtkWidget *rc;
  char buf[32];
  if (n >= MAX_TICKS) {
    errmsg ("MAX_TICKS exceeded");
    return FALSE;
  }
  if (n > cur_max_ticks && n < MAX_TICKS) {
    for (i = cur_max_ticks; i < n; i++) {
      wspec[i].box = rc = gg_CreateHContainer (parent);
      sprintf(buf, "%2d", i);
      wspec[i].major    = gg_check_new (rc ,buf);
      wspec[i].loc    	= gg_entry_new (rc ,"" ,12);
      wspec[i].label  	= gg_string_new (rc ,"" ,30);
      gtk_widget_show_all (wspec[i].box);
      g_signal_connect (wspec[i].major ,"toggled" 
			,G_CALLBACK (ge_axis_t_spec_major_CB) 
			,GINT_TO_POINTER (i));
      gg_set_int (wspec[i].major ,TRUE);
    }
  } else if (n < cur_max_ticks) {
/* Managing many lines for special ticks can make rpane update slow 
 * thus we destroy unused widgets  */
    for (i = cur_max_ticks-1; i >= n; i--) {
      gtk_widget_destroy (wspec[i].label);
      gtk_widget_destroy (wspec[i].loc);
      gtk_widget_destroy (wspec[i].major);
      gtk_widget_destroy (wspec[i].box);
      wspec[i].box = NULL;
    }
  }
  cur_max_ticks = n;
  return TRUE;
}

GtkWidget *ge_axis_create_menu (GtkWidget *parent)
{
  GtkWidget *rc  ,*rc2 ,*ta ,*sw;
  char buf[32];
  int i;

  gg_set_wait_cursor();
  if (titre_item == NULL) {
    block_instant_update = TRUE;
    vbox = gg_CreateVContainer (parent);
    rc = gg_CreateHContainer (vbox);
    sprintf (buf ,"Axis  ");
    titre_item  = gg_label_new (rc ,buf);
    gg_frame_connect (NULL);  
    axis_edit.w = gg_combo_new (rc ,"    choose:" ,5
				     ,"X axis"       	   /* X_AXIS */
				     ,"Y axis"       	   /* Y_AXIS */
				     ,"Alt X axis"   	   /* ZX_AXIS */
				     ,"Alt Y axis"   	   /* ZY_AXIS */
				     );
    gg_frame_connect (ge_axis_apply_CB);
    layer.w 	= gg_layer_new (rc ,"Layer");

    /* Notebook */
    w_notebook = gtk_notebook_new ();
    gtk_box_pack_start_defaults (GTK_BOX (vbox) ,w_notebook);

    /* ------------ create Main tab -------------- */
    w_tab_main = gg_CreateTabPage (w_notebook ,"Main");

    rc 		       = gg_frame     (w_tab_main ,NULL  ,&wheat ,2 ,2);
    axis_world_start.w = gg_entry_new (rc, "Start:", 14);
    axis_world_stop.w  = gg_entry_new (rc, "Stop:" , 14);
    axis_invert.w      = gg_check_new (rc ,"Invert axis");

    gg_frame_connect (NULL);          /* special callback ge_axis_scale_CB */
    axis_scale.w = gg_combo_new (rc ,"Scale:" ,6
				 ,"Linear"        	   /* SCALE_NORMAL */
				 ,"Logarithmic"   	   /* SCALE_LOG    */
				 ,"Reciprocal"    	   /* SCALE_REC    */
				 ,"Logit"         	   /* SCALE_LOGIT  */
				 ,"Degrees"                /* SCALE_DEGREES */
				 );
    gg_frame_connect (ge_axis_apply_CB);

    ta 	     	= gg_frame (w_tab_main ,"Tick properties"       ,&wheat ,2 ,2);
    tmajor.w 	= gg_entry_new    	(ta ,"Major spacing:", 8);
    nminor.w 	= gg_spin_new   	(ta ,"Minor ticks:", 0.0 ,(double) MAX_TICKS - 1, 1.0);
    tl_format.w = gg_format_new 	(ta ,"Format:");
    tl_prec.w 	= gg_spin_new   	(ta ,"Precision:" ,0.0 ,16.0 ,1.0);

    ta 		 = gg_frame 	(w_tab_main ,"Axis placement"   ,&wheat ,2 ,2);
    zero.w 	 = gg_check_new (ta 	    ,"Zero axis");
    w_blank      = gg_label_new (ta 	    ,NULL);
    offsx.w      = gg_entry_new (ta 	    ,"Offsets :   Normal:" ,6);
    offsy.w      = gg_entry_new (ta 	    ,"Opposite:"           ,6);

    rc 		 = gg_frame 	(w_tab_main ,"Tick label properties" ,&bleuciel ,0 ,1);
    tl_font.w    = gg_font_new  (rc 	    ,"Font:");
    tl_color.w   = gg_color_new (rc 	    ,"Color:");


    /* ------------ create Axis Label & Bar tab -------------- */

    w_tab_axis_label = gg_CreateTabPage (w_notebook ,"Axis");

    ta 		     = gg_frame        (w_tab_axis_label ,"Axis bar properties" ,&wheat ,2 ,2);
    t_drawbarcolor.w = gg_color_new    (ta ,"Color:");
    t_drawbarlinew.w = gg_spin_new     (ta ,"Width:" ,0.0 ,MAX_LINEWIDTH ,0.5);
    t_drawbarlines.w = gg_lines_new    (ta ,"Line style:");

    ta 		     = gg_frame        (w_tab_axis_label ,"Axis label properties" ,&bleuciel ,0 ,1);
    label_font.w     = gg_font_new     (ta ,"Font:");
    label_color.w    = gg_color_new    (ta ,"Color:");
    label_charsize.w = gg_charsize_new (ta ,"Char size");
    label_layout.w   = gg_combo_new    (ta ,"Layout:" ,3
					,"Parallel to axis"
					,"Perpendicular to axis");
    label_op.w       = gg_combo_new    (ta ,"Side:" ,4
					,"Normal"
					,"Opposite"
					,"Both");
    label_place.w    = gg_combo_new    (ta ,"Location" ,3
					,"Auto"                      /* TYPE_AUTO */
					,"Specified");               /* TYPE_SPEC */
    label_x1.w 	     = gg_entry_new    (ta ,"Parallel offset:"      ,7);
    label_y1.w 	     = gg_entry_new    (ta ,"Perpendicular offset:" ,7);

    /* ------------ create Ticks Label tab -------------- */

    w_tab_ticks_label = gg_CreateTabPage (w_notebook ,"Tick labels");

    rc 		  = gg_frame 	    (w_tab_ticks_label ,"Labels"   ,&wheat ,1 ,0);
    tl_charsize.w = gg_charsize_new (rc ,"Char size");
    tl_angle.w    = gg_angle_new    (rc ,"Angle");

    ta 		  = gg_frame 	    (w_tab_ticks_label ,"Placement"   ,&bleuciel ,2 ,3);
    tl_op.w       = gg_combo_new    (ta ,"Side:" ,4
				     ,"Normal"
				     ,"Opposite"
				     ,"Both");
    tl_staggered.w = gg_combo_new   (ta ,"Stagger:" ,11
				     ,"0" ,"1" ,"2" ,"3" ,"4" ,"5" ,"6" ,"7" ,"8" ,"9");
    tl_starttype.w = gg_combo_new   (ta ,"Start at:" ,3
				     ,"Axis min" ,"Specified:");
    tl_start       = gg_entry_new   (ta ,"" ,8);
    tl_stoptype.w  = gg_combo_new   (ta ,"Stop  at:" ,3
				     ,"Axis max" ,"Specified:");
    tl_stop        = gg_entry_new   (ta ,"" ,8);

    ta 		   = gg_frame 	    (w_tab_ticks_label ,"Extra"   ,&wheat ,0 ,1);
    tl_skip.w      = gg_combo_new   (ta ,"Skip every:" ,11
				     ,"0" ,"1" ,"2" ,"3" ,"4" ,"5" ,"6" ,"7" ,"8" ,"9");
    tl_formula.w   = gg_entry_new   (ta ,"Axis transform:" ,20);
    tl_prestr.w    = gg_string_new  (ta ,"Prepend:" ,13);
    tl_appstr.w    = gg_string_new  (ta ,"Append:"  ,13);
    tl_gaptype.w   = gg_combo_new   (ta ,"Location:" ,3
				     ,"Auto"                 /* TYPE_AUTO */
				     ,"Specified");          /* TYPE_SPEC */
    tl_gap_para.w  = gg_entry_new   (ta ,"Parallel offset:" ,7);
    tl_gap_perp.w  = gg_entry_new   (ta ,"Perpendicular offset:" ,7);

    /* ------------ create Ticks Marks tab -------------- */

    w_tab_ticks_marks = gg_CreateTabPage (w_notebook ,"Tick marks");

    ta 	      	= gg_frame     (w_tab_ticks_marks ,"Placement"   ,&bleuciel ,0  ,1);
    t_inout.w 	= gg_combo_new (ta ,"Pointing:" ,4
				,"In" ,"Out" ,"Both");
    t_round.w   = gg_check_new (ta ,"Place at rounded positions");
    t_autonum.w = gg_combo_new (ta ,"Autotick divisions" ,12
				,"2" ,"3" ,"4" ,"5" ,"6" ,"7" ,"8" ,"9" ,"10" ,"11" ,"12");

    rc2 	      = gg_CreateHContainer (w_tab_ticks_marks);
    rc 		      = gg_frame 	 (rc2 ,"Major ticks"   ,&wheat ,0 ,1);
    props_gridflag.w  = gg_check_new     (rc ,"Draw grid lines");
    props_size.w      = gg_charsize_new  (rc ,"Tick length");
    props_color.w     = gg_color_new     (rc ,"Color:");
    props_linew.w     = gg_spin_new 	 (rc ,"Line width:" ,0.0 ,MAX_LINEWIDTH ,0.5);
    props_lines.w     = gg_lines_new 	 (rc ,"Line style:");
    rc 		      = gg_frame 	 (rc2 ,"Minor ticks"   ,&wheat ,0 ,1);
    mprops_gridflag.w = gg_check_new     (rc ,"Draw grid lines");
    mprops_size.w     = gg_charsize_new  (rc ,"Tick length");
    mprops_color.w    = gg_color_new     (rc ,"Color:");
    mprops_linew.w    = gg_spin_new 	 (rc ,"Line width:" ,0.0 ,MAX_LINEWIDTH ,0.5);
    mprops_lines.w    = gg_lines_new 	 (rc ,"Line style:");

    /* ------------ create Special tab -------------- */
    gg_frame_connect (NULL);                  /* special callbacks for this tab */
    w_tab_special = gg_CreateTabPage (w_notebook ,"Special");
    rc 		  = gg_CreateVContainer (w_tab_special);
    t_spec.w   	  = gg_combo_new  (rc ,"Special ticks:" ,4
				   ,"None"                     		 /* TICKS_SPEC_NONE  */
				   ,"Tick marks"               		 /* TICKS_SPEC_MARKS */
				   ,"Tick marks and labels");  		 /* TICKS_SPEC_BOTH  */
    rc2 	   = gg_CreateHContainer (rc);
    nticks.w       = gg_spin_new  (rc2 ,"Nb:" ,0.0 ,(double)MAX_TICKS ,1.0);
    w_hide_minor   = gg_check_new (rc2 ,"hide minor ticks");
    gg_frame_connect (ge_axis_apply_CB);

    rc2 = gg_CreateHContainer (rc);
    gg_label_new (rc2 ,"Major" );
    gg_label_new (rc2 ,"Tick location");
    gg_label_new (rc2 ,"Tick Label:");
    gtk_box_set_homogeneous (GTK_BOX (rc2) ,TRUE);

    sw = gtk_scrolled_window_new (NULL,NULL);
    gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW(sw)
 				     ,GTK_POLICY_AUTOMATIC
 				     ,GTK_POLICY_AUTOMATIC);
    gtk_widget_set_size_request (GTK_WIDGET (sw) ,specticks_width ,specticks_height);
    w_specrc = gtk_vbox_new (FALSE ,2);
    cur_max_ticks = 0;
    for (i = 0; i < MAX_TICKS; i++) wspec[i].box = NULL;
    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(sw) ,w_specrc);
    gtk_widget_show (sw);
    gtk_box_pack_start (GTK_BOX (rc) ,sw ,FALSE ,FALSE  ,1);

    /* --------------- create Bottom widgets  ------------------ */
    gg_frame_connect (ge_axis_apply_CB);
    rc 		= gg_frame (vbox, "Display options" ,&wheat ,2 ,2);
    tl_flag.w  	= gg_check_new (rc, "Display tick labels");
    t_drawbar.w = gg_check_new (rc, "Display axis bar");
    t_flag.w   	= gg_check_new (rc, "Display tick marks");
    t_op.w    	= gg_combo_new (rc ,"Draw on:" ,4
				,"Normal side"
				,"Opposite side"
				,"Both sides");

    rc = gg_CreateHContainer (vbox);
    axis_applyto.w = gg_combo_new (rc ,"Apply to:" ,5
					 ,"Current axis"
					 ,"All axes ,current graph"
					 ,"Current axis ,all graphs"
					 ,"All axes ,all graphs");
    axis_hidden.w  = gg_check_new (rc ,"Hide");

    /* ---------------- Connect handlers ---------------- */
    g_signal_connect (axis_edit.w      ,"changed" ,G_CALLBACK (ge_axis_set_CB)        ,NULL);
    g_signal_connect (axis_scale.w     ,"changed" ,G_CALLBACK (ge_axis_scale_CB)      ,NULL);
    g_signal_connect (label_place.w    ,"changed" ,G_CALLBACK (ge_axislabelplace_CB)  ,NULL);
    g_signal_connect (tl_gaptype.w     ,"changed" ,G_CALLBACK (ge_tickslabelplace_CB) ,NULL);
    g_signal_connect (t_spec.w         ,"changed" ,G_CALLBACK (ge_axis_t_spec_CB)     ,NULL);
    g_signal_connect (nticks.w   ,"value-changed" ,G_CALLBACK (ge_axis_nticks_CB)     ,NULL);
    g_signal_connect (w_hide_minor     ,"toggled" ,G_CALLBACK (ge_axis_hide_minor_CB) ,NULL);
    menu_finalized = TRUE;
    gg_frame_connect (NULL);
    block_instant_update = FALSE;
  }

  /* --------------------------------------- */
  gtk_widget_show_all (vbox);
  ge_axis_update (cg ,curaxis);
  ge_expand_graph_or_obj (Q_Graph ,cg);

  handler_id = g_signal_connect (w_notebook ,"switch-page" ,G_CALLBACK (ge_axis_store_page_CB) ,NULL);
  current_page = 0;
  gg_unset_wait_cursor();
  return vbox;
}


/* ------------ U P D A T E S  ------------ */

/* ------------ update all tabs -------------- */
/**
 *  Updates axes rpane menu
 *  axisno < 0 : 
 */
void ge_axis_update (int gno ,int axisno)
{
  tickmarks *t;
  world w;
  char buf[128];
  int axe_active ,axe_hidden;
  double ax_start ,ax_stop ,ax_tmajor;
  int i ,num;

  if (axisno >= 0 && axisno < MAXAXES) {
    curaxis = axisno;
  }

  if (titre_item != NULL) {
    if (axisno < 0 || axisno >= MAXAXES) {
      if (ge_rpane_get_type () != Q_Axis)   return;
      if (curaxis < 0 || curaxis >= MAXAXES) return;
      axisno = curaxis;
    }

    t = get_graph_tickmarks (gno, curaxis);
    if (!t) return;
    ax_tmajor = t->tmajor;
    block_instant_update = TRUE;

    sprintf (buf ,"    Graph %d " ,gno);
    gtk_label_set_text (GTK_LABEL (titre_item) ,buf);

    /* --------------------------------------- */
    axe_active = is_axis_active (gno, curaxis);
    axe_hidden = (axe_active == TRUE) ? FALSE : TRUE ;
    gg_set_int (axis_hidden.w ,axe_hidden);
    gtk_widget_set_sensitive (w_notebook ,axe_active);

    gg_set_int (axis_edit.w, curaxis);

    num = obj_tid_get_num (Q_Axis ,axisno ,Q_Graph ,gno);
    gg_set_int (layer.w ,objs[num].layer);

    get_graph_world (gno, &w);
    if (is_xaxis (curaxis)) {
      if (get_graph_xscale (gno) == SCALE_DEGREES) {
	ax_start  = w.xg1 * 180.0 / M_PI;
	ax_stop   = w.xg2 * 180.0 / M_PI;
	ax_tmajor *= 180.0 / M_PI;
      } else {
	ax_start = w.xg1;
	ax_stop  = w.xg2;
      }
      gg_setstr_2d (axis_world_start.w ,axis_world_stop.w ,ax_start ,ax_stop);
      gg_set_int   (axis_scale.w       ,get_graph_xscale (gno));
      gg_set_int   (axis_invert.w      ,is_graph_xinvert (gno));
    } else {
      ax_start = w.yg1;
      ax_stop  = w.yg2;
      gg_setstr_2d (axis_world_start.w ,axis_world_stop.w ,ax_start ,ax_stop);
      gg_set_int   (axis_scale.w       ,get_graph_yscale (gno));
      gg_set_int   (axis_invert.w      ,is_graph_yinvert (gno));
    }

    /* ------------ update Main tab -------------- */
    ge_label_update_current (t->label.s);

    if (is_log_axis(gno, curaxis)) {
      if (ax_tmajor <= 1.0) {
 	t->tmajor = 10.0;
      }
      sprintf(buf, "%g", t->tmajor);
    } else if (is_logit_axis(gno, curaxis)) {
      if (ax_tmajor <= 0.0) {
 	t->tmajor = 0.1;
      }
      else if (ax_tmajor >= 0.5) {
 	t->tmajor = 0.4;
      }
      sprintf(buf, "%g", t->tmajor);
    } else if (ax_tmajor > 0) {
      sprintf(buf, "%g", ax_tmajor);
    } else {
      strcpy(buf, "UNDEFINED");
    }
    gg_setstr  	(tmajor.w        ,buf);
    gg_set_int 	(nminor.w        ,t->nminor);
    gg_set_int 	(tl_format.w     ,t->tl_format);
    gg_set_int  (tl_prec.w       ,t->tl_prec);
    gg_set_int 	(tl_flag.w       ,t->tl_flag);
    gg_set_int 	(t_drawbar.w     ,t->t_drawbar);
    gg_set_int 	(t_flag.w        ,t->t_flag);
    gg_set_int 	(zero.w    	 ,is_zero_axis (gno, curaxis));
    gg_setstr_d (offsx.w ,"%.4f" ,t->offsx ,buf);
    gg_setstr_d (offsy.w ,"%.4f" ,t->offsy ,buf);
    gg_set_int  (tl_font.w       ,t->tl_font);
    gg_set_int  (tl_color.w      ,t->tl_color);

    /* ------------ update Axis Label tab -------------- */
    gg_set_int  (label_font.w       ,t->label.font);
    gg_set_int  (label_color.w      ,t->label.color);
    gg_set_dble (label_charsize.w   ,t->label.charsize);
    gg_set_int  (label_layout.w     ,t->label_layout == LAYOUT_PERPENDICULAR ? 1 : 0);
    gg_set_int  (label_op.w         ,t->label_op);
    gg_set_int  (label_place.w      ,t->label_place);
    gg_setstr_d (label_x1.w,"%.4f"  ,t->label.x1  ,buf);
    gg_setstr_d (label_y1.w,"%.4f"  ,t->label.y1  ,buf);
    gg_set_int  (t_drawbarcolor.w   ,t->t_drawbarcolor);
    gg_set_dble (t_drawbarlinew.w   ,t->t_drawbarlinew);
    gg_set_int  (t_drawbarlines.w   ,t->t_drawbarlines);

    gtk_widget_set_sensitive (label_x1.w     ,t->label_place == TYPE_SPEC);
    gtk_widget_set_sensitive (label_y1.w     ,t->label_place == TYPE_SPEC);

    /* ------------ update Ticks Label tab -------------- */
    gg_set_dble (tl_charsize.w    ,t->tl_charsize);
    gg_set_int  (tl_angle.w       ,t->tl_angle);
    gg_set_int  (tl_op.w          ,t->tl_op);
    gg_set_int  (tl_staggered.w   ,t->tl_staggered);
    gg_set_int  (tl_starttype.w   ,t->tl_starttype == TYPE_SPEC);
    if (t->tl_starttype == TYPE_SPEC) {
      gg_setstr_d (tl_start ,"%f" ,t->tl_start ,buf);
    }
    gg_set_int (tl_stoptype.w    ,t->tl_stoptype == TYPE_SPEC);
    if (t->tl_stoptype == TYPE_SPEC) {
      gg_setstr_d (tl_stop  ,"%f" ,t->tl_stop  ,buf);
    }
    gg_set_int  (tl_skip.w          ,t->tl_skip);
    gg_setstr   (tl_formula.w       ,t->tl_formula);
    gg_setstr  	(tl_prestr.w        ,t->tl_prestr);
    gg_setstr  	(tl_appstr.w        ,t->tl_appstr);
    gg_set_int  (tl_gaptype.w       ,t->tl_gaptype);

    if (get_graph_type (cg) == GRAPH_POLAR) {
      gg_setstr_d (tl_gap_para.w ,"%.4f" ,t->tl_gap.y  ,buf);
      gg_setstr_d (tl_gap_perp.w ,"%.4f" ,t->tl_gap.x  ,buf);
    } else {
      gg_setstr_d (tl_gap_para.w ,"%.4f" ,t->tl_gap.x  ,buf);
      gg_setstr_d (tl_gap_perp.w ,"%.4f" ,t->tl_gap.y  ,buf);
    }
    gtk_widget_set_sensitive (tl_gap_para.w ,t->tl_gaptype == TYPE_SPEC);
    gtk_widget_set_sensitive (tl_gap_perp.w ,t->tl_gaptype == TYPE_SPEC);

    /* ------------ update Ticks Marks tab -------------- */
    switch (t->t_inout) {
    case TICKS_IN:
      gg_set_int (t_inout.w ,0);
      break;
    case TICKS_OUT:
      gg_set_int (t_inout.w ,1);
      break;
    case TICKS_BOTH:
      gg_set_int (t_inout.w ,2);
      break;
    }
    gg_set_int  (t_op.w      	   ,t->t_op);
    gg_set_int  (t_round.w        ,t->t_round);
    gg_set_int  (t_autonum.w      ,t->t_autonum - 2);

    gg_set_int  (props_gridflag.w ,t->props.gridflag);
    gg_set_dble (props_size.w     ,t->props.size);
    gg_set_int  (props_color.w    ,t->props.color);
    gg_set_dble (props_linew.w    ,t->props.linew);
    gg_set_int  (props_lines.w    ,t->props.lines);

    gg_set_int  (mprops_gridflag.w ,t->mprops.gridflag);
    gg_set_dble (mprops_size.w     ,t->mprops.size);
    gg_set_int  (mprops_color.w    ,t->mprops.color);
    gg_set_dble (mprops_linew.w    ,t->mprops.linew);
    gg_set_int  (mprops_lines.w    ,t->mprops.lines);

    /* ------------ update Special tab -------------- */
    gg_set_int (t_spec.w     ,t->t_spec);
    gg_set_int (w_hide_minor ,hide_minor);
  
    if (t->t_spec == TICKS_SPEC_NONE) {     /* don't show any tick */
      gg_set_int (nticks.w ,0);
      ge_axis_spec_ticks_max (w_specrc ,0);
    } else {
      if (ge_axis_spec_ticks_max (w_specrc ,t->nticks)) {
	gg_set_int (nticks.w ,t->nticks);
	for (i = 0; i < t->nticks; i++) {
	  gg_setstr_d (wspec[i].loc ,"%.9g" ,t->tloc[i].wtpos ,buf);
	  if (t->tloc[i].type == TICK_TYPE_MAJOR) {
	    gg_setstr (wspec[i].label       ,t->tloc[i].label);
 	    gg_set_int (wspec[i].major ,TRUE);
 
	  } else {
	    gg_setstr (wspec[i].label       ,"");
 	    gg_set_int (wspec[i].major ,FALSE);
 
	  }
	}
      }
    }
    obj_tid_make_current (Q_Axis ,curaxis ,Q_Graph ,cg);
    ge_tree_need_update  (!ge_select_current ());
    block_instant_update = FALSE;
  }
}

/* ------------ A P P L Y  ------------ */

/**
 *  ge_axis_apply_to : read rpane and apply changes to "t"
 */
static int ge_axis_apply_to (int gno ,int axisno ,tickmarks *t)
{
  int i;
  const char *cp;
  int axe_hidden  = gg_get_int (axis_hidden.w);
  t->active 	  = (axe_hidden == TRUE) ? FALSE : TRUE;
  int num 	  = obj_tid_get_num (Q_Axis ,axisno ,Q_Graph ,gno);
  objs[num].layer = gg_get_int (layer.w);
  gg_update_layers_hbox ();

  /* ------------ apply_to Main tab -------------- */
  if (gg_evalexpr (tmajor.w, &(t->tmajor)) != RETURN_SUCCESS) {
    errmsg( "Specify major tick spacing" );
    free_graph_tickmarks (t);
    return RETURN_FAILURE;
  }
  set_plotstr_string (&(t->label) ,get_current_label ());

  t->nminor    = gg_get_int (nminor.w);
  t->tl_format = gg_get_int (tl_format.w);
  t->tl_prec   = gg_get_int (tl_prec.w);
  strncpy      (t->tl_prestr, gg_getstr(tl_prestr.w) ,63);
  t->zero      = gg_get_int (zero.w);
  gg_evalexpr  (offsx.w, &(t->offsx));
  gg_evalexpr  (offsy.w, &(t->offsy));
  t->tl_font   = gg_get_int (tl_font.w);
  t->tl_color  = gg_get_int (tl_color.w);

  /* ------------ apply_to Axis Label tab -------------- */
  t->label.font     = gg_get_int           (label_font.w);
  t->label.color    = gg_get_int           (label_color.w);
  t->label.charsize = gg_get_dble (label_charsize.w);
  t->label_layout   = gg_get_int           (label_layout.w) ? LAYOUT_PERPENDICULAR : LAYOUT_PARALLEL;
  /* somehow the value of label_op.w gets automagically correctly
     applied to all selected axes without checking for the value of
     applyto directly here (strange...) */
  t->label_op       = gg_get_int           (label_op.w);
  t->label_place    = gg_get_int           (label_place.w);
  if (t->label_place == TYPE_SPEC) {
    gg_evalexpr (label_x1.w, &(t->label.x1));
    gg_evalexpr (label_y1.w, &(t->label.y1));
  }
  t->t_drawbarcolor = gg_get_int  	   (t_drawbarcolor.w);
  t->t_drawbarlinew = gg_get_dble 	   (t_drawbarlinew.w);
  t->t_drawbarlines = gg_get_int  	   (t_drawbarlines.w);

  /* ------------ apply_to Ticks Label tab -------------- */
  t->tl_charsize    = gg_get_dble (tl_charsize.w);
  t->tl_angle       = gg_get_int           (tl_angle.w);
  t->tl_op          = gg_get_int           (tl_op.w);
  t->tl_staggered   = gg_get_int           (tl_staggered.w);
  t->tl_starttype   = gg_get_int           (tl_starttype.w) == 0 ? TYPE_AUTO : TYPE_SPEC;
  if (t->tl_starttype == TYPE_SPEC) {
    if (gg_evalexpr (tl_start ,&(t->tl_start)) != RETURN_SUCCESS) {
      errmsg( "Specify tick label start" );
      free_graph_tickmarks (t);
      return RETURN_FAILURE;
    }
  }
  t->tl_stoptype    = gg_get_int           (tl_stoptype.w) == 0 ? TYPE_AUTO : TYPE_SPEC;
  if (t->tl_stoptype == TYPE_SPEC) {
    if (gg_evalexpr (tl_stop ,&(t->tl_stop)) != RETURN_SUCCESS){
      errmsg( "Specify tick label stop" );
      free_graph_tickmarks(t);
      return RETURN_FAILURE;
    }
  }
  t->tl_skip    = gg_get_int (tl_skip.w);
  t->tl_formula = copy_string (NULL,  gg_getstr(tl_formula.w));
  strncpy 	(t->tl_prestr, gg_getstr (tl_prestr.w) ,63);
  strncpy 	(t->tl_appstr, gg_getstr (tl_appstr.w) ,63);
  t->tl_gaptype = gg_get_int (tl_gaptype.w);
  if (t->tl_gaptype == TYPE_SPEC) {
    if (get_graph_type (gno) == GRAPH_POLAR) {
      gg_evalexpr (tl_gap_para.w, &t->tl_gap.y);
      gg_evalexpr (tl_gap_perp.w, &t->tl_gap.x);
    } else {
      gg_evalexpr (tl_gap_para.w, &t->tl_gap.x);
      gg_evalexpr (tl_gap_perp.w, &t->tl_gap.y);
    }
  }

  /* ------------ apply_to Ticks Marks tab -------------- */
  switch (gg_get_int (t_inout.w)) {
  case 0:
    t->t_inout = TICKS_IN;
    break;
  case 1:
    t->t_inout = TICKS_OUT;
    break;
  case 2:
    t->t_inout = TICKS_BOTH;
    break;
  }
  t->t_op           = gg_get_int  (t_op.w);
  t->t_round        = gg_get_int  (t_round.w);
  t->t_autonum      = gg_get_int  (t_autonum.w) + 2;

  t->props.gridflag = gg_get_int  (props_gridflag.w);
  t->props.size     = gg_get_dble (props_size.w);
  t->props.color    = gg_get_int  (props_color.w);
  t->props.linew    = gg_get_dble (props_linew.w);
  t->props.lines    = gg_get_int  (props_lines.w);

  t->mprops.gridflag= gg_get_int  (mprops_gridflag.w);
  t->mprops.size    = gg_get_dble (mprops_size.w);
  t->mprops.color   = gg_get_int  (mprops_color.w);
  t->mprops.linew   = gg_get_dble (mprops_linew.w);
  t->mprops.lines   = gg_get_int  (mprops_lines.w);


  /* --------------- Bottom widgets  ------------------ */
  t->tl_flag   = gg_get_int (tl_flag.w);
  t->t_drawbar = gg_get_int (t_drawbar.w);
  t->t_flag    = gg_get_int (t_flag.w);

  /* ------------ apply_to Special tab -------------- */
  t->t_spec         = gg_get_int (t_spec.w);
  if (t->t_spec == TICKS_SPEC_NONE) {
    /* don't display ticks info */
    ge_axis_spec_ticks_max (w_specrc ,0);
  } else { 
    if (ge_axis_spec_ticks_max (w_specrc ,t->nticks)) {
      /* ensure that enough tick positions have been specified */
      for (i = 0; i < t->nticks; i++) {
	t->nticks = gg_get_int (nticks.w);
	if (gg_evalexpr (wspec[i].loc, &(t->tloc[i].wtpos)) == RETURN_SUCCESS) {
	  cp = gg_getstr (wspec[i].label);
	  if (cp[0] == '\0') {
	    t->tloc[i].type = TICK_TYPE_MINOR;
	  } else {
	    t->tloc[i].type = TICK_TYPE_MAJOR;
	  }
	  if (t->t_spec == TICKS_SPEC_BOTH) {
	    t->tloc[i].label = copy_string (t->tloc[i].label, cp);
	  } else {
	    t->tloc[i].label = copy_string (t->tloc[i].label, NULL);
	  }
	} else {
	  errmsg("Not enough tick locations specified");  /* should never happen */
	  free_graph_tickmarks(t);
	  return RETURN_FAILURE;
	}
      }
    } else {
      return RETURN_FAILURE;
    }
  }
  return RETURN_SUCCESS;
}

/**
 *  ge_axis_apply : called by ge_axis_apply_CB() or by
 *                  ge_rpane_apply(), i.e. "Apply" button is clicked
 */
void ge_axis_apply (int gno ,int axisno)
{
  tickmarks *t ,*old ,*old1;
  QDobject oobj ,oobj1;
  int applyto = gg_get_int (axis_applyto.w);
  int axis_start, axis_stop, graph_start, graph_stop;
  int i, j ,num;
  int scale, invert;
  double axestart, axestop;
  world w ,w_old ,w_old1;
  block_instant_update = TRUE;
  t = copy_graph_tickmarks (get_graph_tickmarks (gno ,axisno));
  if (!t) return;
  if (get_graph_type (gno) == GRAPH_POLAR && is_xaxis (axisno)) {
    fswap (&t->tl_gap.x ,&t->tl_gap.y);
  }

  /* undo/redo and follow_me_on */
  old = copy_graph_tickmarks (get_graph_tickmarks (gno ,axisno));
  num = obj_tid_get_num (Q_Axis ,axisno ,Q_Graph ,gno);
  oobj = objs[num];

  if (ge_axis_apply_to (gno ,axisno ,t) == RETURN_FAILURE) return;

  /*------ choose the graphs to apply --------------*/
  // A REVOIR
  switch (applyto) {
  case 0:                     /* current axis */
    axis_start = axisno;
    axis_stop  = axisno;
    graph_start = gno;
    graph_stop  = gno;
    break;
  case 1:                     /* all axes, current graph */
    // Change aussi les "altaxis" : A REVOIR
    axis_start = 0;
    axis_stop  = MAXAXES - 1;
    graph_start = gno;
    graph_stop  = gno;
    break;
  case 2:                     /* current axis, all graphs */
    axis_start = axisno;
    axis_stop  = axisno;
    graph_start = 0;
    graph_stop  = number_of_graphs() - 1;
    break;
  case 3:                     /* all axes, all graphs */
    axis_start = 0;
    axis_stop  = MAXAXES - 1;
    graph_start = 0;
    graph_stop  = number_of_graphs() - 1;
    break;
  default:
    axis_start = axisno;
    axis_stop  = axisno;
    graph_start = gno;
    graph_stop  = gno;
    break;
  }

  if (gg_evalexpr (axis_world_start.w, &axestart) != RETURN_SUCCESS ||
      gg_evalexpr (axis_world_stop.w,  &axestop)  != RETURN_SUCCESS) {
    errmsg ("Axis start/stop values undefined");
    free_graph_tickmarks (t);
    return;
  }

  /*  Apply "t" to graphs */
  for (i = graph_start; i <= graph_stop; i++) {
    for (j = axis_start; j <= axis_stop; j++) {
      scale = gg_get_int (axis_scale.w);
      if (is_xaxis(j)) {
	set_graph_xscale(i, scale);
      } else {
	set_graph_yscale(i, scale);
      }
      get_graph_world (i, &w);
      get_graph_world (i, &w_old);
      get_graph_world (i, &w_old1);
      if (is_xaxis(j)) {
	if (scale == SCALE_DEGREES) {
	  w.xg1      = axestart * M_PI / 180.0;
	  w.xg2      = axestop  * M_PI / 180.0;
	  t->tmajor *= M_PI / 180.0;
	} else {
	  w.xg1 = axestart;
	  w.xg2 = axestop;
	}
      } else {
	w.yg1 = axestart;
	w.yg2 = axestop;
      }
      set_graph_world (i, w);

      invert = gg_get_int (axis_invert.w);
      if (is_xaxis(j)) {
	set_graph_xinvert(i, invert);
      } else {
	set_graph_yinvert(i, invert);
      }

      /* This change all the parameters and is not a good thing */
      set_graph_tickmarks (i, j, t);

      if (scale == SCALE_DEGREES)  t->tmajor *= 180.0 / M_PI;

      /* undo/redo and follow_me_on */
      old1  = copy_graph_tickmarks (old);
      oobj1 = oobj;
      nn_cmd_axis (i ,j ,old ,&w_old ,&oobj ,FALSE ,TRUE); /* nn_cmd_axis change old, w_old */
      old   = copy_graph_tickmarks (old1);
      w_old = w_old1;
      oobj  = oobj1;
      xfree (old1);
    }
  }
  free_graph_tickmarks(t);
  gtk_widget_set_sensitive (w_notebook ,is_axis_active (cg, curaxis));
  ge_hidden_update (Q_Axis ,curaxis ,Q_Graph ,cg ,!is_axis_active (cg, curaxis));
  gg_drawgraph();

  free (old);
  current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (w_notebook));
  block_instant_update = FALSE;
}


void ge_axis_set_page (void)
{
  gtk_notebook_set_current_page (GTK_NOTEBOOK (w_notebook) ,current_page);
}


/**************** C A L L B A C K S ****************/


void ge_axis_apply_CB  (GtkWidget *w ,gpointer p)
{
  int i;
  int gno    = get_cg ();
  int axisno = cur_obj_id;
  if (instant_update && menu_finalized && 
      block_instant_update == FALSE && is_valid_axis (gno ,axisno)) {
    ge_axis_apply (gno ,axisno);
    i = obj_tid_get_num (Q_Axis ,axisno ,Q_Graph ,gno);
    ge_update_explorer ();
    obj_make_current   (i);
    ge_expand_current  ();
    ge_select_current  ();
  }
}

/**
 * This CB services the axis "Scale" selector
 */
static void ge_axis_scale_CB (GtkWidget *w ,gpointer p)
{
  double major_space, axestart, axestop;
  int auton;
  char buf[32];
  int scale ,old_scale;
  if (titre_item == NULL)   return;
  if (block_instant_update) return;

  int gno =  get_cg (); // cg  provisoire : faut-il balayer les graphs select ?
  old_scale = is_xaxis (curaxis) ? get_graph_xscale (gno) : get_graph_yscale (gno);
  scale = gg_get_int (w);
  if (get_graph_type (gno) == GRAPH_POLAR && is_yaxis (curaxis) && scale != SCALE_NORMAL) {
    errmsg ("Only linear rho scale is supported in Polar plots");
    goto erreur;
  }
  gg_evalexpr (tmajor.w, &major_space);
  gg_evalexpr (axis_world_start.w, &axestart) ;
  gg_evalexpr (axis_world_stop.w,  &axestop);
  auton = gg_get_int (t_autonum.w) + 2;
  switch (scale) {
  case SCALE_NORMAL:
    if (old_scale == SCALE_DEGREES) {    /* return to radians */
       axestart    *= M_PI / 180.0;
       axestop     *= M_PI / 180.0;
       major_space *= M_PI / 180.0;
       gg_setstr_2d (axis_world_start.w ,axis_world_stop.w ,axestart ,axestop);
       gg_setstr_d (tmajor.w ,"%g" ,major_space ,buf);
    }
    if (major_space <= 0.0) {
      gg_setstr_d (tmajor.w ,"%g" ,(axestop - axestart)/auton ,buf);
    }
    break;
  case SCALE_LOG:
    if (get_graph_type (gno) == GRAPH_POLAR) {
      errmsg ("no logarithmic scale for polar graphs");
      goto erreur;
    }
    if (axestart <= 0.0 && axestop <= 0.0) {
      errmsg ("Can't set logarithmic scale for negative coordinates");
      gtk_combo_box_set_active (GTK_COMBO_BOX (axis_scale.w) ,SCALE_NORMAL);
      return;
    } else if (axestart <= 0.0) {
      axestart = axestop/1.0e3;
      gg_setstr_d (axis_world_start.w ,"%g" ,axestart ,buf);
    }
    gg_setstr  (tmajor.w, "10");
    gg_set_int (nminor.w, 9);
    break;
  case SCALE_LOGIT:
    if (get_graph_type (gno) == GRAPH_POLAR) {
      errmsg ("no logit scale for polar graphs");
      goto erreur;
    }
    if (axestart <= 0.0 && axestop <= 0.0) {
      errmsg("Can't set logit scale for values outside 0 and 1");
      gtk_combo_box_set_active (GTK_COMBO_BOX (axis_scale.w) ,SCALE_NORMAL);
      return;
    }
    if (axestart <= 0.0) {
      axestart = 0.1;
      gg_setstr_d (axis_world_start.w ,"%g" ,axestart ,buf);
    }
    if (axestop >= 1.0) {
      axestop = 0.95;
      gg_setstr_d (axis_world_stop.w ,"%g" ,axestop ,buf);
    }
    if (major_space >= 1.0) {
      gg_setstr (tmajor.w, "0.6");
    }
    break;
   case SCALE_DEGREES:
     if (get_graph_type (gno) != GRAPH_POLAR || is_yaxis (curaxis)) {
       errmsg("Can use degrees only for phi axis in polar graphs");
       gg_set_int (w ,old_scale);
     } else {
       axestart    *= 180.0 / M_PI;
       axestop     *= 180.0 / M_PI;
       major_space *= 180.0 / M_PI;
       gg_setstr_2d (axis_world_start.w ,axis_world_stop.w ,axestart ,axestop);
       if (major_space <= 0.0) {
	 printf ("ge_axis_scale_CB : major_space <= 0.0 \n");
	 gg_setstr_d (tmajor.w ,"%g" ,(axestop - axestart)/auton ,buf);
       }
     }
     break;
   case SCALE_REC:
    if (get_graph_type (gno) == GRAPH_POLAR) {
      errmsg ("no reciprocal scale for polar graphs");
      goto erreur;
    }
  }
  if (is_xaxis (curaxis)) {
    set_graph_xscale (gno ,scale);
  } else {
    set_graph_yscale (gno ,scale);
  }
  gg_drawgraph();
  return;
 erreur:
  block_instant_update = TRUE;
  gg_set_int (axis_scale.w ,old_scale);
  block_instant_update = FALSE;
  return;
}

/**
 *  Callback for the axis_edit.w button to choose the axis edited
 */
static void ge_axis_set_CB  (GtkWidget *w ,gpointer p)
{
  int i;
  curaxis = gg_get_int (w);
  if (block_instant_update == FALSE) {
    /* if and alternate axis, set it visible */
    if (curaxis > 1) set_graph_axis_active (cg ,curaxis ,TRUE);
    ge_axis_update (cg ,curaxis);
    i = obj_tid_get_num (Q_Axis ,curaxis ,Q_Graph ,cg);
    ge_update_explorer ();
    obj_make_current   (i);
    ge_expand_current  ();
    ge_select_current  ();
  }
  ge_select_current ();
}

static void ge_axislabelplace_CB (GtkWidget *w ,gpointer p)
{
  if (w != NULL) {
    gboolean choice = gg_get_int (w);
    gtk_widget_set_sensitive (label_x1.w ,choice == TYPE_SPEC);
    gtk_widget_set_sensitive (label_y1.w ,choice == TYPE_SPEC);
  }
}

static void ge_tickslabelplace_CB (GtkWidget *w ,gpointer p)
{
  if (w != NULL) {
    gboolean choice = gg_get_int (w);
    gtk_widget_set_sensitive (tl_gap_para.w ,choice == TYPE_SPEC);
    gtk_widget_set_sensitive (tl_gap_perp.w ,choice == TYPE_SPEC);
  }
}


/* ------------ Special tab callbacks -------------- */
static int current_page_saved;            /* because ge_axis_apply can change current_page */

static void ge_axis_update_special (tickmarks *t)
{
  int i;
  if (hide_minor) {
    for (i = cur_max_ticks-1; i >= 0; i--) {
      if (t->tloc[i].type == TICK_TYPE_MINOR) gtk_widget_hide (wspec[i].box);
    }
  } else {
    for (i = 0; i < cur_max_ticks; i++) {
      gtk_widget_show_all (wspec[i].box);
    }
  }
}

/**
 * Called when you choose to use or not special ticks
 */
static void ge_axis_t_spec_CB (GtkWidget *w ,gpointer p)
{
  int old_t_spec;
  tickmarks *t;
  if (titre_item != NULL) {
    current_page_saved = current_page;
    t 	       = get_graph_tickmarks (cg, curaxis);
    old_t_spec = t->t_spec;
    t->t_spec  = gg_get_int (t_spec.w);      /* change special ticks switch of the current axis */
    ge_axis_update (cg ,curaxis);  	     /* updates other widgets */
    if (old_t_spec == TICKS_SPEC_NONE) ge_axis_update_special (t);
    ge_axis_apply  (cg ,curaxis);  	     /* apply the changes to all selected axes */
    current_page = current_page_saved;
  }
}

/**
 *  Called when a special tick is switched major/minor
 */
static void ge_axis_t_spec_major_CB (GtkWidget *w ,gpointer p)
{
  if (w != NULL) {
    int tmaj;
    tickmarks *t = get_graph_tickmarks (cg, curaxis);
    int i = GPOINTER_TO_INT (p);
    block_instant_update = TRUE;
    tmaj = gg_get_int (wspec[i].major) ? TICK_TYPE_MAJOR : TICK_TYPE_MINOR;
    t->tloc[i].type = tmaj;
    block_instant_update = FALSE;
  }
}

/**
 * Called when the number of special ticks is changed
 */
static void ge_axis_nticks_CB (GtkWidget *w ,gpointer p)
{
  int n;
  tickmarks *t;
  if (w != NULL) {
    current_page_saved = current_page;
    n = gg_get_int (nticks.w);
    if (ge_axis_spec_ticks_max (w_specrc ,n)) { /* update cur_max_ticks */
      t = get_graph_tickmarks (cg, curaxis);
      t->nticks = n;			     	/* change current axis */
      ge_axis_update (cg ,curaxis);  	     	/* updates other widgets */
      ge_axis_apply  (cg ,curaxis);  	     	/* apply the changes to all selected axes */
      current_page = current_page_saved;
    }
  }
}

/**
 * Called when you choose to hide/show minor special ticks
 */
static void ge_axis_hide_minor_CB (GtkWidget *w ,gpointer p)
{
  tickmarks *t;
  if (w != NULL) {
    hide_minor = gg_get_int (w);
    if (gg_get_int (t_spec.w) != TICKS_SPEC_NONE) {
      t = get_graph_tickmarks (cg, curaxis);
      ge_axis_update_special (t);
    }
  }
}

/************** COLLECTIVE and SELECTIVE UPDATE of AXES *******************/


/************** Menu3 for AXES *******************/

static GtkWidget *u_axis_dialog = NULL;

/**
 *  Called by ge_explorer_popup with CB = ge_axis_menu3_CB
 *  Compare to gg_CreateSetPopupEntries
 */
AxisMenu3Struct *ge_CreateAxisPopupEntries (AxisMenu3Struct *p ,GtkWidget *list
					  ,void (*CB) (GtkWidget *w ,gpointer p))
{
  GtkWidget *menu;
  if (p  == NULL) {
    p = xmalloc (sizeof (AxisMenu3Struct));
    menu = gtk_menu_new ();
    p->popup 	 = menu;
    p->hide  	 = gg_CreateMenuButton (menu ,"Hide"          ,'H'  ,list ,CB ,MenuHideCB);
    p->show  	 = gg_CreateMenuButton (menu ,"Show"          ,'S'  ,list ,CB ,MenuShowCB);
    p->update 	 = gg_CreateMenuButton (menu ,"Update axis"   ,' '  ,list ,CB ,MenuAxesUpdate);
    p->font_tool = gg_CreateMenuButton (menu ,"Use font tool" ,' '  ,list ,CB ,MenuUseFontTool);
  }
  return (p);
}

void ge_axis_popup_menu3 (AxisMenu3Struct *p)
{
  gtk_menu_popup (GTK_MENU(p->popup) ,NULL ,NULL ,NULL ,NULL ,3
		  ,gtk_get_current_event_time () );
}


void ge_axis_act (int action ,int num)
{
  tickmarks *t = get_graph_tickmarks (objs[num].father_id ,objs[num].id);
  if (!t) return;
  t->active = (action == MenuShowCB);
  ge_hidden_update (Q_Axis ,objs[num].id ,Q_Graph ,objs[num].father_id ,!(t->active));
  set_dirtystate ();
}

// gg_sets_menu3_CB
void ge_axis_menu3_CB (GtkWidget *w ,gpointer pact)
{
  Menu3action action  = GPOINTER_TO_INT (pact);
  int	      num ,axisno ,gno;
  tickmarks  *t;
  switch (action) {
  case MenuHideCB:
  case MenuShowCB:
    if (ge_selection_for_each (action ,ge_axis_act)) {
      gg_drawgraph();
    }
    break;
  case MenuAxesUpdate:
    ge_axes_u_new ();
    wu_update_on (TRUE);
    gtk_widget_show_all (u_axis_dialog);
    break;
  case MenuUseFontTool:
    num = ge_selection_get_num ();
    if (num >= 0) {
      axisno = objs[num].id;
      gno = get_cg ();
      t = get_graph_tickmarks (gno ,axisno);
      gg_fontwin_create (NULL ,t->label.s);
    }
    break;
  default:
    break;
  }
}

#define U_AXIS_RESET 1001

static GtkWidget *ge_axes_u_new (void)
{
  GtkWidget *vb ,*ta;
  if (u_axis_dialog == NULL) {
    u_axis_dialog = gg_CreateAACDialog ("Update axes" ,ge_axes_u_AAC_CB ,0 ,0 ,&vb);
    gtk_dialog_add_buttons (GTK_DIALOG (u_axis_dialog) ,"Reset" ,U_AXIS_RESET ,NULL);
    gg_label_new (vb ,"Choose items to update in the selected graphs");

    ta 	      	       = gg_frame     (vb ,"Axis layer"  	  ,&wheat ,4,1);
    layer.u            = gg_check_new (ta, "Layer");

    ta 		       = gg_frame     (vb ,"Axes scaling"  ,&wheat ,4 ,1);
    axis_world_start.u = gg_check_new (ta, "Start");
    axis_world_stop.u  = gg_check_new (ta, "Stop");
    axis_scale.u       = gg_check_new (ta ,"Scale");
    axis_invert.u      = gg_check_new (ta ,"Invert axis");

    ta 		       = gg_frame     (vb, "Display options" ,&bleuciel ,3 ,1);
    tl_flag.u  	       = gg_check_new (ta, "Tick labels");
    t_drawbar.u        = gg_check_new (ta, "Axis bar");
    t_flag.u   	       = gg_check_new (ta, "Tick marks");

    ta 		       = gg_frame     (vb ,"Axes placement"   ,&wheat ,4 ,1);
    zero.u 	       = gg_check_new (ta ,"Zero axis");
    gg_label_new (ta ,"Offsets: ");
    offsx.u            = gg_check_new (ta ,"Normal");
    offsy.u            = gg_check_new (ta ,"Opposite");

    ta 		       = gg_frame     (vb ,"Axes label properties" ,&bleuciel ,4 ,2);
    label_font.u       = gg_check_new (ta ,"Font");
    label_color.u      = gg_check_new (ta ,"Color");
    label_charsize.u   = gg_check_new (ta ,"Char size");
    label_layout.u     = gg_check_new (ta ,"Layout");
    label_op.u         = gg_check_new (ta ,"Side");
    label_place.u      = gg_check_new (ta ,"Location");
    label_x1.u 	       = gg_check_new (ta ,"Par. offset");
    label_y1.u 	       = gg_check_new (ta ,"Perp. offset");

    ta 		       = gg_frame     (vb ,"Bar properties" ,&wheat ,3 ,1);
    t_drawbarcolor.u   = gg_check_new (ta ,"Color");
    t_drawbarlinew.u   = gg_check_new (ta ,"Width");
    t_drawbarlines.u   = gg_check_new (ta ,"Line style");

    ta 	     	       = gg_frame     (vb ,"Tick properties" ,&bleuciel ,4 ,1);
    tmajor.u 	       = gg_check_new (ta ,"Major spacing");
    nminor.u 	       = gg_check_new (ta ,"Minor ticks");
    tl_format.u        = gg_check_new (ta ,"Format");
    tl_prec.u 	       = gg_check_new (ta ,"Precision");

    ta 	     	       = gg_frame     (vb ,"Tick labels" ,&wheat ,4 ,4);
    tl_font.u          = gg_check_new (ta ,"Font");
    tl_color.u         = gg_check_new (ta ,"Color");
    tl_charsize.u      = gg_check_new (ta ,"Char size");
    tl_angle.u         = gg_check_new (ta ,"Angle");
    tl_op.u            = gg_check_new (ta ,"Side");
    tl_staggered.u     = gg_check_new (ta ,"Stagger");
    tl_starttype.u     = gg_check_new (ta ,"Start");
    tl_stoptype.u      = gg_check_new (ta ,"Stop");
    tl_skip.u          = gg_check_new (ta ,"Skip");
    tl_formula.u       = gg_check_new (ta ,"Transform");
    tl_prestr.u        = gg_check_new (ta ,"Prepend");
    tl_appstr.u        = gg_check_new (ta ,"Append");
    tl_gaptype.u       = gg_check_new (ta ,"Location");
    tl_gap_para.u      = gg_check_new (ta ,"Par. offset");
    tl_gap_perp.u      = gg_check_new (ta ,"Perp. offset");

    ta 	     	       = gg_frame     (vb ,"Tick marks" ,&bleuciel ,4 ,4);
    t_inout.u 	       = gg_check_new (ta ,"In/out");
    t_op.u    	       = gg_check_new (ta ,"Side");
    t_round.u          = gg_check_new (ta ,"Round");
    t_autonum.u        = gg_check_new (ta ,"Divisions");

    ta 		       = gg_frame     (vb ,"Major ticks"   ,&bleuciel ,4 ,2);
    props_gridflag.u   = gg_check_new (ta ,"Draw grid");
    props_size.u       = gg_check_new (ta ,"Tick length");
    props_color.u      = gg_check_new (ta ,"Color");
    props_linew.u      = gg_check_new (ta ,"Line width");
    props_lines.u      = gg_check_new (ta ,"Line style");

    ta 		       = gg_frame     (vb ,"Minor ticks"   ,&bleuciel ,4 ,2);
    mprops_gridflag.u  = gg_check_new (ta ,"Draw grid");
    mprops_size.u      = gg_check_new (ta ,"Tick length");
    mprops_color.u     = gg_check_new (ta ,"Color");
    mprops_linew.u     = gg_check_new (ta ,"Line width");
    mprops_lines.u     = gg_check_new (ta ,"Line style");
  }
  gtk_widget_show_all (u_axis_dialog);
  return u_axis_dialog;
}

static int ge_axis_u_apply (tickmarks *t ,int gno ,int axisno)
{
  world w;
  int rok1 ,rok2;
  get_graph_world (gno, &w);

  /* ------------ Main tab -------------- */
  if (is_xaxis (axisno)) {
    if (wu_evalexpr (axis_world_start, &(w.xg1)) != RETURN_SUCCESS) {
      errmsg ("Error reading axis start value");
      return RETURN_FAILURE;
    }
    if (wu_evalexpr (axis_world_stop, &(w.xg2)) != RETURN_SUCCESS) {
      errmsg ("Error reading axis stop value");
      return RETURN_FAILURE;
    }
    if (gg_get_int (axis_invert.u)) {
      invert = gg_get_int (axis_invert.w);
      set_graph_xinvert (gno, invert);
    }
  } else {
    if (wu_evalexpr (axis_world_start, &(w.yg1)) != RETURN_SUCCESS) {
      errmsg ("Error reading axis start value");
      return RETURN_FAILURE;
    }
    if (wu_evalexpr (axis_world_stop, &(w.yg2)) != RETURN_SUCCESS) {
      errmsg ("Error reading axis stop value");
      return RETURN_FAILURE;
    }
    if (gg_get_int (axis_invert.u)) {
      invert = gg_get_int (axis_invert.w);
      set_graph_yinvert (gno, invert);
    }
  }
  set_graph_world (gno, w);
  // A FAIRE axis_scale voir ge_axis_update <<<<<<<<<<<<<<<<<<<<

  int num = obj_tid_get_num (Q_Axis ,axisno ,Q_Graph ,gno);
  wu_get_int (layer ,&objs[num].layer);

  if (wu_evalexpr (tmajor, &(t->tmajor)) != RETURN_SUCCESS) {
    errmsg( "Error reading major tick spacing" );
    return RETURN_FAILURE;
  }
  wu_get_int (nminor ,&(t->nminor));
  wu_get_int (tl_format ,&(t->tl_format));
  wu_get_int (tl_prec   ,&(t->tl_prec));
  if (gg_get_int (tl_prestr.u)) {
    strncpy (t->tl_prestr, gg_getstr(tl_prestr.w) ,63);
  }
  wu_get_int (tl_flag   ,&(t->tl_flag));
  wu_get_int (t_drawbar ,&(t->t_drawbar));
  wu_get_int (tl_font   ,&(t->tl_font));
  wu_get_int (tl_color  ,&(t->tl_color));
  if (wu_evalexpr (offsx, &(t->offsx)) == RETURN_FAILURE) {
    errmsg( "Error reading x offset" );
    return RETURN_FAILURE;
  }
  if (wu_evalexpr (offsy, &(t->offsy)) == RETURN_FAILURE) {
    errmsg( "Error reading y offset" );
    return RETURN_FAILURE;
  }

  /* ------------ Axis Label tab -------------- */
  wu_get_int  (label_font     ,&(t->label.font));
  wu_get_int  (label_color    ,&(t->label.color));
  wu_get_dble (label_charsize ,&(t->label.charsize));
  if (gg_get_int (label_layout.u)) {
    t->label_layout = gg_get_int (label_layout.w) ? LAYOUT_PERPENDICULAR : LAYOUT_PARALLEL;
  }
  wu_get_op   (label_op 	     ,&(t->label_op));
  //  if (gg_get_int (label_op.u)) t->label_op = gg_get_int (label_op.w);
  wu_get_int  (label_place    ,&(t->label_place));
  if (t->label_place == TYPE_SPEC) {
    if (wu_evalexpr (label_x1, &(t->label.x1)) == RETURN_FAILURE) {
      errmsg( "Error reading label x offset" );
      return RETURN_FAILURE;
    }
    if (wu_evalexpr (label_y1, &(t->label.y1)) == RETURN_FAILURE) {
      errmsg( "Error reading label y offset" );
      return RETURN_FAILURE;
    }
  }
 wu_get_int  (t_drawbarcolor ,&(t->t_drawbarcolor));
 wu_get_dble (t_drawbarlinew ,&(t->t_drawbarlinew));
 wu_get_int  (t_drawbarlines ,&(t->t_drawbarlines));

 /* ------------ Ticks Label tab -------------- */
 wu_get_int  (tl_font      ,&(t->tl_font));
 wu_get_int  (tl_color     ,&(t->tl_color));
 wu_get_dble (tl_charsize  ,&(t->tl_charsize));
 wu_get_int  (tl_angle     ,&(t->tl_angle));
 wu_get_op   (tl_op        ,&(t->tl_op));
 wu_get_int  (tl_staggered ,&(t->tl_staggered));
 if (gg_get_int (tl_starttype.u)) {
   t->tl_starttype = gg_get_int (tl_starttype.w);
   if (t->tl_starttype == TYPE_SPEC) {
     if (gg_evalexpr (tl_start ,&(t->tl_start))  == RETURN_FAILURE) {
       errmsg( "Error reading tick label start value" );
       return RETURN_FAILURE;
     }
   }
 }
 if (gg_get_int (tl_stoptype.u)) {
   t->tl_stoptype = gg_get_int (tl_stoptype.w);
   if (t->tl_stoptype == TYPE_SPEC) {
     if (gg_evalexpr (tl_stop ,&(t->tl_stop))  == RETURN_FAILURE) {
       errmsg( "Error reading tick label stop value" );
       return RETURN_FAILURE;
     }
   }
 }
 wu_get_int  (tl_skip      ,&(t->tl_skip));
 if (gg_get_int (tl_formula.u)) {
   xfree (t->tl_formula);
   t->tl_formula = copy_string (NULL,  gg_getstr(tl_formula.w));
 }
 if (gg_get_int (tl_prestr.u)) strncpy (t->tl_prestr, gg_getstr(tl_prestr.w) ,63);
 if (gg_get_int (tl_appstr.u)) strncpy (t->tl_appstr, gg_getstr(tl_appstr.w) ,63);
 if (gg_get_int (tl_gaptype.u)) {
   t->tl_gaptype = gg_get_int (tl_gaptype.w);
   if ( t->tl_gaptype == TYPE_SPEC) {
    if (get_graph_type (cg) == GRAPH_POLAR) {
      rok1 = gg_evalexpr (tl_gap_para.w, &t->tl_gap.y);
      rok2 = gg_evalexpr (tl_gap_perp.w, &t->tl_gap.x);
    } else {
      rok1 = gg_evalexpr (tl_gap_para.w, &t->tl_gap.x);
      rok2 = gg_evalexpr (tl_gap_perp.w, &t->tl_gap.y);
    }
    if (rok1  == RETURN_FAILURE || rok2  == RETURN_FAILURE) {
      errmsg( "Error reading tick label offset" );
      return RETURN_FAILURE;
    }
   }
 }

  /* ------------ Ticks Marks tab -------------- */
 wu_get_int  (t_inout 	     ,&(t->t_inout));
 wu_get_op   (t_op    	     ,&(t->t_op));
 wu_get_int  (t_round 	     ,&(t->t_round));
 wu_get_int  (t_autonum      ,&(t->t_autonum));

 wu_get_int  (props_gridflag ,&(t->props.gridflag));
 wu_get_dble (props_size     ,&(t->props.size));
 wu_get_int  (props_color    ,&(t->props.color));
 wu_get_dble (props_linew    ,&(t->props.linew));
 wu_get_int  (props_lines    ,&(t->props.lines));

 wu_get_int  (mprops_gridflag ,&(t->mprops.gridflag));
 wu_get_dble (mprops_size     ,&(t->mprops.size));
 wu_get_int  (mprops_color    ,&(t->mprops.color));
 wu_get_dble (mprops_linew    ,&(t->mprops.linew));
 wu_get_int  (mprops_lines    ,&(t->mprops.lines));
  return RETURN_SUCCESS;
}

static void ge_axes_u_AAC_CB (GtkWidget *widget ,gint reponse)
{
  int gno ,axisno;
  gno = get_cg ();  // cg et 0 provisoires : il faut balayer les graphs select.
  axisno = 0;
  if (reponse == U_AXIS_RESET) {
    wu_reset_u (layer);
    wu_reset_u (axis_world_start);
    wu_reset_u (axis_world_stop);
    wu_reset_u (axis_scale);
    wu_reset_u (axis_invert);
    wu_reset_u (tl_flag);
    wu_reset_u (t_drawbar);
    wu_reset_u (t_flag);
    wu_reset_u (zero);
    wu_reset_u (offsx);
    wu_reset_u (offsy);
    wu_reset_u (label_font);
    wu_reset_u (label_color);
    wu_reset_u (label_charsize);
    wu_reset_u (label_layout);
    wu_reset_u (label_op);
    wu_reset_u (label_place);
    wu_reset_u (label_x1);
    wu_reset_u (label_y1);
    wu_reset_u (t_drawbarcolor);
    wu_reset_u (t_drawbarlinew);
    wu_reset_u (t_drawbarlines);
    wu_reset_u (tmajor);
    wu_reset_u (nminor);
    wu_reset_u (tl_format);
    wu_reset_u (tl_prec);
    wu_reset_u (tl_font);
    wu_reset_u (tl_color);
    wu_reset_u (tl_charsize);
    wu_reset_u (tl_angle);
    wu_reset_u (tl_op);
    wu_reset_u (tl_staggered);
    wu_reset_u (tl_starttype);
    wu_reset_u (tl_stoptype);
    wu_reset_u (tl_skip);
    wu_reset_u (tl_formula);
    wu_reset_u (tl_prestr);
    wu_reset_u (tl_appstr);
    wu_reset_u (tl_gaptype);
    wu_reset_u (tl_gap_para);
    wu_reset_u (tl_gap_perp);
    wu_reset_u (t_inout);
    wu_reset_u (t_op);
    wu_reset_u (t_round);
    wu_reset_u (t_autonum);
    wu_reset_u (props_gridflag);
    wu_reset_u (props_size);
    wu_reset_u (props_color);
    wu_reset_u (props_linew);
    wu_reset_u (props_lines);
    wu_reset_u (mprops_gridflag);
    wu_reset_u (mprops_size);
    wu_reset_u (mprops_color);
    wu_reset_u (mprops_linew);
    wu_reset_u (mprops_lines);
  } else if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY) {
    Qtype typ;
    GtkTreeIter iter;
    GtkTreeSelection *select;
    GList *lpath = NULL;
    Ge_tree *getree;
    getree = get_getree ();
    int n = ge_selection_is_homogeneous (&typ);
    if (n < 1 || typ != Q_Axis) {
      errmsg ("Selection must have one or several axis only");
      return;
    }
    select = gtk_tree_view_get_selection (GTK_TREE_VIEW (getree->view));
    lpath  = gtk_tree_selection_get_selected_rows (select ,&(getree->model));
    tickmarks *t    = new_graph_tickmarks();
    if (!t) return;
    while (lpath != NULL) {
      if (gtk_tree_model_get_iter (getree->model ,&iter ,lpath->data)) {
	gtk_tree_model_get (getree->model ,&iter
			    ,GE_TREE_ID        ,&axisno
			    ,GE_TREE_PARENT_ID ,&gno
			    ,-1);
	t = get_graph_tickmarks  (gno ,axisno);
	ge_axis_u_apply (t ,gno ,axisno);
	lpath = g_list_next (lpath);
      }
    }
    set_dirtystate ();
    gg_drawgraph  ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (u_axis_dialog);
  }
  wu_update_on (FALSE);
}

/******************** GRACE-5 COMPATIBILITY ********************/

void ge_axis_g5compat_CB (GtkWidget *w ,gpointer p)
{
  int i ,axisno;
  int gno = get_cg ();
  for (axisno = 0; axisno < MAXAXES; axisno++) {
    i = obj_tid_get_num (Q_Axis ,axisno ,Q_Graph ,gno);
    if (obj_is_active (i)) break;
    i = obj_tid_get_graph_num (gno);
    if (i < 0) i = 0;
  }
  ge_explorer_popup ();
  i = obj_tid_get_num (Q_Axis ,0 ,Q_Graph ,gno);
  obj_make_current (i);
  current_page = 0;
  ge_expand_current ();
  ge_unselect_all   ();
  ge_select_current ();
}
