/*
 * This NCSA software product is public domain software.  Permission
 * is granted to do whatever you like with it. Should you feel compelled 
 * to make a contribution for the use of this software, please send 
 * comments as to what you like or don't like about the software, 
 * how you use it, how it helps your work, etc. to softdev@ncsa.uiuc.edu.
 *
 * Please send bug reports to bugs@ncsa.uiuc.edu
 *
 * Author: Dave Thompson, National Center for Supercomputing Applications
 *         davet@ncsa.uiuc.edu

This file was originally part of XIMAGE. It has been hacked to be part of XDS.

Conversion notes:
	The XDS read palette routine(s) should call SaveForUndo.
	(see CBLoadPal).
 */
#if ! defined(lint) && ! defined(LINT)
static char rcs_id[] = "$Id: xi_palette.c,v 1.3 1994/01/03 16:59:10 sxu Exp $";
#endif

/*  Compile, since we choose the palette option at run time.
 *  #ifdef XIMAGE_PALETTE 
 * gbourhis Feb 93.
 */
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>

#include <Xw/Xw.h>
#include <Xw/Toggle.h>

/*
#include <stdio.h>
*/
#include <math.h>

#include "gr_com.h"
/*#include "xi_buttons.h"*/

#include "ximage.h"

/*#include "xi_paletteP.h"*/


#define PALCOMPHEIGHT	100
#define PAL_WIDTH	28

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

/* Stuff from XDS. */
/*extern void gr_LoadPALSplit();*/
/*extern XColor gr_origCells[];*/		/* In gr_pal.c */

/* copy a color cell */
#define cpccell(a,b)	{\
			a.red = b.red; \
			a.green = b.green; \
			a.blue = b.blue;\
			a.flags = b.flags; \
			a.pad = b.pad;\
			}

#define MAX3(a,b,c) ((a>b)&&(a>c)) ? a : ((b > c)? b : c)
#define MIN3(a,b,c) ((a<b)&&(a<c)) ? a : ((b < c)? b : c)
#define SIGN(a) ((a)?(a/abs(a)):1) /* return 1 if zero */


extern	Widget	toplevelform;			/* The top dude (composite)*/
extern	void	CBEditPalEntry();
extern Widget MakeRasterImage();

static unsigned long white;
static unsigned long black;

/* added by gbourhis. Jan 93 */
static	A_Color_t *currentCS;			/* current color Structure */

static	Display	*myDpy;				/* Display for this program*/
static	Visual	*myVis;
static	Widget	top_pal_ctrl_widget;		/* pal ctrl window ap shell*/
static	Widget	pal_ctrl_widget;		/* composite widget ctrl win*/
static	XWindowAttributes pcw_attrib;		/* window attributes */
static	char	pal_loaded	= FALSE;	/* Is the palette loaded */
/*static*/	
/*   Colormap fcmap=0;    */
static	char palette_ctrl_window_showing = FALSE;	/* self explanitory */
static	XColor	uccells[256];			/* Undo to these colors*/
static	XColor	bccells[256];			/* Back up copy */
	XColor	rccells[256];			/* current colors */
static	XColor	origccells[256];		/* original copy */

static	int	numColors;		/* max num colors on this screen*/

static	char	pal_sfile[80];			/* palette save file name */
static	char	use_entire_palette=FALSE;
static	XImage	*palImage;			/* the palette display XImage*/
static	Widget	pal_image;			/* The palette display window*/
static	crlastx = 0;
static	Widget pal_comp;
static	GC 	pal_comp_gc;
static	int	comp_pen=0;		/* color to draw new component */
static	unsigned long comp_pen_dcolor;	/* color to draw comp pen */
static	int	comp_last_x=0;
static	int	comp_last_y=0;
static	XPoint	rpoints[256];		/*drawn red points(CBDrawComponent)*/
static	XPoint	gpoints[256];		/*drawn green points*/
static	XPoint	bpoints[256];		/*drawn blue points*/
static	XPoint	cpoints[256];		/*drawn cyan  */
static	XPoint	mpoints[256];		/*drawn magenta  */
static	XPoint	ypoints[256];		/*drawn yellow */
static	XPoint	hpoints[256];		/*drawn hue */
static	XPoint	spoints[256];		/*drawn saturation*/
static	XPoint	vpoints[256];		/*drawn value */
static	unsigned int	rgbcmyhsv=0;	/* What's plotted (r=(1<<9),v=(1<<1))*/
static	palRedraw = FALSE;

static void	CBInitRotate();
static void	CBReset();
#ifdef UNDER_DEVELOPMENT
static void	CBEvalExpr();
#endif
static void	CBNewLoadPal();
static void	CBSetPen();
static void	CBUnSetPen();
static void	CBPrepChangeComp();
static void	CBChangeComponent();
static void	CBEndChangeComp();
void	RedrawComponent();
static void	CBTranspose();
static void	TransposeCMap();
static void	CBFiddle();
static void	CRotate();
static int	ChooseColor();
static void	CBRedrawComponents();
void	CBPalSave();
static void	CBUndo();
static void	SaveForUndo();
static void	CBSmooth();
static void	CBInstallCMap();
static void	CBUnInstallCMap();
static void	CBDrawComponent();
static void	CBUnDrawComponent();



/* Copy colormap cells from one XColor array to another.
in,out	XColor pointers to XColor arrays to be copied.
num		Number of XColor elements to copy.
copypixel	Copies the pixel value if true.
NOTE:
	Assumes there is space in the output array!!
*/
void copy_colors(in, out, num, copypixel)
register XColor	*in,*out;
register int	num, copypixel;
{
	while(--num > 0)
	{	out->red = in->red;
		out->green = in->green;
		out->blue = in->blue;
		out->flags = in->flags;
		if(copypixel)
			out->pixel = in->pixel;
		out->pad = in->pad;
		out++; in++;
	}
}

/* Mod by gbourhis on Jan 93 : remove cmap parameter */
void StoreColors(ccells,cmap, redraw)
/* Store colors in colormap */
XColor	ccells[];	/* colors to be stored */
Colormap cmap;          /* Color map to be stored  */
int	redraw;		/* Should I redraw components */
/* store colors in colormap, except for black & white if 
 * the global variable use_entire_palette is set to false*/
{
        Visual *vis;

	vis = myVis;
	if (vis->class == StaticColor) {
		gr_TextMsgOut("Can't set colors for this StaticColor display\n");
		return;
		}
	if (vis->class != PseudoColor) {
	    gr_TextMsgOut("Can't set colors for this non-PseudoColor display\n");
	    return;
	    }
	if (!use_entire_palette) {
		XColor	inblackcell;
		XColor	inwhitecell;

		inblackcell = ccells[black];
		inwhitecell = ccells[white];

		/* restore black and white */
		ccells[black].red   = (unsigned short) 0;
		ccells[black].blue  = (unsigned short) 0;
		ccells[black].green = (unsigned short) 0;
		ccells[black].flags = DoRed|DoGreen|DoBlue;

		ccells[white].red   = (unsigned short) 65535;
		ccells[white].blue  = (unsigned short) 65535;
		ccells[white].green = (unsigned short) 65535;
		ccells[white].flags = DoRed|DoGreen|DoBlue;

		XStoreColors(myDpy,cmap,ccells,numColors);
		DBPRINTARG("colormap id: %x\n", cmap);

		/* take it back out */
		ccells[black]=inblackcell;
		ccells[white]=inwhitecell;
		}
	else
		XStoreColors(myDpy,cmap,ccells,numColors);

	if (redraw && palette_ctrl_window_showing)
	  {	/* gbourhis Jan 93 : if redraw is asked and the
		   colors that we just stored comes from the same
		   color structure as the current one, we update
		   rccells.		*/
		if (currentCS->cmapCells == ccells)
		  {
		    copy_colors(ccells, rccells, currentCS->maxColors,
				FALSE);
		  }
		RedrawComponent();
	  }

	return;
} /* StoreColors() */



