/*
	Program mviewm.

	Show nD data on screen.

	This code is a part of the MNMR package from
	Carlsberg Research Laboratory.

	(C) Copyright 1992-2000 by Carlsberg A/S
	    All Rights Reserved


	20000503	Modified for Motif 1.2
*/
#include <nmrio.h>
#include <stdio.h>
#include <fcntl.h>
#include <math.h>
#include <signal.h>

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/Scale.h>
#include <Xm/Label.h>
#include <Xm/ScrollBar.h>
#include <Xm/RowColumn.h>
#include <Xm/TextF.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/MessageB.h>

#ifndef XmSET
#define XmSET True
#endif

#ifndef XmUNSET
#define XmUNSET False
#endif

#include "Map.h"
#include "Slice.h"

void quit_callback();
void slider1_callback();
void slider2_callback();
void button1_callback();
void button2_callback();
void button3_callback();
void scale_callback();
void xdim_callback_dont_doit();
void xdim_callback_doit();
void xdim_callback();
void ydim_callback_dont_doit();
void ydim_callback_doit();
void ydim_callback();
void update_index_editors();
void read_index_editors();
void sliceno_callback();
void phaseoffset_callback();
void phase0_callback();
void phase1_callback();
void phase1_minus_callback();
void phase1_plus_callback();
void wdim_callback();
void motion_callback();
void apply_callback();
void selectslice_callback();
void selectphaseoffset_callback();
void stopslice_callback();
void scaleupslice_callback();
void scaledownslice_callback();
void shiftupslice_callback();
void shiftdownslice_callback();
void getslicedata();
void update_phase_sliders();
float unitcircle();
double dmin, dmax;
int minmax_valid;
static int *idmin, *idmax, *idataptr;

int n;
Arg wargs[1000];

Widget toplevel, form, form2, map, slider1, slider2, quit, selectslice, selectphaseoffset, headline, 
       scale_up, scale_down, scale_full,
       phase0_title, phase0_scale,
       phase1_title, phase1_minus, phase1_scale, phase1_plus,
       first_dim, last_dim,
       xdim_r,ydim_r,wdim_r,
       set_xdim[NMR_MAX_DIM-2], set_ydim[NMR_MAX_DIM-2], set_wdim[2],
       sliceno[NMR_MAX_DIM-2], slicenotext[NMR_MAX_DIM-2],
       ppm_text[NMR_MAX_DIM],
       xdim_text, ydim_text, wdim_text,
       xdim_edit, ydim_edit;

Widget apply;
static Widget xdim_dialog=NULL;
static Widget ydim_dialog=NULL;

#define MAKELIST_SELECT 0
#define MAKELIST_RADIO 1

int field_dim[NMR_MAX_DIM-2], nfields;
char name[16];
char disk[16];
char user[16];
char cheadline[200];
int expno, procno;
float *dataptr=NULL;
int datarow, datacol;
int fftdatarow, fftdatacol;
int extdatarow, extdatacol;
int xdim_index, ydim_index;
float offset, width;
float phase0, phase1;
int phase1_min, phase1_max;
float iphase0, iphase1;
int *ioffset, *iwidth;
int xdim=0, ydim=1;
int last_xdim= -1, last_ydim= -2;
int currentindex[NMR_MAX_DIM]; /* current plane for 3D, current box for 4D, unused for 2D */
static char clabel[100];

/*
	scale is the current scale of the display. If one of the scale buttons is hit, two
	things can happen:

	The scale is lowered: change scale of display, so that current display is contained within.

	The scale is increased: set newscale value to desired value. When the mouse is hit in the
	window, display correct scaling around value hit.

*/
int scale, newscale;
int collow, colhigh, rowlow, rowhigh, yindex, xhair, yhair;
int dim; /* dimension to work with */

extern void CvtStringToFloat();

struct NMRFILE *file1, *nmrio_open();

#define MAPSIZE 512

#define SLIDERMAX 128
#define SLIDEREXTENT 4
int slider1_position=SLIDERMAX-SLIDEREXTENT, slider2_position=SLIDERMAX-SLIDEREXTENT;

/*
	Structure for slices created.
*/

struct slice_inf
{
  struct slice_inf *next_slice;
  int dim; /* dimension: 0, 1 etc. */
  int sliceno; /* slice number */
  int ndata,nzdata; /* orig. no. of points(increased to power of 2), and zerofilled no. of points. */
  float sweep;
  Widget shell;
  Widget form;
  Widget slice;
  float *dataptr; /* contains a copy of the WHOLE slice! */

  /* initial limits */
  int colmin, colmax; /* start and end point number in slice */
  float dmin, dmax;

  /* current limits */
  int ccolmin, ccolmax;
  float cdmin, cdmax;
};

struct slice_inf *first_slice=NULL;

static void MKXtDefaultError(message)
char *message;
{
  fprintf(stderr, "Error: %s\n", message);
  kill(getpid(), SIGQUIT);
}

static int mkpow2(i)
int i;
{
  int j;

  j=1;

  while(j<i) j*=2;
  return(j);
}

