/** File gg_compwin.c
 *  Transcripted from Motif to GTK+ by P. Vincent to
 *  Replace compwin.c
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cmath.h>

#include <gtk/gtk.h>

#include "defines.h"
#include "graphs.h"
#include "utils.h"
#include "noxprotos.h"
#include "ssdata.h"

#include "gw_list.h"

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

#include "computils.h"
#include "draw.h"
#include "zc.h"


static gint popup_width = 450  ,list_height = 250;

extern GdkColor  bleuciel ,wheat;

static void gg_compute_AAC_CB 	(GtkWidget *w ,gint reponse);
static void gg_interp_AAC_CB  	(GtkWidget *w ,gint reponse);
static void gg_histo_AAC_CB   	(GtkWidget *w ,gint reponse);

static void gg_runavg_AAC_CB    (GtkWidget *w ,gint reponse);
static void gg_regui_AAC_CB   	(GtkWidget *w ,gint reponse);

static void gg_iui_AAC_CB     	(GtkWidget *w ,gint reponse);
static void gg_sui_AAC_CB     	(GtkWidget *w ,gint reponse);
static void gg_crossui_AAC_CB 	(GtkWidget *w ,gint reponse);
static void gg_samp_AAC_CB    	(GtkWidget *w ,gint reponse);
static void gg_prune_AAC_CB   	(GtkWidget *w ,gint reponse);
static void gg_digfilter_AAC_CB (GtkWidget *w ,gint reponse);
static void gg_linearc_AAC_CB   (GtkWidget *w ,gint reponse);
static void gg_geom_AAC_CB      (GtkWidget *w ,gint reponse);

static void gg_prune_toggle (void);

/********** Evaluate expression *************/

typedef struct _gg_Eval_ui {
  GtkWidget *top;
  gg_SrcDestStructure *srcdest;
  GtkTextBuffer *formula_item;
  gg_RestrictionStructure *restr_item;
} gg_Eval_ui;

static gg_Eval_ui eui;

/**
 *  Replace  create_eval_frame    compwin.c   90
 */
void gg_create_eval_popup (void)
{
  GtkWidget *vb;

  if (eui.top == NULL) {
    eui.top          = gg_CreateAACDialog ("evaluateExpression" ,gg_compute_AAC_CB ,0 ,0 ,&vb);
    eui.srcdest      = gg_CreateSrcDestSelector   (vb ,GTK_SELECTION_MULTIPLE);
    eui.formula_item = gg_CreateScrollTextItem2   (vb ,popup_width ,40 ,"Formula:");
    eui.restr_item   = gg_CreateRestrictionChoice (vb ,"Source data filtering");
  }
  gtk_widget_show_all (eui.top);
}



/**
 *  Replace  compute_aac    compwin.c   153
 */
static void gg_compute_AAC_CB (GtkWidget *w ,gint reponse)
{
  int gno1, gno2 ,ns1 ,ns2 ,resno ,i;
  int setno1 = -1;
  int setno2 = -1;
  gint *sl1 ,*sl2;
  GtkTextIter start ,end;
  char fstr[256] ,buf[300];
  int restr_type, restr_negate;
  char *rarray;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY   ) {
    restr_type   = gg_get_int (eui.restr_item->r_sel) - 1;
    if (restr_type == 6) restr_type = RESTRICT_WORLD;
    restr_negate = gg_get_int (eui.restr_item->negate);
    if (gg_GetSrcDestSettings (eui.srcdest ,SD_NSET1_EQ_NSET2
                               ,&gno1 ,&gno2
                               ,&ns1  ,&ns2
                               ,&sl1  ,&sl2) == RETURN_FAILURE) return;

    gtk_text_buffer_get_bounds (eui.formula_item ,&start ,&end);
    strcpy (fstr, gtk_text_buffer_get_text (eui.formula_item
                                            ,&start ,&end ,FALSE));
    for (i = 0; i < ns1; i++) {
      setno1 = sl1[i];
      setno2 = sl2[i];
      resno = get_restriction_array (gno1, setno1 ,restr_type
                                     ,restr_negate ,&rarray);
      if (resno != RETURN_SUCCESS) {
        errmsg("Error in evaluation restriction");
        break;
      }
      resno = do_compute (gno1, setno1, gno2, setno2, rarray, fstr);
      XCFREE(rarray);
      if (resno != RETURN_SUCCESS) {
        errmsg ("Error in do_compute(), check formula");
        break;
      }
    }
    sprintf (buf ,"(%s) on G%d.s%d" ,fstr ,gno1 ,setno1);
    comment_and_legend_set (gno2 ,setno2 ,buf);
    zc_label_free_list (gno2 ,setno2);
    gg_update_all_sets_lists ();
    ge_update_explorer ();
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (eui.top);
  }
}


/**********  Interpolation *************/

#define SAMPLING_MESH   0
#define SAMPLING_SET    1

/* interpolation */

typedef struct _gg_Interp_ui {
  GtkWidget *dialog;
  gg_SrcDestStructure *srcdest;
  GtkWidget *method;
  GtkWidget *sarray;
  GtkWidget *sampling;
  GtkWidget *strict;
  GtkWidget *mrc;
  GtkWidget *mstart;
  GtkWidget *mstop;
  GtkWidget *mlength;
  GtkWidget *xspline_s;
  GtkWidget *xspline_p;
  GtkWidget *sset_sel;
  SetsMenu3Struct  *sset_menu3;
} gg_Interp_ui;


static gg_Interp_ui *interpui = NULL;

static void method_changed_CB (GtkWidget *w ,gpointer p);

/**
 *  Replace  sampling_cb    compwin.c   258
 */
static void gg_sampling_CB (GtkWidget *w ,gpointer p)
{

  gint value = gg_get_int (interpui->sampling);
  if (value == SAMPLING_MESH) {
    gtk_widget_set_sensitive (interpui->mrc      ,TRUE);
    gtk_widget_set_sensitive (interpui->sset_sel ,FALSE);
  } else {
    gtk_widget_set_sensitive (interpui->mrc      ,FALSE);
    gtk_widget_set_sensitive (interpui->sset_sel ,TRUE);
  }
}

/**
 *  Replace  create_interp_frame    compwin.c   271
 */