static void CBUseEntirePalette(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	use_entire_palette = ! use_entire_palette;
	StoreColors(rccells,currentCS->cmap,TRUE);

	if (use_entire_palette) {
                gr_LabelSetValue(w,"Use entire palette");
		gr_ButtonSet(w,True);
		}
	else {
                gr_LabelSetValue(w,"Don't use entire palette");
		gr_ButtonSet(w,True);
		}
}

/* Close/destroy palettebox window. Also copy current colormap values
back to xds caller.
*/
void ClosePaletteBox(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
A_Palette_t	*PalData = (A_Palette_t *) client_data;

/*	XtUnmanageChild(top_pal_ctrl_widget);*/


	if (palette_ctrl_window_showing) {
		if( (PalData != NULL) && (PalData->cs != NULL))
		{	copy_colors(rccells, PalData->cs->cmapCells,
				256, FALSE);
		}
/*		CBUnInstallCMap(top_pal_ctrl_widget,NULL,NULL);*/
		XtDestroyWidget(top_pal_ctrl_widget);
		}


	palette_ctrl_window_showing = FALSE;
}


static int palette_initialized = 0;

/*int InitPalette(dpy)*/
int InitPalette(wid)
Widget	wid;
{
Display *dpy;
int x;
int screen;

	if (palette_initialized)
	{	printf("InitPalette called again.\n");
		return(1);
	}
	dpy    = XtDisplay(wid);
	myDpy = dpy;
	screen = DefaultScreen(dpy);
	myVis = gr_GetVisual(dpy, screen);

	white = WhitePixel(dpy,screen);
	black = BlackPixel(dpy,screen);

	numColors = XDisplayCells(dpy,screen);
	if (numColors > 256) {
		numColors = 256;   /* only use max 256 color entries */
		}

	/* Create startup default palette (use X servers) */ 
#ifdef OLD
	/* Now done in gr_pal.c */
	for(x=0;x < 256; x++)
		origccells[x].pixel = x;
	XQueryColors(dpy,DefaultColormap(dpy,screen),
			origccells,numColors);
#endif
	if((palImage = gr_ImageCreate(wid,gr_colorSplit.maxColors,30,
		gr_palData))== NULL)
		return(0);
	palette_initialized = 1;
	return(1); /* initialize ok */
}

#ifdef UNDER_DEVELOPMENT
void CBInitPal(w,client_data,call_data)
/* This procedure called on exposure of palette control window*/
/* Sets the colormap for the window */
Widget w;
caddr_t client_data;
caddr_t call_data;
{
        Display *dpy;
	Arg arg;

	w = top_pal_ctrl_widget;
	/* printf("CBInitPal() I've been called\n"); */
	fflush(stdout);
	dpy = XtDisplay(w);
/*	XSync(dpy,False);*/

	if (!defStaticVisual)
	  {
#ifdef XtSpecificationRelease
	    XtSetArg(arg, XtNcolormap, fcmap);
	    XtSetValues(w, &arg, (Cardinal)1);
#else
	    XSetWindowColormap(dpy,XtWindow(w),fcmap);
#endif /* XtSpecificationRelease */
	  }

	XtRemoveEventHandler(w,ExposureMask,0,CBInitPal,NULL);

	/* I don't think this command should be here, but it seems *
	 * to make it work.....oh well... 			   *
	 * Shake up the ICCCM window manager maybe? 		   */
	if (gr_Data.installCMap)
/**/		XInstallColormap(dpy,fcmap);

	if (!defStaticVisual) {
		XSetWindowColormap(dpy,XtWindow(w),fcmap);
		XSync(dpy,False);
		}

}
#endif

/* Create a new color map, initialize and install it.
Should only be called once, but at this point, I don't know who will do it.
Its quite likely that windows other than w will want to have fcmap installed.
But then fcmap is a global, isn't it?


This should support really creating multiple colormaps.
	One colormap for each image window. Map should be passed
	to install routines rather than requesting a new one. This
	may require adding a colormap field to the _t structs?
*/
static XIMAGE_newcolormap(dpy, w, gr_color, v, alloc)
Display	*dpy;
Widget	w;			/* gbourhis Jan 93: changed w from Window */
				/* to Widget type; w need not to be realized */
A_Color_t *gr_color;
Visual	*v;
int	alloc;
{
        int	x;
#ifndef XtSpecificationRelease
	XSetWindowAttributes attrib;
#else
	Arg arg;
#endif
#define fcmap gr_color->cmap

	if (myVis->class != PseudoColor)
        {	gr_TextMsgOut(
			"Can't set colors for this non-PseudoColor display\n");
		return;
	}

	if( fcmap == 0)
	{
		DBPRINT("XIMAGE_newcolormap: creating new color map.\n"); 
		fcmap = XCreateColormap(dpy, RootWindowOfScreen(XtScreen(w)),
					v, alloc);
		for(x=0;x < 256; x++)
			origccells[x].pixel = x;
		XQueryColors(dpy,DefaultColormap(dpy,DefaultScreen(dpy)),
				origccells,numColors);
		for(x=0;x < 256; x++) {
			uccells[x].pixel = rccells[x].pixel = x;
			cpccell(rccells[x],origccells[x]);
			cpccell(uccells[x],origccells[x]);
			}
	}
/*	This probably wants some attribute changed instead of slamming it in.
*/
	if (!defStaticVisual) {
/*
		printf( "XIMAGE_newcolormap: Installing color map 0x%x on Window 0x%x.\n",
			fcmap, w);
*/
	  /* Use the intrinsics to set the colormap. gbourhis Jan 93 */
#ifdef XtSpecificationRelease
		XtSetArg(arg, XtNcolormap, fcmap);
		XtSetValues(w, &arg, (Cardinal)1);
		if (XtIsRealized(w))
		  XSetWindowColormap(dpy,XtWindow(w),fcmap);
#else
		attrib.colormap = fcmap;
		XChangeWindowAttributes(dpy,XtWindow(w),CWColormap,&attrib);
#endif /* XtSpecificationRelease */

	        if (gr_Data.installCMap)
			XInstallColormap(dpy,fcmap);
	}
#undef   fcmap
}

