/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
/* |                                                                   | */
/* | Permission to use, copy, modify, and to distribute this software  | */
/* | and its documentation for any purpose is hereby granted without   | */
/* | fee, provided that the above copyright notice appear in all       | */
/* | copies and that both that copyright notice and this permission    | */
/* | notice appear in supporting documentation.  There is no           | */
/* | representations about the suitability of this software for        | */
/* | any purpose.  this software is provided "as is" without express   | */
/* | or implied warranty.                                              | */
/* |                                                                   | */
/* +-------------------------------------------------------------------+ */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Shell.h>
#include <stdio.h>
#include "xpaint.h"
#include "misc.h"
#include "Paint.h"
#include "palette.h"

/*
**  It is now historical, that the Box and Area selection
**    operations are contained in the same file.
*/

static int		cutMode = 0;
static unsigned char	backgroundRGB[3] = { 255, 255, 255 };
static unsigned char	varianceRGB[3] = { 0, 0, 0 };

typedef struct {
	Boolean		area;		/* area or box */
	Boolean		lastType;

	Widget		w;
	Drawable	drawable;

	Boolean		drawn;

	int		wx, wy, dx, dy;

	/*
	**  The point region for area operators
	*/
	int		size, npoint;
	XPoint		*real_p, *window_p;

	/*
	**  The rectangles for a box
	*/
	int		lastX, lastY;
	XRectangle	rect;

	GC		gcx;

	/*
	**  The interesting stuff, for the active region
	**    the important part of pixBox is the width, height
	**    the x,y is where it is presently located on the screen.
	*/
	XRectangle	pixBox;
} LocalInfo;

#define MKRECT(rect, sx, sy, ex, ey, typeFlag) do {			\
	if (typeFlag) {							\
		(rect)->width  = MIN(ABS(sx - ex),ABS(sy - ey));	\
		(rect)->height = (rect)->width;				\
		(rect)->x = (ex - sx < 0) ? sx - (rect)->width : sx;	\
		(rect)->y = (ey - sy < 0) ? sy - (rect)->height : sy;	\
	} else {							\
		(rect)->x      = MIN(sx, ex);				\
		(rect)->y      = MIN(sy, ey);				\
		(rect)->width  = MAX(sx, ex) - (rect)->x;		\
		(rect)->height = MAX(sy, ey) - (rect)->y;		\
	}								\
} while (0)

/*
**  press
*/
static void	press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
{
	/*
	**  Check to make sure all buttons are up, before doing this
	*/
	if ((event->state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)) != 0)
		return;

	if (info->surface == opWindow) {
		l->w     = w;
	
		l->wx = event->x;
		l->wy = event->y;

		l->drawn = False;

		return;
	}
	
	/*
	**  Must be on the surface == pixmap now
	*/

	l->drawable = info->drawable;

	l->real_p[0].x = info->x;
	l->real_p[0].y = info->y;
	l->window_p[0].x = l->wx - info->zoom / 2;
	l->window_p[0].y = l->wy - info->zoom / 2;
	l->npoint = 1;
}

static void	keyPress(Widget w, LocalInfo *l, XKeyEvent *event, OpInfo *info) 
{
	KeySym	keysym;
	int	len, i;
	char	buf[21];

        if ((len = XLookupString(event, buf, sizeof(buf) - 1, &keysym, NULL)) == 0)
		return;

	/*
	**  Look for either backspace or delete and remove region
	*/
	for (i = 0; i < len; i++) {
		if (buf[i] == 0x08 || buf[i] == 0x7f) {
			PwRegionClear(w);
			return;
		}
	}
}