void gg_create_interp_popup (void)
{
  GtkWidget *vb ,*rc2;
  if (interpui == NULL) {
    interpui = xmalloc (sizeof (gg_Interp_ui));
    interpui->dialog  = gg_CreateAACDialog ("Interpolation" ,gg_interp_AAC_CB ,0 ,0 ,&vb);
    interpui->srcdest = gg_CreateSrcDestSelector (vb ,GTK_SELECTION_MULTIPLE);

    rc2 = gg_CreateHContainer (vb);
    interpui->method   = gg_combo_new (rc2 ,"Method:" ,6
				       ,"Linear"        /* INTERP_LINEAR  */
				       ,"Cubic spline"  /* INTERP_SPLINE  */
				       ,"Akima spline"  /* INTERP_ASPLINE */
				       ,"X-spline"      /* INTERP_XSPLINE */
				       ,"XY-spline");   /* INTERP_XYSPLINE */

    interpui->sarray   = gg_frame (vb ,"Sampling array" ,&wheat ,0 ,1);
    interpui->strict   = gg_check_new (interpui->sarray ,"Strict (within source set bounds)");
    interpui->sampling = gg_combo_new (interpui->sarray ,"Sampling:" ,3
				       ,"Linear mesh"                /* SAMPLING_MESH */
				       ,"Abscissas of another set"); /* SAMPLING_SET */
    interpui->mrc = gg_CreateHContainer (interpui->sarray);
    interpui->mstart  = gg_entry_new (interpui->mrc ,"Start at:" ,10);
    interpui->mstop   = gg_entry_new (interpui->mrc ,"Stop at:" ,10);
    interpui->mlength = gg_entry_new (interpui->mrc ,"Length:" ,6);

    interpui->xspline_s  = gg_spin_new (vb ,"X-spline param s"   ,-1.0 ,1.0 ,0.1);
    interpui->xspline_p  = gg_spin_new (vb ,"X-spline param p"   ,0.002  ,0.5  ,0.002);
    gg_set_dble (interpui->xspline_s ,-0.5);
    gg_set_dble (interpui->xspline_p ,0.002);

    interpui->sset_menu3 = NULL;
    interpui->sset_sel = gg_CreateSetChoice ("Sampling set" ,GTK_SELECTION_SINGLE
                                             ,popup_width ,list_height
                                             ,NULL
					     ,&(interpui->sset_menu3)
					     ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,interpui->sset_sel);
    gtk_widget_set_sensitive (interpui->sset_sel ,FALSE);

    g_signal_connect (interpui->sampling ,"changed" ,G_CALLBACK (gg_sampling_CB) ,interpui);
    g_signal_connect (interpui->method   ,"changed" ,G_CALLBACK (method_changed_CB)      ,NULL);

    method_changed_CB (interpui->method,NULL);
  }
  gtk_widget_show_all (interpui->dialog);

}


/**
 *  Replace  do_interp_proc    compwin.c   323
 */
static void gg_interp_AAC_CB (GtkWidget *w ,gint reponse)
{
  int error, res;
  int gno1, gno2 ,ns1 ,ns2;
  gint *sl1 ,*sl2;
  int method, sampling, strict;
  int i, meshlen ,setlen;
  double *mesh = NULL;
  double start, stop;
  int setnosrc, setnodest;
  double *x ,*y ,*xint ,*yint ,xspline_s ,xspline_p;
  int interp_setno ,n_interp;
  char buf[64];

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY   ) {
    error = FALSE;
    if (gg_GetSrcDestSettings (interpui->srcdest ,SD_NSET1_EQ_NSET2 | SD_EXCLUSIVE
                               ,&gno1 ,&gno2
                               ,&ns1  ,&ns2
                               ,&sl1  ,&sl2) == RETURN_FAILURE) return;
    method   = gg_get_int (interpui->method);
    if (method == INTERP_XYSPLINE) {
      if (ns1 != 1 && ns2 != 1) {
	errmsg ("XY-spline requires only one source and destination  set");
	return;
      }
      setlen       = getsetlength (gno1 ,sl1[0]);
      xspline_s    = gg_get_dble (interpui->xspline_s);
      xspline_p    = gg_get_dble (interpui->xspline_p);
      interp_setno = sl2[0];
      xint 	   = xcalloc (setlen ,SIZEOF_DOUBLE);
      yint 	   = xcalloc (setlen ,SIZEOF_DOUBLE);
      x 	   = getx (gno1 ,sl1[0]);
      y 	   = gety (gno1 ,sl1[0]);
      if (xspline_eval_xy (&xint ,&yint ,setlen ,x ,y ,setlen ,&n_interp ,xspline_s ,xspline_p) == RETURN_FAILURE) {
	xfree (xint);
	xfree (yint);
	return;
      }
      copyset     (gno1 ,sl1[0] ,gno2 ,sl2[0]);
      killsetdata (gno2 ,sl2[0]);
      setcol 	  (gno2 ,interp_setno ,DATA_X ,xint ,n_interp);
      setcol 	  (gno2 ,interp_setno ,DATA_Y ,yint ,n_interp);
      sprintf (buf, "XY-spline of G%d.s%d", gno1 ,sl1[0]);
      comment_and_legend_set (gno2 ,interp_setno ,buf);
      sampling = SAMPLING_MESH;
    } else {              /* method != INTERP_XYSPLINE */
      sampling = gg_get_int (interpui->sampling);
      strict   = gg_get_int (interpui->strict);
      if (sampling == SAMPLING_SET) {
	int gsampl, setnosampl;
	gsampl = get_cg ();
	res = gg_GetSingleListChoice (GW_LIST (interpui->sset_sel) ,&setnosampl);
	if (res != TRUE) {
	  errmsg("Please select single sampling set");
	  return;
	} else {
	  meshlen = getsetlength (gsampl, setnosampl);
	  mesh = getcol (gsampl, setnosampl, DATA_X);
	}
      } else {
	if (gg_evalexpr  (interpui->mstart, &start)    != RETURN_SUCCESS ||
	    gg_evalexpr  (interpui->mstop,  &stop)     != RETURN_SUCCESS ||
	    gg_evalexpri (interpui->mlength, &meshlen) != RETURN_SUCCESS ) {
	  errmsg ("Can't parse mesh settings");
	  return;
	} else {
	  mesh = allocate_mesh (start, stop, meshlen);
	  if (mesh == NULL) {
	    errmsg ("Can't allocate mesh");
	    return;
	  }
	}
      }
      for (i = 0; i < ns1; i++) {
	setnosrc = sl1[i];
	if (ns2 != 0) {
	  setnodest = sl2[i];
	} else {
	  setnodest = SET_SELECT_NEXT;
	}
	res = do_interp (gno1, setnosrc, gno2, setnodest,
			 mesh, meshlen, method, strict
			 ,  /* Default for INTERP_XSPLINE xspline_s = */ -0.5);
	if (res != RETURN_SUCCESS) {
	  errmsg ("Error in do_interp()");
	  error = TRUE;
	  break;
	}
      }
    }
    xfree (sl1);
    if (ns2 > 0) xfree (sl2);
    if (sampling == SAMPLING_MESH) xfree (mesh);

    gg_update_all_sets_lists ();
    gg_drawgraph ();
    if (error) return;
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}

static void method_changed_CB (GtkWidget *w ,gpointer p)
{
  if (interpui != NULL) {
    int m = gg_get_int (w);
    gtk_widget_set_sensitive (interpui->sarray    ,m != INTERP_XYSPLINE);
    gtk_widget_set_sensitive (interpui->xspline_p ,m == INTERP_XYSPLINE);
    gtk_widget_set_sensitive (interpui->xspline_s ,m == INTERP_XYSPLINE || m == INTERP_XSPLINE);

  }
}


/******************* Histograms  *********************/