/* Called whenever palette button is pushed. */
void PaletteBox(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
        Widget	buttonbox1;
	Widget	buttonbox2;
	Widget	buttonbox3;
	Widget	boxwind;
	
	Display *dpy;
	Visual	*vis;
	int x;
	int	xpos,ypos;
	A_Palette_t	*PalData = (A_Palette_t *) client_data;

	if (palette_ctrl_window_showing) {
		gr_TextMsgOut("Palette window already open\n");
		return;
		}

	/* Make sure client_data is OK. */
	if( (PalData->Load_Palette == NULL) ||
		    (PalData->Save_Palette == NULL))
		{	
		        printf("PaletteBox called with bad client_data\n");
			return;
		}

	currentCS = PalData->cs; /* gbourhis Jan 93 */

	dpy = XtDisplay(toplevelform);
	vis = gr_GetVisual(myDpy, DefaultScreen(myDpy));
	if (vis->class != PseudoColor) {
		gr_TextMsgOut("Can't use X Image Palette on this display.\n");
		gr_TextMsgOut("Not a Pseudo Color device\n");
		return;
		}

	if ( DisplayPlanes(dpy,XDefaultScreen(dpy)) != 8 ) {
		gr_TextMsgOut("Can't use X Image Palette on this display.\n");
		gr_TextMsgOut("Not an 8 bit display\n");
		return;
		}
		

	gr_TextMsgOut("Opening Palette Box\n");

	rgbcmyhsv = 0;
	comp_pen = 0;
	comp_last_x = comp_last_y = 0;
	crlastx = 0;

	top_pal_ctrl_widget = 
		gr_MakeWindow("XDS Palette", 
			gr_topLevel,
			&boxwind, ClosePaletteBox,
			PALWIND, "XDS Palette", "Close", client_data, 5,5,
/*			ANIWIND, "XDS Palette", "Close", NULL, 5,5,*/
			360, 290+PALCOMPHEIGHT);
/*			360, 285+PALCOMPHEIGHT);*/
	pal_ctrl_widget = boxwind;

/*	XSync(dpy,False);*/
	XIMAGE_newcolormap(dpy, /*gbourhis Jan 93*/top_pal_ctrl_widget,
		currentCS, gr_GetVisual(dpy,DefaultScreen(dpy)),AllocAll);

	/* Copy current colors used by calling window. */
	copy_colors(PalData->cs->cmapCells, rccells, 256, TRUE);
	copy_colors(rccells, origccells, 256, TRUE);
	copy_colors(PalData->cs->cmapCells, uccells, 256, TRUE);

	/* Make compatible with Release 2 window managers */

        if (gr_Data.installCMap) /* Add the handlers only if */
	  {			/*  installCMap is on. gbourhis Jan 93 */
	    XtAddEventHandler(top_pal_ctrl_widget,EnterWindowMask,FALSE,
			      CBInstallCMap,NULL);
	    XtAddEventHandler(top_pal_ctrl_widget,LeaveWindowMask,FALSE,
			      CBUnInstallCMap,NULL);
	  }

#ifdef XtSpecificationRelease	/* gbourhis Jan 93 */
	XtManageChild(top_pal_ctrl_widget);
#endif

	buttonbox1 = gr_MakeBulletin("XPAL",pal_ctrl_widget,
		1,180+PALCOMPHEIGHT, 355,80);

/*
	b[PAL_LOAD] = gr_MakeButton("XPAL",buttonbox1,"Load",
		CBNewLoadPal,NULL,5,1,0,0);
*/
/*
	b[PAL_LOAD] = gr_MakeButton("XPAL",buttonbox1,"Load",
		PalData->Load_Palette,PalData->client_data,5,1,0,0);
*/
	b[PAL_LOAD] = gr_MakeButton("XPAL",buttonbox1,"Load",
		CBNewLoadPal, client_data,5,1,0,0);

	b[PAL_RESET] = gr_MakeButton("XPAL",buttonbox1,"Reset",
		CBReset,(caddr_t)NULL,
		40,1,0,0);
	(void) gr_MakeButton("XPAL",buttonbox1,"Undo",CBUndo,
			     (caddr_t)NULL,83,1,0,0);
	b[PAL_SMOOTH] = gr_MakeButton("XPAL",buttonbox1,"Smooth",
				CBSmooth,(caddr_t)&comp_pen,300,1,0,0);

#ifdef UNDER_DEVELOPMENT
	(void) gr_MakeButton("XPAL",buttonbox1,"Edit Pal Entry",CBEditPalEntry,
					rccells,142,1,0,0);
	b[PAL_EVAL] = gr_MakeButton("XPAL",buttonbox1,"Eval Expr",
				CBEvalExpr,NULL,240,1,0,0);
#endif


/*
	b[PAL_SAVE] = gr_MakeButton("XPAL",buttonbox1,"Save",CBPalSave,NULL,5,30,0,0);
*/
/*
	b[PAL_SAVE] = gr_MakeButton("XPAL",buttonbox1,"Save",
		PalData->Save_Palette, PalData->client_data,5,30,0,0);
*/
	b[PAL_SAVE] = gr_MakeButton("XPAL",buttonbox1,"Save",
		PalData->Save_Palette, (caddr_t)PalData,5,30,0,0);

/*
	pal_sfile[0]='\0';
	{ Widget msgVport;

		gr_MakeText("XDStext", buttonbox1, &msgVport,
			NOSCROLL, SELECTABLE,
			STRINGSOURCE, pal_sfile,45,32,300,20);
	}
*/
	gr_MakeToggle("XDStoggle", buttonbox1, "Don't use entire palette",
		DIAMOND, True, CBUseEntirePalette, CBUseEntirePalette,NULL,
		45, 60, 0, 0);
	buttonbox2 = gr_MakeBulletin("XPAL",pal_ctrl_widget,1,
			40+PALCOMPHEIGHT, 80,135);

	gr_MakeTitleBar("XDSlabel", buttonbox2, "Wholistic", 1,2, 78, 0);
	b[PAL_FIDDLE] = gr_MakeButton("XPAL",buttonbox2,"Fiddle",
			CBFiddle, (caddr_t)NULL,5,25,0,0);
	b[PAL_INVERT] = gr_MakeButton("XPAL",buttonbox2,"Flip",
			CBTranspose, (caddr_t)NULL,5,55,0,0);
/*b[PAL_T_ROTATE] =gr_MakeButton("XPAL",buttonbox2,"Track Rotate",
			CBRotate,NULL,70,25,0,0);
*/
/*	b[PAL_ROTATE] = gr_MakeButton("XPAL",buttonbox2,"Rotate",
			NULL,NULL,5,85,0,0);
*/
	gr_WidgetCursor(buttonbox2,XC_hand2);

	buttonbox3 = gr_MakeBulletin("XPAL",pal_ctrl_widget,
			85,40+PALCOMPHEIGHT, 270,135);

	gr_MakeTitleBar("XDSlabel", buttonbox3,
		"Component Palette Manipulation",
		1, 1, 268, 0);
	b[PAL_PRED] = gr_MakeToggle("XDStoggle", buttonbox3, "",SQUARE,
				False,
				CBDrawComponent, CBUnDrawComponent, CRED,
				5, 25, 0, 0);
	b[PAL_RED] = gr_MakeToggle("XDStoggle", buttonbox3, "Red",DIAMOND,
                                False,
                                CBSetPen, CBUnSetPen, CRED,
                                25, 25, 0, 0);

	b[PAL_PGREEN] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CGREEN,5,55,0,0);
	b[PAL_GREEN] = gr_MakeToggle("XDStoggle",buttonbox3,"Green",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CGREEN,25,55,0,0);
	b[PAL_PBLUE] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CBLUE,5,85,0,0);
	b[PAL_BLUE] = gr_MakeToggle("XDStoggle",buttonbox3,"Blue",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CBLUE,25,85,0,0);
	b[PAL_PCYAN] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CCYAN,80,25,0,0);
	b[PAL_CYAN] = gr_MakeToggle("XDStoggle",buttonbox3,"Cyan",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CCYAN,100,25,0,0);
	b[PAL_PMAGENTA] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CMAGENTA,80,55,0,0);
	b[PAL_MAGENTA] = gr_MakeToggle("XDStoggle",buttonbox3,"Magenta",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CMAGENTA,
				100,55,0,0);
	b[PAL_PYELLOW] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CYELLOW,80,85,0,0);
	b[PAL_YELLOW] = gr_MakeToggle("XDStoggle",buttonbox3,"Yellow",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CYELLOW,
				100,85,0,0);
	b[PAL_PHUE] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CHUE,170,25,0,0);
	b[PAL_HUE] = gr_MakeToggle("XDStoggle",buttonbox3,"Hue",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CHUE,190,25,0,0);
	b[PAL_PSATURATION] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CSATURATION,170,55,0,0);
	b[PAL_SATURATION] = gr_MakeToggle("XDStoggle",buttonbox3,"Saturation",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CSATURATION,
				190,55,0,0);
	b[PAL_PVALUE] = gr_MakeToggle("XDStoggle",buttonbox3,"",
				SQUARE, False,
				CBDrawComponent,
				CBUnDrawComponent,CVALUE,170,85,0,0);
	b[PAL_VALUE] = gr_MakeToggle("XDStoggle",buttonbox3,"Value",
				DIAMOND, False,
				CBSetPen,CBUnSetPen,CVALUE,
				190,85,0,0);

	gr_WidgetCursor(buttonbox3,XC_hand2);

	pal_image = MakeRasterImage("PaletteDisplay",pal_ctrl_widget,
				47,0,palImage,currentCS->cmap,NULL,NULL);


	pal_comp = gr_MakeBulletin("Palette_Components",pal_ctrl_widget,
				47,35,255,
				PALCOMPHEIGHT+2);

	pal_comp = gr_MakeWorkSpace("XDSworkspace", pal_ctrl_widget,
			CBRedrawComponents, NULL, NULL, NULL,
			47,35,255,PALCOMPHEIGHT+2);

	{
	static XGCValues gcvalues;
	gcvalues.foreground = black;
	gcvalues.background = white;
	pal_comp_gc = XtGetGC(pal_comp,(GCForeground|GCBackground),&gcvalues);
	}

	
	/* Component palette display window drawing */
	XtAddEventHandler(pal_comp,ButtonPressMask,0,
			CBPrepChangeComp,NULL );
        XtAddEventHandler(pal_comp,Button1MotionMask,0,
			CBChangeComponent,NULL );
	XtAddEventHandler(pal_comp,ButtonReleaseMask|LeaveWindowMask,0,
			CBEndChangeComp,NULL );
	gr_WidgetCursor(pal_comp,XC_pencil);


        XtAddEventHandler(pal_image,ButtonPressMask,0,CBInitRotate,NULL );
        XtAddEventHandler(pal_image,Button1MotionMask,0,CRotate,NULL );
        gr_WidgetCursor(pal_image,XC_sb_h_double_arrow);

