/*
 * National Center for SuperComputing Applications, University of Illinois
 *
 * This NCSA software product is public domain software.  Permission
 * is hereby granted to do whatever you like with it. Should you wish
 * to make a contribution towards the production of this software, please
 * send us your comments about your experience with the software,  why
 * you liked or disliked it, how you use it, and most importantly, how it
 * helps your work. We will receive your comments at softdev@ncsa.uiuc.edu.
 *
 * Please send bug reports to bugs@ncsa.uiuc.edu
 *
 * Author: Eng-Whatt Toh, National Center for Supercomputing Applications
 *         ewtoh@ncsa.uiuc.edu
 */

/*
 *	File:		gr_anilev.c
 *	Contents:	Animate level window functions for graphics module
 */

#include "gr_com.h"
#include <X11/StringDefs.h>

#include <signal.h>
extern long td_CurrentTime();
extern int	gr_AniTimeOut();
extern int gr_RasterImagePrint ();
extern int gr_Anibegincontour();
extern void gr_ImageInitCMapHDF();
extern void gr_AniDrawGrid();
extern void gr_AniDrawImage();
extern void gr_AniDrawLoad();

#define	OFFSET			50
#define GR_ANIDELAYMAX  2000000
#define GR_ANIDELAYGRD  10000
#define	MINWINXSIZE	285
#define MINWINYSIZE	100
#define	MAXWINXSIZE	900
#define MAXWINYSIZE	900
#define LEEWAY		2

/* #ifdef XIMAGE_PALETTE  now dynamically choose (gr_Data.paletteEditor).
   gbourhis Feb 93 */
/* Stuff for Ximage changes. */
extern void PaletteBox();
extern void CBPalSave();
static A_Palette_t PalData = { &gr_color, NULL, gr_LoadPAL, CBPalSave};
/* #endif   XIMAGE_PALETTE */
static Widget palWidget;	/* added by gbourhis Jan 93 */

/*
 * Make control buttons for animation window
 */
gr_MakeAniControls(boxWind,tmp,numplanes)
Widget		boxWind;
A_AniWind_t	*tmp;
int			numplanes;
{
		Widget RCWind;
		XImage *palimage;

		palimage = gr_ImageCreate(boxWind,gr_color.maxColors,30,gr_palData);
		palWidget =	/* gbourhis Jan 93 */
		  gr_MakeImageStatic("XDSstaticimage",boxWind,palimage,
					  NULL,(caddr_t)NULL,10,5,256,30);
		gr_MakeButton("XDSbutton",boxWind,"<<",
					  (XtCallbackProc)gr_AniPlayBackward,(caddr_t)tmp,
					  55,42,20,20);
		gr_MakeButton("XDSbutton",boxWind,"<",
					  (XtCallbackProc)gr_AniStepBackward,(caddr_t)tmp,
					  78,42,20,20);
		gr_MakeButton("XDSbutton",boxWind,"<>",
					  (XtCallbackProc)gr_AniPlayStop,(caddr_t)tmp,
					  101,42,20,20);
		gr_MakeButton("XDSbutton",boxWind,">",
					  (XtCallbackProc)gr_AniStepForward,(caddr_t)tmp,
					  124,42,20,20);
		gr_MakeButton("XDSbutton",boxWind,">>",
					  (XtCallbackProc)gr_AniPlayForward,(caddr_t)tmp,
					  147,42,20,20);

		tmp->frameSlider =
			gr_MakeSlider("SDSslider",boxWind,0,numplanes,1,0,1,
				(XtCallbackProc)gr_AniFrameSliderSel,
				(XtCallbackProc)gr_AniFrameSliderMov,
				(XtCallbackProc)gr_AniFrameSliderRel,
				HORIZONLY, (caddr_t)tmp,55,65,112,20);

		RCWind = gr_MakeRowColumn("XDSrowcolumn",boxWind,ONEOFMANY,3,
					2,90,200,20);
		gr_MakeToggle("XDStoggle",RCWind,"Off",DIAMOND,
					TRUE, (XtCallbackProc)gr_AniSetAutoOff,
					NULL,(caddr_t)tmp, 2,2,40,20);
		gr_MakeToggle("XDStoggle",RCWind,"Repeat",DIAMOND,
					FALSE, (XtCallbackProc)gr_AniSetAutoRep,
					NULL,(caddr_t)tmp, 42,2,60,20);
		gr_MakeToggle("XDStoggle",RCWind,"Reverse",DIAMOND,
					FALSE, (XtCallbackProc)gr_AniSetAutoRev,
					NULL,(caddr_t)tmp, 102,2,60,20);

		tmp->frameDialog=
			gr_MakeDialog("XDSdialog",boxWind,"Frame","0",5,
						170,42,50,48);
		gr_MakeButton("XDSbutton",boxWind,"Set",
					  (XtCallbackProc)gr_AniFrameSet,(caddr_t)tmp,
					  170,90,50,20);
		tmp->skipDialog=
			gr_MakeDialog("XDSdialog",boxWind,"Skip ","0",5,
						222,42,50,48);
		gr_MakeButton("XDSbutton",boxWind,"Set",
					  (XtCallbackProc)gr_AniSkipSet,(caddr_t)tmp,
					  222,90,50,20);
		gr_MakeButton("XDSbutton",boxWind,"Fast <-",
					  (XtCallbackProc)gr_AniSpeedFast,(caddr_t)tmp,
					  2,115,50,15);
		tmp->speedSlider =
			gr_MakeSlider("SDSslider",boxWind,0,GR_ANIDELAYMAX+1,1,0,1,
				(XtCallbackProc)gr_AniSpeedSliderSel,
				(XtCallbackProc)gr_AniSpeedSliderMov,
				(XtCallbackProc)gr_AniSpeedSliderRel,
				HORIZONLY, (caddr_t)tmp,54,115,166,15);
		gr_MakeButton("XDSbutton",boxWind,"-> Slow",
					  (XtCallbackProc)gr_AniSpeedSlow,(caddr_t)tmp,
					  222,115,50,15);

}