typedef struct _gg_Histo_ui {
  GtkWidget *dialog;
  gg_SrcDestStructure *srcdest;
  GtkWidget *cumulative;
  GtkWidget *normalize;
  GtkWidget *sampling;
  GtkWidget *mrc;
  GtkWidget *mstart;
  GtkWidget *mstop;
  GtkWidget *mlength;
  GtkWidget *sset_sel;
  SetsMenu3Struct * sset_menu3;
} gg_Histo_ui;

static gg_Histo_ui *histoui = NULL;

/**
 *  Replace binsampling_cb  compwin.c   435
 */
static void gg_binsampling_CB (GtkWidget *w ,gpointer p)
{

  gint value = gg_get_int (histoui->sampling);
  if (value == SAMPLING_MESH) {
    gtk_widget_set_sensitive (histoui->mrc      ,TRUE);
    gtk_widget_set_sensitive (histoui->sset_sel ,FALSE);
  } else {
    gtk_widget_set_sensitive (histoui->mrc      ,FALSE);
    gtk_widget_set_sensitive (histoui->sset_sel ,TRUE);
  }
}

/**
 *  Replace create_histo_frame  compwin.c   448
 */
void gg_create_histo_popup (void)
{
  GtkWidget *vb ,*rc2;

  if (histoui == NULL) {
    histoui = xmalloc (sizeof (gg_Histo_ui));
    histoui->dialog  = gg_CreateAACDialog ("Histograms" ,gg_histo_AAC_CB ,0 ,0 ,&vb);
    histoui->srcdest = gg_CreateSrcDestSelector (vb ,GTK_SELECTION_MULTIPLE);

    rc2 = gg_CreateHContainer (vb);
    histoui->cumulative = gg_check_new (rc2 ,"Cumulative histogram");
    histoui->normalize  = gg_check_new (rc2, "Normalize");
    histoui->sampling   = gg_combo_new (vb ,"Bin sampling:" ,3
                                               ,"Linear mesh"                /* SAMPLING_MESH */
                                               ,"Abscissas of another set"); /* SAMPLING_SET */
    histoui->mrc = gg_CreateHContainer (vb);
    histoui->mstart  = gg_entry_new (histoui->mrc ,"Start at:" ,10);
    histoui->mstop   = gg_entry_new (histoui->mrc ,"Stop at:" ,10);
    histoui->mlength = gg_entry_new (histoui->mrc ,"# of bins:" ,6);

    histoui->sset_menu3 = NULL;
    histoui->sset_sel = gg_CreateSetChoice ("Sampling set" ,GTK_SELECTION_SINGLE
                                             ,popup_width ,list_height
                                             ,NULL
					    ,&(histoui->sset_menu3)
					    ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,histoui->sset_sel);
    gtk_widget_set_sensitive (histoui->sset_sel ,FALSE);
    g_signal_connect (histoui->sampling ,"changed" ,G_CALLBACK (gg_binsampling_CB) ,NULL);
  }
  gtk_widget_show_all (histoui->dialog);
}

/**
 *  Replace  do_histo_proc    compwin.c   492
 */