/*	XSync(dpy,False);
	StoreColors(rccells,TRUE);
	XSync(dpy,False);
*/

	StoreColors(rccells,currentCS->cmap,TRUE);

	palette_ctrl_window_showing = TRUE;

	return;

} /* PaletteBox() */



static void CBRedrawComponents(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	RedrawComponent();
}

#if 0				/* not used */
static void CBCompKey(w,client_data,call_data)
/* this routine is suppose to set which component to draw with 
 * but the HP workspace widget doesn't seem to be returning anything
 * meaningful when a key pressed.... either that or I don't know how
 * to use it. 
 */
Widget w;
caddr_t client_data;
caddr_t call_data;
{
/*	printf("Just pressed %d key(call_data)\n",(int) call_data);
	printf("Just pressed %c key(call_data)\n",(char *) call_data);
	printf("Just pressed %d key(client_data)\n",(int) client_data);
*/
	/* will use CBSetPen() */
	/* then set the toggle */
}
#endif				/* not used */

static void CBTranspose(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	TransposeCMap();
	return;
}

static void CBInstallCMap(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
        if (gr_Data.installCMap) /* gbourhis Jan 93 */
		XInstallColormap(XtDisplay(w),currentCS->cmap);
}

static void CBUnInstallCMap(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
        if (gr_Data.installCMap) /* gbourhis Jan 93 */
		XUninstallColormap(XtDisplay(w),currentCS->cmap);
}

static void CBInitRotate(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
Window root, child;
int	root_x,root_y;
int	win_x,win_y;
unsigned int	keys_buttons;

	SaveForUndo(rccells);
	if (XQueryPointer(XtDisplay(w),XtWindow(w),&root,&child,
		&root_x,&root_y,&win_x,&win_y,&keys_buttons)) {
		crlastx = win_x;
		}
}

/*
static void GotPalFile()
{
	CBLoadPal(top_pal_ctrl_widget,NULL,NULL);
	
}
*/
static void DidntGetPalFile()
{
	gr_TextMsgOut("Palette load canceled\n");
}

/* Load new palette by calling xds routine then copying data from where
it was put.
*/
static void CBNewLoadPal(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
A_Palette_t     *PalData = (A_Palette_t *) client_data;

	/* Make sure we have something to call. */
	if( (PalData == NULL) || (PalData->Load_Palette == NULL))
		return;
	/* Call appropriate XDS routine to read file. */
	(PalData->Load_Palette)(w, PalData->client_data, call_data);
	/* Now, copy data to rccells so we can fiddle, etc. */
	/* CAN'T copy, since window isn't even painted yet! */
}


void ConvertHSVtoRGB(h,s,v,pr,pg,pb)
double h; /* 0.0 to 360.0 */
double s; /* 0.0 to 1.0 */
double v; /* 0.0 to 1.0 */
unsigned short *pr,*pg,*pb; /* 0 to 65535 */
{
double r,g,b;
int i;
double f;
double p1,p2,p3;

	r = ((double) *pr) / (double) 65535.0;
	g = ((double) *pg) / (double) 65535.0;
	b = ((double) *pb) / (double) 65535.0;

	if (h == 360.0)
		h = 0.0;

	h = h / 60.0;

	i = (int) h;
	f = h - ((double) i);

	p1 = v * (1.0 - s);
	p2 = v * (1.0 - (s * f));
	p3 = v * (1.0 - (s * (1.0 - f)));

	switch (i) {
		case 0:
			r = v; g = p3; b = p1;
			break;
		case 1:
			r = p2; g = v; b = p1;
			break;
		case 2:
			r = p1; g = v; b = p3;
			break;
		case 3:
			r = p1; g = p2; b = v;
			break;
		case 4:
			r = p3; g = p1; b = v;
			break;
		case 5:
			r = v; g = p1; b = p2;
			break;
		}

	*pr = (unsigned short) (r * 65535.0);
	*pg = (unsigned short) (g * 65535.0);
	*pb = (unsigned short) (b * 65535.0);

} /* ConvertHSVtoRGB */

int ConvertRGBtoHSV(pr,pg,pb,h,s,v)
/* will return 0 if hue is undefined else return 1*/
unsigned short pr,pg,pb; /* 0 to 65535 */
double	*h; /* between 0.0 and 360.0 */
double	*s; /* between 0.0 and 1.0 */
double	*v; /* between 0.0 and 1.0 */
{
double	r,g,b;
double	range;
double	min;
double  rl,gl,bl;

	r = ((double)pr) / (double)65535.0;
	g = ((double)pg) / (double)65535.0;
	b = ((double)pb) / (double)65535.0;

	*v  = MAX3(r,g,b);
	min = MIN3(r,g,b);

	range = *v - min;

	if (*v)
		*s = range / *v;
	else
		*s = 0;

        if (*s) {
		rl = (*v - r) / range;
		gl = (*v - g) / range;
		bl = (*v - b) / range;

	        if ( *v == r ) {
			if ( min == g)
				*h = 5.0 + bl;
			else
				*h = 1.0 - gl;
	                }
		else {
			if ( *v == g) {
				if ( min == b)
					*h = 1.0 + rl;
				else
					*h = 3.0 - bl;
				}
			else {
				if (min == r)
					*h = 3.0 + gl;
				else
					*h = 5.0 - rl;
				}
			}
		*h = *h * 60.0;
		} /* if (*s)
	else
		return(0); /* h is undefined */

	return(1);
	
} /* ConvertRGBtoHSV() */