/*
 * Animate along cartesian axes
 */
A_AniWind_t
*gr_InitAniLevel(header,shellName,parent,numplanes,incr,scale,orient,tparent,
	pathname)
A_AniWind_t *header;
char   	 *shellName;
Widget	 parent;
int		 numplanes,incr,scale;
A_Axes_t		orient;
A_CubeWind_t	*tparent;
char	*pathname;
{
	A_BossWind_t	*bossWin=tparent->parent;
	A_AniWind_t		*tmp;
	Widget			boxWind;
	int				usePlane,winxsize,winysize,xsize,ysize;
	int				ncols,nrows,numFrames,ret,fileexist;
	short			i,j;
	long			startTime,remTime;
	char			label[120],strng[120];
	XGCValues		gcvals;
	Display			*dpy;
	Window			win;

	gr_WidgetCursor(tparent->shell,XC_watch);

	tmp = (A_AniWind_t *)td_Malloc(sizeof(A_AniWind_t),"A_AniWind_t");

	bossWin->data->scale = scale;

	tmp->usePixmap = tparent->usePixmap;
	tmp->useDisk = tparent->useDisk;
	tmp->gridOn = tparent->gridOn;
	tmp->scale = scale;
	tmp->contourWin = NULL;

	if (tmp->gridOn == FALSE)
	{
		tmp->xorg = tmp->yorg = 0;
	}
	else
	{
		tmp->xorg = OFFSET*7/4;
		tmp->yorg = tmp->offset = OFFSET;
	}

	if (pathname==NULL) 
		tmp->pathname = NULL;
	else {
		tmp->pathname = (char *)td_Malloc1D(1,strlen(pathname)+1,
							(unsigned int)sizeof(char), "td_Malloc1D");
#ifdef RIOS
		Strcpy(tmp->pathname,pathname);
#else
		strcpy(tmp->pathname,pathname);
#endif
		}

	if (tmp->useDisk == TRUE)
	{
		numFrames = 1;
	}
	else
	{
		numFrames = numplanes;
	}

	tmp->imagexsize = (int *)calloc(numFrames,sizeof(int));
	if (tmp->imagexsize == NULL)
	{
		fprintf(stderr,"Error\t: Out of memory in calloc imagexsize.\n");
		exit(-1);
	}
	tmp->imageysize = (int *)calloc(numFrames,sizeof(int));
	if (tmp->imageysize == NULL)
	{
		fprintf(stderr,"Error\t: Out of memory in calloc imageysize.\n");
		exit(-1);
	}

	ncols = td_HdfgetDim(bossWin->data,orient.col);
	nrows = td_HdfgetDim(bossWin->data,orient.row);

	if ((tparent->interp == TRUE) && (tparent->cull == FALSE))
	{
		ncols--; nrows--;
	}

	if (tparent->cull == FALSE)
	{
		xsize = ncols*scale;
		ysize = nrows*scale;
	}
	else
	{
		xsize = ncols/scale;
		if (xsize*scale < ncols) xsize++;
		ysize = nrows/scale;
		if (ysize*scale < nrows) ysize++;
	}

	if (xsize > MINWINXSIZE)
		if (xsize > MAXWINXSIZE)
			winxsize = MAXWINXSIZE;
		else
			winxsize = xsize+LEEWAY;
	else
		winxsize = MINWINXSIZE+LEEWAY;

	if (ysize > MINWINYSIZE)
		if (ysize > MAXWINYSIZE)
			winysize = MAXWINYSIZE;
		else
			winysize = ysize+LEEWAY;
	else
		winysize = MINWINYSIZE+LEEWAY;

	if (tmp->gridOn == TRUE)
	{
		winxsize += 2*OFFSET; winysize += 2*OFFSET;
	}

	sprintf(label,"%s: Animate %d planes",tparent->parent->filename,
			numplanes);

	tmp->shell = gr_MakeWindow("XDS Frame",parent,&(tmp->win),
					(XtCallbackProc)gr_CloseAniLevel,
					ANIWIND,label,"Close",(caddr_t)tmp,
					110,10,winxsize+8,winysize+170);

	gr_ImageSetCMap(tmp->shell); /* two lines added by */
	XtManageChild(tmp->shell); /* gbourhis. Jan 93 */

	boxWind = gr_MakeBulletin("XDSbulletin",tmp->win,
		2,winysize+2,275,134);

	gr_MakeButton("XDSbutton",boxWind,"Save",
		      (XtCallbackProc)gr_SaveAni,(caddr_t)tmp,
		      2,42,50,20);

/* #ifdef XIMAGE_PALETTE */
	if (gr_Data.paletteEditor) /* gbourhis Feb 93 */
	  {
	    PalData.client_data = (caddr_t) tmp->shell;
	    gr_MakeButton("XDSbutton",boxWind,"Palette",
			  (XtCallbackProc)PaletteBox, (caddr_t) &PalData,
			  2,65,50,20);
	  }
	else			/* #else before */
	  gr_MakeButton("XDSbutton",boxWind,"Palette",
			(XtCallbackProc)gr_LoadPAL,(caddr_t)tmp->shell,
			2,65,50,20);
/* #endif */

	gr_MakeAniControls(boxWind,tmp,numplanes);

	tmp->imageVPort = gr_MakeVPort("XDSvport",tmp->win,
						NOSCROLL,HP,NULL, NULL,5,(caddr_t)tmp,
						2,2,winxsize+2,winysize+2);

	if (tmp->gridOn == FALSE)
	tmp->imageWin = gr_MakeWorkSpace("XDSworkspace",tmp->imageVPort,
					 (XtCallbackProc)gr_AniExpose,
					 NULL,NULL,(caddr_t)tmp,
					 0,0,xsize,ysize);
	else
	tmp->imageWin = gr_MakeWorkSpace("XDSworkspace",tmp->imageVPort,
					 (XtCallbackProc)gr_AniExpose,
					 NULL,NULL,(caddr_t)tmp,
					 0,0,xsize+2*OFFSET,ysize+2*OFFSET);

	tmp->data = td_Malloc2D(1,numplanes,(long)sizeof(char *),"td_Malloc2D");
	if (tmp->usePixmap == TRUE)
	tmp->image = (Pixmap *)td_Malloc1D(1,numFrames,(long)sizeof(Pixmap),
		"td_Malloc1D");
	else
	tmp->ximage = (XImage **)td_Malloc1D(1,numFrames,(long)sizeof(XImage *),
		"td_Malloc1D");

	tmp->aniType = 1;
	tmp->playStop = 1;
	tmp->autoMode = AUTOOFF;
	tmp->curplane = 0;
	tmp->speed = 0;
	tmp->skip = 0;
	tmp->numplanes = numplanes;
	tmp->axesOrient = orient;

	dpy = XtDisplay(tmp->imageWin);
	win = XtWindow(tmp->imageWin);
	gcvals.foreground = BlackPixel(dpy,DefaultScreen(dpy));
	tmp->imageWinGC = XtGetGC(tmp->imageWin, GCForeground, &gcvals);
	XSetTSOrigin(dpy,tmp->imageWinGC,0,0);
	XSetFillStyle(dpy,tmp->imageWinGC,FillTiled);

	startTime = td_CurrentTime();

	i=0;
	for (j=0;j<numplanes;j++)
	{
		usePlane = orient.plane+(j*incr);
		if (tmp->useDisk == FALSE)
			i = j;

		tmp->imagexsize[i] = xsize;
		tmp->imageysize[i] = ysize;
		if ((tmp->useDisk == TRUE) && (j > 0))
		{
			if (tmp->usePixmap == TRUE)
				XFreePixmap(dpy,tmp->image[0]);
			else
				XDestroyImage(tmp->ximage[0]);
			td_Free((char *)tmp->data[0]);
		}
		tmp->data[i] = td_HdfgetPixData(bossWin->data,
				orient.row,orient.col,orient.axis,
				usePlane,tparent->interp,tparent->cull,
				(unsigned char)gr_color.nColors);

		if (tmp->usePixmap == TRUE)
		{
		tmp->image[i] = gr_PixmapCreate(tmp->imageWin,tmp->imageWinGC,
				tmp->xorg,tmp->yorg,
				tmp->imagexsize[i],tmp->imageysize[i],tmp->data[i]);
		}
		else
		{
		tmp->ximage[i] = gr_ImageCreate(tmp->imageWin,
				tmp->imagexsize[i],tmp->imageysize[i],tmp->data[i]);
		}
		gr_AniDrawImage(dpy,win,tmp,i);

		if (tmp->useDisk == TRUE)
		{
			fileexist = td_FileExist(pathname);

			if (fileexist == 0)
				ret = td_HdfPutImage(pathname,tmp->data[i],gr_color.palette,
				tmp->imagexsize[i],tmp->imageysize[i]);
			else
				ret = td_HdfAddImage(pathname,tmp->data[i],gr_color.palette,
				tmp->imagexsize[i],tmp->imageysize[i]);
			if (ret == -1)
				gr_TextMsgOut("Error in saving Animation image!\n");
			else
				gr_TextMsgOut("Saved ");
		}
		remTime = (long)((td_CurrentTime()-startTime)/(j+1.0)*
						 (numplanes-j-1.0));
		sprintf(strng,"Generated frame %d, %5lds to completion...\n",j,remTime);
		gr_TextMsgOut(strng);
	}

	if (tmp->useDisk == TRUE)
		gr_AniDrawLoad(dpy,win,tmp,0);
	else
		gr_AniDrawImage(dpy,win,tmp,0);

	tmp->parent	= tparent;
	tmp->arbparent = NULL;
	tmp->prev	= NULL;
	tmp->next	= header;
	if (header != NULL)
		header->prev = tmp;

	if (tmp->gridOn == TRUE)
		gr_AniDrawGrid(tmp);

	gr_WidgetCursor(tmp->shell,XC_draped_box);
	gr_WidgetCursor(tparent->shell,XC_draped_box);

	return(tmp);
}