static void gg_histo_AAC_CB (GtkWidget *w ,gint reponse)
{
  int error, res;
  int gno1, gno2 ,ns1 ,ns2;
  gint *sl1 ,*sl2;
  int cumulative, normalize, sampling;
  int i, nbins;
  double *bins = NULL;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY   ) {
    error = FALSE;
    cumulative = gg_get_int (histoui->cumulative);
    normalize  = gg_get_int (histoui->normalize);
    sampling   = gg_get_int (histoui->sampling);
    if (sampling == SAMPLING_SET) {
      int gsampl, setnosampl;
      gsampl = get_cg ();
      res = gg_GetSingleListChoice (GW_LIST (histoui->srcdest->src->sets)
                                    , &setnosampl);
      if (res != RETURN_SUCCESS) {
        errmsg("Please select single sampling set");
	return;
      } else {
        nbins = getsetlength (gsampl, setnosampl);
        bins  = getcol (gsampl, setnosampl, DATA_X);
      }
    } else {
      double start, stop;
      if (gg_evalexpr  (histoui->mstart, &start)    != RETURN_SUCCESS ||
          gg_evalexpr  (histoui->mstop,  &stop)     != RETURN_SUCCESS ||
          gg_evalexpri (histoui->mlength, &nbins) != RETURN_SUCCESS ) {
        errmsg ("Can't parse mesh settings");
	return;
      } else {
        bins = allocate_mesh (start, stop, nbins + 1);
        if (bins == NULL) {
          errmsg("Can't allocate mesh");
	  return;
        }
      }
    }
    if (gg_GetSrcDestSettings (histoui->srcdest ,SD_NSET1_EQ_NSET2 | SD_EXCLUSIVE  // ,FALSE ,TRUE ,TRUE
                               ,&gno1 ,&gno2
                               ,&ns1  ,&ns2
                               ,&sl1  ,&sl2) == RETURN_FAILURE) return;
    for (i = 0; i < ns1; i++) {
      int setnosrc, setnodest;
      setnosrc = sl1[i];
      if (ns2 != 0) {
        setnodest = sl2[i];
      } else {
        setnodest = SET_SELECT_NEXT;
      }
      res = do_histo (gno1, setnosrc, gno2, setnodest,
                       bins, nbins, cumulative, normalize);
      if (res != RETURN_SUCCESS) {
        errmsg("Error in do_histo()");
        error = TRUE;
        break;
      }
    }
    xfree (sl1);
    if (ns2 > 0) xfree (sl2);
    if (sampling == SAMPLING_MESH) xfree (bins);

    gg_switch_current_graph (gno1);
    gg_update_all_sets_lists ();
    gg_switch_current_graph (gno2);
    gg_update_all_sets_lists ();
    gg_drawgraph ();
    if (error) return;
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/************ Running averages, medians, min, max, std. deviation   ********/

typedef struct _gg_Run_ui {
  GtkWidget *top;
  gg_SrcDestStructure *srcdest;
  GtkWidget *len;
  GtkWidget *type;
  GtkWidget *region;
  GtkWidget *rinvert;
  SetsMenu3Struct *menu3;
} gg_Run_ui;

static gg_Run_ui rui;


/*********** Running averages ************/


/**
 *  Replace  create_run_frame    compwin.c   798
 */
void gg_create_run_popup (void)
{
  GtkWidget *vb;
  if (rui.top == NULL) {
    rui.top = gg_CreateAACDialog ("Running averages" ,gg_runavg_AAC_CB ,0 ,0 ,&vb);
    rui.menu3 = NULL;
    rui.srcdest = gg_CreateSrcDestSelector (vb ,GTK_SELECTION_MULTIPLE);
    rui.type   = gg_combo_new (vb ,"Running:" ,6
				       ,"Average"
				       ,"Median"
				       ,"Minimum"
				       ,"Maximum"
				       ,"Std. dev.");

    rui.len    = gg_spin_new (vb ,"Length of average:" ,2. ,1000. ,1.);
    rui.region = gg_combo_new (vb ,"Restrictions:" ,9
				       ,"None"
				       ,"Region 0"
				       ,"Region 1"
				       ,"Region 2"
				       ,"Region 3"
				       ,"Region 4"
				       ,"Inside graph"
				       ,"Outside graph");

    rui.rinvert = gg_check_new (vb ,"Invert region");
  }
  gtk_widget_show_all (rui.top);
}

/**
 *  Replace  do_runavg_proc    compwin.c   872
 */
static void gg_runavg_AAC_CB (GtkWidget *w ,gint reponse)
{
  int runlen ,runtype ,rno ,invr;
  int gno1 ,gno2 ,ns1 ,ns2 ,i;
  gint *sl1 ,*sl2;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    if (gg_GetSrcDestSettings (rui.srcdest ,SD_NSET1_EQ_NSET2
			       ,&gno1 ,&gno2
			       ,&ns1  ,&ns2
			       ,&sl1  ,&sl2) == RETURN_FAILURE) return;
    if (gg_evalexpri (rui.len ,&runlen ) != RETURN_SUCCESS) return;
    runtype = gg_get_int (rui.type);
    rno     = gg_get_int (rui.region) - 1;
    invr    = gg_get_int (rui.rinvert);
    for (i = 0; i < ns1; i++) {
      do_runavg12 (gno1 ,sl1[i] ,gno2 ,sl2[i]
		  ,runlen ,runtype ,rno ,invr);
    }
    gg_drawgraph ();
    gg_update_all_sets_lists ();

    ge_update_explorer ();
    xfree (sl1);
    xfree (sl2);
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}

/***********  Regressions ************/

typedef struct _gg_Reg_ui {
  GtkWidget *top;
  GtkWidget *sel;
  GtkWidget *degree;
  GtkWidget *zero;
  GtkWidget *resid;
  GtkWidget *region;
  GtkWidget *rinvert;
  GtkWidget *start;
  GtkWidget *stop;
  GtkWidget *step;
  GtkWidget *fload_rc;
  GtkWidget *method;
  SetsMenu3Struct *menu3;
} gg_Reg_ui;

static gg_Reg_ui regui;

/**
 *    set_regr_sensitivity    compwin.c   927
 */

/**
 *  Replace   create_reg_frame   compwin.c   937
 */
void gg_create_reg_popup (void)
{

  GtkWidget *vb ,*rc2 ,*sep;

  if (regui.top == NULL) {
    regui.top = gg_CreateAACDialog ("Regression" ,gg_regui_AAC_CB ,0 ,0 ,&vb);
    regui.menu3 = NULL;
    regui.sel = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_MULTIPLE
                                    ,popup_width ,list_height
                                    ,NULL
				    ,&(regui.menu3)
				    ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,regui.sel);

    regui.degree = gg_combo_new (vb ," " ,16
                                         ,"Linear"
                                         ,"Quadratic"
                                         ,"Cubic"
                                         ,"4th degree"
                                         ,"5th degree"
                                         ,"6th degree"
                                         ,"7th degree"
                                         ,"8th degree"
                                         ,"9th degree"
                                         ,"10th degree"
                                         ,"1-10"
                                         ,"Power y=A*x^B"
                                         ,"Exponential y=A*exp(B*x)"
                                         ,"Logarithmic y=A+B*ln(x)"
                                         ,"Inverse y=1/(A+Bx)");

    regui.resid = gg_combo_new (vb ,"Load: " ,4
                                        ,"Fitted values"
                                        ,"Residuals"
                                        ,"Function");
    rc2 = gg_CreateHContainer (vb);
    regui.region = gg_combo_new (rc2 ,"Restrictions:" ,9
                                         ,"None"
                                         ,"Region 0"
                                         ,"Region 1"
                                         ,"Region 2"
                                         ,"Region 3"
                                         ,"Region 4"
                                         ,"Inside graph"
                                         ,"Outside graph");
    regui.rinvert = gg_check_new (rc2 ,"Invert region");

    sep = gtk_hseparator_new ();
    gtk_box_pack_start (GTK_BOX (vb) ,sep ,FALSE ,TRUE ,1);

    regui.fload_rc  = gg_CreateHContainer (vb);
    regui.start = gg_entry_new (regui.fload_rc ,"Start load at:" ,6);
    regui.stop  = gg_entry_new (regui.fload_rc ,"Stop load at:"  ,6);
    regui.step  = gg_entry_new (regui.fload_rc ,"# of points:"   ,4);
    gtk_widget_set_sensitive (regui.fload_rc ,FALSE);
  }
  gtk_widget_show_all (regui.top);
}

/**
 *  Replace  do_regress_proc    compwin.c   1055
 */