/*
**  motion
*/
static void	motionBoxBand(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info) 
{
	XRectangle	rect;

	if (l->drawn) {
		MKRECT(&rect, l->window_p[0].x, l->window_p[0].y, 
			      l->lastX, l->lastY, l->lastType);
		XDrawRectangles(XtDisplay(w), XtWindow(w), l->gcx, &rect, 1);
	}

	l->lastX = event->x - info->zoom / 2;
	l->lastY = event->y - info->zoom / 2;
	l->lastType = (event->state & ShiftMask);

	if (l->drawn = (l->window_p[0].x != l->lastX && l->window_p[0].y != l->lastY)) {
		MKRECT(&rect, l->window_p[0].x, l->window_p[0].y, 
				l->lastX, l->lastY, l->lastType);
		XDrawRectangles(XtDisplay(w), XtWindow(w), l->gcx, &rect, 1);
	}
}
static void	motionAreaBand(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info) 
{
	if (l->npoint != 0 && (l->real_p[l->npoint - 1].x == info->x) && (l->real_p[l->npoint - 1].y == info->y))
		return;

	l->window_p[l->npoint].x = event->x;
	l->window_p[l->npoint].y = event->y;
	l->real_p[l->npoint].x = info->x;
	l->real_p[l->npoint].y = info->y;

	XDrawLine(XtDisplay(w), XtWindow(w), l->gcx,
		l->window_p[l->npoint-1].x,
		l->window_p[l->npoint-1].y,
		l->window_p[l->npoint].x,
		l->window_p[l->npoint].y);
	XDrawPoint(XtDisplay(w), XtWindow(w), l->gcx,
		l->window_p[l->npoint].x,
		l->window_p[l->npoint].y);
		
		
	l->npoint++;

	if (l->npoint > l->size - 3) {
		l->size += 256;
		l->real_p = (XPoint*)XtRealloc((XtPointer)l->real_p,
					l->size * sizeof(XPoint));
		l->window_p = (XPoint*)XtRealloc((XtPointer)l->window_p,
					l->size * sizeof(XPoint));
	}
}
static void	motion(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info) 
{
	if (l->area)
		motionAreaBand(w, l, event, info);
	else
		motionBoxBand(w, l, event, info);
}

static Boolean	chromaCut(Widget w, LocalInfo *l, Pixmap *mask)
{
	GC		gc;
	XImage		*src, *mimg;
	XRectangle	*rect = PwScaleRectangle(w, &l->pixBox);
	int		x, y, count = 0;
	Pixel		p;
	XColor		*xcol;
	int		br, bg, bb;
	int		vr, vg, vb;
	int		pr, pg, pb;
	Boolean		mode = (cutMode == 1);
	Palette		*map;
	Colormap	cmap;
	int		step;

	src = PwGetImage(w, rect);
	XtVaGetValues(GetShell(w), XtNcolormap, &cmap, NULL);
	map = PaletteFind(w, cmap);

	if (*mask != None) {
		mimg = XGetImage(XtDisplay(w), *mask, 0, 0, rect->width, rect->height, AllPlanes, ZPixmap);
	} else {
		char	*data = (char*)XtMalloc(rect->width * rect->height * sizeof(long));
		int		i;

		mimg = NewXImage(XtDisplay(w), DefaultVisualOfScreen(XtScreen(w)), 1, rect->width, rect->height);

		memset(mimg->data, ~0, rect->height * mimg->bytes_per_line);
	}

	br = backgroundRGB[0];
	bg = backgroundRGB[1];
	bb = backgroundRGB[2];
	vr = varianceRGB[0];
	vg = varianceRGB[1];
	vb = varianceRGB[2];

	if (rect->height * rect->width > 2048)
		StateSetBusy(True);
	step = 256 * 64 / rect->width;

	for (y = 0; y < rect->height; y++) {
		for (x = 0; x < rect->width; x++) {
			if (!XGetPixel(mimg, x, y))
				continue;

			p = XGetPixel(src, x + rect->x, y + rect->y);

			xcol = PaletteLookup(map, p);
			pr = (xcol->red >> 8) & 0xff;
			pg = (xcol->green >> 8) & 0xff;
			pb = (xcol->blue >> 8) & 0xff;

			if (((br - vr) <= pr && pr <= (br + vr) &&
			     (bg - vg) <= pg && pg <= (bg + vg) &&
			     (bb - vb) <= pb && pb <= (bb + vb)) == mode)
				XPutPixel(mimg, x, y, False);
			else
				count++;
		}
		if (y % step == 0)
			StateTimeStep();
	}

	if (count != 0) {
		/*
		**  Not a solid region.
		*/

		if (*mask == None)
			*mask = XCreatePixmap(XtDisplay(w), XtWindow(w), rect->width, rect->height, 1);
		gc = XCreateGC(XtDisplay(w), *mask, 0, 0);
		XPutImage(XtDisplay(w), *mask, gc, mimg, 0, 0, 0, 0, rect->width, rect->height);
		XFreeGC(XtDisplay(w), gc);
	}

	XDestroyImage(mimg);

	if (rect->height * rect->width > 2048)
		StateSetBusy(False);


	return count != 0;
}