main(argc, argv)
int argc;
char **argv;
{
  int i,j;
  Widget xref;
  static char wtitle[80];

  /*
	Usage: mview name expno procno disk user
  */

  n=0;
  toplevel=XtInitialize("hansen", "Mview", (XrmOptionDescRec *) wargs, n, &argc, argv);

#ifdef DEBUG
  XtSetErrorHandler(MKXtDefaultError);
#endif

  XtAddConverter(XtRString, XtRFloat, CvtStringToFloat, NULL, 0);

  if(argc<6)
  {
    printf("Usage: mview <name> <expno> <procno> <disk> <user>\n");
    exit(-1);
  }

  strcpy(name, argv[1]);
  strcpy(disk, argv[4]);
  strcpy(user, argv[5]);
  sscanf(argv[2], "%d", &expno);
  sscanf(argv[3], "%d", &procno);

  ioffset = (int *) &offset;
  iwidth = (int *) &width;


  /*
	Open the file:
  */

  file1=nmrio_open(name, disk, user, expno, procno, O_RDONLY);

  if(file1 == NULL)
  {
    printf("Input file not found.\n");
    exit(-1);
  }

  n=0;
  sprintf(wtitle, "%s %d %d %s %s", name, expno, procno, disk, user);
  XtSetArg(wargs[n], XtNtitle, wtitle); n++;
  XtSetValues(toplevel, wargs, n);

  for(i=0; i<NMR_N_DIM(file1); i++) currentindex[i]=0;
  xdim_index = 0;
  ydim_index = 0;

  dmin = file1->dmin;
  dmax = file1->dmax;

  minmax_valid = dmin < dmax;

#ifdef DEBUG
  printf("Got from file: dmin: %g dmax: %g\n", dmin, dmax);
#endif

  if(!minmax_valid)
  {
    printf("Ignoring min and max values from file header.\n");
  }

  /*
	Create the window stuff:
  */

  n=0;
  form=XtCreateManagedWidget("form", xmFormWidgetClass, toplevel,
       wargs, n);

  n=0;
  sprintf(cheadline, "%s", "                                                            ");
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(cheadline)); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  headline=XtCreateManagedWidget("headline", xmLabelWidgetClass,
	   form, wargs, n);


  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, headline); n++;
  form2=XtCreateManagedWidget("form2", xmFormWidgetClass, form,
       wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Quit")); n++;
  quit=XtCreateManagedWidget("quit", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(quit, XmNactivateCallback, quit_callback, NULL);

  /*
	Make widgets to navigate through dimensions.
  */

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, quit); n++;
  XtSetArg(wargs[n], XmNmarginTop, 5); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("X dimension: ")); n++;
  xdim_text=XtCreateManagedWidget("xdimtext", xmLabelWidgetClass, form2,
       wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, quit); n++;
  XtSetArg(wargs[n], XmNleftWidget, xdim_text); n++;
  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  /*
  XtSetArg(wargs[n], XmNradioAlwaysOne, True); n++;
  XtSetArg(wargs[n], XmNradioBehavior, True); n++;

  xdim_r = XtCreateManagedWidget("rc", xmRowColumnWidgetClass, form2,
       wargs, n);
  */
  xdim_r = XmCreateRadioBox(form2, "xdim_r", wargs, n);

  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    sprintf(clabel, "%d", i);
    n=0;
    set_xdim[i] = XtCreateManagedWidget(clabel, xmToggleButtonGadgetClass, xdim_r, wargs, n);
    XtAddCallback(set_xdim[i], XmNvalueChangedCallback, xdim_callback, (XtPointer) i);
  }
  XmToggleButtonGadgetSetState(set_xdim[xdim], True, False);
  XtManageChild(xdim_r);

  /*
	Create editor to set index no.
  */

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, xdim_r); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, xdim_r); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNcolumns, 10); n++;
  XtSetArg(wargs[n], XmNvalue, "0"); n++;
  xdim_edit=XtCreateManagedWidget("xdim_edit", xmTextFieldWidgetClass, form2, wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, xdim_text); n++;
  XtSetArg(wargs[n], XmNtopOffset, 10); n++;
  XtSetArg(wargs[n], XmNmarginTop, 5); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Y dimension: ")); n++;
  ydim_text=XtCreateManagedWidget("ydimtext", xmLabelWidgetClass, form2,
       wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, ydim_text); n++;
  XtSetArg(wargs[n], XmNleftWidget, ydim_text); n++;
  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  XtSetArg(wargs[n], XmNradioAlwaysOne, True); n++;
  XtSetArg(wargs[n], XmNradioBehavior, True); n++;
  ydim_r = XtCreateManagedWidget("rc", xmRowColumnWidgetClass, form2,
       wargs, n);

  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    sprintf(clabel, "%d", i);
    n=0;
    if(i==xdim)
    {
      XtSetArg(wargs[n], XmNsensitive, False); n++;
    }
    set_ydim[i] = XtCreateManagedWidget(clabel, xmToggleButtonGadgetClass, ydim_r, wargs, n);
    XtAddCallback(set_ydim[i], XmNvalueChangedCallback, ydim_callback, (XtPointer) i);
  }
  XmToggleButtonGadgetSetState(set_ydim[ydim], True, False);

  /*
	Create editor to set index no.
  */

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, ydim_r); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, ydim_r); n++;
  XtSetArg(wargs[n], XmNcolumns, 10); n++;
  XtSetArg(wargs[n], XmNvalue, "0"); n++;
  ydim_edit=XtCreateManagedWidget("ydim_edit", xmTextFieldWidgetClass, form2, wargs, n);

  update_index_editors();

  /*
	Make fields for selecting slice number in the dimensions not used for display on screen.
  */

  nfields=0;

  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    if(i!=xdim && i!=ydim)
    {
      n=0;
      if(nfields==0)
      {
	XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
	XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
	XtSetArg(wargs[n], XmNtopWidget, ydim_text); n++;
	XtSetArg(wargs[n], XmNtopOffset, 20); n++;
      }
      else
      {
	XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
	XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
	XtSetArg(wargs[n], XmNtopWidget, slicenotext[nfields-1]); n++;
	XtSetArg(wargs[n], XmNtopOffset, 10); n++;
      }
      XtSetArg(wargs[n], XmNmarginTop, 5); n++;
      if(i==2)
      {
	sprintf(clabel, "Set index for 3rd dimension: ");
      }
      else
      {
	sprintf(clabel, "Set index for %dth dimension: ", i+1);
      }
      XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(clabel)); n++;
      slicenotext[nfields]=XtCreateManagedWidget("fieldtext", xmLabelWidgetClass, form2,
	   wargs, n);

      n=0;
      XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
      XtSetArg(wargs[n], XmNleftWidget, slicenotext[nfields]); n++;
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(wargs[n], XmNtopWidget, slicenotext[nfields]); n++;
      XtSetArg(wargs[n], XmNcolumns, 10); n++;
      XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
      XtSetArg(wargs[n], XmNvalue, "0"); n++;
      sliceno[nfields]=XtCreateManagedWidget("field", xmTextFieldWidgetClass, form2, wargs, n);
      XtAddCallback(sliceno[nfields], XmNactivateCallback, sliceno_callback, (XtPointer) nfields);
      field_dim[nfields++]=i;
    }
  }

  n=0;
  if(nfields==0)
  {
    XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(wargs[n], XmNtopWidget, ydim_text); n++;
  }
  else
  {
    XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(wargs[n], XmNtopWidget, slicenotext[nfields-1]); n++;
  }
  XtSetArg(wargs[n], XmNtopOffset, 10); n++;

  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Select Slice")); n++;
  selectslice=XtCreateManagedWidget("selectslice", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(selectslice, XmNactivateCallback, selectslice_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, selectslice); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, selectslice); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Select Phase Offset")); n++;
  selectphaseoffset=XtCreateManagedWidget("phaseoffset", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(selectphaseoffset, XmNactivateCallback, selectphaseoffset_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, selectslice); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, selectslice); n++;
  XtSetArg(wargs[n], XmNtopOffset, 10); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Scale FULL")); n++;
  scale_full=XtCreateManagedWidget("scale_full", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(scale_full, XmNactivateCallback, scale_callback, 0);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, scale_full); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, scale_full); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Zoom in")); n++;
  scale_down=XtCreateManagedWidget("scale_down", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(scale_down, XmNactivateCallback, scale_callback, (XtPointer) -1);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, scale_down); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, scale_down); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Zoom out")); n++;
  scale_up=XtCreateManagedWidget("scale_up", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(scale_up, XmNactivateCallback, scale_callback, (XtPointer) 1);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, scale_full); n++;
  XtSetArg(wargs[n], XmNtopOffset, 20); n++;
  XtSetArg(wargs[n], XmNmarginTop, 5); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Working dimension: ")); n++;
  wdim_text=XtCreateManagedWidget("wdimtext", xmLabelWidgetClass, form2,
       wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, wdim_text); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, wdim_text); n++;
  XtSetArg(wargs[n], XmNleftOffset, 10); n++;
  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  wdim_r = XtCreateManagedWidget("rc", xmRowColumnWidgetClass, form2,
       wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNset, dim==0?True:False); n++;
  set_wdim[0] = XtCreateManagedWidget("0", xmToggleButtonGadgetClass, wdim_r, wargs, n);
  XtAddCallback(set_wdim[0], XmNvalueChangedCallback, wdim_callback, (XtPointer) 0);

  n=0;
  XtSetArg(wargs[n], XmNset, dim==1?True:False); n++;
  set_wdim[1] = XtCreateManagedWidget("1", xmToggleButtonGadgetClass, wdim_r, wargs, n);
  XtAddCallback(set_wdim[1], XmNvalueChangedCallback, wdim_callback, (XtPointer) 1);

  n=0;
  XtSetArg(wargs[n], XmNmarginTop, 5); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, wdim_text); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Zero-order phase correction:")); n++;
  phase0_title=XtCreateManagedWidget("phase0_title", xmLabelWidgetClass, form2,
                wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, phase0_title); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNshowValue, True); n++;
  XtSetArg(wargs[n], XmNminimum, 0); n++;
  XtSetArg(wargs[n], XmNmaximum, 360); n++;
  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  phase0_scale=XtCreateManagedWidget("phase0_scale", xmScaleWidgetClass, form2, wargs, n);
  XtAddCallback(phase0_scale, XmNvalueChangedCallback, phase0_callback, NULL);
  XtAddCallback(phase0_scale, XmNdragCallback, phase0_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XmNmarginTop, 5); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, phase0_scale); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("First-order phase correction:")); n++;
  phase1_title=XtCreateManagedWidget("phase1_title", xmLabelWidgetClass, form2,
                wargs, n);

  phase1_min = 0;
  phase1_max = 359;
  n=0;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, phase1_title); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNshowValue, True); n++;
  XtSetArg(wargs[n], XmNminimum, phase1_min); n++;
  XtSetArg(wargs[n], XmNmaximum, phase1_max); n++;
  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  phase1_scale=XtCreateManagedWidget("phase1_scale", xmScaleWidgetClass, form2, wargs, n);
  XtAddCallback(phase1_scale, XmNvalueChangedCallback, phase1_callback, NULL);
  XtAddCallback(phase1_scale, XmNdragCallback, phase1_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, phase1_scale); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("-180")); n++;
  phase1_minus=XtCreateManagedWidget("phase1_minus", xmPushButtonWidgetClass, form2,
       wargs, n);
  XtAddCallback(phase1_minus, XmNactivateCallback, phase1_minus_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, phase1_scale); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(wargs[n], XmNrightWidget, phase1_scale); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("+180")); n++;
  phase1_plus=XtCreateManagedWidget("phase1_plus", xmPushButtonWidgetClass, form2,
       wargs, n);
  XtAddCallback(phase1_plus, XmNactivateCallback, phase1_plus_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, phase1_minus); n++;
  XtSetArg(wargs[n], XmNtopOffset, 10); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Apply phase correction to spectrum")); n++;
  apply=XtCreateManagedWidget("apply", xmPushButtonWidgetClass, form2,
       wargs, n);

  XtAddCallback(apply, XmNactivateCallback, apply_callback, NULL);

  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    n=0;
    if(i==0)
    {
      XtSetArg(wargs[n], XmNmarginTop, 25); n++;
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
      XtSetArg(wargs[n], XmNtopWidget, apply); n++;
    }
    else
    {
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
      XtSetArg(wargs[n], XmNtopWidget, ppm_text[i-1]); n++;
    }
    XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
    sprintf(clabel, "Dimension: %d  Index: %5d  ppm: %7.3f", i, 0, 0.0);
    XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(clabel)); n++;
    ppm_text[i]=XtCreateManagedWidget("fieldtext", xmLabelWidgetClass, form2,
                wargs, n);
  }

  iphase0 = unitcircle(PHASE0(file1, 0));
  iphase1 = PHASE1(file1, 0);
  phase0 = iphase0;
  phase1 = iphase1;

  update_phase_sliders();
  
  n=0;
  XtSetArg(wargs[n], XtNheight, MAPSIZE); n++;
  XtSetArg(wargs[n], XmNminimum, 1); n++;
  XtSetArg(wargs[n], XmNmaximum, SLIDERMAX); n++;
  XtSetArg(wargs[n], XmNsliderSize, SLIDEREXTENT); n++;
  XtSetArg(wargs[n], XmNvalue, SLIDERMAX-SLIDEREXTENT); n++;
  XtSetArg(wargs[n], XmNorientation, XmVERTICAL); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, form2); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, headline); n++;
  XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  slider1=XtCreateManagedWidget("slider1", xmScrollBarWidgetClass,
	  form, wargs, n);

  XtAddCallback(slider1, XmNdecrementCallback, slider1_callback, NULL);
  /* XtAddCallback(slider1, XmNdragCallback, slider1_callback, NULL); */
  XtAddCallback(slider1, XmNincrementCallback, slider1_callback, NULL);
  XtAddCallback(slider1, XmNpageDecrementCallback, slider1_callback, NULL);
  XtAddCallback(slider1, XmNpageIncrementCallback, slider1_callback, NULL);
  XtAddCallback(slider1, XmNvalueChangedCallback, slider1_callback, NULL);

  n=0;
  XtSetArg(wargs[n], XtNheight, MAPSIZE); n++;
  XtSetArg(wargs[n], XmNminimum, 1); n++;
  XtSetArg(wargs[n], XmNmaximum, SLIDERMAX); n++;
  XtSetArg(wargs[n], XmNsliderSize, SLIDEREXTENT); n++;
  XtSetArg(wargs[n], XmNvalue, SLIDERMAX-SLIDEREXTENT); n++;
  XtSetArg(wargs[n], XmNorientation, XmVERTICAL); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, slider1); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, headline); n++;
  XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  slider2=XtCreateManagedWidget("slider2", xmScrollBarWidgetClass,
	  form, wargs, n);

  XtAddCallback(slider2, XmNdecrementCallback, slider2_callback, NULL);
  /* XtAddCallback(slider2, XmNdragCallback, slider2_callback, NULL); */
  XtAddCallback(slider2, XmNincrementCallback, slider2_callback, NULL);
  XtAddCallback(slider2, XmNpageDecrementCallback, slider2_callback, NULL);
  XtAddCallback(slider2, XmNpageIncrementCallback, slider2_callback, NULL);
  XtAddCallback(slider2, XmNvalueChangedCallback, slider2_callback, NULL);

  readdata();

  collow=0;
  colhigh=datacol-1;
  rowlow=0;
  rowhigh=datarow-1;

  xhair = datacol/2;
  yhair = datarow/2;

  n=0;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