static void gg_regui_AAC_CB (GtkWidget *w ,gint reponse)
{
  int gno = get_cg();
  gint *selsets;
  int cnt ,rno ,invr;
  int setno, ideg, iresid, i, j, k;
  int nstep = 0, rx, rset = 0;
  double xstart, xstop, stepsize = 0.0, *xr;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    selsets = gw_list_selected_list (GW_LIST (regui.sel) ,&cnt);
    if (cnt == 0)  {
      errmsg  ("No sets selected");
      return;
    }
    rno  = gg_get_int (regui.region) - 1;
    invr = gg_get_int (regui.rinvert);
    ideg = gg_get_int (regui.degree) + 1;
    rx   = gg_get_int (regui.resid);
    switch (rx) {
    case 0:             /* evaluate fitted function at original x's */
      iresid = 0;
      rset = -1;
      break;
    case 1:               /* load residue at original x points */
      iresid = 1;
      rset = -1;
      break;
    case 2:               /* evaluate fitted function at new x points */
      iresid = 0;
      if(gg_evalexpri (regui.step ,&nstep) != RETURN_SUCCESS || nstep < 2 ) {
	gg_errwin ("Number points < 2");
	return;
      }
      if (gg_evalexpr (regui.start ,&xstart ) != RETURN_SUCCESS) {
	gg_errwin("Specify starting value");
	return;
      }
      if (gg_evalexpr (regui.stop ,&xstop) != RETURN_SUCCESS) {
	gg_errwin ("Specify stopping value");
	return;
      } else {
	stepsize = (xstop - xstart)/(nstep-1);
      }
      break;
    default:
      gg_errwin ("Internal error");
      return;
    }
    for (i = (ideg==11?1:ideg); i <= (ideg==11?10:ideg); i++) {
      for (j = 0; j < cnt; j++) {
	setno = selsets[j];
	if( rx == 2 ) {
	  if( (rset = nextset( gno )) == -1 ){
	    gg_errwin ("Not enough sets");
	    return;
	  }
	  activateset (gno ,rset);
	  setlength (gno ,rset ,nstep);
	  xr = getx( gno ,rset );
	  for( k=0; k<nstep; k++ )
	    xr[k] = xstart + k*stepsize;
	}
	do_regress (gno ,setno ,i ,iresid ,rno ,invr ,rset);
      }
    }
    gg_update_all_sets_lists ();
    xfree (selsets);
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/****** Finite differencing/derivating *******/


typedef struct _gg_Diff_ui {
  GtkWidget *top;
  gg_SrcDestStructure *srcdest;
  GtkWidget *type;
  GtkWidget *xplace;
  GtkWidget *period;
  GtkWidget *region;
  GtkWidget *rinvert;
} gg_Diff_ui;

static gg_Diff_ui dui;

static void gg_diff_AAC_CB (GtkWidget *w ,gint reponse);


/**
 *  Replace create_diff_frame  compwin.c   1139
 */
void gg_diff_create_win (void)
{
  GtkWidget *vb;

  if (dui.top == NULL) {
    dui.top     = gg_CreateAACDialog ("Differences/derivatives" ,gg_diff_AAC_CB ,0 ,0 ,&vb);
    dui.srcdest = gg_CreateSrcDestSelector (vb ,GTK_SELECTION_MULTIPLE);
    dui.type    = gg_combo_new (vb ,"Type:" ,3
					,"Plain differences"  /* DIFF_TYPE_PLAIN      */
					,"Derivative");       /* DIFF_TYPE_DERIVATIVE */
    dui.xplace  = gg_combo_new (vb ,"X placement:" ,4
					,"Left"               /* DIFF_XPLACE_LEFT   */
					,"Center"             /* DIFF_XPLACE_CENTER */
					,"Right");            /* DIFF_XPLACE_RIGHT  */
    dui.period  = gg_spin_new  (vb ,"Period:" ,1.0 ,999999.0 ,1.0);
    /* set defaults */
    gg_diff_update ();
  }
  gtk_widget_show_all (dui.top);
}

void gg_diff_update (void)
{
  if (dui.top != NULL) {
    DIFFParams p;
    if (diff_params_get (&p) == RETURN_SUCCESS) {
      gg_set_int (dui.type   ,p.derivative);
      gg_set_int (dui.xplace ,p.xplace);
      gg_set_int (dui.period ,p.period);
    }
  }
}

/**
 *  Replace do_differ_proc  compwin.c   1180
 */
static void gg_diff_AAC_CB (GtkWidget *w ,gint reponse)
{
  DIFFParams p;
  int gno1 ,gno2 ,ns1 ,ns2 ,i;
  gint *sl1 ,*sl2;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    if (gg_GetSrcDestSettings (dui.srcdest ,SD_NSET1_EQ_NSET2
			       ,&gno1 ,&gno2
			       ,&ns1  ,&ns2
			       ,&sl1  ,&sl2) == RETURN_FAILURE) return;
    p.derivative = gg_get_int (dui.type);
    p.xplace     = gg_get_int (dui.xplace);
    p.period     = gg_get_int (dui.period);
    diff_params_set (&p);

    for (i = 0; i < ns1; i++) {
      do_diff (gno1 ,sl1[i] ,gno2 ,sl2[i]);
    }
    gg_drawgraph ();
    gg_update_all_sets_lists ();

    ge_update_explorer ();
    xfree (sl1);
    xfree (sl2);
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/******* Numerical integration **********/

typedef struct _gg_Int_ui {
    GtkWidget *top;
    GtkWidget *sel;
    GtkWidget *type;
    GtkWidget *sum;
    GtkWidget *region;
    GtkWidget *rinvert;
  SetsMenu3Struct *menu3;
} gg_Int_ui;

static gg_Int_ui iui;

/**
 *  Replace create_int_frame  compwin.c   1217
 */
void gg_create_int_popup (void)
{
  GtkWidget *vb;

  if (iui.top == NULL) {
    iui.top = gg_CreateAACDialog ("Integration"  ,gg_iui_AAC_CB ,0 ,0 ,&vb);
    iui.menu3 = NULL;
    iui.sel = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_MULTIPLE
				  ,popup_width ,list_height
				  ,NULL
				  ,&(iui.menu3)
				  ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,iui.sel);

    iui.type = gg_combo_new (vb  ,"Load:" ,3
				     ,"Cumulative sum"
				     ,"Sum only");
    iui.sum  = gg_entry_new (vb ,"Sum:" ,10);
  }
  gtk_widget_show_all (iui.top);
}

/**
 *  Replace do_int_proc  compwin.c   1258
 */
static void gg_iui_AAC_CB (GtkWidget *w ,gint reponse)
{
  int gno = get_cg();
  int *selsets;
  int i ,cnt;
  int setno ,itype;
  double sum;
  char buf[32];

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    selsets = gw_list_selected_list (GW_LIST (iui.sel) ,&cnt);
    if (cnt == 0)  {
      errmsg  ("No sets selected");
      return;
    }
    itype = gg_get_int (iui.type);
    for (i = 0; i < cnt; i++) {
      setno = selsets[i];
      sum = do_int (gno ,setno ,itype);
      gg_setstr_d (iui.sum ,"%g", sum ,buf);

    }
    gg_update_all_sets_lists ();
    xfree (selsets);
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/******** Seasonal differencing ************/

typedef struct _gg_Seas_ui {
  GtkWidget *top;
  GtkWidget *sel;
  GtkWidget *type;
  GtkWidget *period;
  GtkWidget *region;
  GtkWidget *rinvert;
  SetsMenu3Struct *menu3;
} gg_Seas_ui;

static gg_Seas_ui sui;

/**
 *  Replace create_seasonal_frame  compwin.c   1300
 */
void gg_create_seasonal_popup (void)
{
  GtkWidget *vb;

  if (sui.top == NULL) {
    sui.top = gg_CreateAACDialog ("Seasonal differences"  ,gg_sui_AAC_CB ,0 ,0 ,&vb);
    sui.menu3 = NULL;
    sui.sel = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_MULTIPLE
				  ,popup_width ,list_height
				  ,NULL
				  ,&(sui.menu3)
				  ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,sui.sel);

    sui.period = gg_entry_new (vb ,"Period:" ,10);
  }
  gtk_widget_show_all (sui.top);
}

/**
 *  Replace do_seasonal_proc  compwin.c   1335
 */
static void gg_sui_AAC_CB (GtkWidget *w ,gint reponse)
{
  int *selsets;
  int i ,cnt;
  int setno, period;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    selsets = gw_list_selected_list (GW_LIST (sui.sel) ,&cnt);
    if (cnt == 0)  {
      errmsg  ("No sets selected");
      return;
    }
    if (gg_evalexpri (sui.period, &period ) != RETURN_SUCCESS)
      return;
    for (i = 0; i < cnt; i++) {
      setno = selsets[i];
      do_seasonal_diff (setno, period);
    }
    gg_update_all_sets_lists ();
    xfree (selsets);
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}

/********** Cross correlation ************/

typedef struct _gg_Cross_ui {
  GtkWidget *top;
  GtkWidget *sel1 ,*sel2;
  GtkWidget *lag;
  GtkWidget *covar;
  SetsMenu3Struct *sel1_menu3;
  SetsMenu3Struct *sel2_menu3;
} gg_Cross_ui;

static gg_Cross_ui crossui;

/**
 *  Replace create_xcor_frame  compwin.c   1373
 */
void gg_create_xcor_popup (void)
{
  GtkWidget *vb;

  if (crossui.top == NULL) {
    crossui.top = gg_CreateAACDialog ("Correlation/Covariance"  ,gg_crossui_AAC_CB ,0 ,0 ,&vb);
    crossui.sel1_menu3 = NULL;
    crossui.sel1 = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_BROWSE
				       ,popup_width ,list_height
				       ,NULL
				       ,&(crossui.sel1_menu3)
				       ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,crossui.sel1);

    crossui.sel2_menu3 = NULL;
    crossui.sel2 = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_BROWSE
				       ,popup_width ,list_height
				       ,NULL
				       ,&(crossui.sel2_menu3)
				       ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,crossui.sel2);

    crossui.lag   = gg_entry_new   (vb ,"Maximum lag:" ,10);
    crossui.covar = gg_check_new (vb ,"Calculate covariance");
  }
  gtk_widget_show_all (crossui.top);
}