static void	releaseBoxBand(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
{
	XRectangle	rect;
	int		width, height;

	MKRECT(&rect, l->window_p[0].x, l->window_p[0].y, l->lastX, l->lastY, l->lastType);
	if (l->drawn) 
		XDrawRectangles(XtDisplay(w), XtWindow(w), l->gcx, &rect, 1);
	

	MKRECT(&l->pixBox, l->real_p[0].x, l->real_p[0].y, info->x, info->y, l->lastType);
	XtVaGetValues(w, XtNdrawWidth, &width, XtNdrawHeight, &height, NULL);

	if (l->pixBox.x + l->pixBox.width > width) 
		l->pixBox.width = width - l->pixBox.x;
	if (l->pixBox.y + l->pixBox.height > height) 
		l->pixBox.height = height - l->pixBox.y;
	if (l->pixBox.x < 0) {
		l->pixBox.width += l->pixBox.x;
		l->pixBox.x = 0;
	}
	if (l->pixBox.y < 0) {
		l->pixBox.height += l->pixBox.y;
		l->pixBox.y = 0;
	}
}
static Boolean	releaseAreaBand(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info, Pixmap *mask) 
{
	int	xmax, xmin, ymax, ymin;
	int	width, height, i;
	GC	gc;
	XPoint	tmp;

	XDrawLines(XtDisplay(w), XtWindow(w), l->gcx,
			l->window_p, l->npoint, CoordModeOrigin);
	
	if (l->npoint <= 2) 
		return False;
	
	l->window_p[l->npoint] = l->window_p[0];
	l->real_p[l->npoint]   = l->real_p[0];
	l->npoint++;
	
	xmin = xmax = l->real_p[0].x;		
	ymin = ymax = l->real_p[0].y;
	for (i = l->npoint - 1; i > 0; i--) {
		xmin = MIN(xmin, l->real_p[i].x);
		ymin = MIN(ymin, l->real_p[i].y);
		xmax = MAX(xmax, l->real_p[i].x);
		ymax = MAX(ymax, l->real_p[i].y);

		l->window_p[i].x = l->window_p[i].x - l->window_p[i-1].x;
		l->window_p[i].y = l->window_p[i].y - l->window_p[i-1].y;
		l->real_p[i].x   = l->real_p[i].x   - l->real_p[i-1].x;
		l->real_p[i].y   = l->real_p[i].y   - l->real_p[i-1].y;
	}

	XYtoRECT(xmin, ymin, xmax, ymax, &l->pixBox);
	XtVaGetValues(w, XtNdrawWidth, &width, XtNdrawHeight, &height, NULL);
	if (l->pixBox.x + l->pixBox.width > width)
		l->pixBox.width = width - l->pixBox.x;
	if (l->pixBox.y + l->pixBox.height > height) 
		l->pixBox.height = height - l->pixBox.y;
	if (l->pixBox.x < 0) {
		l->pixBox.width += l->pixBox.x;
		l->pixBox.x = 0;
	}
	if (l->pixBox.y < 0) {
		l->pixBox.height += l->pixBox.y;
		l->pixBox.y = 0;
	}

	*mask = XCreatePixmap(XtDisplay(w), XtWindow(w), 
				l->pixBox.width, l->pixBox.height, 1);
	gc = XCreateGC(XtDisplay(w), *mask, 0, 0);
	XSetFunction(XtDisplay(w), gc, GXclear);
	XFillRectangle(XtDisplay(w), *mask, gc, 0, 0, l->pixBox.width, l->pixBox.height);
	XSetFunction(XtDisplay(w), gc, GXset);
	tmp = l->real_p[0];
	l->real_p[0].x = l->dx = l->real_p[0].x - xmin;
	l->real_p[0].y = l->dy = l->real_p[0].y - ymin;
	XFillPolygon(XtDisplay(w), *mask, gc, l->real_p, l->npoint, 
				Complex, CoordModePrevious);
	l->real_p[0] = tmp;

	XFreeGC(XtDisplay(w), gc);

	return True;
}
static void	release(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
{
	int	mask;
	Pixmap	mpix;

	/*
	**  Check to make sure all buttons are up, before doing this
	*/
	mask = Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask;
	switch (event->button) {
	case Button1:	mask ^= Button1Mask; break;
	case Button2:	mask ^= Button2Mask; break;
	case Button3:	mask ^= Button3Mask; break;
	case Button4:	mask ^= Button4Mask; break;
	case Button5:	mask ^= Button5Mask; break;
	}
	if ((event->state & mask) != 0)
		return;

	mpix = None;

	if (l->area) {
		if (releaseAreaBand(w, l, event, info, &mpix) == False) {
			PwRegionFinish(w, True);
			return;
		}
	} else {
		releaseBoxBand(w, l, event, info);
	}

	if (l->pixBox.width <= 1 || l->pixBox.height <= 1) {
		PwRegionFinish(w, True);
		return;
	}
	if (cutMode != 0 && !chromaCut(w, l, &mpix)) {
		PwRegionFinish(w, True);
		return;
	}

	PwRegionSet(w, &l->pixBox, None, mpix);
}

/*
**  Those public functions
*/
void *SelectBoxAdd(Widget w)
{
	LocalInfo	*l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));

	l->area     = False;
	l->lastType = False;
	l->gcx      = GetGCX(w);

	l->size     = 8;
	l->real_p   = (XPoint *)XtCalloc(sizeof(XPoint), l->size);
	l->window_p = (XPoint *)XtCalloc(sizeof(XPoint), l->size);

	XtVaSetValues(w, XtNcompress, True, NULL);

	OpAddEventHandler(w, opWindow|opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
	OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, (OpEventProc)motion, l);
	OpAddEventHandler(w, opWindow, ButtonReleaseMask, FALSE, (OpEventProc)release, l);

	OpAddEventHandler(w, opWindow, KeyPressMask, FALSE, (OpEventProc)keyPress, l);
	SetCrossHairCursor(w);

	return l;
}
void SelectBoxRemove(Widget w, LocalInfo *l)
{
	OpRemoveEventHandler(w, opWindow|opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
	OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, (OpEventProc)motion, l);
	OpRemoveEventHandler(w, opWindow, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
	OpRemoveEventHandler(w, opWindow, KeyPressMask, FALSE, (OpEventProc)keyPress, l);
	PwRegionFinish(w, False);

	XtFree((XtPointer)l->window_p);
	XtFree((XtPointer)l->real_p);
	XtFree((XtPointer)l);
}

void *SelectAreaAdd(Widget w)
{
	LocalInfo	*l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));

	l->area   = True;
	l->gcx    = GetGCX(w);

	XtVaSetValues(w, XtNcompress, False, NULL);

	l->size     = 256;
	l->real_p   = (XPoint *)XtCalloc(sizeof(XPoint), l->size);
	l->window_p = (XPoint *)XtCalloc(sizeof(XPoint), l->size);

	OpAddEventHandler(w, opWindow|opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
	OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, (OpEventProc)motion, l);
	OpAddEventHandler(w, opWindow, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
	OpAddEventHandler(w, opWindow, KeyPressMask, FALSE, (OpEventProc)keyPress, l);

	SetPencilCursor(w);

	return l;
}
void SelectAreaRemove(Widget w, LocalInfo *l)
{
	OpRemoveEventHandler(w, opWindow|opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
	OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, (OpEventProc)motion, l);
	OpRemoveEventHandler(w, opWindow, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
	OpRemoveEventHandler(w, opWindow, KeyPressMask, FALSE, (OpEventProc)keyPress, l);
	PwRegionFinish(w, False);

	XtFree((XtPointer)l->window_p);
	XtFree((XtPointer)l->real_p);
	XtFree((XtPointer)l);
}

/*
**  Dialog box
*/
typedef struct {
	Widget	redBar, greenBar, blueBar;
	Widget	redText, greenText, blueText;
	Widget	mode;
	Widget	shell;
	float	r, g, b;
	float	vr, vg, vb;
	Pixel	pixel;
} DialogInfo;

static DialogInfo	*dInfo = NULL;

static void closePopup(Widget w, Widget shell)
{
	XtPopdown(shell);
}
static void barCB(Widget bar, DialogInfo *l, float *percent)
{
	Widget	t;
	char	buf[20];

	if (l->redBar == bar) {
		l->vr = *percent;
		t = l->redText;
	} else if (l->greenBar == bar) {
		l->vg = *percent;
		t = l->greenText;
	} else if (l->blueBar == bar) {
		l->vb = *percent;
		t = l->blueText;
	} else {
		return;
	}
	sprintf(buf, "%d", (int)(255 * *percent));
	XtVaSetValues(t, XtNstring, buf, NULL);
}

static Widget addSB(Widget parent, Widget above, char *title, Widget *bar, Widget *text)
{
	Widget	form, label;

	form = XtVaCreateManagedWidget("form", formWidgetClass, parent,
			XtNborderWidth, 0,
			XtNfromVert, above,
			NULL);
	label = XtVaCreateManagedWidget("varianceLabel", labelWidgetClass, form,
			XtNlabel, title,
			XtNborderWidth, 0,
			XtNright, XtChainLeft,
			XtNleft, XtChainLeft,
			NULL);
	*bar = XtVaCreateManagedWidget("varianceBar", scrollbarWidgetClass, form,
			XtNorientation, XtorientHorizontal,
			XtNfromHoriz, label,
			XtNleft, XtChainLeft,
			NULL);
	*text = XtVaCreateManagedWidget("varianceText", asciiTextWidgetClass, form,	
		        XtNfromHoriz, *bar,
			XtNeditType, XawtextEdit,
			XtNwrap, XawtextWrapNever,
		        XtNresize, XawtextResizeWidth,
			XtNwidth, 50,
			XtNlength, 5,
			XtNstring, "0",
			NULL);

	return form;
}
static void deltaCB(Widget w, DialogInfo *l, XtPointer junk)
{
	XColor		*xcol, xcol2;
	int		dr, dg, db;
	char		buf[20];

	xcol = DoGrabColor(w);
	
	xcol2.pixel = l->pixel;
	XQueryColor(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)), &xcol2);

	dr = xcol->red - xcol2.red;
	dg = xcol->green - xcol2.green;
	db = xcol->blue - xcol2.blue;
	if (dr < 0) dr = -dr;
	if (dg < 0) dg = -dg;
	if (db < 0) db = -db;

	l->vr = (float)((dr >> 8) & 0xff) / 255.0;
	l->vg = (float)((dg >> 8) & 0xff) / 255.0;
	l->vb = (float)((db >> 8) & 0xff) / 255.0;

	sprintf(buf, "%d", (int)(255 * l->vr));
	XtVaSetValues(l->redText, XtNstring, buf, NULL);
	XawScrollbarSetThumb(l->redBar, l->vr, -1.0);
	sprintf(buf, "%d", (int)(255 * l->vg));
	XtVaSetValues(l->greenText, XtNstring, buf, NULL);
	XawScrollbarSetThumb(l->greenBar, l->vg, -1.0);
	sprintf(buf, "%d", (int)(255 * l->vb));
	XtVaSetValues(l->blueText, XtNstring, buf, NULL);
	XawScrollbarSetThumb(l->blueBar, l->vb, -1.0);
}