static void DrawComponent(component)
/* Draw the color components in the component window */
int	component;	/* which component to draw */
{
int x;
int y;
XGCValues	gcval;

        gcval.foreground = ChooseColor(rccells,component);
        XChangeGC(XtDisplay(pal_comp), pal_comp_gc, GCForeground, &gcval);
	switch (component){
		case CRED :
			for (x = 0 ; x < 256 ; x++ ) {
				y = (int) ((float) (rccells[x].red >> 8)* 
						(float) (100.0 / 255.0));
				rpoints[x].x = x;
				rpoints[x].y = 100 - y;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,rpoints,256,CoordModeOrigin);
			break;
		case CGREEN:
			for (x = 0 ; x < 256 ; x++ ) {
				y = (int) ((float) (rccells[x].green >> 8)* 
						(float) (100.0 / 255.0));
				gpoints[x].x = x;
				gpoints[x].y = 100 - y;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,gpoints,256,CoordModeOrigin);
			break;
		case CBLUE:
			for (x = 0 ; x < 256 ; x++ ) {
				y = (int) ((float) (rccells[x].blue >> 8)* 
						(float) (100.0 / 255.0));
				bpoints[x].x = x;
				bpoints[x].y = 100 -y;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,bpoints,256,CoordModeOrigin);
			break;
		case CCYAN:
			for (x = 0 ; x < 256 ; x++ ) {
				y = (int) ((float) (rccells[x].red >> 8)* 
						(float) (100.0 / 255.0));
				cpoints[x].x = x;
				cpoints[x].y = y;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,cpoints,256,CoordModeOrigin);
			break;
		case CMAGENTA:
			for (x = 0 ; x < 256 ; x++ ) {
				y = (int) ((float) (rccells[x].green >> 8)* 
						(float) (100.0 / 255.0));
				mpoints[x].x = x;
				mpoints[x].y = y;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,mpoints,256,CoordModeOrigin);
			break;
		case CYELLOW:
			for (x = 0 ; x < 256 ; x++ ) {
				y = (int) ((float) (rccells[x].blue >> 8)* 
						(float) (100.0 / 255.0));
				ypoints[x].x = x;
				ypoints[x].y = y;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,ypoints,256,CoordModeOrigin);
			break;
		case CHUE: {
			double h,s,v;
			for (x= 0; x < 256; x++ ) {
				if (!ConvertRGBtoHSV(rccells[x].red,
					rccells[x].green,rccells[x].blue,
					&h,&s,&v)) {
					h = 0; /* undefined */
					}
		
				y = (int) ((double)(h * (100.0 / 360.0)));
				hpoints[x].x = x;
				hpoints[x].y = 100 - y;
				} 
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,hpoints,256,CoordModeOrigin);
			}
			break; /*CHUE*/
		case CSATURATION: {
			int r,g,b;
			int s;
			int max,min;

			for (x = 0 ; x < 256 ; x++ ) {
				r = (int) (((float) (rccells[x].red >> 8))* 
						(float) (100.0 / 255.0));
				g = (int) (((float) (rccells[x].green >> 8))* 
						(float) (100.0 / 255.0));
				b = (int) (((float) (rccells[x].blue >> 8))* 
						(float) (100.0 / 255.0));

				max = MAX3(r,g,b);
				min = MIN3(r,g,b);

				if (max != 0)
		    		    s=(int)(100.0 *(((float) (max - min)) / 
						((float) max)));
				else
				     s = 0;
		
				spoints[x].x = x;
				spoints[x].y = 100 - s;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,spoints,256,CoordModeOrigin);
			}
			break;
		case CVALUE: {
			int r,g,b;
			int value;
			for (x = 0 ; x < 256 ; x++ ) {
				r = (int) ((float) (rccells[x].red >> 8)* 
						(float) (100.0 / 255.0));
				g = (int) ((float) (rccells[x].green >> 8)* 
						(float) (100.0 / 255.0));
				b = (int) ((float) (rccells[x].blue >> 8)* 
						(float) (100.0 / 255.0));

				value = (int) MAX3(r,g,b);

				vpoints[x].x = x;
				vpoints[x].y = 100 - value;
				}
			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,vpoints,256,CoordModeOrigin);
			}
			break;
		} /* switch */

			
	
	rgbcmyhsv = rgbcmyhsv | component;
	return;
	
} /* DrawComponent() */

static void CBDrawComponent(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	DrawComponent((int) client_data);
}