#ifdef DEBUG
  printf("dataptr: %d\n", dataptr);
  printf("datarow: %d, datacol: %d\n", datarow, datacol);
  printf("setting collow: %d, colhigh: %d, rowlow: %d, rowhigh: %d\n", collow, colhigh, rowlow, rowhigh);
#endif
  XtSetArg(wargs[n], XtNdataPtr, dataptr); n++;
  XtSetArg(wargs[n], XtNdataRow, datarow); n++;
  XtSetArg(wargs[n], XtNdataCol, datacol); n++;
  XtSetArg(wargs[n], XtNdMin, *ioffset); n++;
  XtSetArg(wargs[n], XtNdSize, *iwidth); n++;
  XtSetArg(wargs[n], XtNsign, 7); n++;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNleftWidget, slider2); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopWidget, headline); n++;
  XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XtNxHair, xhair); n++;
  XtSetArg(wargs[n], XtNyHair, yhair); n++;
  map=XtCreateManagedWidget("map", XsmapWidgetClass, form, wargs, n);

  XtAddCallback(map, XtNrelease1, button1_callback, NULL);
  XtAddCallback(map, XtNrelease2, button2_callback, NULL);
  XtAddCallback(map, XtNrelease3, button3_callback, NULL);
  XtAddCallback(map, XtNmotion, motion_callback, NULL);

  set_headline();

  XtRealizeWidget(toplevel);
  setwminput(toplevel);
  XtMainLoop();
}

readdata()
{
  int i,j;
  int index[NMR_MAX_DIM];
  int low_bounds[NMR_MAX_DIM];
  int high_bounds[NMR_MAX_DIM];
  float *ptr;
  double a;

#ifdef DEBUG
  printf("readdata called.\n");
#endif

  if(xdim!=last_xdim || ydim!=last_ydim)
  {
  /*
    nmrio_setbuffers(file1, (NMR_N_DIM(file1)>2) ? NXDIM(file1, ydim) : 1);
  */
    nmrio_setdirection(file1, xdim);
    last_xdim=xdim;
    last_ydim=ydim;
#ifdef DEBUG
    printf("NEW BUFFERS.\n");
#endif
  }

#ifdef DEBUG2
  printf("\nBefore reading:\n");
  nmrio_dumpbuf(file1);
#endif

  datarow = NDIM(file1, ydim);
  datacol = NDIM(file1, xdim);
  fftdatarow = FFTSIZE(file1, ydim);
  fftdatacol = FFTSIZE(file1, xdim);
  extdatarow = EXTRACT1(file1, ydim);
  extdatacol = EXTRACT1(file1, xdim);

#ifdef DEBUG
  printf("Rows: %d, Cols: %d\n", datarow, datacol);
  printf("FFT rows: %d, FFT cols: %d\n", fftdatarow, fftdatacol);
  printf("EXTRACT1 rows: %d, cols: %d\n", extdatarow, extdatacol);
#endif

  if(dataptr != NULL)
  {
#ifdef DEBUG
    printf("Free dataptr.\n");
#endif
    XtFree((char *) dataptr);
  }

#ifdef DEBUG
  printf("Allocate %d bytes for dataptr.\n", sizeof(*dataptr)*datarow*datacol);
#endif
  dataptr = (float *) XtMalloc(sizeof(*dataptr)*datarow*datacol);

  if(dataptr == NULL)
  {
    fprintf(stderr, "Couldn't allocate memory for data.\n");
    exit(1);
  }

  /*
	Read in all the data!
  */

  /*
	Setup reading window:
  */
  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    low_bounds[i] = currentindex[i];
    high_bounds[i] = currentindex[i];
    if(low_bounds[i] == 0 && high_bounds[i] == 0) high_bounds[i] = 1;
  }
  low_bounds[xdim] = 0;
  low_bounds[ydim] = 0;
  high_bounds[xdim] = 0;
  high_bounds[ydim] = 0;
  nmrio_setwindow(file1, low_bounds, high_bounds);

  if(!minmax_valid)
  {
    dmin = 1.0e30;
    dmax = -1.0e30;
  }

  for(i=0; i<NDIM(file1, ydim); i++)
  {
    for(j=0; j<NMR_N_DIM(file1); j++) index[j]=currentindex[j];
    index[xdim]=0;
    index[ydim]=i;
    ptr = dataptr+i*datacol;
    nmrio_set_index(file1, index);
    nmrio_read_real_slice(file1, ptr);
#ifdef DEBUG2
    printf("Slice: %d\n", i);
    for(j=0; j<15; j++) printf("  %d %g\n", j, ptr[j]);
#endif
    for(j=NDIM(file1, xdim); j<datacol; j++) ptr[j]=ptr[NDIM(file1,xdim)-1];
    if(!minmax_valid)
    {
      for(j=0; j<NDIM(file1, xdim); j++)
      {
	if(ptr[j]<dmin) dmin=ptr[j];
	if(ptr[j]>dmax) dmax=ptr[j];
      }
#ifdef DEBUG2
      printf("After slice %d: dmin: %g, dmax: %g\n", i, dmin, dmax);
#endif
    }
  }
  for(i=NDIM(file1, ydim); i<datarow; i++)
  {
    ptr=dataptr+i*datacol;
    for(j=0; j<datacol; j++) ptr[j]=0.0;
  }

  if(!minmax_valid)
  {
    if(dmin >= dmax)
    {
      dmin = -1.0;
      dmax = 1.0;
    }
  }

#ifdef DEBUG2
  printf("\nAfter reading:\n");
  nmrio_dumpbuf(file1);
#endif

  a=exp(((double) slider1_position)/4.0- (double) (SLIDERMAX-SLIDEREXTENT)/4.0);
  offset=dmax*a;

  a=exp(((double) slider2_position)/4.0- (double) (SLIDERMAX-SLIDEREXTENT)/4.0);
  width=(dmax-dmin)*a;

}

/*	Callbacks	*/

void quit_callback(w, client_data, user_data)
Widget w;
caddr_t client_data, user_data;
{
  /*
	Print out phases before terminating:
  */

  printf("Final phases:\n");
  printf("Dim: %d, delta0: %g, delta1: %g\n", dim, phase0-iphase0, phase1-iphase1);
  nmrio_close(file1);
  exit(0);
}

void slider1_callback(w, client_data, position)
Widget w;
caddr_t client_data;
XmScrollBarCallbackStruct *position;
{
  double a;
#ifdef DEBUG
  printf("slider1_callback: %d\n", position->value);
#endif

  slider1_position=position->value;

  a=exp(((double) slider1_position)/4.0- (double) (SLIDERMAX-SLIDEREXTENT)/4.0);

  offset=dmax*a;
#ifdef DEBUG
  printf("dmin: %g, dmax: %g, offset: %g, width: %g\n",
	 dmin, dmax, offset, width);
  printf("collow: %d, colhigh: %d, rowlow: %d, rowhigh: %d\n", collow, colhigh, rowlow, rowhigh);
#endif

  set_headline();

  n=0;
  XtSetArg(wargs[n], XtNdMin, *ioffset); n++;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetValues(map, wargs, n);
}

void slider2_callback(w, client_data, position)
Widget w;
caddr_t client_data;
XmScrollBarCallbackStruct *position;
{
  double a;
#ifdef DEBUG
  printf("slider2_callback: %d\n", position->value);
#endif

  slider2_position = position->value;

  a=exp(((double) slider2_position)/4.0- (double) (SLIDERMAX-SLIDEREXTENT)/4.0);

  width=(dmax-dmin)*a;
#ifdef DEBUG
  printf("dmin: %g, dmax: %g, offset: %g, width: %g\n",
	 dmin, dmax, offset, width);
#endif

  set_headline();

  n=0;
  XtSetArg(wargs[n], XtNdSize, *iwidth); n++;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetValues(map, wargs, n);
}