static void applyCB(Widget w, DialogInfo *l, XtPointer junk)
{
	XColor	xcol;
	int	t;

	xcol.pixel = l->pixel;
	xcol.flags = DoRed|DoGreen|DoBlue;
	XQueryColor(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)), &xcol);

	backgroundRGB[0] = (xcol.red >> 8) & 0xff;
	backgroundRGB[1] = (xcol.green >> 8) & 0xff;
	backgroundRGB[2] = (xcol.blue >> 8) & 0xff;

#define STUFF(src, dst) \
	t = (src) * 255; if (t < 0) t = 0; else if (t > 255) t = 255; dst = t

	STUFF(l->vr, varianceRGB[0]);
	STUFF(l->vg, varianceRGB[1]);
	STUFF(l->vb, varianceRGB[2]);

#undef STUFF

	if (l->mode != None)
		cutMode = ((int)XawToggleGetCurrent(l->mode)) - 1;
	OperationSelectCallAcross(cutMode);
}
static void okCB(Widget w, DialogInfo *l, XtPointer junk)
{
	applyCB(w,l,junk);
	closePopup(w, GetShell(w));
}

void SelectChromaDialog(Widget w)
{
	Widget			topform, form, cpick, ok, cancel, apply;
	Widget			label, tog;
	Widget			above;
	DialogInfo		*l = dInfo;

	if (l != NULL && l->shell != None) {
		if (l->mode != None)
			XawToggleSetCurrent(l->mode, (XtPointer)(cutMode+1));
		XtPopup(l->shell, XtGrabNone);
		XMapRaised(XtDisplay(l->shell), XtWindow(l->shell));
		return;
	}

	dInfo = l = XtNew(DialogInfo);

	l->r = (float)backgroundRGB[0] / 255.0;
	l->g = (float)backgroundRGB[1] / 255.0;
	l->b = (float)backgroundRGB[2] / 255.0;
	l->vr = (float)varianceRGB[0] / 255.0;
	l->vg = (float)varianceRGB[1] / 255.0;
	l->vb = (float)varianceRGB[2] / 255.0;

	l->shell = XtVaCreatePopupShell("chroma", topLevelShellWidgetClass, GetToplevel(w),
				NULL);

	topform = XtVaCreateManagedWidget("form", formWidgetClass, l->shell,
				NULL);

	/*
	**  First create the list of toggle buttons for the mode selection
	*/
#if 0
	form = XtVaCreateManagedWidget("form", formWidgetClass, topform,
				XtNborderWidth, 0,
				NULL);

	label = XtVaCreateManagedWidget("selectModeLabel", labelWidgetClass, form,
				XtNborderWidth, 0,
				NULL);

	/*
	**  radioData = mode + 1
	*/
	tog = None;
	tog = XtVaCreateManagedWidget("mode0", toggleWidgetClass, form,
				XtNfromVert, label,
				XtNradioGroup, tog,
				XtNradioData, 1,
				XtNstate, (cutMode == 0),
				NULL);
	tog = XtVaCreateManagedWidget("mode1", toggleWidgetClass, form,
				XtNfromVert, tog,
				XtNradioGroup, tog,
				XtNradioData, 2,
				XtNstate, (cutMode == 1),
				NULL);
	tog = XtVaCreateManagedWidget("mode2", toggleWidgetClass, form,
				XtNfromVert, tog,
				XtNradioGroup, tog,
				XtNradioData, 3,
				XtNstate, (cutMode == 2),
				NULL);
	l->mode = tog;
#else
	l->mode = None;
#endif

	/*
	**  Now the color choser.
	*/
	form = XtVaCreateManagedWidget("form", formWidgetClass, topform,
#if 0
				XtNfromHoriz, form,
#endif
				XtNborderWidth, 0,
				NULL);

	cpick = ColorPicker(form, DefaultColormapOfScreen(XtScreen(w)), NULL);
	l->pixel = ColorPickerGetPixel(cpick);

	above = XtVaCreateManagedWidget("delta", commandWidgetClass, form,
				XtNfromVert, cpick,
				NULL);
	XtAddCallback(above, XtNcallback, (XtCallbackProc)deltaCB, (XtPointer)l);
	
	above = addSB(form, above, "Red Variance",
				&l->redBar, &l->redText);
	above = addSB(form, above, "Green Variance", 
				&l->greenBar, &l->greenText);
	above = addSB(form, above, "Blue Variance", 
				&l->blueBar, &l->blueText);

        XtAddCallback(l->redBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);
        XtAddCallback(l->greenBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);
        XtAddCallback(l->blueBar, XtNjumpProc, (XtCallbackProc)barCB, (XtPointer)l);

        AddDestroyCallback(l->shell, (void (*)(Widget, void *, XEvent *))closePopup, l->shell);

	ok = XtVaCreateManagedWidget("ok", commandWidgetClass, form,
				XtNfromVert, above,
				NULL);
	apply = XtVaCreateManagedWidget("apply", commandWidgetClass, form,
				XtNfromVert, above,
				XtNfromHoriz, ok,
				NULL);
	cancel = XtVaCreateManagedWidget("cancel", commandWidgetClass, form,
				XtNfromVert, above,
				XtNfromHoriz, apply,
				NULL);
	XtAddCallback(cancel, XtNcallback, (XtCallbackProc)closePopup, (XtPointer)l->shell);
	XtAddCallback(apply, XtNcallback, (XtCallbackProc)applyCB, (XtPointer)l);
	XtAddCallback(ok, XtNcallback, (XtCallbackProc)okCB, (XtPointer)l);

	XtPopup(l->shell, XtGrabNone);
}

void SelectSetCutMode(int value)
{
	cutMode = value;

	if (dInfo != NULL && dInfo->mode != None)  
		XawToggleSetCurrent(dInfo->mode, (XtPointer)(cutMode+1));
}
