/***********************************************************************
 *
 * TITLE:
 *	rectlist.c
 *
 * AUTHOR:
 *	Kevin J. Miller
 *
 * DESCRIPTION:
 *	This is a set of routines to manage rectangle lists that
 *	are part of standard screen objects.
 *
 *				CHANGE HISTORY
 *
 * $Log: rectlist.c,v $
 * Revision 1.7  1994/05/19  22:36:04  kevin
 * renamed add_expose_event to AddExposeEvent
 *
 * Revision 1.6  1994/04/30  02:44:04  kevin
 * port to ANSI
 *
 * Revision 1.5  1993/10/08  21:07:23  chester
 * update message functions
 *
 * Revision 1.4  1991/12/05  23:20:12  chester
 * added getSenseRect function.
 *
 * Revision 1.3  1991/09/04  22:34:32  kevin
 * added new functions from Chester
 *
 * Revision 1.2  1991/08/12  23:28:06  kevin
 * added background sense
 *
 * Revision 1.1  1991/08/12  21:41:08  kevin
 * Initial revision
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *
 * GLOBALS:
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] =
    "$Id: rectlist.c,v 1.7 1994/05/19 22:36:04 kevin OEL $";
#endif

#include <stdarg.h>

#include "rectlist.h"
#include "message.h"

/*
 * external function prototype
 */
extern AddExposeEvent(int, XRectangle *);

static XRectangle *moverects[16];
static int bg_sense;

/***********************************************************************
 *
 * FUNCTION:
 *	newRectList()
 *
 * INPUTS:
 *	count		- (int) count of rectangles
 *	rval		- (XRectangle *) pointer to a rectangle
 *	type		- (int) flags to assign to this rectangle
 *	 :		- more (rval, type) pairs
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	rlist		- (RectList *) pointer to new rectangle list
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This function creates, assembles, and returns a new rectangle
 *	list, which is generally part of the screen object structure.
 */

RectList *
newRectList(int count, ...)
{
    va_list ap;		/* variable argument list */
    RectList *rlist;	/* pointer to list of rectangles */
    int i;		/* local index */

    va_start(ap, count);
    rlist = XtNew(RectList);
    rlist->avail = rlist->count = count;
    if (rlist->count) {
	rlist->rects = (RectElem (*)[])XtCalloc((Cardinal)rlist->count,
	    (Cardinal)sizeof(RectElem));
	for (i = 0; i < rlist->count; ++i) {
	    (*(rlist->rects))[i].rvals = *va_arg(ap, XRectangle *);
	    (*(rlist->rects))[i].type = va_arg(ap, int);
	}
    } else {
	rlist->rects = NULL;
    }
    va_end(ap);
    return rlist;
}

/***********************************************************************
 *
 * FUNCTION:
 *	setRectList()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing structure
 *	count		- (int) count of rectangles
 *	rval		- (XRectangle *) pointer to a rectangle
 *	type		- (int) flags to assign to this rectangle
 *	 :		- more (rval, type) pairs
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This sets an existing rectangle list to the new values.
 */

void
setRectList(RectList *rlist, ...)
{
    va_list ap;		/* variable argument list */
    int i;		/* local index */

    va_start(ap, rlist);
    if (rlist == NULL) {
	Message("Internal editor error - fail at setRectList()");
    } else {
	rlist->count = va_arg(ap, int);
	if (rlist->count > rlist->avail) {
	    if (rlist->rects != NULL) XtFree((char *)(rlist->rects));
	    rlist->rects = (RectElem (*)[])XtCalloc((Cardinal)rlist->count,
		sizeof(RectElem));
	    rlist->avail = rlist->count;
	}
	for (i = 0; i < rlist->count; ++i) {
	    (*(rlist->rects))[i].rvals = *va_arg(ap, XRectangle *);
	    (*(rlist->rects))[i].type = va_arg(ap, int);
	}
    }
    va_end(ap);
}

/***********************************************************************
 *
 * FUNCTION:
 *	freeRectList()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This function frees up memory used by an rectangle list.
 */