void read_index_editors()
{
  char *s;

  s = XmTextFieldGetString(xdim_edit);
  sscanf(s, "%d", &xdim_index);
  XtFree(s);

  s = XmTextFieldGetString(ydim_edit);
  sscanf(s, "%d", &ydim_index);
  XtFree(s);
}

void update_phase_sliders()
{
  phase1_min = floor(phase1/360.0)*360;
  phase1_max = phase1_min + 359;

  n=0;
  XtSetArg(wargs[n], XmNvalue, (int) phase0); n++;
  XtSetValues(phase0_scale, wargs, n);

  n=0;
  XtSetArg(wargs[n], XmNvalue, (int) phase1); n++;
  XtSetArg(wargs[n], XmNminimum, phase1_min); n++;
  XtSetArg(wargs[n], XmNmaximum, phase1_max); n++;
  XtSetValues(phase1_scale, wargs, n);


}

void update_index_editors()
{
  char clabel[20];

  sprintf(clabel, "%d", xdim_index);
  XmTextFieldSetString(xdim_edit, clabel);

  sprintf(clabel, "%d", ydim_index);
  XmTextFieldSetString(ydim_edit, clabel);
}

void button1_callback(w, client_data, new_xhair)
Widget w;
caddr_t client_data;
struct xhair_coord *new_xhair;
{
  xdim_index = new_xhair->x;
  ydim_index = new_xhair->y;

  update_index_editors();
}

void button2_callback(w, client_data, new_xhair)
Widget w;
caddr_t client_data;
struct xhair_coord *new_xhair;
{
  int xcenter, ycenter, xsize, ysize;

  xcenter=new_xhair->x;
  xsize=(colhigh-collow+1);
  ycenter=new_xhair->y;
  ysize=(rowhigh-rowlow+1);

  xsize = xsize/2;
  ysize = ysize/2;

  collow = xcenter-xsize/2;
  colhigh = xcenter+xsize/2;
  rowlow = ycenter-ysize/2;
  rowhigh = ycenter+ysize/2;

  if(collow<0) collow=0;
  if(colhigh>=datacol) colhigh=datacol-1;
  if(rowlow<0) rowlow=0;
  if(rowhigh>=datarow) rowhigh=datarow-1;

  n=0;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetValues(map, wargs, n);
  set_headline();
}

void button3_callback(w, client_data, new_xhair)
Widget w;
caddr_t client_data;
struct xhair_coord *new_xhair;
{
  int xcenter, ycenter, xsize, ysize;

  xcenter=new_xhair->x;
  xsize=(colhigh-collow+1);
  ycenter=new_xhair->y;
  ysize=(rowhigh-rowlow+1);

  xsize = xsize*2;
  ysize = ysize*2;

  collow = xcenter-xsize/2;
  colhigh = xcenter+xsize/2;
  rowlow = ycenter-ysize/2;
  rowhigh = ycenter+ysize/2;

  if(collow<0) collow=0;
  if(colhigh>=datacol) colhigh=datacol-1;
  if(rowlow<0) rowlow=0;
  if(rowhigh>=datarow) rowhigh=datarow-1;

  n=0;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetValues(map, wargs, n);
  set_headline();
}

void motion_callback(w, client_data, new_xhair)
Widget w;
caddr_t client_data;
struct xhair_coord *new_xhair;
{
  currentindex[xdim]=new_xhair->x;
  currentindex[ydim]=new_xhair->y;
  update_indices();
}

reshow_slices()
{
  struct slice_inf *spnt;
  int nslicedata, *idataptr, *idmin, *idmax;

  /*
	Process each slice at a time.

	Reextract the slice from the datamatrix, perform zerofill, and
	rephase the data.

	The slices are shown again.
  */

  spnt = first_slice;

  while(spnt != NULL)
  {
#ifdef DEBUG
    printf("zerofill(%d) slice: %d, colmin: %d, colmax: %d\n", 1,
	   spnt->sliceno, spnt->colmin, spnt->colmax);
#endif

    getslicedata(spnt);

    idmin = (int *) &(spnt->cdmin);
    idmax = (int *) &(spnt->cdmax);
    nslicedata = ((spnt->colmax)-(spnt->colmin)+1);
    idataptr = (int *) ((spnt->dataptr)+(spnt->colmin));

#ifdef DEBUG
    printf("nslicedata: %d, idataptr: %8.8x\n", nslicedata, (int) idataptr);
    printf("colmin: %d, colmax: %d, zfill: %d\n", spnt->colmin, spnt->colmax, 1);
#endif

    n=0;
    XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
    XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
    XtSetArg(wargs[n], XtNdataPtr, idataptr); n++;
    XtSetArg(wargs[n], XtNdataNpoint, nslicedata); n++;
    XtSetValues(spnt->slice, wargs, n);

    spnt=spnt->next_slice;
  }
}

void scale_callback(w, desiredscale, call_data)
Widget w;
int desiredscale;
caddr_t call_data;
{
  int xcenter,ycenter,xsize,ysize;
#ifdef DEBUG
  printf("scale_callback: desiredscale: %d\n", desiredscale);
#endif

  read_index_editors();

  if(desiredscale == 0)
  {
    collow = 0;
    colhigh = datacol-1;
    rowlow = 0;
    rowhigh = datarow-1;
  }
  else
  {
    xcenter=xdim_index;
    xsize=(colhigh-collow+1);
    ycenter=ydim_index;
    ysize=(rowhigh-rowlow+1);
#ifdef DEBUG
    printf("before: xsize: %d ysize: %d\n", xsize, ysize);
#endif

    if(desiredscale == -1)
    {
      xsize = xsize/2;
      ysize = ysize/2;
    }
    else if(desiredscale == 1)
    {
      xsize = xsize*2;
      ysize = ysize*2;
    }

#ifdef DEBUG
    printf("after: xsize: %d ysize: %d\n", xsize, ysize);
#endif

#ifdef DEBUG
    printf("before: collow: %d colhigh: %d rowlow: %d rowhigh: %d\n", collow, colhigh, rowlow, rowhigh);
#endif

    collow = xcenter-xsize/2;
    colhigh = xcenter+xsize/2;
    rowlow = ycenter-ysize/2;
    rowhigh = ycenter+ysize/2;

#ifdef DEBUG
    printf("after I: collow: %d colhigh: %d rowlow: %d rowhigh: %d\n", collow, colhigh, rowlow, rowhigh);
#endif

    if(collow<0) collow=0;
    if(colhigh>=datacol) colhigh=datacol-1;
    if(rowlow<0) rowlow=0;
    if(rowhigh>=datarow) rowhigh=datarow-1;
#ifdef DEBUG
    printf("after II: collow: %d colhigh: %d rowlow: %d rowhigh: %d\n", collow, colhigh, rowlow, rowhigh);
#endif

  }

  n=0;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetValues(map, wargs, n);
  set_headline();
}

static void ForceDialog(w)
Widget w;
{
  Widget diashell, topshell;
  Window diawindow, topwindow;
  Display *dpy;
  XWindowAttributes xwa;
  XEvent event;
  XtAppContext cxt;

  for (diashell = w; !XtIsShell(diashell); diashell = XtParent(diashell));

  for (topshell = diashell; !XtIsTopLevelShell(topshell); topshell = XtParent(topshell));

  if (XtIsRealized(diashell) && XtIsRealized(topshell))
  {
    dpy = XtDisplay(topshell);
    diawindow = XtWindow(diashell);
    topwindow = XtWindow(topshell);
    cxt = XtWidgetToApplicationContext(diashell);

    while (XGetWindowAttributes(dpy, diawindow, &xwa), xwa.map_state != IsViewable)
    {
      if (XGetWindowAttributes(dpy, topwindow, &xwa), xwa.map_state != IsViewable) break;

      XtAppNextEvent(cxt, &event);
      XtDispatchEvent(&event);
    }
  }
  XmUpdateDisplay(topshell);
}

void apply_callback(w, client_data, call_data)
Widget w;
caddr_t client_data, call_data;
{
  int pdim,i,j;
  int datacol;
  float *dataptr;
  int index[NMR_MAX_DIM], sindex[NMR_MAX_DIM];
  Widget working_dialog;
  Widget progress_scale;
  int islice, nslices, progress_step;
  /*
  	Phase the whole spectrum, reread data.
  */

  closeslices();

  n=0;
  XtSetArg(wargs[n], XmNmessageString,
           XmStringCreateLtoR("Phasing the spectrum, please wait...", XmSTRING_DEFAULT_CHARSET)); n++;
  working_dialog = XmCreateWorkingDialog(toplevel, "working_dialog", wargs, n);

  XtUnmanageChild(XmMessageBoxGetChild(working_dialog, XmDIALOG_HELP_BUTTON));
  XtUnmanageChild(XmMessageBoxGetChild(working_dialog, XmDIALOG_OK_BUTTON));
  XtUnmanageChild(XmMessageBoxGetChild(working_dialog, XmDIALOG_CANCEL_BUTTON));

  nmrio_close(file1);

  file1=nmrio_open(name, disk, user, expno, procno, O_RDWR);

  if(file1 == NULL)
  {
    printf("Could not open NMR file for read/write.\n");
    file1=nmrio_open(name, disk, user, expno, procno, O_RDONLY);
    return;
  }

  pdim = (dim==0)?xdim:ydim;

  nmrio_setdirection(file1, pdim);

  datacol = mkpow2(NDIM(file1, pdim));
  dataptr = (float *) malloc(sizeof(*dataptr)*datacol);

  setupphase(datacol, phase0-iphase0, phase1-iphase1, FFTSIZE(file1, pdim), EXTRACT1(file1, pdim));

  for(i=0; i<NMR_N_DIM(file1); i++) sindex[i]=0;

  nslices=1;
  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    if(i!=NMR_I_DIM(file1)) nslices *= XDIM(file1,i)*NXDIM(file1,i);
  }