static void UnDrawComponent(component)
int component;
{
XGCValues	gcval;
static	Arg arglist[]={{XtNset,(XtArgVal) True}};

        gcval.foreground = white;
        XChangeGC(XtDisplay(pal_comp), pal_comp_gc, GCForeground, &gcval);
	switch (component) {
		case CRED:
			if ((comp_pen == CRED) && (! palRedraw)){
				XtSetValues(b[PAL_PRED],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,rpoints,256,CoordModeOrigin);
			break;
		case CGREEN:
			if ((comp_pen == CGREEN) && (! palRedraw)){
				XtSetValues(b[PAL_PGREEN],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,gpoints,256,CoordModeOrigin);
			break;
		case CBLUE:
			if ((comp_pen == CBLUE) && (! palRedraw)){
				XtSetValues(b[PAL_PBLUE],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,bpoints,256,CoordModeOrigin);
			break;
		case CCYAN:
			if ((comp_pen == CCYAN) && (! palRedraw)){
				XtSetValues(b[PAL_PCYAN],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,cpoints,256,CoordModeOrigin);
			break;
		case CMAGENTA:
			if ((comp_pen == CMAGENTA) && (! palRedraw)){
				XtSetValues(b[PAL_PMAGENTA],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,mpoints,256,CoordModeOrigin);
			break;
		case CYELLOW:
			if ((comp_pen == CYELLOW) && (! palRedraw)){
				XtSetValues(b[PAL_PYELLOW],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,ypoints,256,CoordModeOrigin);
			break;
		case CHUE:
			if ((comp_pen == CHUE) && (! palRedraw)){
				XtSetValues(b[PAL_PHUE],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,hpoints,256,CoordModeOrigin);
			break;
		case CSATURATION:
			if ((comp_pen == CSATURATION) && (! palRedraw)){
				XtSetValues(b[PAL_PSATURATION],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,spoints,256,CoordModeOrigin);
			break;
		case CVALUE:
			if ((comp_pen == CVALUE) && (! palRedraw)){
				XtSetValues(b[PAL_PVALUE],arglist,1);
				return;
				}

			XDrawPoints(XtDisplay(pal_comp),XtWindow(pal_comp),
				pal_comp_gc,vpoints,256,CoordModeOrigin);
			break;
	} /* switch */

	rgbcmyhsv = rgbcmyhsv ^ (rgbcmyhsv & component) ;
	if (! palRedraw)
		RedrawComponent();

} /* UnDrawComponent() */

static void CBUnDrawComponent(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	UnDrawComponent((int) client_data);
}



static void CBReset(w,client_data,call_data)
/* Set colormap back to last loaded colors */
Widget w;
caddr_t client_data;
caddr_t call_data;
{
int x;
	SaveForUndo(rccells);
	for(x=0; x < 256 ; x++) {
		rccells[x].pixel = x;
		cpccell(rccells[x],origccells[x]);
		}
	RedrawComponent();
	StoreColors(rccells,currentCS->cmap,TRUE);
} /* CBReset() */

/*
static void CBEvalExpr(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	* Not working yet, but we'll blame it on the user for
	   not knowing how to use this feature *

	gr_TextMsgOut("Bad expression in cut/paste buffer\n");
}
*/


static void TransposeCMap()
/* Flip the colormap:  (0<-> 255, 1<->254, etc.)*/
{
int	x;
XColor	tmp;

	SaveForUndo(rccells);
	for (x=0; x < 128 ;x++) {
		cpccell(tmp,rccells[255-x]);
		cpccell(rccells[255-x],rccells[x]);
		cpccell(rccells[x],tmp);
		}
	StoreColors(rccells,currentCS->cmap,TRUE);

	return;

} /* TransposeCMap() */


static void FiddlePalette(w,xdim,ydim,xpos,ypos)
Widget w;
int	xdim,ydim;
int	xpos,ypos;
{
double a,b;
double unit_Theta = (double) 3.14159 / (double) (ydim*2);
double up,down;
register int prej,i,j,k;
int	NUMCOLORS = 256;

	xpos = (((xpos < 0)?0:xpos)>xdim)?xdim:xpos;
	ypos = (((ypos < 0)?0:ypos)>ydim)?ydim:ypos;

	a = (double) tan((double) (unit_Theta * (double) (ydim - ypos)));

	up = 1 + (short) (127.0 * a);
	down = 256 - (short) (128.0 * a);
	if (up > down)
		b = (((double)xpos / (double)xdim) * (double)(up - down))
				 + (double) down;
	else
		b = (((double)xpos / (double)xdim) * (double)(down - up))
			 + (double) up;
	
	prej = 1;

	for ( i = 1 ; i <= NUMCOLORS - 2 ; i++) {
	    j = (short) (a * (double) (i - (NUMCOLORS/2)) + b);
	    if ((j > 0) && (j <= NUMCOLORS-2)) {
		for ( k = prej; k <= j - 1 ; k++)
		   /*if((rccells[k].pixel!=white)&&(rccells[k].pixel!=black))*/
				cpccell(rccells[k],bccells[i]);
		/*if ((rccells[j].pixel!=white)&&(rccells[j].pixel!=black))*/
			cpccell(rccells[j],bccells[i]);
		}
	    else
		if (j >= NUMCOLORS-1) {
			for ( k = prej; k <= NUMCOLORS-2; k++)
				/*if ((rccells[k].pixel!=white)
				    &&(rccells[k].pixel!=black))*/
					cpccell(rccells[k],bccells[i]);
			break;
			}
		else
			continue;

	    prej = j + 1;
 	    }

	for(;j < NUMCOLORS;j++) 
		/*ccells[j].pixel = bccells[255].pixel;*/
		cpccell(rccells[j],bccells[255]);

        StoreColors(rccells,currentCS->cmap,TRUE);
}

static void Cfiddle(w,client_data,call_data)
/* Do linear expansion and compression on palette */
Widget w;
caddr_t client_data;
caddr_t call_data;
{
Window root, child;
int	root_x,root_y;
int	win_x,win_y;
unsigned int	keys_buttons;

	if (XQueryPointer(XtDisplay(w),XtWindow(w),&root,&child,
	    &root_x,&root_y,&win_x,&win_y,&keys_buttons)) {
		FiddlePalette(w,pcw_attrib.width,pcw_attrib.height,
			win_x,win_y);
		}

} /* Cfiddle() */


static void CBPrepFiddle(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
int	x;
	SaveForUndo(rccells);
	for (x=0; x< 256 ; x++) {
		cpccell(bccells[x],rccells[x]);
		bccells[x].pixel = rccells[x].pixel;
		}
}

static void CBEndFiddle(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
Window root, child;
int     root_x,root_y;	/* X & Y coordinates with respect to root */
int     win_x,win_y;	/* X & Y coordinates with respect to window */
unsigned int    keys_buttons;
int	win;

	win = XtWindow(w);

        if (XQueryPointer(XtDisplay(w),win,&root,&child,
                &root_x,&root_y,&win_x,&win_y,&keys_buttons)) {
		XWarpPointer(XtDisplay(w),win,win,win_x,win_y,
		pcw_attrib.width,pcw_attrib.height,30,200);
		}
	XUngrabPointer(XtDisplay(w),CurrentTime);
        XtRemoveEventHandler(pal_ctrl_widget,Button1MotionMask,0,Cfiddle,NULL);
	XtRemoveEventHandler(pal_ctrl_widget,ButtonReleaseMask,0,
			CBEndFiddle,NULL);
} /* CBEndFiddle() */


static void CBFiddle(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	if(XGrabPointer(XtDisplay(w),XtWindow(pal_ctrl_widget),False,
		PointerMotionMask|ButtonReleaseMask,
		GrabModeAsync,GrabModeSync,
		XtWindow(pal_ctrl_widget),
		XCreateFontCursor(XtDisplay(w),XC_fleur),
		CurrentTime)) {
			gr_TextMsgOut("Can't grab pointer for fiddle\n");
			return;
			}

        XtAddEventHandler(pal_ctrl_widget,Button1MotionMask,0,Cfiddle,NULL );
	XtAddEventHandler(pal_ctrl_widget,ButtonReleaseMask,0,
			CBEndFiddle,NULL);

	CBPrepFiddle(pal_ctrl_widget,(caddr_t)NULL,(caddr_t)NULL);


	XGetWindowAttributes(XtDisplay(w),XtWindow(pal_ctrl_widget),
			&pcw_attrib);
} /* CBFiddle() */

static RotatePalette(w,xdim,ydim,xpos,ypos)
Widget w;
int xdim,ydim;
int xpos,ypos;
{
int offset;
int x;
int new;

	if ((crlastx)&& (crlastx != xpos)) {
		for(x = 0;x < 256; x++)
			cpccell(bccells[x],rccells[x]);

		offset = xpos - crlastx;

		for(x=0; x < 256; x++) {
			new = x + offset;
			new = (new > 255) ? (new - 256) : 
					(new < 0) ? (new + 256): new;
			cpccell(rccells[new],bccells[x]);
			}

		StoreColors(rccells,currentCS->cmap,TRUE);
		}
	crlastx = xpos;
	return;

} /* RotatePalette() */


static void CRotate(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
Window root, child;
int     root_x,root_y;	/* X & Y coordinates with respect to root */
int     win_x,win_y;	/* X & Y coordinates with respect to window */
unsigned int    keys_buttons;

        if (XQueryPointer(XtDisplay(w),XtWindow(w),&root,&child,
                &root_x,&root_y,&win_x,&win_y,&keys_buttons)) {

		if ((win_x <= 255) && (win_x > 0))
	                RotatePalette(w,255,28,win_x,win_y);
                }
}





/*static*/ void RedrawComponent()
{
	palRedraw = TRUE;
	if (rgbcmyhsv & CRED ){
		UnDrawComponent(CRED);
		DrawComponent(CRED);
		}
	if (rgbcmyhsv & CGREEN) {
		UnDrawComponent(CGREEN);
		DrawComponent(CGREEN);
		}
	if (rgbcmyhsv & CBLUE) {
		UnDrawComponent(CBLUE);
		DrawComponent(CBLUE);
		}
	if (rgbcmyhsv & CCYAN) {
		UnDrawComponent(CCYAN);
		DrawComponent(CCYAN);
		}
	if (rgbcmyhsv & CMAGENTA) {
		UnDrawComponent(CMAGENTA);
		DrawComponent(CMAGENTA);
		}
	if (rgbcmyhsv & CYELLOW) {
		UnDrawComponent(CYELLOW);
		DrawComponent(CYELLOW);
		}
	if (rgbcmyhsv & CHUE) {
		UnDrawComponent(CHUE);
		DrawComponent(CHUE);
		}
	if (rgbcmyhsv & CSATURATION) {
		UnDrawComponent(CSATURATION);
		DrawComponent(CSATURATION);
		}
	if (rgbcmyhsv & CVALUE) {
		UnDrawComponent(CVALUE);
		DrawComponent(CVALUE);
		}
	palRedraw = FALSE;
	return;
} /* RedrawComponent() */

static void CBSetPen(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
Arg	arglist[10];
Cardinal i=0;

	XtSetArg(arglist[i],XtNset,False);	i++;
	/*****reset old toggle*/
	switch(comp_pen) {
		case CRED:
			XtSetValues(b[PAL_RED],arglist,i);
			break;
		case CGREEN:
			XtSetValues(b[PAL_GREEN],arglist,i);
			break;
		case CBLUE:
			XtSetValues(b[PAL_BLUE],arglist,i);
			break;
		case CCYAN:
			XtSetValues(b[PAL_CYAN],arglist,i);
			break;
		case CMAGENTA:
			XtSetValues(b[PAL_MAGENTA],arglist,i);
			break;
		case CYELLOW:
			XtSetValues(b[PAL_YELLOW],arglist,i);
			break;
		case CHUE:
			XtSetValues(b[PAL_HUE],arglist,i);
			break;
		case CSATURATION:
			XtSetValues(b[PAL_SATURATION],arglist,i);
			break;
		case CVALUE:
			XtSetValues(b[PAL_VALUE],arglist,i);
			break;
		default:
			break;
		} /* switch */
	
	comp_pen = (unsigned int) client_data;

	if (!(comp_pen & rgbcmyhsv)) { /* if not already drawn then draw it*/
		i=0;
	 	XtSetArg(arglist[i],XtNset,True);	i++;
		switch (comp_pen) {
			case CRED:
				DrawComponent(CRED);
				XtSetValues(b[PAL_PRED],arglist,i);
				break;
			case CGREEN:
				DrawComponent(CGREEN);
				XtSetValues(b[PAL_PGREEN],arglist,i);
				break;
			case CBLUE:
				DrawComponent(CBLUE);
				XtSetValues(b[PAL_PBLUE],arglist,i);
				break;
			case CCYAN:
				DrawComponent(CCYAN);
				XtSetValues(b[PAL_PCYAN],arglist,i);
				break;
			case CMAGENTA:
				DrawComponent(CMAGENTA);
				XtSetValues(b[PAL_PMAGENTA],arglist,i);
				break;
			case CYELLOW:
				DrawComponent(CYELLOW);
				XtSetValues(b[PAL_PYELLOW],arglist,i);
				break;
			case CHUE:
				DrawComponent(CHUE);
				XtSetValues(b[PAL_PHUE],arglist,i);
				break;
			case CSATURATION:
				DrawComponent(CSATURATION);
				XtSetValues(b[PAL_PSATURATION],arglist,i);
				break;
			case CVALUE:
				DrawComponent(CVALUE);
				XtSetValues(b[PAL_PVALUE],arglist,i);
				break;
			default:
				break;
			} /* switch */
		} /* if */
} /* CBSetPen() */



static void CBUnSetPen(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	comp_pen = 0;
}



static void SetPenColor(dpy,wingc,color)
/*
 * Set pen color for drawing.
 * Using an 8-bit palette, 0 <= color <= 255
 */
Display		*dpy;
GC		wingc;
unsigned long color;		/* changed from short to long. gbourhis
				   Jan 93 */
{
XGCValues	gcval;
        gcval.foreground = color;
        XChangeGC(dpy,wingc, GCForeground, &gcval);
}

		
PlotComp(w,x,y,comp)
Widget w;
int x,y;
int comp;
{
Display	*dpy; 
Window	win;

	dpy = XtDisplay(w);
	win = XtWindow(w);

	switch(comp) {
		case CRED:	
			rccells[x].red = (int) ((((float) y)/
					((float) PALCOMPHEIGHT)) * 65535.0);
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,rpoints[x].y);
			rpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,rpoints[x].y);
			break;
		case CGREEN:	
			rccells[x].green= (int) ((((float)y)/
					((float) PALCOMPHEIGHT)) * 65535.0);
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,gpoints[x].y);
			gpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,gpoints[x].y);
			break;
		case CBLUE:	
			rccells[x].blue= (int) ((((float) y)/
					((float) PALCOMPHEIGHT)) * 65535.0);
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,bpoints[x].y);
			bpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,bpoints[x].y);
			break;
		case CCYAN:	
			rccells[x].red = (int) (65535.0 - ((((float) y)/
						((float) PALCOMPHEIGHT))
						 * 65535.0));
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,cpoints[x].y);
			cpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,cpoints[x].y);
			break;
		case CMAGENTA:	
			rccells[x].green= (int) (65535.0 - ((((float) y)/
						((float) PALCOMPHEIGHT))
						 * 65535.0));
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,mpoints[x].y);
			mpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,mpoints[x].y);
			break;
		case CYELLOW:	
			rccells[x].blue = (int) (65535.0 - ((((float) y)/
						((float) PALCOMPHEIGHT))
						 * 65535.0));
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,ypoints[x].y);
			ypoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,ypoints[x].y);
			break;
		case CHUE:{

			double h,s,v;
			if (!ConvertRGBtoHSV(rccells[x].red,rccells[x].green,
					rccells[x].blue,&h,&s,&v)) {
				h = 0;
				}
			h = ((double)360.0)
				*((double) y) / ((double) PALCOMPHEIGHT);
			ConvertHSVtoRGB(h,s,v,&(rccells[x].red),
				&(rccells[x].green),&(rccells[x].blue));

			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,hpoints[x].y);
			hpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,hpoints[x].y);
			
			}
			break;
		case CSATURATION:
			{
			double h,s,v;

			if (!ConvertRGBtoHSV(rccells[x].red,rccells[x].green,
					rccells[x].blue,&h,&s,&v)) {
				h = 0;
				}

			s = ((double)y) / ((double) PALCOMPHEIGHT);

			ConvertHSVtoRGB(h,s,v,&(rccells[x].red),
				&(rccells[x].green),&(rccells[x].blue));

			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,spoints[x].y);
			spoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,spoints[x].y);
			
			}
			break;
		case CVALUE: {
			int max;
			double ratio;
			double yval;

			yval = ((double) y) * 
					(65535.0 / ((double)PALCOMPHEIGHT));
			max = MAX3(rccells[x].red,rccells[x].green,
				rccells[x].blue);
			if (max != 0) {
				ratio =((double) rccells[x].red)/(double) max;
				rccells[x].red = (int) (ratio *  yval);
				ratio =((double) rccells[x].green)/(double)max;
				rccells[x].green = (int) (ratio *  yval);
				ratio =((double) rccells[x].blue)/(double) max;
				rccells[x].blue = (int) (ratio *  yval);
				}
			else {
				rccells[x].red = rccells[x].blue = 
					rccells[x].green = yval;
				}
			SetPenColor(dpy,pal_comp_gc,white);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,vpoints[x].y);
			vpoints[x].y = PALCOMPHEIGHT - y;
			SetPenColor(dpy,pal_comp_gc,comp_pen_dcolor);
			XDrawPoint(dpy,win,pal_comp_gc,
					x,vpoints[x].y);
			}
			break;

		default:
			break;
		}
		
	return;
} /* PlotComp() */