/*
 * Animate along arbitrary axes
 */
A_AniWind_t
*gr_InitAniLevel3(header,shellName,parent,numplanes,zincr,scale,tparent,pathname)
A_AniWind_t *header;
char   	 *shellName;
Widget	 parent;
int		 numplanes,scale;
double	 zincr;
A_ArbWind_t	*tparent;
char	 *pathname;
{
	A_BossWind_t	*bossWin=tparent->parent;
	A_AniWind_t		*tmp;
	A_Box_t			*box=tparent->xybox;
	Widget			boxWind;
	int		winxsize,winysize,xsize,ysize,numFrames,fileexist,ret;
	short			i,j;
	long			startTime,remTime;
	char			label[120],strng[120];
	double			useDepth,startInDepth;
	Boolean			quit = FALSE;
	XGCValues		gcvals;
	Display			*dpy;
	Window			win;

	gr_WidgetCursor(tparent->shell,XC_watch);

	tmp = (A_AniWind_t *)td_Malloc(sizeof(A_AniWind_t),"A_AniWind_t");

	bossWin->data->scale = scale;

	tmp->gridOn = FALSE;
	tmp->usePixmap = tparent->usePixmap;
	tmp->useDisk = tparent->useDisk;

	tmp->xorg = tmp->yorg = 0;
	xsize = (int)(((int)box->xmax-(int)box->xmin)*scale);
	ysize = (int)(((int)box->ymax-(int)box->ymin)*scale);
	if (xsize > MINWINXSIZE)
		if (xsize > MAXWINXSIZE)
			winxsize = MAXWINXSIZE;
		else
			winxsize = xsize+LEEWAY;
	else
		winxsize = MINWINXSIZE+LEEWAY;

	if (ysize > MINWINYSIZE)
		if (ysize > MAXWINYSIZE)
			winysize = MAXWINYSIZE;
		else
			winysize = ysize+LEEWAY;
	else
		winysize = MINWINYSIZE+LEEWAY;

	startInDepth = (double)box->indepth;

	i = 0; quit = FALSE;
	while ((i< numplanes) && (quit == FALSE))
	{
		useDepth = (double)i*zincr+startInDepth;
		if (useDepth < 100.0)
			i++;
		else
			quit = TRUE;
	}

	if (numplanes > i)
	{
	sprintf(strng,"Warning: Only %d frames can be generated.\n",
		/* numplanes replaced by i. gbourhis Jan 93 */ i);
	gr_TextMsgOut(strng);
	}

	numplanes = i;

	if (pathname==NULL)	/* test added by gbourhis. Jan 93 */
		tmp->pathname = NULL;
	else {
	        tmp->pathname = (char *)td_Malloc1D(1,strlen(pathname)+1,
						    sizeof(char),
						    "td_Malloc1D");
#ifdef RIOS
		Strcpy(tmp->pathname,pathname);
#else
		strcpy(tmp->pathname,pathname);
#endif
	      }
	if (tmp->useDisk == TRUE)
	{
		numFrames = 1;
	}
	else
	{
		numFrames = numplanes;
	}

	tmp->imagexsize = (int *)td_Malloc1D(1,numFrames,sizeof(int),"td_Malloc1D");
	if (tmp->imagexsize == NULL)
	{
		fprintf(stderr,"Error\t: Out of memory in calloc imagexsize.\n");
		exit(-1);
	}
	tmp->imageysize = (int *)td_Malloc1D(1,numFrames,sizeof(int),"td_Malloc1D");
	if (tmp->imageysize == NULL)
	{
		fprintf(stderr,"Error\t: Out of memory in calloc imageysize.\n");
		exit(-1);
	}

	sprintf(label,"%s: Animate %d planes",tparent->parent->filename,
			numplanes);

	tmp->shell = gr_MakeWindow("XDS Frame",parent,&(tmp->win),
					(XtCallbackProc)gr_CloseAniLevel,
					ANIWIND,label,"Close",(caddr_t)tmp,
					110,10,winxsize+8,winysize+170);

	gr_ImageSetCMap(tmp->shell);/* two lines added by */
	XtManageChild(tmp->shell); /* gbourhis. Jan 93 */

	boxWind = gr_MakeBulletin("XDSbulletin",tmp->win,
		2,winysize+2,275,134);
		gr_MakeButton("XDSbutton",boxWind,"Save",
					  (XtCallbackProc)gr_SaveAni,(caddr_t)tmp,
					  2,42,50,20);
/* #ifdef XIMAGE_PALETTE */
	if (gr_Data.paletteEditor) /* gbourhis Feb 93 */
	  {
	    PalData.client_data = (caddr_t) tmp->shell;
	    gr_MakeButton("XDSbutton",boxWind,"Palette",
			  (XtCallbackProc)PaletteBox, (caddr_t) &PalData,
			  2,65,50,20);
	  }
	else /* #else before */
	  gr_MakeButton("XDSbutton",boxWind,"Palette",
			(XtCallbackProc)gr_LoadPAL,(caddr_t)tmp->shell,
			2,65,50,20);
/* #endif */
	gr_MakeAniControls(boxWind,tmp,numplanes);

	tmp->imageVPort = gr_MakeVPort("XDSvport",tmp->win,
						NOSCROLL,HP,NULL, NULL,5,(caddr_t)tmp,
						2,2,winxsize,winysize);

	tmp->imageWin = gr_MakeWorkSpace("XDSworkspace",tmp->imageVPort,
					(XtCallbackProc)gr_AniExpose,NULL,NULL,(caddr_t)tmp,
					0,0,xsize,ysize);

	tmp->data = (char **)td_Malloc2D(1,numFrames,sizeof(char *),"td_Malloc2D");
	if (tmp->usePixmap == TRUE)
	tmp->image = (Pixmap *)td_Malloc1D(1,numFrames,sizeof(Pixmap),
		"td_Malloc1D");
	else
	tmp->ximage = (XImage **)td_Malloc1D(1,numFrames,sizeof(XImage *),
		"td_Malloc1D");

	dpy = XtDisplay(tmp->imageWin);
	win = XtWindow(tmp->imageWin);
	gcvals.foreground = BlackPixel(dpy,DefaultScreen(dpy));
	tmp->imageWinGC = XtGetGC(tmp->imageWin, GCForeground, &gcvals);
	XSetTSOrigin(dpy,tmp->imageWinGC,0,0);
	XSetFillStyle(dpy,tmp->imageWinGC,FillTiled);

	tmp->aniType = 3;
	tmp->playStop = 1;
	tmp->autoMode = AUTOOFF;
	tmp->curplane = 0;
	tmp->speed = 0;
	tmp->skip = 0;
	tmp->numplanes = numplanes;
	tmp->contourWin = NULL;

	startTime = td_CurrentTime();

	i = 0;
	for (j=0;j<numplanes;j++)
	{
		if (tmp->useDisk == FALSE)
			i=j;

		useDepth = (double)j*zincr+startInDepth;
		gr_ArbZSliderSel(tparent->zSlider,(caddr_t)tparent,
			(caddr_t)(100-(int)useDepth) /* parenthesis added,
							gbourhis, Feb 93 */);
		tmp->imagexsize[i] = xsize;
		tmp->imageysize[i] = ysize;

		if ((tmp->useDisk == TRUE) && (j > 0))
		{
			td_Free((char *)tmp->data[0]);
			if (tmp->usePixmap == TRUE)
				XFreePixmap(dpy,tmp->image[0]);
			else
			XDestroyImage(tmp->ximage[0]);
		}
		if ((tmp->data[i] = gr_ViewgetData(box,scale,2,bossWin))
		    == NULL) {	/* test added by gbourhis. Jan 93 */
		  XtDestroyWidget(tmp->shell);
		  gr_WidgetCursor(tparent->shell,XC_draped_box);
		  return NULL;
		}

		if (tmp->usePixmap == TRUE)
		{
		tmp->image[i] = gr_PixmapCreate(tmp->imageWin,tmp->imageWinGC,
					tmp->xorg,tmp->yorg,
					tmp->imagexsize[i],tmp->imageysize[i],tmp->data[i]);
		}
		else
		{
		tmp->ximage[i] = gr_ImageCreate(tmp->imageWin,
					tmp->imagexsize[i],tmp->imageysize[i],tmp->data[i]);
		}
		gr_AniDrawImage(dpy,win,tmp,i);

		if (tmp->useDisk == TRUE)
		{
			fileexist = td_FileExist(pathname);

			if (fileexist == 0)
				ret = td_HdfPutImage(pathname,tmp->data[i],gr_color.palette,
				tmp->imagexsize[i],tmp->imageysize[i]);
			else
				ret = td_HdfAddImage(pathname,tmp->data[i],gr_color.palette,
				tmp->imagexsize[i],tmp->imageysize[i]);
			if (ret == -1)
				gr_TextMsgOut("Error in saving Animation image!\n");
			else
				gr_TextMsgOut("Saved ");
		}
		remTime = (long)((td_CurrentTime()-startTime)/(j+1.0)*
						 (numplanes-j-1.0));
		sprintf(strng,"Generated frame %d, %5lds to completion...\n",j,remTime);
		gr_TextMsgOut(strng);
	}

	if (tmp->useDisk == TRUE)
		gr_AniDrawLoad(dpy,win,tmp,0);
	else
		gr_AniDrawImage(dpy,win,tmp,0);

	tmp->arbparent	= tparent;
	tmp->parent		= NULL;
	tmp->prev	= NULL;
	tmp->next	= header;
	if (header != NULL)
		header->prev = tmp;

	gr_WidgetCursor(tmp->shell,XC_draped_box);
	gr_WidgetCursor(tparent->shell,XC_draped_box);

	return(tmp);
}