#ifdef DEBUG
  printf("Has to phase %d slices.\n", nslices);
#endif

  islice=0;
  progress_step = nslices/100;

  n=0;
  XtSetArg(wargs[n], XmNshowValue, True); n++;
  XtSetArg(wargs[n], XmNeditable, False); n++;
  XtSetArg(wargs[n], XmNslidingMode, XmTHERMOMETER); n++;
  XtSetArg(wargs[n], XmNvalue, islice); n++;
  XtSetArg(wargs[n], XmNminimum, 0); n++;
  XtSetArg(wargs[n], XmNmaximum, nslices); n++;
  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  progress_scale=XtCreateManagedWidget("progress_scale", xmScaleWidgetClass, working_dialog, wargs, n);

  XtManageChild(working_dialog);
  XFlush(XtDisplay(w));
  ForceDialog(working_dialog);

  for(;;)
  {
    for(i=0; i<NMR_N_DIM(file1); i++) index[i]=sindex[i]*XDIM(file1, i);
    for(;;)
    {
#ifdef DEBUG
      printf("Slice: ");
      for(i=0; i<NMR_N_DIM(file1); i++) printf("%d ",index[i]);
      printf("\n");
#endif
      nmrio_set_index(file1, index);

      nmrio_read_real_slice(file1, dataptr);

      for(i=NDIM(file1, dim); i<datacol; i++) dataptr[i]=0.0;

      phase(dataptr);

      nmrio_set_index(file1, index);

      nmrio_write_real_slice(file1, dataptr);

      islice++;
      if( (islice%progress_step == 0) ||
          (islice==nslices) ||
	  (islice==1) )
      {
	n=0;
	XtSetArg(wargs[n], XmNvalue, islice); n++;
	XtSetValues(progress_scale, wargs, n);
	XFlush(XtDisplay(w));
      }

      i=0;
      if(NMR_I_DIM(file1) == 0) i=1;
      for(;;)
      {
	index[i]++;
	if(index[i]%XDIM(file1,i) != 0) break;
	index[i]-=XDIM(file1, i);
	i++;
	if(i==NMR_I_DIM(file1)) i++;
	if(i>=NMR_N_DIM(file1)) goto exit2;
      }
    }
exit2:
    i=0;
    if(NMR_I_DIM(file1) == 0) i=1;
    for(;;)
    {
      sindex[i]++;
      if(sindex[i]<NXDIM(file1, i)) break;
      sindex[i]=0;
      i++;
      if(i==NMR_I_DIM(file1)) i++;
      if(i>=NMR_N_DIM(file1)) goto exit1;
    }
  }
exit1:

  free((char *) dataptr);

  file1->pars_modified = 1;
  file1->phase0[pdim] = unitcircle(phase0);
  file1->phase1[pdim] = phase1;

  nmrio_close(file1);

  file1=nmrio_open(name, disk, user, expno, procno, O_RDONLY);

  last_xdim= -1;
  last_ydim= -2;

  iphase0 = phase0;
  iphase1 = phase1;

  update_map(FALSE);
  set_headline();
  XtUnmanageChild(working_dialog);
}

void phase0_callback(w, clientdata, cbs)
Widget w;
caddr_t clientdata;
XmScaleCallbackStruct *cbs;
{
  float rdphase;

  rdphase = ((float) cbs->value)-phase0;

  phaseslices(rdphase, (float) 0.0);

  phase0 = (float) cbs->value;

  update_phase_sliders();
  set_headline();
}

void phase1_minus_callback(w, clientdata, call_data)
Widget w;
caddr_t clientdata;
caddr_t call_data;
{
  XmScaleCallbackStruct cbs;
  cbs.value = phase1-180;
  phase1_callback(w, NULL, &cbs);
}

void phase1_plus_callback(w, dphase, call_data)
Widget w;
int dphase;
caddr_t call_data;
{
  XmScaleCallbackStruct cbs;
  cbs.value = phase1+180;
  phase1_callback(w, NULL, &cbs);
}

void phase1_callback(w, clientdata, cbs)
Widget w;
caddr_t clientdata;
XmScaleCallbackStruct *cbs;
{
  float rdphase=((float)cbs->value)-phase1;
  float d0phase;
  int ndata;

  switch(dim)
  {
  case 0:
    ndata=datacol;
    d0phase = rdphase * (0.5 - ((double) (xhair+extdatacol) / (double) fftdatacol));
    break;
  case 1:
    ndata=datarow;
    d0phase = rdphase * (0.5 - ((double) (yhair+extdatarow) / (double) fftdatarow));
    break;
  }


  phaseslices(d0phase, rdphase);

  phase0 = unitcircle(phase0+d0phase);
  phase1 += rdphase;

  update_phase_sliders();
  set_headline();
}

void selectslice_callback(w, client_data, call_data)
Widget w;
caddr_t client_data, call_data;
{
  int sliceno, colmin, colmax;
 
  read_index_editors();

#ifdef DEBUG
  printf("xdim_index: %d, ydim_index: %d\n", xdim_index, ydim_index);
#endif

  switch(dim)
  {
  case 0:
    sliceno = ydim_index;
    colmin = collow;
    colmax = colhigh;
    break;
  case 1:
    sliceno = xdim_index;
    colmin = rowlow;
    colmax = rowhigh;
    break;
  }
  setup_slice(sliceno, colmin, colmax);
}

void selectphaseoffset_callback(w, client_data, call_data)
Widget w;
caddr_t client_data, call_data;
{

  read_index_editors();
 
#ifdef DEBUG
  printf("xdim_index: %d, ydim_index: %d\n", xdim_index, ydim_index);
#endif

  xhair = xdim_index;
  yhair = ydim_index;
  n=0;
  XtSetArg(wargs[n], XtNxHair, xhair); n++;
  XtSetArg(wargs[n], XtNyHair, yhair); n++;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetValues(map, wargs, n);
}

set_headline()
{
/*
  sprintf(cheadline, "%s %d %d %s %s: Scaling x %d, xindex: %d, yindex %d",
	  name, expno, procno, disk, user, 1<<(scale-1), xindex, yindex);
*/
  sprintf(cheadline, "Scaling x %d, collow: %d, colhigh: %d, rowlow: %d, rowhigh: %d, p0: %g, p1: %g",
	  1<<(scale-1), collow, colhigh, rowlow, rowhigh, phase0, phase1);

  n=0;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(cheadline)); n++;
  XtSetValues(headline, wargs, n); 
#ifdef DEBUG
  printf("%s\n", cheadline);
#endif

}

update_indices()
{
  int i;
  char clabel[100];

  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    n=0;
    sprintf(clabel, "Dimension: %d  Index: %5d  ppm: %7.3f", i, currentindex[i], WVALUE(file1, i, currentindex[i]));
    XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(clabel)); n++;
    XtSetValues(ppm_text[i], wargs, n); 
  }
}

makelist(parent, xalign, buttontype, addwidth, xoffset,
       yalign, addheight, yoffset, nrow, ncol, valuelist, callback,
       firstwidget, lastwidget, headline)
Widget parent, xalign, yalign;
int buttontype;
int addwidth, addheight;
int nrow, ncol, *valuelist;
void (*callback)();
Widget *firstwidget, *lastwidget;
char *headline;
{
  Widget hline;
  Widget pb;
  Widget rc;
  int irow,icol,j;
  char label[10];

  if(headline!=NULL)
  {
    n=0;
    if(yalign==parent)
    {
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
    }
    else
    {
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
      XtSetArg(wargs[n], XmNtopWidget, yalign); n++;
    }
    if(yoffset)
    {
      XtSetArg(wargs[n], XmNtopOffset, yoffset); n++;
    }
    if(addheight)
    {
    }
    if(xalign==parent)
    {
      XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
    }
    else
    {
      XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
      XtSetArg(wargs[n], XmNleftWidget, xalign); n++;
    }
    if(addwidth)
    {
    }
    if(xoffset)
    {
      XtSetArg(wargs[n], XmNleftOffset, xoffset); n++;
    }
    XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(headline)); n++;
    hline=XtCreateManagedWidget("hline", xmLabelWidgetClass, parent,
	 wargs, n);
  }

  n=0;
  if(headline==NULL)
  {
    if(yalign==parent)
    {
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
    }
    else
    {
      XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
      XtSetArg(wargs[n], XmNtopWidget, yalign); n++;
    }
  }
  else
  {
    XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(wargs[n], XmNtopWidget, hline); n++;
  }
  if(xalign==parent)
  {
    XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  }
  else
  {
    XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(wargs[n], XmNleftWidget, xalign); n++;
  }

  XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL); n++;
  XtSetArg(wargs[n], XmNpacking, XmPACK_COLUMN); n++;
  XtSetArg(wargs[n], XmNnumColumns, nrow); n++;
  XtSetArg(wargs[n], XmNadjustLast, False); n++;
  rc=XtCreateManagedWidget("rc", xmRowColumnWidgetClass, parent,
       wargs, n);


  for(irow=0; irow<nrow; irow++)
  {
    for(icol=0; icol<ncol; icol++)
    {
      j=irow*ncol+icol;
      sprintf(label, "%d", valuelist[j]);

      n=0;
      if(buttontype==MAKELIST_SELECT)
      {
	pb=XtCreateManagedWidget(label, xmPushButtonGadgetClass, rc,
	     wargs, n);
	XtAddCallback(pb, XmNactivateCallback, callback, (XtPointer) valuelist[j]);
      }
      else
      {
	pb=XtCreateManagedWidget(label, xmToggleButtonGadgetClass, rc,
	     wargs, n);
	XtAddCallback(pb, XmNvalueChangedCallback, callback, (XtPointer) valuelist[j]);
      }
    }
  }

  if(headline==NULL)
  {
    *firstwidget=rc;
  }
  else
  {
    *firstwidget=hline;
  }
  *lastwidget=rc;
}

