/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: DNDDrop3.c /main/8 1995/07/14 11:52:47 drk $"
#endif
#endif
/*
*  (c) Copyright 1987, 1988, 1989 HEWLETT-PACKARD COMPANY */
/*
 *	file: DNDDrop3.c
 *
 *	This tests non-rectangular dropSites, i.e., dropSites that have to be
 *	represented by more that one rectangle.
 */

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <Xm/TextP.h>
#include <Xm/TextFP.h>
#include <Xm/FormP.h>
#include <Xm/PushBP.h>
#include <Xm/RowColumn.h>
#include <Xm/LabelP.h>
#include <Xm/DropSMgrP.h>
#include <Xm/DragCP.h>
#include <Xm/AtomMgr.h>


static void StartMyDragProc();
static void RaiseProc();
static void LowerProc();


XRectangle rects0[] = {
	{  40,   0,  40,  40 },
	{   0,  40, 120,  40 },
	{  40,  80,  40,  40 },
};

XRectangle rects1[] = {
	{   0,   0,  40,  40 },
	{  80,   0,  40,  40 },
	{   0,  40, 120,  40 },
};

XRectangle rects2[] = {
	{  20,   0,  40,  40 },
	{   0,  40,  80,  20 },
};

XRectangle rects3[] = {
	{   0,   0,  40,  60 },
	{  40,  20,  40,  20 },
};

typedef struct _DropZoneRec {
	char	*name;
	XRectangle *rects;
	int		num_rects;
	Region	region;
	Widget	refW;
	Widget	icon;
} DropZoneRec, *DropZone;

static DropZoneRec DropZones[] = {
	{ "cross", rects0, XtNumber(rects0), NULL, NULL, NULL},
	{ "trough", rects1, XtNumber(rects1), NULL, NULL, NULL},
	{ "MwmIcon", rects2, XtNumber(rects2), NULL, NULL, NULL},
	{ "mallet", rects3, XtNumber(rects3), NULL, NULL, NULL},
};

static int numZones = XtNumber(DropZones);

static String myDNDTranslations = 
	" <Btn2Down> :  StartMyDrag() \n\
	 m <Btn1Up>  :  Raise(1)        \n\
	   <Btn1Up>  :  Raise(0)        \n\
	 m <Btn1Up>  :  Lower(1)        \n\
	   <Btn1Up>  :  Lower(0)";


static XtActionsRec myDNDActions[] = {
	{ "StartMyDrag", StartMyDragProc },
	{ "Raise", RaiseProc },
	{ "Lower", LowerProc },
};


Widget shell1;
Widget form1;
Widget p0, p1, p2, p3;
Widget text1;
int n = 0;
Arg args[30];
XtAppContext this_app;
Display *display;
int i;


Pixel GetPixel(dpy, name)
Display  *dpy;
char     *name;
{

	XColor color, exact_color;
	int           scr = DefaultScreen(dpy);
	Colormap      cmap = DefaultColormap(dpy, scr);

	XAllocNamedColor(dpy, cmap, name, &color, &exact_color);

	return(color.pixel);
}

void ExposeEventHandler(w, client_data, event, continue_to_dispatch)
Widget w;
XtPointer client_data;
XEvent *event;
Boolean *continue_to_dispatch;
{
	static Boolean first_time = True;
	XGCValues values;
	unsigned long  valueMask;
	static GC dzGC;
	Pixel zoneColor;
	int i, j;
	Region clipRegion = NULL;
	Region sibRegion = NULL;

	*continue_to_dispatch = True;

	if (first_time)
	{
		valueMask = GCGraphicsExposures;
		values.graphics_exposures = False;
		dzGC = XCreateGC(XtDisplay(w), XtWindow(w), valueMask, &values);

		clipRegion = XCreateRegion();
		sibRegion = XCreateRegion();
	}

	for (i=0; i < XtNumber(DropZones); i++)
	{
		valueMask = (GCForeground | GCBackground);
		values.background = DropZones[i].refW->core.background_pixel;
		values.foreground = DropZones[i].refW->core.background_pixel;
		XChangeGC(XtDisplay(w), dzGC, valueMask, &values);

		XUnionRegion(DropZones[i].region, DropZones[i].region,
			clipRegion);
		XOffsetRegion(clipRegion, XtX(w), XtY(w));

		for (j=0; j < i ; j++)
		{
			XUnionRegion(DropZones[j].region, DropZones[j].region,
				sibRegion);
			XOffsetRegion(sibRegion, XtX(DropZones[j].refW),
				XtY(DropZones[j].refW));
			XSubtractRegion(clipRegion, sibRegion, clipRegion);
		}

		XSetRegion(XtDisplay(w), dzGC, clipRegion);

		XFillRectangle(XtDisplay(w), XtWindow(w), dzGC, 
			XtX(w), XtY(w), XtWidth(w), XtHeight(w));
	}
}