/* ------------------------------------------------------------------ */
#define MAXCONLEVELS 50

/* begin to generate the contours for a RASTER */

gr_Anibegincontour ( w, client_data, call_data)
Widget	w;
caddr_t	client_data;
caddr_t	call_data;
{
	A_HistWind_t   *histWin  = (A_HistWind_t *)client_data;
	A_AniWind_t    * aWin = (A_AniWind_t*) histWin->parent;
	long i;
	float *im;
	int nx,ny;
   int curplane;
	unsigned char * rasterdata;
	float clevels[MAXCONLEVELS];
   int nlev;
	char word[80], *ss;

	curplane = aWin->curplane;
   nx = aWin->imagexsize[curplane];
   ny = aWin->imageysize[curplane];
	rasterdata = (unsigned char*) aWin->data[curplane];

	if(NULL== (im = (float*) malloc(sizeof(float)*nx*ny))) 
			{ printf("Aniocontour malloc error for image to print\n"); return; }
	
	/* convert raster image to a float array so that dumppscontour can use */
	for(i=0;i<nx*ny;i++) im[i] = (float) (rasterdata[i] * 1.0); 

	/* ---------------------- */	
      nlev =  20;
      for(i=0;i<nlev;i++) clevels[i] = i*13.5; /* must not be exact integer */
	  ss = gr_DialogGetValue(histWin->conDialog);
  	 i=0;
  	 str_setstring(ss);
  	 while(str_getnextword(word)) {
      if (sscanf(word,"%f",&clevels[i])) { i++; }
      if (i>=MAXCONLEVELS) break;
      }
   nlev = i;
	/* ---------------------- */	

	gr_WidgetCursor(aWin->shell,XC_watch);

  	gr_TextMsgOut ("Wait - CONTOURING Raster..."); beep();

  	gr_MakeContourLines (im, nx, ny, 1, 1, clevels, nlev);
  	gr_DrawContourLines (aWin->imageWin ); /* draw contour over image */
  	gr_TextMsgOut ("done.\n "); beep();

	gr_WidgetCursor(aWin->shell,XC_draped_box);

	free (im);
  printcontour();

}