/**
 *  Replace do_xcor_proc  compwin.c
 */
static void gg_crossui_AAC_CB (GtkWidget *w ,gint reponse)
{
  int gno = get_cg();
  int set1 ,set2 ,maxlag ,covar;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    set1 = gw_list_get_first_selected_row_num (GW_LIST(crossui.sel1));
    set2 = gw_list_get_first_selected_row_num (GW_LIST(crossui.sel2));

    if (gg_evalexpri (crossui.lag ,&maxlag) != RETURN_SUCCESS) return;
    covar = gg_get_int (crossui.covar);
    do_xcor (gno ,set1 ,gno ,set2 ,maxlag ,covar);
    gg_update_all_sets_lists ();
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/********** Sample a set *************/

/* sample a set */

typedef struct _gg_Samp_ui {
  GtkWidget *top;
  GtkWidget *sel;
  GtkWidget *type;
  GtkWidget *start;
  GtkWidget *step;
  GtkWidget *expr;
  GtkWidget *region;
  GtkWidget *rinvert;
  SetsMenu3Struct *menu3;
} gg_Samp_ui;

static gg_Samp_ui sampui;

/**
 *  Replace create_samp_frame  compwin.c   1452
 */
void gg_create_samp_popup (void)
{
  GtkWidget *vb;

  if (sampui.top == NULL) {
    sampui.top = gg_CreateAACDialog ("Sample points"  ,gg_samp_AAC_CB ,0 ,0 ,&vb);
    sampui.menu3 = NULL;
    sampui.sel = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_MULTIPLE
				  ,popup_width ,list_height
				  ,NULL
				  ,&(sampui.menu3)
				     ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,sampui.sel);

    sampui.type = gg_combo_new (vb  ,"Sample type:" ,3
					,"Start/step"
					,"Expression");

    sampui.start = gg_entry_new (vb ,"Start:"              ,10);
    sampui.step  = gg_entry_new (vb ,"Step:"               ,10);
    sampui.expr  = gg_entry_new (vb ,"Logical expression:" ,10);
  }
  gtk_widget_show_all (sampui.top);
}


/**
 *  Replace do_sample_proc  compwin.c   1508
 */
static void gg_samp_AAC_CB (GtkWidget *w ,gint reponse)
{
  int *selsets;
  int i ,cnt;
  int setno, typeno;
  const char *exprstr;
  int startno, stepno;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    selsets = gw_list_selected_list (GW_LIST (sampui.sel) ,&cnt);
    if (cnt == 0)  {
      errmsg  ("No sets selected");
      return;
    }
    typeno = gg_get_int (sampui.type);
    if (typeno == 0) {
      exprstr = "";
      if (gg_evalexpri (sampui.start ,&startno) != RETURN_SUCCESS ||
	  gg_evalexpri (sampui.step  ,&stepno)  != RETURN_SUCCESS) {
	errmsg ("Please select start and step values");
	return;
      }
    } else {
      exprstr = gg_getstr (sampui.expr);
      startno = stepno = 1;
    }

    for (i = 0; i < cnt; i++) {
      setno = selsets[i];
      do_sample (setno ,typeno ,exprstr ,startno ,stepno);
    }
    gg_update_all_sets_lists ();
    xfree (selsets);
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}

/************* Prune data *************/

typedef struct _gg_Prune_ui {
  GtkWidget *top;
  GtkWidget *sel;
  GtkWidget *type;
  GtkWidget *dxtype;
  GtkWidget *dytype;
  GtkWidget *deltatype;
  GtkWidget *dx;
  GtkWidget *dy;
  SetsMenu3Struct *menu3;
} gg_Prune_ui;

static gg_Prune_ui pruneui;

/**
 *  Replace update_prune_frame  compwin.c   1641
 */
void gg_update_prune_popup (void)
{
  if (pruneui.top != NULL) {
    gg_set_int (pruneui.dxtype ,(get_graph_xscale(get_cg()) == SCALE_LOG) ? 1 : 0);
    gg_set_int (pruneui.dytype ,(get_graph_yscale(get_cg()) == SCALE_LOG) ? 1 : 0);
  }
}


/**
 *  Replace create_prune_frame  compwin.c   1569
 */
void gg_create_prune_popup (void)
{
  GtkWidget *vb ,*sep;

  if (pruneui.top == NULL) {
    pruneui.top = gg_CreateAACDialog ("Prune data"  ,gg_prune_AAC_CB ,0 ,0 ,&vb);
    pruneui.menu3 = NULL;
    pruneui.sel = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_MULTIPLE
				      ,popup_width ,list_height
				      ,NULL
				      ,&(pruneui.menu3)
				      ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,pruneui.sel);

    pruneui.type = gg_combo_new (vb  ,"Prune type: ", 5
					 ,"Interpolation"
					 ,"Circle"
					 ,"Ellipse"
					 ,"Rectangle");
    pruneui.dx    = gg_entry_new  (vb ,"Delta X:" ,17);
    pruneui.dy    = gg_entry_new  (vb ,"Delta Y:" ,17);

    sep = gtk_hseparator_new ();
    gtk_box_pack_start (GTK_BOX (vb) ,sep ,FALSE ,TRUE ,1);

    pruneui.deltatype = gg_combo_new (vb ,"Type of Delta coordinates:" ,3
					      ,"Viewport"
					      ,"World");
    pruneui.dxtype    = gg_combo_new (vb ,"Scaling of Delta X:" ,3
					      ,"Linear"
					      ,"Logarithmic");
    pruneui.dytype    = gg_combo_new (vb ,"Scaling of Delta Y:" ,3
					      ,"Linear"
					      ,"Logarithmic");
    gg_update_prune_popup ();
    gg_prune_toggle ();

    g_signal_connect (pruneui.type 	,"changed" ,G_CALLBACK (gg_update_prune_popup) ,NULL);
    g_signal_connect (pruneui.type 	,"changed" ,G_CALLBACK (gg_prune_toggle)       ,NULL);
    g_signal_connect (pruneui.deltatype ,"changed" ,G_CALLBACK (gg_prune_toggle) ,NULL);
  }
  gtk_widget_show_all (pruneui.top);
}