setup_slice(sliceno, colmin, colmax)
int sliceno, colmin, colmax;
{
  Widget stopslice, scaleupslice, scaledownslice, shiftupslice, shiftdownslice;
  struct slice_inf *sinf;
  char title_name[160], ctmp[160];
  char icon_name[160];
  double dmin, dmax;
  int i, i1, i2, nslicedata, slicedim;

  /*
	Create slice selected.

	The slice will obey phase corrections etc.

	All slices displayed must come from same dimension, else phase corrections will be very
	difficult.
  */

#ifdef DEBUG
  printf("Allocate %d bytes for sinf.\n", sizeof(*sinf));
#endif
  sinf = (struct slice_inf *) XtMalloc(sizeof(*sinf));

#ifdef DEBUG
  printf("selecting slice no: %d, dim: %d, colmin: %d, colmax: %d\n",
	 sliceno, dim, colmin, colmax);
#endif

  sinf->next_slice = first_slice;
  first_slice = sinf;
  sinf->dim = dim;
  sinf->sweep = SWEEP(file1, dim);
  sinf->sliceno = sliceno;
  sinf->colmin = colmin;
  sinf->colmax = colmax;
  sinf->ccolmin = colmin;
  sinf->ccolmax = colmax;
  sinf->dataptr = NULL;
  sinf->ndata = mkpow2((dim==0) ? datacol : datarow);
  nslicedata = ((sinf->colmax)-(sinf->colmin)+1);

  /*
	Move the whole slice!
  */

  getslicedata(sinf);

  idmin = (int *) &(sinf->cdmin);
  idmax = (int *) &(sinf->cdmax);
  idataptr = (int *) ((sinf->dataptr)+colmin);

  slicedim = (dim == 0) ? xdim : ydim;

  sprintf(title_name, "Dim %d: Slice %d", slicedim, sliceno);

  /*
	Append indices to title name:
  */

  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    if(i != xdim && i != ydim)
    {
      sprintf(ctmp, ", Index[%d]: %d", i, currentindex[i]);
      strcat(title_name, ctmp);
    }
  }
      
  sprintf(icon_name, "%d", sliceno);

  n=0;
  XtSetArg(wargs[n], XtNtitle, title_name); n++;
  XtSetArg(wargs[n], XtNiconName, icon_name); n++;

  /* sinf->shell = XtCreateApplicationShell("slice", topLevelShellWidgetClass, wargs, n); */
  sinf->shell = XtCreatePopupShell("slice", topLevelShellWidgetClass, toplevel, wargs, n);
  n=0;
  sinf->form = XtCreateManagedWidget("slice_form", xmFormWidgetClass, sinf->shell, wargs, n);

  /*
	Add pushbuttons for this slice:
  */

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("EXIT Slice")); n++;
  stopslice=XtCreateManagedWidget("stopslice", xmPushButtonWidgetClass, sinf->form,
       wargs, n);
  XtAddCallback(stopslice, XmNactivateCallback, stopslice_callback, sinf);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNleftWidget, stopslice); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Scale ^")); n++;
  scaleupslice=XtCreateManagedWidget("scaleupslice", xmPushButtonWidgetClass, sinf->form,
       wargs, n);
  XtAddCallback(scaleupslice, XmNactivateCallback, scaleupslice_callback, sinf);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNleftWidget, scaleupslice); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Scale v")); n++;
  scaledownslice=XtCreateManagedWidget("scaledownslice", xmPushButtonWidgetClass, sinf->form,
       wargs, n);
  XtAddCallback(scaledownslice, XmNactivateCallback, scaledownslice_callback, sinf);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNleftWidget, scaledownslice); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Shift ^")); n++;
  shiftupslice=XtCreateManagedWidget("shiftupslice", xmPushButtonWidgetClass, sinf->form,
       wargs, n);
  XtAddCallback(shiftupslice, XmNactivateCallback, shiftupslice_callback, sinf);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNleftWidget, shiftupslice); n++;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple("Shift v")); n++;
  shiftdownslice=XtCreateManagedWidget("shiftdownslice", xmPushButtonWidgetClass, sinf->form,
       wargs, n);
  XtAddCallback(shiftdownslice, XmNactivateCallback, shiftdownslice_callback, sinf);

  n=0;
  XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNtopWidget, stopslice); n++;
  XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
  XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
  XtSetArg(wargs[n], XtNdataPtr, idataptr); n++;
  XtSetArg(wargs[n], XtNdataNpoint, nslicedata); n++;

  sinf->slice = XtCreateManagedWidget("slice",
           XssliceWidgetClass, sinf->form, wargs, n);
  XtAddCallback(sinf->slice, XmNdestroyCallback, stopslice_callback, sinf);

  XtPopup(sinf->shell, XtGrabNone);
  setwminput(sinf->shell);
}

void getslicedata(sinf)
struct slice_inf *sinf;
{
  int i,i1,i2,ilimit;
  float *tmpslice;
  double slice_dmin, slice_dmax;

  sinf->nzdata = sinf->ndata;

#ifdef DEBUG
  printf("getslicedata: ndata: %d zfill: %d nzdata: %d\n", sinf->ndata, 1, sinf->nzdata);
  printf("sinf: %8.8x\n", (int) sinf);
#endif

  switch(sinf->dim)
  {
  case 0:
    i1=sinf->sliceno*datacol;
    i2=1;
    ilimit=datacol;
    break;
  case 1:
    i1=sinf->sliceno;
    i2=datacol;
    ilimit=datarow;
    break;
  }
#ifdef DEBUG
  printf("start(i1): %d, step(i2): %d, ilimit: %d\n", i1, i2, ilimit);
#endif

  if(sinf->dataptr != NULL)
  {
#ifdef DEBUG
    printf("Free sinf->dataptr\n");
#endif
    XtFree((char *) (sinf->dataptr));
  }
#ifdef DEBUG
  printf("Allocate %d bytes for dataptr.\n", sizeof(*(sinf->dataptr))*(sinf->nzdata));
#endif

  sinf->dataptr = (float *) XtMalloc(sizeof(*(sinf->dataptr))*(sinf->nzdata));

  for(i=0; i<(sinf->ndata); i++)
  {
    if(i>=ilimit)
    {
      sinf->dataptr[i]=dataptr[i1+(ilimit-1)*i2];
    }
    else
    {
      sinf->dataptr[i]=dataptr[i1+i*i2];
    }
  }

  /*
	If phasing has been started since this slice is created, prephase it:
  */
  
  if((iphase0!=phase0) || (iphase1!=phase1))
  {
    phaseslice(sinf, phase0-iphase0, phase1-iphase1);
  }

  slice_dmin = 1e30;
  slice_dmax = -1e30;
  for(i=(sinf->colmin); i<(sinf->colmax+1); i++)
  {
    if(sinf->dataptr[i] < slice_dmin) slice_dmin=sinf->dataptr[i];
    if(sinf->dataptr[i] > slice_dmax) slice_dmax=sinf->dataptr[i];
  }

#ifdef DEBUG
  printf("Slice: dmin: %g, dmax: %g\n", slice_dmin, slice_dmax);
#endif

  sinf->dmin = slice_dmin;
  sinf->cdmin = slice_dmin;
  sinf->dmax = slice_dmax;
  sinf->cdmax = slice_dmax;
}


void stopslice_callback(w, sinf, call_data)
Widget w;
struct slice_inf *sinf;
caddr_t call_data;
{
  struct slice_inf *p, *pprev;

  p = first_slice;
  pprev = NULL;

  while(p != NULL)
  {
    if(p == sinf)
    {
#ifdef DEBUG
      printf("removing slice: %d, dim: %d, colmin: %d, colmax: %d\n",
	     p->sliceno, p->dim, p->colmin, p->colmax);
#endif
      XtUnrealizeWidget(p->shell);
      XtDestroyWidget(p->shell);

      if(pprev == NULL)
      {
	first_slice = p->next_slice;
      }
      else
      {
	pprev->next_slice = p->next_slice;
      }
#ifdef DEBUG
      printf("Free dataptr and p.\n");
#endif
      XtFree((char *) (p->dataptr));
      XtFree((char *) p);
      break;
    }
    pprev = p;
    p = p->next_slice;
  }
}