/* ------------------------------------------------------------------ */
/* jng 23-feb-91 */

gr_RasterImagePrint( w, client_data, call_data)
Widget	w;
caddr_t	client_data;
caddr_t	call_data;
{
	A_AniWind_t	*aWin=(A_AniWind_t *)client_data;
	long i;
	float *im;
	int nx,ny;
   int curplane;
	unsigned char * rasterdata;
	char title[120];

	curplane = aWin->curplane;
   nx = aWin->imagexsize[curplane];
   ny = aWin->imageysize[curplane];
	rasterdata = (unsigned char*) aWin->data[curplane];

	gr_WidgetCursor(aWin->shell,XC_watch);

	if(NULL== (im = (float*) malloc(sizeof(float)*nx*ny))) 
			{ printf("Raster Print malloc error for image to print\n"); return; }
	
	/* convert raster image to a float array so that dumppsimage can use */
	for(i=0;i<nx*ny;i++) im[i] = (float) (rasterdata[i] * 1.0); 

	sprintf(title,"RASTER: %s",aWin->pathname);

   /* dumppsimage (im, nx, ny,  1, 1,  0.0,  255.0, title); */
   dumppsCOLORimage (im, nx, ny, 1,1, 0.0, 255.0, title, gr_color.palette);
   free (im);

	gr_WidgetCursor(aWin->shell,XC_draped_box);
	beep();
}