static void gg_prune_toggle (void)
{
  int typeno ,deltatypeno;

  typeno      = gg_get_int (pruneui.type);
  deltatypeno = gg_get_int (pruneui.deltatype);

  switch (typeno) {
  case PRUNE_CIRCLE:
    gtk_widget_set_sensitive (pruneui.dx ,TRUE);
    gtk_widget_set_sensitive (pruneui.dy ,FALSE);
    switch (deltatypeno) {
    case PRUNE_VIEWPORT:
      gtk_widget_set_sensitive (pruneui.dxtype ,FALSE);
      gtk_widget_set_sensitive (pruneui.dytype ,FALSE);
      break;
    case PRUNE_WORLD:
      gtk_widget_set_sensitive (pruneui.dxtype ,TRUE);
      gtk_widget_set_sensitive (pruneui.dytype ,FALSE);
      break;
    }
    break;
  case PRUNE_ELLIPSE:
  case PRUNE_RECTANGLE:
    gtk_widget_set_sensitive (pruneui.dx ,TRUE);
    gtk_widget_set_sensitive (pruneui.dy ,TRUE);
    switch (deltatypeno) {
    case PRUNE_VIEWPORT:
      gtk_widget_set_sensitive (pruneui.dxtype ,FALSE);
      gtk_widget_set_sensitive (pruneui.dytype ,FALSE);
      break;
    case PRUNE_WORLD:
      gtk_widget_set_sensitive (pruneui.dxtype ,TRUE);
      gtk_widget_set_sensitive (pruneui.dytype ,TRUE);
      break;
    }
    break;
  case PRUNE_INTERPOLATION:
    gtk_widget_set_sensitive (pruneui.dx ,FALSE);
    gtk_widget_set_sensitive (pruneui.dy ,TRUE);
    switch (deltatypeno) {
    case PRUNE_VIEWPORT:
      gtk_widget_set_sensitive (pruneui.dxtype ,FALSE);
      gtk_widget_set_sensitive (pruneui.dytype ,FALSE);
      break;
    case PRUNE_WORLD:
      gtk_widget_set_sensitive (pruneui.dxtype ,FALSE);
      gtk_widget_set_sensitive (pruneui.dytype ,TRUE);
      break;
    }
    break;
  }
}


/**
 *  Replace  do_prune_proc    compwin.c   1710
 */
static void gg_prune_AAC_CB (GtkWidget *w ,gint reponse)
{
  int *selsets;
  int i ,cnt;
  int setno ,typeno ,deltatypeno;
  int dxtype ,dytype;
  double deltax ,deltay;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    selsets = gw_list_selected_list (GW_LIST (pruneui.sel) ,&cnt);
    if (cnt == 0)  {
      errmsg  ("No sets selected");
      return;
    }
    typeno      = gg_get_int (pruneui.type);
    deltatypeno = gg_get_int (pruneui.deltatype);
    dxtype      = gg_get_int (pruneui.dxtype);
    dytype      = gg_get_int (pruneui.dytype);

    if (GTK_WIDGET_SENSITIVE (pruneui.dx)) {
      if (gg_evalexpr (pruneui.dx ,&deltax) != RETURN_SUCCESS)
	return;
    } else{
      deltax = 0.0;
    }

    if (GTK_WIDGET_SENSITIVE (pruneui.dy)) {
      if (gg_evalexpr (pruneui.dy ,&deltay) != RETURN_SUCCESS)
	return;
    } else{
      deltay = 0.0;
    }

    for (i = 0; i < cnt; i++) {
      setno = selsets[i];
      do_prune (setno ,typeno ,deltatypeno ,deltax ,deltay ,dxtype ,dytype);
    }
    gg_update_all_sets_lists ();
    xfree (selsets);
    gg_drawgraph ();
  }

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}

/***** Apply a digital filter in set 2 to set 1 *****/

typedef struct _gg_Digf_ui {
  GtkWidget *top;
  GtkWidget *sel1 ,*sel2;
  GtkWidget *type;
  GtkWidget *region;
  GtkWidget *rinvert;
  SetsMenu3Struct *sel1_menu3;
  SetsMenu3Struct *sel2_menu3;
} gg_Digf_ui;

static gg_Digf_ui digfui;

/**
 *  Replace create_digf_frame  compwin.c  1765
 */
void gg_create_digf_popup (void)
{
  GtkWidget *vb;

  if (digfui.top == NULL) {
    digfui.top  = gg_CreateAACDialog ("Digital filter"  ,gg_digfilter_AAC_CB ,0 ,0 ,&vb);
    digfui.sel1_menu3 = NULL;
    digfui.sel1 = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_BROWSE
				       ,popup_width ,list_height
				      ,NULL
				      ,&(digfui.sel1_menu3)
				      ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,digfui.sel1);

    digfui.sel2_menu3 = NULL;
    digfui.sel2 = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_BROWSE
				       ,popup_width ,list_height
				      ,NULL
				      ,&(digfui.sel2_menu3)
				      ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,digfui.sel2);

  }
  gtk_widget_show_all (digfui.top);
}

/**
 *  Replace  do_digfilter_proc    compwin.c   1804
 */
static void gg_digfilter_AAC_CB (GtkWidget *w ,gint reponse)
{
  int set1, set2;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    set1 = gw_list_get_first_selected_row_num (GW_LIST(digfui.sel1));
    set2 = gw_list_get_first_selected_row_num (GW_LIST(digfui.sel2));
    do_digfilter (set1 ,set2);
    gg_update_all_sets_lists ();
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/************ Linear convolution **************/


typedef struct _gg_Lconv_ui {
  GtkWidget *top;
  GtkWidget *sel1 ,*sel2;
  GtkWidget *type;
  GtkWidget *region;
  GtkWidget *rinvert;
  SetsMenu3Struct *sel1_menu3;
  SetsMenu3Struct *sel2_menu3;
} gg_Lconv_ui;

static gg_Lconv_ui lconvui;

/**
 *  Replace create_lconv_frame  compwin.c  1834
 */
void gg_create_lconv_popup (void)
{
  GtkWidget *vb;

  if (lconvui.top == NULL) {
    lconvui.top  = gg_CreateAACDialog ("Linear convolution"  ,gg_linearc_AAC_CB ,0 ,0 ,&vb);
    lconvui.sel1_menu3 = NULL;
    lconvui.sel1 = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_BROWSE
				       ,popup_width ,list_height
				       ,NULL
				       ,&(lconvui.sel1_menu3)
				       ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,lconvui.sel1);

    lconvui.sel2_menu3 = NULL;
    lconvui.sel2 = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_BROWSE
				       ,popup_width ,list_height
				       ,NULL
				       ,&(lconvui.sel2_menu3)
				       ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,lconvui.sel2);

  }
  gtk_widget_show_all (lconvui.top);
}

/**
 *  Replace  do_linearc_proc    compwin.c   1873
 */
static void gg_linearc_AAC_CB (GtkWidget *w ,gint reponse)
{
  int set1, set2;

  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_APPLY ) {
    set1 = gw_list_get_first_selected_row_num (GW_LIST(lconvui.sel1));
    set2 = gw_list_get_first_selected_row_num (GW_LIST(lconvui.sel2));
    do_linearc (get_cg () ,set1 ,get_cg () ,set2);
    gg_update_all_sets_lists ();
    gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide (w);
  }
}