void 
freeRectList(RectList *rlist)
{
    if (rlist != NULL) {
	if (rlist->rects != NULL) XtFree((char *)(rlist->rects));
	XtFree((char *)(rlist));
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	copyRectList()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	rlistcpy	- (RectList *) pointer to copy of above
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This function returns a copy of an existing RectList.
 */

RectList *
copyRectList(RectList *rlist)
{
    RectList *rlistcpy;
    int i;

    if (rlist != NULL) {
	rlistcpy = XtNew(RectList);
	rlistcpy->count = rlist->count;
	rlistcpy->avail = rlist->avail;
	if (rlistcpy->avail) {
	    rlistcpy->rects = (RectElem (*)[])XtCalloc(
		(Cardinal)rlistcpy->avail, (Cardinal)sizeof(RectElem));
	    for (i = 0; i < rlist->count; ++i) {
		(*(rlistcpy->rects))[i].rvals = (*(rlist->rects))[i].rvals;
		(*(rlistcpy->rects))[i].type = (*(rlist->rects))[i].type;
	    }
	} else {
	    rlistcpy->rects = NULL;
	}
    } else {
	rlistcpy = NULL;
    }
    return rlistcpy;
}

/***********************************************************************
 *
 * FUNCTION:
 *	getMoveRect()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	moverects	- (XRectangle *(*)[]) pointer to MOVE rectangle
 *			  array
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *	moverects	- (static XRectangle *[]) set to all movables
 *
 * DESCRIPTION:
 *	This function returns the a pointer to a static array of all
 *	movable rectangles from the rectangle list.
 */

XRectangle *(*
getMoveRect(RectList *rlist))[]
{
    int i, j;

    j = 0;
    if (rlist != NULL) {
	for (i = 0; i < rlist->count; ++i) {
	    if ((*(rlist->rects))[i].type & RL_MOVER) {
		moverects[j++] = &((*(rlist->rects))[i].rvals);
	    }
	}
    }
    moverects[j] = NULL;
    return (XRectangle *(*)[])moverects;
}

/***********************************************************************
 *
 * FUNCTION:
 *	getSenseRect()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	moverects	- (XRectangle *(*)[]) pointer to MOVE rectangle
 *			  array
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *	moverects	- (static XRectangle *[]) set to all movables
 *
 * DESCRIPTION:
 *	This function returns the a pointer to a static array of all
 *	movable rectangles from the rectangle list.
 */

XRectangle *(*
getSenseRect(RectList *rlist))[]
{
    int i, j;

    j = 0;
    if (rlist != NULL) {
	for (i = 0; i < rlist->count; ++i) {
	    if ((*(rlist->rects))[i].type & RL_SENSE) {
		moverects[j++] = &((*(rlist->rects))[i].rvals);
	    }
	}
    }
    moverects[j] = NULL;
    return (XRectangle *(*)[])moverects;
}

/***********************************************************************
 *
 * FUNCTION:
 *	getSecondaryRect()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	moverects	- (XRectangle *(*)[]) pointer to MOVE rectangle
 *			  array
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *	moverects	- (static XRectangle *[]) set to all movables
 *
 * DESCRIPTION:
 *	This function returns the a pointer to a static array of all
 *	secondary rectangles from the rectangle list.
 */

XRectangle *(*
getSecondaryRect(RectList *rlist))[]
{
    int i, j;

    j = 0;
    if (rlist != NULL) {
	for (i = 0; i < rlist->count; ++i) {
	    if ((*(rlist->rects))[i].type == RL_SECONDARY) {
		moverects[j++] = &((*(rlist->rects))[i].rvals);
	    }
	}
    }
    moverects[j] = NULL;
    return (XRectangle *(*)[])moverects;
}

/***********************************************************************
 *
 * FUNCTION:
 *	getExposeRect()
 *
 * INPUTS:
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	moverects	- (XRectangle *(*)[]) pointer to MOVE rectangle
 *			  array
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *	moverects	- (static XRectangle *[]) set to all movables
 *
 * DESCRIPTION:
 *	This function returns the a pointer to a static array of all
 *	the EXPOSE rectangles from the rectangle list.
 */

XRectangle *(*
getExposeRect(RectList *rlist))[]
{
    int i, j;

    j = 0;
    if (rlist != NULL) {
	for (i = 0; i < rlist->count; ++i) {
	    if ((*(rlist->rects))[i].type == RL_EXPOSE) {
		moverects[j++] = &((*(rlist->rects))[i].rvals);
	    }
	}
    }
    moverects[j] = NULL;
    return (XRectangle *(*)[])moverects;
}

/***********************************************************************
 *
 * FUNCTION:
 *	exposeRectList()
 *
 * INPUTS:
 *	notlast		- (int) this number is 0 on the last expose event
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This function returns the primary rectangle from the rectangle
 *	list.
 */

void 
exposeRectList(int notlast, RectList *rlist)
{
    int i;

    if (rlist != NULL) {
   	/*
	 * count down so we can test for (i == 0)
	 */
	for (i = rlist->count - 1; i >= 0; --i) {
	    if ((*(rlist->rects))[i].type & RL_EXPOSE) {
		/*
		 * if (notlast == 0) and (i == 0) then we actually do the
		 * expose
		 */
		AddExposeEvent((notlast || i),
		    &((*(rlist->rects))[i].rvals));
	    }
	}
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	cliptestRectList()
 *
 * INPUTS:
 *	clip_region	- (Region) clip region to test list against
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	TRUE		- if rlist intersects clip_region
 *	FALSE		- otherwise
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This function checks a rectangle list against a clip region.
 */

int 
cliptestRectList(Region clip_region, RectList *rlist)
{
    int i;
    int code;
    
    code = FALSE;
    if (rlist != NULL) {
	for (i = 0; i < rlist->count; ++i) {
	    if ((*(rlist->rects))[i].type & RL_EXPOSE) {
		if (XRectInRegion(clip_region, ((*(rlist->rects))[i].rvals).x,
			((*(rlist->rects))[i].rvals).y,
			(unsigned int)((*(rlist->rects))[i].rvals).width,
			(unsigned int)((*(rlist->rects))[i].rvals).height)
			!= RectangleOut) {
		    code = TRUE;
		    break;
		}
	    }
	}
    }
    return code;
}

/***********************************************************************
 *
 * FUNCTION:
 *	pointinRectList()
 *
 * INPUTS:
 *	x, y		- (int, int) coordinates of point
 *	rlist		- (RectList *) pointer to existing rectangle list
 *
 * OUTPUTS:
 *
 * RETURNS:
 *	TRUE		- if rectangle list contains point
 *	FALSE		- otherwise
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This function checks a point against a rectangle list.
 */

int 
pointinRectList(int x, int y, RectList *rlist)
{
    int i;
    int code;
    
    code = FALSE;
    if (rlist != NULL) {
	for (i = 0; i < rlist->count; ++i) {
	    if (((*(rlist->rects))[i].type & RL_SENSE) ||
		(bg_sense && ((*(rlist->rects))[i].type & RL_BG_SENSE))) {
		if ((x >= ((*(rlist->rects))[i].rvals).x) &&
		    (y >= ((*(rlist->rects))[i].rvals).y) &&
		    (x <= ((*(rlist->rects))[i].rvals).x +
			((*(rlist->rects))[i].rvals).width) &&
		    (y <= ((*(rlist->rects))[i].rvals).y +
			((*(rlist->rects))[i].rvals).height)) {
		    code = TRUE;
		    break;
		}
	    }
	}
    }
    return code;
}

/***********************************************************************
 *
 * FUNCTION:
 *	setBackgroundSense()
 *
 * INPUTS:
 *	val		- (int) TRUE or FALSE
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *	bg_sense	- (int) set to val
 *
 * DESCRIPTION:
 *	This function sets the background sense flag.
 */

void 
setBackgroundSense(int val)
{
    bg_sense = val;
}