/* ------------------------------------------------------------------ */
/*
 *	Animate from stored raster images
*  also have a print button jng 23-feb-91
 */
#define MYEXTRA  26 /* for print button jng 23-feb-91 */

A_AniWind_t
*gr_InitAniLevel2(header,filename,pathname,parent,start,stop,numplanes,
	xsize,ysize,ispal,usePixmap,useDisk)
A_AniWind_t *header;
char   	 *filename,*pathname;
Widget	 parent;
int		 start,stop,numplanes,xsize,ysize,ispal;
Boolean	 usePixmap,useDisk;
{
	A_AniWind_t	*tmp;
	Widget		boxWind;
	short		i,j,winxsize,winysize,numFrames,frameStop;
	char		label[120],strng[120];
	XGCValues		gcvals;
	Display			*dpy;
	Window			win;
	Boolean     noCMap=TRUE;
	extern void gr_Anicontourdialog();

	gr_WidgetCursor(gr_topWin.shell,XC_watch);

	tmp = (A_AniWind_t *)td_Malloc(sizeof(A_AniWind_t),"A_AniWind_t");

	sprintf(label,"Animate %d planes from %s",numplanes,filename);

	tmp->gridOn = FALSE;
	tmp->usePixmap = usePixmap;
	tmp->useDisk = useDisk;
	tmp->xorg = tmp->yorg = 0;

	tmp->pathname = (char *)td_Malloc1D(1,strlen(pathname)+1,sizeof(char),
						"td_Malloc1D");
#ifdef RIOS
		Strcpy(tmp->pathname,pathname);
#else
		strcpy(tmp->pathname,pathname);
#endif
	if (tmp->useDisk == TRUE)
	{
		numFrames = 1;
		frameStop = start;
	}
	else
	{
		numFrames = numplanes;
		frameStop = stop;
	}
	tmp->imagexsize = (int *)td_Malloc1D(1,numFrames,sizeof(int),
		"td_Malloc1D");
	if (tmp->imagexsize == NULL)
	{
		fprintf(stderr,"Error\t: Out of memory in calloc imagexsize.\n");
		exit(-1);
	}
	tmp->imageysize = (int *)td_Malloc1D(1,numFrames,sizeof(int),
		"td_Malloc1D");
	if (tmp->imageysize == NULL)
	{
		fprintf(stderr,"Error\t: Out of memory in calloc imageysize.\n");
		exit(-1);
	}

	if (xsize > MINWINXSIZE)
		if (xsize > MAXWINXSIZE)
			winxsize = MAXWINXSIZE;
		else
			winxsize = xsize+LEEWAY;
	else
		winxsize = MINWINXSIZE+LEEWAY;

	if (ysize > MINWINYSIZE)
		if (ysize > MAXWINYSIZE)
			winysize = MAXWINYSIZE;
		else
			winysize = ysize+LEEWAY;
	else
		winysize = MINWINYSIZE+LEEWAY;

	tmp->shell = gr_MakeWindow("XDS Frame",parent,&(tmp->win),
					(XtCallbackProc)gr_CloseAniLevel,
					ANIWIND,label,"Close",(caddr_t)tmp,
					110,10,winxsize+8,winysize+170+MYEXTRA);

	XtManageChild(tmp->shell); /* gbourhis Jan 93 */

	boxWind = gr_MakeBulletin("XDSbulletin",tmp->win,
		2,winysize+2 ,275,134+MYEXTRA);

		gr_MakeButton("XDSbutton",boxWind,"Save",
					  (XtCallbackProc)gr_SaveAni,(caddr_t)tmp,
					  2,42,50,20);
/* #ifdef XIMAGE_PALETTE */
	if (gr_Data.paletteEditor) /* gbourhis Feb 93 */
	  {
	    PalData.client_data = (caddr_t) tmp->shell;
	    gr_MakeButton("XDSbutton",boxWind,"Palette",
			  (XtCallbackProc)PaletteBox, (caddr_t) &PalData,
			  2,65,50,20);
	  }
	else /* #else */
	  gr_MakeButton("XDSbutton",boxWind,"Palette",
			(XtCallbackProc)gr_LoadPAL,(caddr_t)tmp->shell,
			2,65,50,20);
/* #endif */

	gr_MakeButton("XDSbutton",boxWind,"Print",
		      (XtCallbackProc)gr_RasterImagePrint ,(caddr_t)tmp,
		      2,135,50,20);
	gr_MakeButton("XDSbutton",boxWind,"Contour",
		      (XtCallbackProc) gr_Anicontourdialog ,(caddr_t)tmp,
		      56,135,50,20);


	gr_MakeAniControls(boxWind,tmp,numplanes);

	tmp->imageVPort = gr_MakeVPort("XDSvport",tmp->win,
				       NOSCROLL,HP,NULL, NULL,5,(caddr_t)tmp,
				       2,2,winxsize,winysize);

	tmp->imageWin = gr_MakeWorkSpace("XDSworkspace",tmp->imageVPort,
					(XtCallbackProc)gr_AniExpose,NULL,NULL,(caddr_t)tmp,
					0,0,xsize,ysize);

	tmp->data = (char **)td_Malloc2D(1,numFrames,sizeof(char *),"td_Malloc2D");
	if (tmp->usePixmap == TRUE)
	tmp->image = (Pixmap *)td_Malloc1D(1,numFrames,sizeof(Pixmap),
		"td_Malloc1D");
	else
	tmp->ximage = (XImage **)td_Malloc1D(1,numFrames,sizeof(XImage *),
		"td_Malloc1D");

	dpy = XtDisplay(tmp->imageWin);
	win = XtWindow(tmp->imageWin);
	gcvals.foreground = BlackPixel(dpy,DefaultScreen(dpy));
	gcvals.background = WhitePixel(dpy,DefaultScreen(dpy));
	tmp->imageWinGC = XtGetGC(tmp->imageWin,
		GCForeground|GCBackground, &gcvals);
	XSetTSOrigin(dpy,tmp->imageWinGC,0,0);
	XSetFillStyle(dpy,tmp->imageWinGC,FillTiled);
	tmp->aniType = 2;
	tmp->playStop = 1;
	tmp->autoMode = AUTOOFF;
	tmp->curplane = 0;
	tmp->skip = 0;
	tmp->speed = 0;
	tmp->numplanes = numplanes;
	tmp->contourWin = NULL;

	for (j=0;j<start;j++) {
	   td_HdfgetRasData(pathname,gr_color.palette,
			&(tmp->imagexsize[0]),&(tmp->imageysize[0]),&ispal,FALSE);
			}

	i = 0;
	for (j=start;j<=frameStop;j++)
	{
		tmp->data[i] = td_HdfgetRasData(pathname,gr_color.palette,
				&(tmp->imagexsize[i]),&(tmp->imageysize[i]),&ispal,TRUE);
		
		if ((ispal == 1) && (noCMap))
		{   /* remove call to gr_ImageSetCMap. gbourhis Jan 93 */
		    gr_ImageInitCMapHDF(gr_color.palette);
		    noCMap = FALSE;
		}
		if (tmp->usePixmap == TRUE)
		{
		tmp->image[i] = gr_PixmapCreate(tmp->imageWin,tmp->imageWinGC,
						tmp->xorg,tmp->yorg,
						tmp->imagexsize[i],tmp->imageysize[i],tmp->data[i]);
		}
		else
		{
		tmp->ximage[i] = gr_ImageCreate(tmp->imageWin,
						tmp->imagexsize[i],tmp->imageysize[i],tmp->data[i]);
		}
		gr_AniDrawImage(dpy,win,tmp,i);
		i++;
	}

	/* Now we associate the shell with a colormap,
	   and we do the same for the image and the palette
	   sub-windows. gbourhis Jan 93 */
	gr_ImageSetCMap(tmp->shell);
#ifdef XtSpecificationRelease
	{
	  Arg arg;
	  Colormap cmap;
	  XtSetArg(arg, XtNcolormap, &cmap);
	  XtGetValues(tmp->shell, &arg, (Cardinal)1);
	  XSetWindowColormap(dpy, win, cmap);
	  XSetWindowColormap(dpy, XtWindow(palWidget), cmap);
	}
#endif

	if (tmp->useDisk == FALSE)
	{
		gr_AniDrawImage(dpy,win,tmp,0);
	}
	sprintf(strng,"First frame ID= %d, Last frame ID= %d\n",start,stop);
	gr_TextMsgOut(strng);
	sprintf(strng,"Dimensions of first frame= %dx%d.\n",
		tmp->imagexsize[0],tmp->imageysize[0]);
	gr_TextMsgOut(strng);

	tmp->parent = NULL;
	tmp->arbparent = NULL;
	tmp->prev 	= NULL;
	tmp->next	= header;
	if (header != NULL)
		header->prev = tmp;

	gr_WidgetCursor(tmp->shell,XC_draped_box);
	gr_WidgetCursor(gr_topWin.shell,XC_draped_box);

	return(tmp);
}