static void CBChangeComponent(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
Window root, child;
int     root_x,root_y;
int     win_x,win_y;
unsigned int    keys_buttons;
int	x;
float	y;
float	yinc,ydiff;
Display	*dpy; 
Window	win;

	if (!comp_pen)		/* No component selected */
		return;

	dpy = XtDisplay(w);
	win = XtWindow(w);
        if (!XQueryPointer(dpy,win,&root,&child,
                &root_x,&root_y,&win_x,&win_y,&keys_buttons)) 
		return;

	win_x = (win_x > 255)? 255 : (win_x <0)? 0 : win_x;
	win_y = (win_y > PALCOMPHEIGHT)? PALCOMPHEIGHT: 
					(win_y < 0)? 0 : win_y;

	win_y = PALCOMPHEIGHT - win_y; /* 4th quadrant -> 1st quadrant */

	if (comp_last_x == 0)
		PlotComp(pal_comp,win_x,win_y,comp_pen);
	else {
		ydiff = (comp_last_x > win_x)?(comp_last_y - win_y):
				(win_y - comp_last_y);

		if (comp_last_x > win_x) {
			yinc = (float) ydiff /((comp_last_x == win_x)?1.0:
					((float)(comp_last_x - win_x)));
			for (x = win_x,y=win_y; x < comp_last_x; x++,y=y+yinc)
				PlotComp(pal_comp,x,(int) y,comp_pen);
			}
		else{
			yinc = (float) ydiff / ((comp_last_x == win_x)?1.0:
					((float)( win_x - comp_last_x)));
			for (x = comp_last_x, y=comp_last_y; x < win_x; x++,y=y+yinc)
				PlotComp(pal_comp,x,(int) y,comp_pen);
			}
		}
	comp_last_x = win_x;
	comp_last_y = win_y;
	StoreColors(rccells,currentCS->cmap,FALSE);
} /* CBChangeComponent() */
			