closeslices()
{
  struct slice_inf *spnt;

  spnt = first_slice;

  while(first_slice != NULL)
  {
#ifdef DEBUG
    printf("removing slice: %d, dim: %d, colmin: %d, colmax: %d\n",
	   first_slice->sliceno, first_slice->dim, first_slice->colmin,
	   first_slice->colmax);
#endif
    XtUnrealizeWidget(first_slice->shell);
    XtDestroyWidget(first_slice->shell);
    spnt = first_slice->next_slice;
#ifdef DEBUG
    printf("Free dataptr and first_slice.\n");
#endif
    XtFree((char *) (first_slice->dataptr));
    XtFree((char *) first_slice);
    first_slice = spnt;
  }
}

phaseslice(spnt, phase0, phase1)
struct slice_inf *spnt;
float phase0, phase1;
{
  setupphase(spnt->nzdata, phase0, phase1,
             FFTSIZE(file1, spnt->dim==0 ? xdim : ydim),
	     EXTRACT1(file1, spnt->dim==0 ? xdim : ydim));
  phase(spnt->dataptr);
}

phaseslices(phase0, phase1)
float phase0, phase1;
{
  struct slice_inf *spnt;
  float dmin, dmax, olddiff, oldscale, oldshift, newdiff, newave, a;
  int *idmin, *idmax;
  int i;
#ifdef DEBUG
  printf("phaseslices: %g %g\n", phase0, phase1);
#endif

  spnt = first_slice;

  while(spnt != NULL)
  {
#ifdef DEBUG
    printf("Phase(%g,%g) slice: %d, colmin: %d, colmax: %d zfill: %d\n", phase0, phase1,
	   spnt->sliceno, spnt->colmin, spnt->colmax, 1);
#endif
    phaseslice(spnt, phase0, phase1);
    idmin = (int *) &(spnt->cdmin);
    idmax = (int *) &(spnt->cdmax);

    n=0;
    XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
    XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
    XtSetValues(spnt->slice, wargs, n);

    spnt=spnt->next_slice;
  }
}

void scaleupslice_callback(w, sinf, call_data)
Widget w;
struct slice_inf *sinf;
caddr_t call_data;
{
  float dmin, dmax, ddiff, dave;
  int *idmin, *idmax;
  int i;
#ifdef DEBUG
  printf("scaleupslice\n");
#endif

  ddiff = sinf->cdmax - sinf->cdmin;
  dave = (sinf->cdmax + sinf->cdmin)*0.5;

  sinf->cdmin = dave - 0.25*ddiff;
  sinf->cdmax = dave + 0.25*ddiff;

#ifdef DEBUG
  printf("dmin: %g, dmax: %g, cdmin: %g, cdmax: %g\n",
	  sinf->dmin, sinf->dmax, sinf->cdmin, sinf->cdmax);
#endif

  idmin = (int *) &(sinf->cdmin);
  idmax = (int *) &(sinf->cdmax);

  n=0;
  XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
  XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
  XtSetValues(sinf->slice, wargs, n);
}

void scaledownslice_callback(w, sinf, call_data)
Widget w;
struct slice_inf *sinf;
caddr_t call_data;
{
  float dmin, dmax, ddiff, dave;
  int *idmin, *idmax;
  int i;
#ifdef DEBUG
  printf("scaledownslice\n");
#endif

  ddiff = sinf->cdmax - sinf->cdmin;
  dave = (sinf->cdmax + sinf->cdmin)*0.5;

  sinf->cdmin = dave - ddiff;
  sinf->cdmax = dave + ddiff;

#ifdef DEBUG
  printf("dmin: %g, dmax: %g, cdmin: %g, cdmax: %g\n",
	  sinf->dmin, sinf->dmax, sinf->cdmin, sinf->cdmax);
#endif

  idmin = (int *) &(sinf->cdmin);
  idmax = (int *) &(sinf->cdmax);

  n=0;
  XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
  XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
  XtSetValues(sinf->slice, wargs, n);
}

void shiftupslice_callback(w, sinf, call_data)
Widget w;
struct slice_inf *sinf;
caddr_t call_data;
{
  float dmin, dmax, ddiff, dave;
  int *idmin, *idmax;
  int i;
#ifdef DEBUG
  printf("shiftupslice\n");
#endif

  ddiff = sinf->cdmax - sinf->cdmin;
  dave = (sinf->cdmax + sinf->cdmin)*0.5;

  sinf->cdmin -= 0.5*ddiff;
  sinf->cdmax -= 0.5*ddiff;

#ifdef DEBUG
  printf("dmin: %g, dmax: %g, cdmin: %g, cdmax: %g\n",
	  sinf->dmin, sinf->dmax, sinf->cdmin, sinf->cdmax);
#endif

  idmin = (int *) &(sinf->cdmin);
  idmax = (int *) &(sinf->cdmax);

  n=0;
  XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
  XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
  XtSetValues(sinf->slice, wargs, n);
}

void shiftdownslice_callback(w, sinf, call_data)
Widget w;
struct slice_inf *sinf;
caddr_t call_data;
{
  float dmin, dmax, ddiff, dave;
  int *idmin, *idmax;
  int i;
#ifdef DEBUG
  printf("shiftdownslice\n");
#endif

  ddiff = sinf->cdmax - sinf->cdmin;
  dave = (sinf->cdmax + sinf->cdmin)*0.5;

  sinf->cdmin += 0.5*ddiff;
  sinf->cdmax += 0.5*ddiff;

#ifdef DEBUG
  printf("dmin: %g, dmax: %g, cdmin: %g, cdmax: %g\n",
	  sinf->dmin, sinf->dmax, sinf->cdmin, sinf->cdmax);
#endif

  idmin = (int *) &(sinf->cdmin);
  idmax = (int *) &(sinf->cdmax);

  n=0;
  XtSetArg(wargs[n], XtNdataMin, *idmin); n++;
  XtSetArg(wargs[n], XtNdataMax, *idmax); n++;
  XtSetValues(sinf->slice, wargs, n);
}

/*

setwminput: Set a flag so that the window manager
            directs input to the window.

*/

setwminput(w)
Widget w;
{
  XWMHints wmhints;

  wmhints.flags = InputHint;
  wmhints.input = True;

  XSetWMHints(XtDisplay(w), XtWindow(w), &wmhints);
}

void wdim_callback(w, desireddim, call_data)
Widget w;
int desireddim;
caddr_t call_data;
{
  int real_dim, old_real_dim;

  real_dim = (desireddim==0) ? xdim : ydim;
  old_real_dim = (dim==0) ? xdim : ydim;
#ifdef DEBUG
  printf("desired dim: %d\n", desireddim);
  printf("real dim: %d\n", real_dim);
#endif
  if(desireddim==dim) return;

  if(first_slice == NULL)
  {
    printf("Previous working dimension: %d, delta0: %g, delta1: %g\n", old_real_dim, phase0-iphase0, phase1-iphase1);

    n=0;
    XtSetArg(wargs[n], XmNset, FALSE); n++;
    XtSetValues(set_wdim[dim], wargs, n);
    dim = desireddim;

    /*
	  Set phases to current values:
    */

    iphase0 = unitcircle(PHASE0(file1, real_dim));
    iphase1 = PHASE1(file1, real_dim);
    phase0 = iphase0;
    phase1 = iphase1;

    update_phase_sliders();
    set_headline();
  }
  else
  {
    n=0;
    XtSetArg(wargs[n], XmNset, FALSE); n++;
    XtSetValues(set_wdim[desireddim], wargs, n);
    n=0;
    XtSetArg(wargs[n], XmNset, TRUE); n++;
    XtSetValues(set_wdim[dim], wargs, n);
    printf("You must close all slices before changing dimension!\n");
  }


}

float unitcircle(x)
float x;
{
  /*
	Don't remove asis - titan compiler will crash without 'em.
  */

#include <asis.h>
  while(x<0.0) x+=360.0;

#include <asis.h>
  while(x>=360.0) x-=360.0;

  return(x);
}

update_map(newdim)
int newdim;
{
  /*
	Reinitializes everything for the Map widget.
  */

  readdata();

  if(newdim)
  {
    scale=1;
    newscale=1;
    collow=0;
    rowlow=0;
    colhigh=datacol-1;
    rowhigh=datarow-1;
    xhair = datacol/2;
    yhair = datarow/2;
  }

#ifdef DEBUG
  printf("update_map: collow: %d, colhigh: %d, rowlow: %d, rowhigh: %d\n", collow, colhigh, rowlow, rowhigh);
#endif

  n=0;
  XtSetArg(wargs[n], XtNdataPtr, dataptr); n++;
  XtSetArg(wargs[n], XtNdataRow, datarow); n++;
  XtSetArg(wargs[n], XtNdataCol, datacol); n++;
  XtSetArg(wargs[n], XtNdMin, *ioffset); n++;
  XtSetArg(wargs[n], XtNdSize, *iwidth); n++;
  XtSetArg(wargs[n], XtNsign, 3); n++;
  XtSetArg(wargs[n], XtNcolLow, collow); n++;
  XtSetArg(wargs[n], XtNcolHigh, colhigh); n++;
  XtSetArg(wargs[n], XtNrowLow, rowlow); n++;
  XtSetArg(wargs[n], XtNrowHigh, rowhigh); n++;
  XtSetArg(wargs[n], XtNxHair, xhair); n++;
  XtSetArg(wargs[n], XtNyHair, yhair); n++;
  XtSetValues(map, wargs, n);

  update_index_editors();

}