/*
 *	Close animation windows
 */
void
gr_CloseAniLevel(w, client_data, call_data)
Widget	w;
caddr_t	client_data;
caddr_t	call_data;
{
	A_AniWind_t	*aniWin=(A_AniWind_t *)client_data;
	Display		*dpy=XtDisplay(aniWin->imageWin);
	short i,numFrames;

	if (aniWin != NULL)
	{
		if (aniWin->playStop == 0)
		{
			/* stop the playing first */
			aniWin->playStop = 1;
			return;
		}

		/* update previous neighbour's pointer */
        if (aniWin->prev != NULL)
            aniWin->prev->next = aniWin->next;
        else
		{
			/* update parent of aniWin */
			switch (aniWin->aniType)
			{
				case 1:
            		aniWin->parent->aniWin = aniWin->next;
        			aniWin->parent->numAniWins--;
					break;
				case 2:
					gr_topWin.aniWin = aniWin->next;
					gr_topWin.numAniWins--;
					break;
				case 3:
            		aniWin->arbparent->aniWin = aniWin->next;
        			aniWin->arbparent->numAniWins--;
					break;
			}
		}

		/* update next neighbour's pointer */
        if (aniWin->next != NULL)
            aniWin->next->prev = aniWin->prev;

		if (aniWin->useDisk == TRUE)
			numFrames = 1;
		else
			numFrames = aniWin->numplanes;

		if (aniWin->usePixmap == TRUE)
			gr_TextMsgOut("Freeing Pixmaps... ");
		else
			gr_TextMsgOut("Freeing XImages... ");

		for (i=0;i<numFrames;i++)
		{
			if (aniWin->usePixmap == TRUE)
			{
				XFreePixmap(dpy,aniWin->image[i]);
			}
			else
			{
				XDestroyImage(aniWin->ximage[i]);
				td_Free((char *)aniWin->ximage[i]);
			}
			td_Free((char *)aniWin->data[i]);
		}
		if (aniWin->usePixmap == TRUE)
			td_Free((char *)aniWin->image);
		else
			td_Free((char *)aniWin->ximage);
		td_Free((char *)aniWin->data);
		td_Free((char *)aniWin->imagexsize);
		td_Free((char *)aniWin->imageysize);
		XtReleaseGC(aniWin->imageWin,aniWin->imageWinGC);
		XtDestroyWidget(aniWin->shell);
     	/* free contour window if necc */
         if (aniWin->contourWin != NULL) {
          	gr_AniClosecontourdialog (NULL, aniWin->contourWin, NULL);
           	aniWin->contourWin = NULL;
           	}

		td_Free((char *)aniWin);
		gr_TextMsgOut("Done.\n");
	}
}