static void RaiseProc(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{

	int	operation;
	if (*num_params)
	{
		/* We only expect one */
		operation = atoi(params[0]);
	}

	switch(operation)
	{
		case 1:
		{
			/* Raise to top of stack */
		}
		break;

		case 0:
		default:
		{
			/* Circulate the stack upwards */
		}
		break;
	}
}

static void LowerProc(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
	
}

static void StartMyDragProc(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
	Arg args[30];
	int n, i;
	XButtonEvent *myEvent = (XButtonEvent *) event;
	Widget dc;

	/* detect which, if any drop zone the drag started in */
	for (i=0; i < numZones; i++)
		if (XPointInRegion(DropZones[i].region, myEvent->x, myEvent->y))
			break;
	
	/* if in a drop zone, load the appropriate cursor */

	if (i == numZones)
		return;
	
	n = 0;
	XtSetArg(args[n], XmNsourceCursorIcon, DropZones[i].icon); n++;
	dc = XmDragStart(w, event, args, n);
}

static void MyDropProc(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
	XmDropProcCallbackStruct *cb =
		(XmDropProcCallbackStruct *) call_data;
	Position newX = cb->x - XtX(w);
	Position newY = cb->y - XtY(w);
	Arg args[5];
	int n;
	Boolean junk;

	n = 0;
	XtSetArg(args[n], XmNx, newX); n++;
	XtSetArg(args[n], XmNy, newY); n++;
	XtSetValues(w, args, n);

	ExposeEventHandler(w, NULL, NULL, &junk);
}

void CreateDropZone(w, targets, num_targets, dz)
Widget w;
Atom *targets;
Cardinal num_targets;
DropZone dz;
{
	Display *display = XtDisplay(w);
	XRectangle clipBox;
	unsigned long vMask;
	XGCValues values;
	Pixmap iconMap, maskMap;
	GC clipGC;
	static Boolean first_time = True;
	static Region r1, r2;
	unsigned long  valueMask;
	char buf[128];

	if (first_time)
	{
		r1 = XCreateRegion();
		r2 = XCreateRegion();
		first_time = False;
	}

	dz->refW = w;

	/* Create and set the region from the rectangle data */
	dz->region = XCreateRegion();
	for (i=0; i < dz->num_rects; i++)
		XUnionRectWithRegion(&(dz->rects[i]), dz->region, dz->region);
	
	/* Get the bounding box of the region */
	XClipBox(dz->region, &clipBox);

	n = 0;
	XtSetArg(args[n], XmNwidth, clipBox.width); n++;
	XtSetArg(args[n], XmNheight, clipBox.height); n++;
	XtSetValues(w, args, n);

	/* Create depth 1 pixmaps the size of bounding box */
	iconMap = XCreatePixmap(display, DefaultRootWindow(display),
		clipBox.width, clipBox.height, 1);
	maskMap = XCreatePixmap(display, DefaultRootWindow(display),
		clipBox.width, clipBox.height, 1);

	/* Fill the bitmaps with 0's */
	vMask = (GCForeground | GCBackground);
	values.background = 0;
	values.foreground = 0;
	clipGC = XCreateGC(display, iconMap, vMask, &values);

	XFillRectangle(display, iconMap, clipGC, 0, 0, clipBox.width,
		clipBox.height);
	XFillRectangle(display, maskMap, clipGC, 0, 0, clipBox.width,
		clipBox.height);

	/* Now we write with 1's */
	valueMask = (GCForeground | GCBackground);
	values.background = 1;
	values.foreground = 1;
	XChangeGC(display, clipGC, valueMask, &values);
	
	/* Fill the shape of the icon with 1's */
	XUnionRegion(dz->region, dz->region, r1);
	XOffsetRegion(r1, (-1 * clipBox.x), (-1 * clipBox.y));
	XSetRegion(display, clipGC, r1);

	XFillRectangle(display, iconMap, clipGC, 
		0, 0, clipBox.width, clipBox.height);

	/* Create a clip region to shoot the 1's thru into the mask */
	XUnionRegion(r1, r1, r2);
	XShrinkRegion(r2, 2, 2);
	XSubtractRegion(r1, r2, r1);

	XSetRegion(display, clipGC, r1);

	XFillRectangle(display, maskMap, clipGC, 
		0, 0, clipBox.width, clipBox.height);
	
	n = 0;
	XtSetArg(args[n], XmNpixmap, iconMap); n++;
	XtSetArg(args[n], XmNmask, maskMap); n++;
	XtSetArg(args[n], XmNdepth, 1); n++;
	XtSetArg(args[n], XmNwidth, clipBox.width); n++;
	XtSetArg(args[n], XmNheight, clipBox.height); n++;
	XtSetArg(args[n], XmNhotX, (clipBox.width / 2)); n++;
	XtSetArg(args[n], XmNhotY, (clipBox.height / 2)); n++;
	dz->icon = XmCreateDragIcon(w, dz->name, args, n);
	
	n = 0;
	XtSetArg(args[n], XmNimportTargets, targets); n++;
	XtSetArg(args[n], XmNnumImportTargets, num_targets); n++;
	XtSetArg(args[n], XmNdropRectangles, dz->rects); n++;
	XtSetArg(args[n], XmNnumDropRectangles, dz->num_rects); n++;
	XtSetArg(args[n], XmNdropProc, MyDropProc); n++;
	XmDropSiteRegister(w, args, n);
}

main(argc, argv)
int argc;
char **argv;
{
	int i;
	Atom targets[1];
	unsigned short *ID;
	XtTranslations myParsedTranslations;

	XtToolkitInitialize();
	this_app = XtCreateApplicationContext();
	display = XtOpenDisplay(this_app, NULL, NULL, "DNDNonRect",
		NULL, 0, &argc, argv);
	
	if (display == NULL) {
		fprintf(stderr, "%s:  Can't open display\n", argv[0]);
		exit(1);
	}

	targets[0] = XmInternAtom(display, "COMPOUND_TEXT", False);

	XtAppAddActions(this_app, myDNDActions, XtNumber(myDNDActions));

	myParsedTranslations = XtParseTranslationTable(myDNDTranslations);

	n = 0;
	XtSetArg(args[n], XmNallowShellResize, True);  n++;
	XtSetArg(args[n], XmNwidth, 400);  n++;
	XtSetArg(args[n], XmNheight, 300);  n++;
	shell1 = XtAppCreateShell(NULL, "XMclient",
		applicationShellWidgetClass, display, args, n);
	
	n = 0;
	form1 = XmCreateForm(shell1, "form1", args, n);
	XtManageChild(form1);
	XtOverrideTranslations(form1, myParsedTranslations);

	XtAddEventHandler(form1, ExposureMask, True, ExposeEventHandler,
		NULL);

	n = 0;
	XtSetArg(args[n], XmNx, 10); n++;
	XtSetArg(args[n], XmNy, 10); n++;
	XtSetArg(args[n], XmNbackground, GetPixel(display, "DarkGreen"));
		n++;
	p0 = XtCreateWidget("p0", xmPrimitiveWidgetClass, form1, args, n);

	CreateDropZone(p0, targets, XtNumber(targets), &DropZones[0]);

	n = 0;
	XtSetArg(args[n], XmNx, 50); n++;
	XtSetArg(args[n], XmNy, 50); n++;
	XtSetArg(args[n], XmNbackground, GetPixel(display, "Blue")); n++;
	p1 = XtCreateWidget("p1", xmPrimitiveWidgetClass, form1, args, n);

	CreateDropZone(p1, targets, XtNumber(targets), &DropZones[1]);

	n = 0;
	XtSetArg(args[n], XmNbackground, GetPixel(display, "Cyan")); n++;
	p2 = XtCreateWidget("p2", xmPrimitiveWidgetClass, form1, args, n);

	CreateDropZone(p2, targets, XtNumber(targets), &DropZones[2]);

	n = 0;
	XtSetArg(args[n], XmNx, 150); n++;
	XtSetArg(args[n], XmNy, 150); n++;
	XtSetArg(args[n], XmNbackground, GetPixel(display, "Orange")); n++;
	p3 = XtCreateWidget("p3", xmPrimitiveWidgetClass, form1, args, n);

	CreateDropZone(p3, targets, XtNumber(targets), &DropZones[3]);

	n = 0;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
	XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
	text1 = XmCreateTextField( form1, "text1", args, n);
	XtManageChild(text1);

	XtRealizeWidget(shell1);

	/* MainLoop */
	XtAppMainLoop(this_app);
}