/******************/
void update_fields()
/******************/
{
  int i;

  nfields=0;
  for(i=0; i<NMR_N_DIM(file1); i++)
  {
    if(i!=xdim && i!=ydim)
    {
      n=0;
      sprintf(clabel, "Set index for %d'th dimension: ", i);
#ifdef DEBUG
      printf("Setting field %d to: %s\n", nfields, clabel);
#endif
      XtSetArg(wargs[n], XtNstring, clabel); n++;
      XtSetValues(slicenotext[nfields], wargs, n);
      sprintf(clabel, "%d", currentindex[i]);
      XmTextFieldSetString(sliceno[nfields], clabel);
      field_dim[nfields++]=i;
    }
  }
  sprintf(clabel, "%d", xdim);
  n=0;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(clabel)); n++;
  XtSetValues(set_wdim[0], wargs, n);
  sprintf(clabel, "%d", ydim);
  n=0;
  XtSetArg(wargs[n], XmNlabelString, XmStringCreateSimple(clabel)); n++;
  XtSetValues(set_wdim[1], wargs, n);
}

/******************************************/
void xdim_callback(w, desireddim, call_data)
/******************************************/
Widget w;
int desireddim;
XmToggleButtonCallbackStruct *call_data;
{
  /* If phases have been modified or slices have been opened,
     ask for a confirmation. */

#ifdef DEBUG
  printf("xdim_callback(%d) called. State: %s\n", desireddim, call_data->set==XmSET?"Set":"Unset");
#endif

  if(call_data->set!=XmSET) return;
  if(desireddim==xdim) return;

  if(phase0 == iphase0 && phase1 == iphase1 && first_slice == NULL)
  {
#ifdef DEBUG
    printf("Phases not changed, and no slices visible: Don't ask.\n");
#endif
    xdim_callback_doit(w, desireddim, call_data);
    return;
  }

  n=0;
  XtSetArg(wargs[n], XmNmessageString,
           XmStringCreateLtoR("This will abandon the phase changes you have made\n\nIf this is not what you want, click Cancel here and click on Apply to update the spectrum file.", XmSTRING_DEFAULT_CHARSET)); n++;
  xdim_dialog = XmCreateWarningDialog(toplevel, "xdim_dialog", wargs, n);

  XtUnmanageChild(XmMessageBoxGetChild(xdim_dialog, XmDIALOG_HELP_BUTTON));

  XtAddCallback(xdim_dialog, XmNokCallback, xdim_callback_doit, (XtPointer) desireddim);
  XtAddCallback(xdim_dialog, XmNcancelCallback, xdim_callback_dont_doit, (XtPointer) desireddim);

  XtManageChild(xdim_dialog);
    
}

/****************************************************/
void xdim_callback_dont_doit(w, desireddim, call_data)
/****************************************************/
Widget w;
int desireddim;
caddr_t call_data;
{
  /* cancel selection */
  if(xdim_dialog)
  {
    XtDestroyWidget(xdim_dialog);
    xdim_dialog=NULL;
  }
  XmToggleButtonGadgetSetState(set_xdim[xdim], True, True);
  return;
}

/***********************************************/
void xdim_callback_doit(w, desireddim, call_data)
/***********************************************/
Widget w;
int desireddim;
caddr_t call_data;
{
  /*
	Unselect previous button. hide corresponding button for ydim.
  */

  if(xdim_dialog!=NULL)
  {
    XtDestroyWidget(xdim_dialog);
    xdim_dialog=NULL;
  }

  closeslices();

#ifdef DEBUG
  printf("xdim_callback_doit(%d) called.\n", desireddim);
#endif

  currentindex[xdim]=xdim_index;
  currentindex[ydim]=ydim_index;

  n=0;
  XtSetArg(wargs[n], XtNsensitive, TRUE); n++;
  XtSetValues(set_ydim[xdim], wargs, n); 

  if(desireddim==ydim)
  {
    ydim=0;
    if(desireddim==0) ydim=1;
    XmToggleButtonGadgetSetState(set_ydim[ydim], True, True);
  }
  n=0;
  XtSetArg(wargs[n], XtNsensitive, FALSE); n++;
  XtSetValues(set_ydim[desireddim], wargs, n); 

  xdim=desireddim;


  xdim_index=currentindex[xdim];
  ydim_index=currentindex[ydim];

  update_fields();
  update_indices();
  update_map(TRUE);

  iphase0 = unitcircle(PHASE0(file1, (dim==0) ? xdim:ydim));
  iphase1 = PHASE1(file1, (dim==0) ? xdim:ydim);
  phase0 = iphase0;
  phase1 = iphase1;
  update_phase_sliders();
  set_headline();
}

/******************************************/
void ydim_callback(w, desireddim, call_data)
/******************************************/
Widget w;
int desireddim;
XmToggleButtonCallbackStruct *call_data;
{
  /* If phases have been modified or slices have been opened,
     ask for a confirmation. */

#ifdef DEBUG
  printf("ydim_callback(%d) called. State: %s\n", desireddim, call_data->set==XmSET?"Set":"Unset");
#endif

  if(call_data->set!=XmSET) return;
  if(desireddim==ydim) return;

  if(phase0 == iphase0 && phase1 == iphase1 && first_slice == NULL)
  {
#ifdef DEBUG
    printf("Phases not changed, and no slices visible: Don't ask.\n");
#endif
    ydim_callback_doit(w, desireddim, call_data);
    return;
  }

  n=0;
  XtSetArg(wargs[n], XmNmessageString,
           XmStringCreateLtoR("This will abandon the phase changes you have made\n\nIf this is not what you want, click Cancel here and click on Apply to update the spectrum file.", XmSTRING_DEFAULT_CHARSET)); n++;
  ydim_dialog = XmCreateWarningDialog(toplevel, "ydim_dialog", wargs, n);

  XtUnmanageChild(XmMessageBoxGetChild(ydim_dialog, XmDIALOG_HELP_BUTTON));

  XtAddCallback(ydim_dialog, XmNokCallback, ydim_callback_doit, (XtPointer) desireddim);
  XtAddCallback(ydim_dialog, XmNcancelCallback, ydim_callback_dont_doit, (XtPointer) desireddim);

  XtManageChild(ydim_dialog);
    
}

/****************************************************/
void ydim_callback_dont_doit(w, desireddim, call_data)
/****************************************************/
Widget w;
int desireddim;
caddr_t call_data;
{
  /* cancel selection */
  if(ydim_dialog!=NULL)
  {
    XtDestroyWidget(ydim_dialog);
    ydim_dialog=NULL;
  }
  XmToggleButtonGadgetSetState(set_ydim[ydim], True, True);
  return;
}

/***********************************************/
void ydim_callback_doit(w, desireddim, call_data)
/***********************************************/
Widget w;
int desireddim;
caddr_t call_data;
{
  int i;
#ifdef DEBUG
  printf("ydim_callback(%d) called.\n", desireddim);
#endif

  if(ydim_dialog!=NULL)
  {
    XtDestroyWidget(ydim_dialog);
    ydim_dialog=NULL;
  }

  closeslices();

#ifdef DEBUG
  printf("ydim_callback_doit before:\n");
  for(i=0; i<NMR_N_DIM(file1); i++)
    printf("ydim_widget[%d]: Sensitive: %s\n", i, XtIsSensitive(set_ydim[i])?"Yes":"No");
#endif

  if(desireddim==ydim) return;

  currentindex[xdim]=xdim_index;
  currentindex[ydim]=ydim_index;

  ydim=desireddim;

  xdim_index=currentindex[xdim];
  ydim_index=currentindex[ydim];

  update_fields();
  update_indices();
  update_map(TRUE);

  iphase0 = unitcircle(PHASE0(file1, (dim==0) ? xdim:ydim));
  iphase1 = PHASE1(file1, (dim==0) ? xdim:ydim);
  phase0 = iphase0;
  phase1 = iphase1;
  update_phase_sliders();
  set_headline();
#ifdef DEBUG
  printf("ydim_callback_doit after:\n");
  for(i=0; i<NMR_N_DIM(file1); i++)
    printf("ydim_widget[%d]: Sensitive: %s\n", i, XtIsSensitive(set_ydim[i])?"Yes":"No");
#endif

}

/*********************************************/
void sliceno_callback(w, idim, call_data)
/*********************************************/
Widget w;
int idim;
caddr_t call_data;
{
  int i, modified;
  char *s, clabel[100];

#ifdef DEBUG
  printf("sliceno_callback(%d) called.\n", idim);
#endif

  s = XmTextFieldGetString(sliceno[idim]);
  sscanf(s, "%d", &i);
  XtFree(s);

#ifdef DEBUG
  printf("Text: %s, value: %d, maximum: %d\n", s, i, NDIM(file1, field_dim[idim]));
#endif

  modified=FALSE;
  if(i<0)
  {
    i=0;
    modified=TRUE;
  }
  else if(i>=NDIM(file1, field_dim[idim]))
  {
    i=NDIM(file1, field_dim[idim])-1;
    modified=TRUE;
  }

  if(modified)
  {
    printf("Sliceno modified: %d\n", i);
    sprintf(clabel, "%d", i);
    XmTextFieldSetString(sliceno[idim], clabel);
  }

  currentindex[field_dim[idim]] = i;
  update_indices();
  update_map(FALSE);
}

#ifdef solaris
void bcopy(s1, s2, len)
char *s1, *s2;
int len;
{
  register int i;
  for(i=0; i<len; i++) s2[i] = s1[i];
}
#endif