static void CBPrepChangeComp(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	comp_last_x = 0;
	comp_last_y = 0;
	comp_pen_dcolor = ChooseColor(rccells,comp_pen);
	SaveForUndo(rccells);
	CBChangeComponent(w,client_data,call_data);
}

static void CBEndChangeComp(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
	if (comp_last_x || comp_last_y)
		RedrawComponent();
	comp_last_x = 0;
	comp_last_y = 0;
}

static int ChooseColor(ccells,whichone)
/* pick the best entry in the palette to match color */
XColor	ccells[];	/* the palette */
int	whichone;	/* which color to find in palette */
{
int best;
int best_cmpval;
int cmpval;
int x;
int r,b,g;

	best = black;
	best_cmpval = -1 - (1 >> 18);
	switch (whichone) {
	case CRED:	/* find purest red */
		for(x=0; x < 256 ; x++) {
			g = ccells[x].green;
			b = ccells[x].blue;
			cmpval = ccells[x].red - g - b - abs(g-b);
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CGREEN:	/* find purest green */
		for(x=0; x < 256 ; x++) {
			r = ccells[x].red;
			b = ccells[x].blue;
			cmpval = ccells[x].green - r - b - abs(r-b);
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CBLUE:	/* find purest blue */
		for(x=0; x < 256 ; x++) {
			r = ccells[x].red;
			g = ccells[x].green;
			cmpval = ccells[x].blue - r - g - abs(r-g);
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CCYAN:	/* find purest cyan */
		for(x=0; x < 256 ; x++) {
			cmpval = ccells[x].green + ccells[x].blue
						- ccells[x].red;
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CMAGENTA:	/* find purest magenta */
		for(x=0; x < 256 ; x++) {
			cmpval = ccells[x].red + ccells[x].blue
						- ccells[x].green;
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CYELLOW:	/* find purest yellow */
		for(x=0; x < 256 ; x++) {
			cmpval = ccells[x].red + ccells[x].green
						- ccells[x].blue;
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CHUE:	/* find purest orange */
		for(x=0; x < 256 ; x++) {
			r = ccells[x].red;
			b = ccells[x].blue;
			cmpval = r-b - abs(((r+b)>>1) - ccells[x].green);
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	case CSATURATION:	/* find purest purplish color?? */
		for(x=0; x < 256 ; x++) {
			r = ccells[x].red;
			g = ccells[x].green;
			cmpval = b-g - abs(((b+g)>>1) - ccells[x].red);
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	
	case CVALUE:	
	default:
		/* find purest black */
		for(x=0; x < 256 ; x++) {
			cmpval = b-r - abs(((b+r)>>1) - ccells[x].green);
			/*cmpval = 65535 - ((ccells[x].red + ccells[x].green
					+ccells[x].blue)/3);
			*/
			if (cmpval > best_cmpval) {
				best_cmpval = cmpval;
				best = x;
				}
			}
		break;
	} /* switch */

	return(best);
}

void CBPalSave(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
A_Palette_t     *PalData = (A_Palette_t *) client_data;

/*	printf("!! Palette Save Not implemented yet.\n");*/
	gr_SavePal(w, PalData->client_data, call_data);

}


static void CBUndo(w,client_data,call_data)
Widget w;
caddr_t client_data;
caddr_t call_data;
{
int	x;
XColor	real_undo[256];

	for(x=0;x < 256; x++) {
		rccells[x].pixel = x;
		cpccell(real_undo[x],uccells[x]);
		}

	SaveForUndo(rccells);

	for(x=0;x < 256; x++) {
		rccells[x].pixel = x;
		cpccell(rccells[x],real_undo[x]);
		}
	StoreColors(rccells,currentCS->cmap,TRUE);
}

static void SaveForUndo(rccells)
XColor	rccells[];
{
int	x;

	for(x=0;x < 256; x++) {
		uccells[x].pixel = x;
		cpccell(uccells[x], rccells[x]);
		}
}

static void CBSmooth(w,client_data,call_data)
Widget w;
caddr_t client_data;	/* contains a pointer to the component*/
caddr_t call_data;
{
int x;
int	comp_pen;	/* Drawing color; smooth this one */

	SaveForUndo(rccells);

	comp_pen = *( (int *) client_data);
	if (!comp_pen) {
		gr_TextMsgOut("Please select a component to manipulate first\n");
		return;
		}

	switch (comp_pen){
		case CRED:
		case CCYAN:
		    rccells[0].red = (rccells[255].red +rccells[1].red)/2;
		    for(x=1; x< 255; x++)
			rccells[x].red = 
				(rccells[x-1].red + rccells[x+1].red)/2;
		    rccells[255].red = (rccells[254].red +rccells[0].red)/2;
		    break;
		case CGREEN:
		case CMAGENTA:
		    rccells[0].green = 
				(rccells[255].green + rccells[1].green)/2;
		    for(x=1; x< 255; x++)
			rccells[x].green = 
				(rccells[x-1].green + rccells[x+1].green)/2;
		    rccells[255].green = 
				(rccells[254].green + rccells[0].green)/2;
		    break;
		case CBLUE:
		case CYELLOW:
		    rccells[0].blue = 
				(rccells[255].blue + rccells[1].blue)/2;
		    for(x=1; x< 255; x++)
			rccells[x].blue = 
				(rccells[x-1].blue + rccells[x+1].blue)/2;
		    rccells[255].blue = 
				(rccells[254].blue + rccells[0].blue)/2;
		    break;
		case CHUE:
		case CSATURATION:
		case CVALUE:
			/* ick, I'll do this some other time */
		    break;
		} /*switch */
		
	StoreColors(rccells,currentCS->cmap,TRUE);
} /* CBSmooth() */

/* Allow xds to call storecolors. */
void XIMAGE_setcmap(wid, gr_color)
Widget	wid;
/*  XColor	colors[];       */
A_Color_t *gr_color;

{
        Display	*dpy;

	dpy = XtDisplay(wid);
	XIMAGE_newcolormap(dpy, /* widget, not window. gbourhis Jan 93 */ wid,
		gr_color, gr_GetVisual(dpy,DefaultScreen(dpy)),AllocAll);

	StoreColors(gr_color->cmapCells, gr_color->cmap,FALSE);


}

int WriteSEQPalette(name,ccells)
char    *name;
XColor  *ccells;
{
FILE    *fp;
int     x;
char    buff[256];

        if (!(fp = fopen(name,"w"))) {
                sprintf(buff,"Can't open for writing file %s\n",name);
		gr_TextMsgOut(buff);
                return(-1);
                }

	/* Pick a default until we figure something better to do. */
	if(ccells == NULL) ccells = rccells;

        for (x=0; x < 256; x++)
                putc(((char )(ccells[x].red >> 8)),fp);
        for (x=0; x < 256; x++)
                putc(((char )(ccells[x].green >> 8)),fp);
        for (x=0; x < 256; x++)
                putc(((char )(ccells[x].blue >> 8)),fp);

        fclose(fp);
}
/* #endif XIMAGE_PALETTE*/