/************** Rotate, scale, translate ************/

#define GEOM_RESET  1001

typedef struct _gg_Geom_ui {
  GtkWidget *top;
  GtkWidget *sel ,*sel2;
  GtkWidget *order;
  GtkWidget *degrees;
  GtkWidget *rotx;
  GtkWidget *roty;
  GtkWidget *scalex;
  GtkWidget *scaley;
  GtkWidget *transx;
  GtkWidget *transy;
  GtkWidget *region;
  GtkWidget *rinvert;
  SetsMenu3Struct *menu3;
} gg_Geom_ui;

static gg_Geom_ui gui;

/**
 *  Replace create_geom_frame  compwin.c   1916
 */
void gg_create_geom_popup (void)
{
  GtkWidget *vb;

  if (gui.top == NULL) {
    gui.top = gg_CreateAACDialog ("Geometric transformations"  ,gg_geom_AAC_CB ,0 ,0 ,&vb);
    gtk_dialog_add_buttons (GTK_DIALOG(gui.top) ,"Reset" ,GEOM_RESET ,NULL);
    gui.menu3 = NULL;
    gui.sel = gg_CreateSetChoice ("Apply to set:" ,GTK_SELECTION_MULTIPLE
				  ,popup_width ,list_height
				  ,NULL
				  ,&(gui.menu3)
				  ,NULL);
    gtk_box_pack_start_defaults (GTK_BOX (vb) ,gui.sel);

    gui.order = gg_combo_new (vb ,"Apply in order:" ,7
				      ,"Rotate, translate, scale"
				      ,"Rotate, scale, translate"
				      ,"Translate, scale, rotate"
				      ,"Translate, rotate, scale"
				      ,"Scale, translate, rotate"
				      ,"Scale, rotate, translate");

    gui.degrees = gg_entry_new (vb ,"Rotation (degrees):" ,10);
    gui.rotx    = gg_entry_new (vb ,"Rotate about X = :"  ,10);
    gui.roty    = gg_entry_new (vb ,"Rotate about Y = :"  ,10);
    gui.scalex  = gg_entry_new (vb ,"Scale X:"            ,10);
    gui.scaley  = gg_entry_new (vb ,"Scale Y:"            ,10);
    gui.transx  = gg_entry_new (vb ,"Translate X:"        ,10);
    gui.transy  = gg_entry_new (vb ,"Translate Y:"        ,10);

    gg_setstr (gui.degrees ,"0.0");
    gg_setstr (gui.rotx    ,"0.0");
    gg_setstr (gui.roty    ,"0.0");
    gg_setstr (gui.scalex  ,"1.0");
    gg_setstr (gui.scaley  ,"1.0");
    gg_setstr (gui.transx  ,"0.0");
    gg_setstr (gui.transy  ,"0.0");
  }
  gtk_widget_show_all (gui.top);
}

/**
 *  Replace  do_geom_proc    compwin.c   1990
 */
static void gg_geom_AAC_CB (GtkWidget *w ,gint reponse)
{
  int i, j, k, cnt, order[3], setno, ord;
  int *selsets;
  double degrees, sx, sy, rotx, roty, tx, ty, xtmp, ytmp, *x, *y;
  double cosd, sind;

  if (reponse == GEOM_RESET) {
    gg_setstr (gui.degrees ,"0.0");
    gg_setstr (gui.rotx    ,"0.0");
    gg_setstr (gui.roty    ,"0.0");
    gg_setstr (gui.scalex  ,"1.0");
    gg_setstr (gui.scaley  ,"1.0");
    gg_setstr (gui.transx  ,"0.0");
    gg_setstr (gui.transy  ,"0.0");
  } else if (reponse == GTK_RESPONSE_ACCEPT ||  reponse == GTK_RESPONSE_APPLY) {
    selsets = gw_list_selected_list (GW_LIST (gui.sel) ,&cnt);
    if (cnt == 0)  {
      errmsg  ("No sets selected");
      return;
    }
    ord = gg_get_int (gui.order);
    switch (ord) {
    case 0:
      order[0] = 0;		/* rotate */
      order[1] = 1;		/* translate */
      order[2] = 2;		/* scale */
      break;
    case 1:
      order[0] = 0;
      order[1] = 2;
      order[2] = 1;
      break;
    case 2:
      order[0] = 1;
      order[1] = 2;
      order[2] = 0;
      break;
    case 3:
      order[0] = 1;
      order[1] = 0;
      order[2] = 2;
      break;
    case 4:
      order[0] = 2;
      order[1] = 1;
      order[2] = 0;
      break;
    case 5:
      order[0] = 2;
      order[1] = 0;
      order[2] = 1;
      break;
    }

	/* check input fields */
    if (gg_evalexpr (gui.degrees, &degrees) != RETURN_SUCCESS ||
        gg_evalexpr (gui.rotx, &rotx)       != RETURN_SUCCESS ||
        gg_evalexpr (gui.roty, &roty)       != RETURN_SUCCESS ||
        gg_evalexpr (gui.transx, &tx)       != RETURN_SUCCESS ||
        gg_evalexpr (gui.transy, &ty)       != RETURN_SUCCESS ||
        gg_evalexpr (gui.scalex, &sx)       != RETURN_SUCCESS ||
        gg_evalexpr (gui.scaley, &sy)       != RETURN_SUCCESS )
      return;

    degrees = M_PI / 180.0 * degrees;
    cosd = cos(degrees);
    sind = sin(degrees);


    for (k = 0; k < cnt; k++) {
      setno = selsets[k];
      if (is_set_active (get_cg (), setno)) {
	x = getx (get_cg (), setno);
	y = gety (get_cg (), setno);
	for (j = 0; j < 3; j++) {
	  switch (order[j]) {
	  case 0:			/* rotate */
	    if (degrees == 0.0) {
	      break;
	    }
	    for (i = 0; i < getsetlength (get_cg (), setno); i++) {
	      xtmp = x[i] - rotx;
	      ytmp = y[i] - roty;
	      x[i] = rotx + cosd * xtmp - sind * ytmp;
	      y[i] = roty + sind * xtmp + cosd * ytmp;
	    }
	    break;
	  case 1:			/* translate */
	    for (i = 0; i < getsetlength (get_cg (), setno); i++) {
	      x[i] += tx;
	      y[i] += ty;
	    }
	    break;
	  case 2:			/* scale */
	    for (i = 0; i < getsetlength (get_cg (), setno); i++) {
	      x[i] *= sx;
	      y[i] *= sy;
	    }
	    break;
	  }		/* end case */
	}		/* end for j */
    gg_update_all_sets_lists ();
      }			/* end if */
    }			/* end for k */
  xfree (selsets);
  set_dirtystate();
  gg_drawgraph ();
  }
  if (reponse == GTK_RESPONSE_ACCEPT || reponse == GTK_RESPONSE_CLOSE) {
    gtk_widget_hide_all (gui.top);
  }
}
