/*
 *	$Source: /u1/Xr/src/Xrlib/Editor/RCS/RSelect.c,v $
 *	$Header: RSelect.c,v 1.1 86/12/17 09:03:10 swick Exp $
 */

#ifndef lint
static char *rcsid_RSelect_c = "$Header: RSelect.c,v 1.1 86/12/17 09:03:10 swick Exp $";
#endif	lint


#include <Xr/xr-copyright.h>

/* $Header: RSelect.c,v 1.1 86/12/17 09:03:10 swick Exp $ */
/* Copyright 1986, Hewlett-Packard Company */
/* Copyright 1986, Massachussetts Institute of Technology */

static char rcsid[] = "$Header: RSelect.c,v 1.1 86/12/17 09:03:10 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        RSelect.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **         This file contains the source code for the raster select
 **         field editor.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	RSelect.c,v $
 * Revision 1.1  86/12/17  09:03:10  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:25:13  08:25:13  fred ()
 * Final QA Release
 * 
 * Revision 6.0  86/11/10  15:33:43  15:33:43  fred ()
 * QA #2 release
 * 
 * Revision 5.1  86/11/07  14:21:16  14:21:16  fred ()
 * Added new copyright message.
 * 
 * Revision 5.0  86/10/28  08:29:51  08:29:51  fred ()
 * QA #1.1 release
 * 
 * Revision 4.1  86/10/22  07:26:57  07:26:57  fred ()
 * Filled in procedure headers.
 * 
 * Revision 4.0  86/10/20  12:12:02  12:12:02  fred ()
 * QA #1 release
 * 
 * Revision 3.3  86/10/16  09:16:06  09:16:06  fred ()
 * Performance enhanced: added use of register variables.
 * 
 * Revision 3.2  86/10/15  09:07:23  09:07:23  fred ()
 * Added setting of value3 (set to index of previously active raster)
 * during select event processing.
 * 
 * Revision 3.1  86/10/09  07:46:06  07:46:06  fred ()
 * Added default color check to create routine.
 * 
 * Revision 3.0  86/10/02  15:59:50  15:59:50  fred ()
 * Alpha release set to 3.0
 * 
 * Revision 2.3  86/09/22  13:11:18  13:11:18  fred ()
 * Added calls to XrEditorGroup().
 * 
 * Revision 2.2  86/09/19  12:17:03  12:17:03  fred ()
 * Modified names of the info and data structures.
 * 
 * Revision 2.1  86/09/19  07:10:54  07:10:54  fred ()
 * Added a check for XrVISIBLE before doing any drawing.
 * 
 * Revision 2.0  86/09/16  08:07:36  08:07:36  fred ()
 * Updated input processing routine to use new SELECT strategy.
 * 
 * Revision 1.2  86/09/16  05:46:33  05:46:33  fred ()
 * Modified to swallow a select up event.
 * 
 * Revision 1.1  86/09/15  08:00:16  08:00:16  fred ()
 * Initial revision
 * 
 * 
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



#include <X/Xlib.h>
#include <Xr/defs.h>
#include <Xr/types.h>
#include <Xr/in_types.h>

extern INT32 createRSelect();
extern INT32 drawRSelect();
extern INT32 processRSelect();
extern INT32 rsFreeMemory();

#define BOXBORDER 2
#define PADDING   8
#define INDICATOR 4




/*************************************<->*************************************
 *
 *  xrEditor *
 *  XrRasterSelect (rasterSelect, message, data)
 *
 *     xrEditor * rasterSelect;
 *     INT32      message;
 *     INT8     * data;
 *
 *   Description:
 *   -----------
 *     This is the main entry point and message handler for the raster
 *     select field editor.  It takes all message requests, and passes
 *     them onto the appropriate handler; invalid messages will fail
 *     and return an error.
 *
 *
 *   Inputs:
 *   ------
 *     rasterSelect = For all messages but MSG_NEW and MSG_SIZE, this
 *                    contains the instance pointer.
 *
 *     message = This indicates which action the editor should perform.
 *
 *     data = This is the message specific data.  It's usage depends upon
 *            the 'message' parameter, and may be a scalar or a pointer.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion of a command, the instance pointer is
 *          returned; additional information may be returned by means
 *          of the 'data' parameter.
 *
 *   Procedures Called
 *   -----------------
 *   _MsgNew()           [MsgCommon.c]
 *   _MsgFree()          [MsgCommon.c]
 *   _MsgGetState()      [MsgCommon.c]
 *   _MsgSetState()      [MsgCommon.c]
 *   _MsgEdit()          [MsgCommon.c]
 *   _XrMakeInvisible()  [editorUtil.c]
 *   XrEditorGroup()     [group.c]
 *   XrCopyRect()        [calc.c]
 *   XrOffsetRect()      [calc.c]
 *   XPixmapPut()        [libX.a]
 *   setUpGCs()
 *   drawIndicator()
 *   sizeRSelect()
 *   createRSelect()
 *   drawRSelect()
 *
 *************************************<->***********************************/

xrEditor *
XrRasterSelect (rasterSelect, message, data)

   register xrEditor * rasterSelect;
            INT32      message;
            INT8     * data;

{
   /* Determine the action being requested */
   switch (message)
   {
      case MSG_NEW:
      {
           /*
            * Create a new instance of the raster select editor.
            * The only parameter of interest is the 'data'
            * parameter, which is a pointer to a filled instance
            * of the xrRasterSelectInfo structure.
            */
           return ((xrEditor *) _MsgNew (rasterSelect, data,
                                         sizeof(xrRasterSelectData),
                                         createRSelect, drawRSelect,
                                         rsFreeMemory, XrRasterSelect, NULL));
      }

      case MSG_FREE:
      {
           /*
            * Destroy the specified raster select editor instance.
            * The 'rasterSelect' parameter specifies the instance
            * to be destroyed; the 'data' parameter is unused.
            */
           return ((xrEditor *) _MsgFree (rasterSelect, rsFreeMemory));
      }

      case MSG_GETSTATE:
      {
           /*
            * Return the settings of the state flags for the
            * specified raster select instance.  The 'rasterSelect'
            * parameter specifies the instance to be queried, while
            * the 'data' parameter must point to an INT8 value, into
            * which the state flags will be placed.
            */
           return ((xrEditor *) _MsgGetState (rasterSelect, data));
      }

      case MSG_SETSTATE:
      {
           /*
            * Change the state flag settings for the specified
            * instance.  The 'rasterSelect' parameter specifies the
            * instance to be modified, and the 'data' parameter is
            * interpreted as an INT8 value, containing the new
            * state flag settings.
            */
           return ((xrEditor *) _MsgSetState (rasterSelect, data,
                                              drawRSelect, NULL));
      }

      case MSG_GETITEMCOUNT:
      {
         /*
          * Return the number of raster select boxes in the instance.
          * The 'rasterSelect' parameter specifies the instance to be
          * queried, while the 'data' parameter must point to an INT32
          * value, into which the count will be placed.
          */
         INT32 * countPtr = (INT32 *) data;

         if (rasterSelect == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }
         else if (countPtr == NULL)
         {
            xrErrno = XrINVALIDPTR;
            return ((xrEditor *) NULL);
         }

         *countPtr = ((xrRasterSelectData *) rasterSelect->editorData)->
                     rasterCount;

         return (rasterSelect);
      }

      case MSG_GETITEMRECTS:
      {
         /*
          * Fill the array passed in by the application, with the
          * rectangle information describing each raster select
          * box in the specified instance.  The 'rasterSelect' parameter
          * indicates the instance to be queried, while the 'data'
          * parameter must point to an array of RECTANGLE structures,
          * into which the individual rectangles will be placed.
          */
         register RECTANGLE     * rectPtr = (RECTANGLE *)data;
         register xrRasterSelectItem * itemData;
         register INT32           i;
         register xrRasterSelectData * rsDataPtr;

         if (rasterSelect == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }
         else if (rectPtr == NULL)
         {
            xrErrno = XrINVALIDPTR;
            return ((xrEditor *) NULL);
         }

         rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;
         itemData = rsDataPtr->rasterData;

         for (i = 0; i < rsDataPtr->rasterCount; i++, rectPtr++, itemData++)
            XrCopyRect (&itemData->itemRect, rectPtr);

         return (rasterSelect);
      }

      case MSG_SIZE:
      {
	   /*
            * Return the size of the rectangle needed to enclose
            * an instance of this editor, using the specifications
            * passed in by the application program.  The 'data'
            * parameter must point to a partially filled out instance
            * of the 'xrRasterSelectInfo' structure; upon completion,
            * the 'editorRect' field of the 'info' structure will
            * be filled.
	    */
           xrRasterSelectInfo * rsInfoPtr;

           rsInfoPtr = (xrRasterSelectInfo *)data;

           if (rsInfoPtr == NULL)
           {
              xrErrno = XrINVALIDPTR;
              return ((xrEditor *)NULL);
           }
           else if (sizeRSelect (rsInfoPtr, &rsInfoPtr->editorRect) == FALSE)
           {
              /* Size request failed; xrErrno set by sizeRSelect() */
              return ((xrEditor *)NULL);
           }

           return ((xrEditor *) TRUE);
      }

      case MSG_RESIZE:
      {
         /*
          * Resize an existing instance of the raster select editor.
          * The 'rasterSelect' parameter indicates the instance to
          * be resized, while the 'data' parameter must point to a
          * RECTANGLE structure, containing the new editor rectangle
          * definition.
          */
                  RECTANGLE          * newRectPtr = (RECTANGLE *)data;
         register xrRasterSelectData * rsDataPtr;
                  xrRasterSelectInfo   rsInfo;
                  RECTANGLE            workRect;

         if (rasterSelect == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }
         else if (newRectPtr == NULL)
         {
            xrErrno = XrINVALIDPTR;
            return ((xrEditor *) NULL);
         }

         /* Create a pseudo info structure */
         rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;
         XrCopyRect (&rasterSelect->editorRect, &workRect);
         XrCopyRect (newRectPtr, &rsInfo.editorRect);
         rsInfo.rasterHeight = rsDataPtr->rasterHeight;
         rsInfo.rasterWidth = rsDataPtr->rasterWidth;
         rsInfo.rasterCount = rsDataPtr->rasterCount;
         rsInfo.colCount = rsDataPtr->colCount;

         /* Recalculate the position of each component */
         if (createRSelect (rsDataPtr, &rsInfo, MSG_RESIZE) == FALSE)
         {
            /* xrErrno has been set by createRSelect() */
            return ((xrEditor *) NULL);
         }
         XrCopyRect (newRectPtr, &rasterSelect->editorRect);

         /* Redraw, if the instance was visible */
         if (rasterSelect->editorState & XrVISIBLE)
         {
            /* Remove the instance from the window */
            _XrMakeInvisible (rasterSelect->editorWindowId, &workRect, TRUE);

            /* Redisplay the instance */
            drawRSelect (rasterSelect, NULL);
         }

         /* Force the editor group rectangle to be recalculated */
         XrEditorGroup (NULL, MSG_ADJUSTGROUPRECT, rasterSelect);
         return (rasterSelect);
      }

      case MSG_CHANGERASTER:
      {
         /*
          * Change the pixmap Id associated with a particular raster
          * select box.  The 'rasterSelect' parameter specifies the
          * instance to be modified, while the 'data' parameter must
          * point to an instance of the 'xrRasterSelectItem' structure,
          * which contains the index of the item to be changed, along
          * with the new pixmap Id.
          */
         register xrRasterSelectData * rsDataPtr;
         register xrRasterSelectItem * rasterItem;
                  newRaster     * newRasterData = (newRaster *)data;
         register INT16           rasterIndex;

         if (rasterSelect == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }
         else if (newRasterData == NULL)
         {
            xrErrno = XrINVALIDPTR;
            return ((xrEditor *) NULL);
         }

         /* Validate the index */
         rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;
         rasterIndex = newRasterData->rasterIndex;
         if ((rasterIndex < 0) || (rasterIndex >= rsDataPtr->rasterCount))
         {
            xrErrno = XrPARMOUTOFRANGE;
            return ((xrEditor *) NULL);
         }

         /* Replace the pixmap id, and redraw the raster box */
         rsDataPtr->rasterData[rasterIndex].rasterId = 
            newRasterData->pixmapId;
         rasterItem = rsDataPtr->rasterData + rasterIndex;
         if (rasterSelect->editorState & XrVISIBLE)
            XPixmapPut (rasterSelect->editorWindowId, 0, 0,
                     rasterItem->itemRect.x + (BOXBORDER >> 1),
                     rasterItem->itemRect.y + (BOXBORDER >> 1),
                     rsDataPtr->rasterWidth, rsDataPtr->rasterHeight,
                     rasterItem->rasterId, GXcopy, AllPlanes);

         return (rasterSelect);
      }

      case MSG_REDRAW:
      {
         /*
          * Redraw an instance of the raster select editor.
          * It is capable of redrawing the complete instance,
          * or just the active box.  The 'rasterSelect' parameter
          * specifies the instance to be redrawn, while the 'data'
          * parameter specifies the type of redraw to perform.
          */
                  INT32                redrawMode = (INT32) data;
         register xrRasterSelectData * rsDataPtr;

         if (rasterSelect == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }

         rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;

         if (redrawMode == XrREDRAW_ALL)
         {
            /* Check for an invalid active index id */
            if ((*rsDataPtr->activeRaster < 0) ||
                (*rsDataPtr->activeRaster >= rsDataPtr->rasterCount))
            {
               *rsDataPtr->activeRaster = rsDataPtr->lastActive;
               xrErrno = XrPARMOUTOFRANGE;
               return ((xrEditor *) NULL);
            }

            /* Redraw the complete instance */
            if (rasterSelect->editorState & XrVISIBLE)
               drawRSelect (rasterSelect, NULL);
            return (rasterSelect);
         }
         else if (redrawMode == XrREDRAW_ACTIVE)
         {
            /* Check for an invalid active index id */
            if ((*rsDataPtr->activeRaster < 0) ||
                (*rsDataPtr->activeRaster >= rsDataPtr->rasterCount))
            {
               *rsDataPtr->activeRaster = rsDataPtr->lastActive;
               xrErrno = XrPARMOUTOFRANGE;
               return ((xrEditor *) NULL);
            }

            /* Remove the indicator from the old active box */
            if (rasterSelect->editorState & XrVISIBLE)
            {
               setUpGCs (rsDataPtr);
               if (rsDataPtr->lastActive != *rsDataPtr->activeRaster)
                  drawIndicator (rasterSelect->editorWindowId,
                         rsDataPtr,
                         &(rsDataPtr->rasterData[rsDataPtr->lastActive]),
                         xrEditorGC4);

               /* Draw the indicator around the new active box */
               drawIndicator (rasterSelect->editorWindowId,
                         rsDataPtr,
                         &(rsDataPtr->rasterData[*rsDataPtr->activeRaster]),
                         xrEditorGC3);
            }

            rsDataPtr->lastActive = *rsDataPtr->activeRaster;
            return (rasterSelect);
         }
         else
         {
            xrErrno = XrINVALIDOPTION;
            return ((xrEditor *) NULL);
         }
      }

      case MSG_MOVE:
      {
         /*
          * Relocate an instance of the raster select editor, to a new
          * location.  The 'rasterSelect' parameter specifies the
          * instance to be moved, while the 'data' parameter must
          * point to a POINT structure, containing the new editor 
          * rectangle origin.
          */
                  POINT         * ptPtr = (POINT *) data;
         register INT16           xDelta, yDelta;
                  RECTANGLE       workRect;
         register xrRasterSelectData * rsDataPtr;
         register INT32           i;

         if (rasterSelect == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }
         else if (ptPtr == NULL)
         {
            xrErrno = XrINVALIDPTR;
            return ((xrEditor *) NULL);
         }

         /* Reset the origin for the editorRect */
         rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;
         XrCopyRect (&rasterSelect->editorRect, &workRect);
         xDelta = ptPtr->x - workRect.x;
         yDelta = ptPtr->y - workRect.y;

         /* Relocate each components of the instance */
         XrOffsetRect (&rasterSelect->editorRect, xDelta, yDelta);
         for (i = 0; i < rsDataPtr->rasterCount; i++)
            XrOffsetRect (&(rsDataPtr->rasterData[i].itemRect), 
                         xDelta, yDelta);

         if (rasterSelect->editorState & XrVISIBLE)
         {
            /* Remove the instance from the window */
            _XrMakeInvisible (rasterSelect->editorWindowId, &workRect, TRUE);

            /* Redisplay the instance */
            drawRSelect (rasterSelect, NULL);
         }

         /* Force the editor group rectangle to be recalculated */
         XrEditorGroup (NULL, MSG_ADJUSTGROUPRECT, rasterSelect);
         return (rasterSelect);
      }

      case MSG_EDIT:
      {
	 /*
          * Process the incoming event, and generate a return
          * event, to indicate to the application program
          * how the editor instance was modified.  The 'data'
          * parameter must point to the event to be processed.
	  */
         return ((xrEditor *) _MsgEdit (rasterSelect, data,
                                         processRSelect, XrRASTERSELECT));
      }

      default:
         /* All other commands are invalid */
         xrErrno = XrINVALIDMSG;
         return ((xrEditor *)NULL);

   }  /* end of switch */
}  /* end of XrRasterSelect() */


/*************************************<->*************************************
 *
 *  INT32
 *  rsFreeMemory (rsDataPtr)
 *
 *     xrRasterSelectData * rsDataPtr;
 *
 *   Description:
 *   -----------
 *     This routine is called both when an existing instance is freed,
 *     and when a MSG_NEW request fails after createRSelect() has
 *     been called.  It will free up all resources which createRSelect()
 *     allocated for the instance.
 *
 *
 *   Inputs:
 *   ------
 *     rsDataPtr = Points to the instance's internal 'data' structure.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

static
INT32
rsFreeMemory (rsDataPtr)

   xrRasterSelectData * rsDataPtr;

{
   (*xrFree) (rsDataPtr->rasterData);
}


/*************************************<->*************************************
 *
 *  INT32
 *  sizeRSelect (rsInfoPtr, rectPtr)
 *
 *     xrRasterSelectInfo * rsInfoPtr;
 *     RECTANGLE          * rectPtr;
 *
 *   Description:
 *   -----------
 *     This routine will validate most of the parameters contained within
 *     the 'info' structure pointed to by 'rsInfoPtr', and will then
 *     calculate the size of the editor rectangle needed to contain the
 *     specified instance.
 *
 *
 *   Inputs:
 *   ------
 *     rsInfoPtr = Points to an instance of the 'xrRasterSelectInfo'
 *                 structure, which describes the instance to be sized.
 *
 *     rectPtr = Points to a RECTANGLE structure, into which the editor
 *               rectangle will be placed.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE is returned, and the editor
 *          rectangle is returned.
 *
 *     Upon failure, FALSE is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

static
INT32
sizeRSelect (rsInfoPtr, rectPtr)

   register xrRasterSelectInfo * rsInfoPtr;
   register RECTANGLE     * rectPtr;

{
   INT16  width = rsInfoPtr->rasterWidth;
   INT16  height = rsInfoPtr->rasterHeight;
   INT16  rasterCount = rsInfoPtr->rasterCount;
   INT16  colCount = rsInfoPtr->colCount;
   INT16  rowCount;

   /* Validate parameters */
   if ((rasterCount <= 0) || (colCount <= 0) || (colCount > rasterCount) || 
       (width <= 0) || (height <= 0))
   {
      xrErrno = XrINVALIDPARM;
      return (FALSE);
   }

   rowCount = (rasterCount + colCount - 1) / colCount;

   /* Set the rectangle coordinates */
   rectPtr->x = 0;
   rectPtr->y = 0;
   rectPtr->height = 1 
            + (rowCount * (BOXBORDER + height + BOXBORDER + PADDING)) 
            + PADDING + 1;
   rectPtr->width = 1
            + (colCount * (BOXBORDER + width + BOXBORDER + PADDING))
            + PADDING + 1;

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  INT32
 *  createRSelect (rsDataPtr, rsInfoPtr, message)
 *
 *     xrRasterSelectData * rsDataPtr;
 *     xrRasterSelectInfo * rsInfoPtr;
 *     INT32                message;
 *
 *   Description:
 *   -----------
 *     if (message == MSG_NEW)
 *     This routine is responsible for creating a new raster select 
 *     instance.  The description of the new instance is contained within
 *     the structure pointed to by the 'rsInfoPtr' parameter.  Besides 
 *     allocating the resources needed for the new instance, this routine
 *     will also fill in the structure pointed to by the 'rsDataPtr'
 *     parameter with the state information for the new instance.
 *
 *     if (message == MSG_RESIZE)
 *     This routine will take the information contained within the 
 *     'rsInfoPtr' structure, and will recalculate the location of
 *     each component within an existing instance of the raster select
 *     editor, to match the new data.  This will do no resource
 *     allocation.
 *
 *
 *   Inputs:
 *   ------
 *     rsDataPtr = Points to the 'data' structure for the instance being
 *                 created or resized.
 *
 *     rsInfoPtr = Points to the 'info' structure, which describes how the
 *                 instance is to be laid out.
 *
 *     message = This can be set to MSG_NEW or MSG_RESIZE;
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE is returned, and the 'rsInfoPtr'
 *          structure is filled out.
 *
 *     Upon failure, FALSE is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XrSetRect()    [calc.c]
 *   sizeRSelect()
 *
 *************************************<->***********************************/

static
INT32
createRSelect (rsDataPtr, rsInfoPtr, message)

   register xrRasterSelectData * rsDataPtr;
   register xrRasterSelectInfo * rsInfoPtr;
            INT32           message;

{
   register xrRasterSelectItem * itemData;
   register RECTANGLE * editorRect = &(rsInfoPtr->editorRect);
            RECTANGLE   workRect;
            INT16       height = rsInfoPtr->rasterHeight;
            INT16       width = rsInfoPtr->rasterWidth;
            INT16       rasterCount = rsInfoPtr->rasterCount;
            INT16       colCount = rsInfoPtr->colCount;
            INT16       rowCount;
            INT16       xPadding, yPadding;
   register INT16       xOrigin, yOrigin;
   register INT32       i, j;

   /* Make sure the editorRect is large enough to hold the instance */
   if (sizeRSelect (rsInfoPtr, &workRect) == FALSE)
      /* xrErrno is set by sizeRSelect */
      return (FALSE);

   if ((editorRect->width < workRect.width) ||
       (editorRect->height < workRect.height))
   {
      xrErrno = XrINVALIDRECT;
      return (FALSE);
   }

   if (message == MSG_NEW)
   {
      /* Validate the incoming instance specifications */
      if ((rsInfoPtr->rasterIds == NULL) || (rsInfoPtr->activeRaster == NULL))
      {
         xrErrno = XrINVALIDPTR;
         return (FALSE);
      }
      else if ((*rsInfoPtr->activeRaster < 0) ||
               (*rsInfoPtr->activeRaster >= rsInfoPtr->rasterCount))
      {
         xrErrno = XrPARMOUTOFRANGE;
         return (FALSE);
      }

      /* 
       * Now that we know all of the parameters are valid, we can start
       * filling in the structure pointed to by 'rsDataPtr'.
       */
      rsDataPtr->rsFGColor = (rsInfoPtr->editorFGColor == -1) ?
                 xrForegroundColor : rsInfoPtr->editorFGColor;
      rsDataPtr->rsBGColor = (rsInfoPtr->editorBGColor == -1) ?
                 xrBackgroundColor : rsInfoPtr->editorBGColor;
      rsDataPtr->rasterHeight = rsInfoPtr->rasterHeight;
      rsDataPtr->rasterWidth = rsInfoPtr->rasterWidth;
      rsDataPtr->rasterCount = rsInfoPtr->rasterCount;
      rsDataPtr->colCount = rsInfoPtr->colCount;
      rsDataPtr->lastActive = *rsInfoPtr->activeRaster;
      rsDataPtr->activeRaster = rsInfoPtr->activeRaster;
   
      if ((rsDataPtr->rasterData = (xrRasterSelectItem *)(*xrMalloc)
          (rsInfoPtr->rasterCount * sizeof(xrRasterSelectItem))) == NULL)
      {
         /* System is out of memory; abort */
         xrErrno = XrOUTOFMEM;
         return (FALSE);
      }
   }

   /* Fill each component of the item structure */
   rowCount = (rasterCount + colCount - 1) / colCount;
   xPadding = (editorRect->width - workRect.width) / (colCount + 1);
   yPadding = (editorRect->height - workRect.height) / (rowCount + 1);
   yOrigin = editorRect->y + PADDING + yPadding + (BOXBORDER >> 1);

   for (i = 0, itemData = rsDataPtr->rasterData; i < rasterCount; 
        i += colCount)
   {
      xOrigin = editorRect->x + PADDING + xPadding + (BOXBORDER >> 1);

      for (j = i; j < i + colCount; j++)
      {
         if (message == MSG_NEW)
            itemData->rasterId = rsInfoPtr->rasterIds[j];
         XrSetRect (&itemData->itemRect, xOrigin, yOrigin,
                    width + BOXBORDER, height + BOXBORDER);
         xOrigin += BOXBORDER + width + BOXBORDER + PADDING + xPadding;
         itemData ++;
      }

      yOrigin += BOXBORDER + height + BOXBORDER + PADDING + yPadding;
   }

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  INT32
 *  drawRSelect (rasterSelect, drawOption)
 *
 *     xrEditor * rasterSelect;
 *     INT32      drawOption;
 *
 *   Description:
 *   -----------
 *     This routine completely draws a raster select instance.
 *
 *
 *   Inputs:
 *   ------
 *     rasterSelect = Points to the instance structure associated with the
 *                    instance to be drawn.  This contains all the data
 *                    needed to draw the particular raster select instance.
 *
 *     drawOption = Not used; this is here so that this routine may be
 *                  called by _MsgNew().
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrMakeInvisible()        [editorUtil.c]
 *   _XrBorderFillRectangle()  [rectUtil.c]
 *   _XrRectangle()            [rectUtil.c]
 *   XPixmapPut()              [libX.a]
 *   setUpGCs()
 *   drawIndicator()
 *
 *************************************<->***********************************/

static
INT32
drawRSelect (rasterSelect, drawOption)

   register xrEditor * rasterSelect;
            INT32      drawOption;

{
   register xrRasterSelectData * rsDataPtr;
   register Window          windowId;
   register RECTANGLE     * editorRect;
   register xrRasterSelectItem * rasterItem;
   register INT32           i;

   /* Initialize variable we will be using */
   rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;
   windowId = rasterSelect->editorWindowId;
   editorRect = &rasterSelect->editorRect;

   /*
    * If the instance is not visible, then fill its area with the
    * background tile for the window, thus making the instance invisible.
    */
   if (!(rasterSelect->editorState & XrVISIBLE))
   {
      _XrMakeInvisible (windowId, editorRect, TRUE);
      return;
   }

   /* Check for an invalid active box index */
   if ((*rsDataPtr->activeRaster < 0) ||
       (*rsDataPtr->activeRaster >= rsDataPtr->rasterCount))
   {
      *rsDataPtr->activeRaster = rsDataPtr->lastActive;
   }
   else
      rsDataPtr->lastActive = *rsDataPtr->activeRaster;

   /* Set up the graphic contexts we will be needing */
   setUpGCs (rsDataPtr);

   /* Draw the bordered box, representing the complete instance */
   _XrBorderFillRectangle (windowId, xrEditorGC1, xrEditorGC2, editorRect);

   /* Display each of the raster select boxes */
   for (i = 0, rasterItem = rsDataPtr->rasterData; 
        i < rsDataPtr->rasterCount; i++, rasterItem++)
   {
      /* Draw a one pixel border */
      _XrRectangle (windowId, xrEditorGC1, &rasterItem->itemRect);

      /* Fill the raster item box */
      XPixmapPut (windowId, 0, 0, rasterItem->itemRect.x + (BOXBORDER >> 1), 
                  rasterItem->itemRect.y + (BOXBORDER >> 1),
                  rsDataPtr->rasterWidth, rsDataPtr->rasterHeight,
                  rasterItem->rasterId, GXcopy, AllPlanes);

      /* Display the active indicator, if this is the active item */
      if (i == rsDataPtr->lastActive)
         drawIndicator (windowId, rsDataPtr, rasterItem, xrEditorGC3);
   }
              
}


/*************************************<->*************************************
 *
 *  INT32
 *  setUpGCs (rsDataPtr)
 *
 *     xrRasterSelectData * rsDataPtr;
 *
 *   Description:
 *   -----------
 *     This routine initializes the 4 graphics contexts which will be
 *     needed during the drawing of a raster select instance.
 *
 *
 *   Inputs:
 *   ------
 *     rsDataPtr = Points to the instance's 'data' structure; the foreground
 *                 and background colors are obtained from here.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrInitEditorGCs()  [gcUtil.c]
 *   _XrCopyGC()         [gcUtil.c]
 *   _XrChangeGC()       [gcUtil.c]
 *
 *************************************<->***********************************/

static
INT32
setUpGCs (rsDataPtr)

   xrRasterSelectData * rsDataPtr;

{
   INT32 changeList[21];

   _XrInitEditorGCs (rsDataPtr->rsFGColor, rsDataPtr->rsBGColor, -1);
   _XrCopyGC (xrEditorGC1, xrEditorGC3);
   changeList[XrLINEWIDTHVAL] = INDICATOR;
   _XrChangeGC (xrEditorGC3, XrLINEWIDTH, changeList);
   _XrCopyGC (xrEditorGC3, xrEditorGC4);
   changeList[XrFOREGROUNDVAL] = rsDataPtr->rsBGColor;
   _XrChangeGC (xrEditorGC4, XrFOREGROUND, changeList);
}


/*************************************<->*************************************
 *
 *  INT32
 *  drawIndicator (windowId, rsDataPtr, rasterItem, GContext)
 *
 *     Window               windowId;
 *     xrRasterSelectData * rsDataPtr;
 *     xrRasterSelectItem * rasterItem;
 *     INT32                GContext;
 *
 *   Description:
 *   -----------
 *     Using the specified graphics context, this routine will draw
 *     the active indicator (a wide box) around the currently active
 *     raster select item.  It can also be used to remove the active
 *     indicator, by passing in a graphics context which has the
 *     foreground color set to the instance's background color.
 *
 *
 *   Inputs:
 *   ------
 *     windowId = Id  for window in which instance is to be drawn.
 *
 *     rsDataPtr = Points to the instance's 'data' structure.
 *
 *     rasterItem = Points to the 'item' structure associated with the
 *                  raster select item which is to have the indicator
 *                  drawn around it.
 *
 *     GContext = This specifies the graphics context to use.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrLine()  [rectUtil.c]
 *
 *************************************<->***********************************/

static
INT32
drawIndicator (windowId, rsDataPtr, rasterItem, GContext)

   Window          windowId;
   xrRasterSelectData * rsDataPtr;
   xrRasterSelectItem * rasterItem;
   INT32           GContext;

{
   register INT16 x1, y1, x2, y2;

   /* Determine the line endpoints */
   x1 = rasterItem->itemRect.x - (BOXBORDER >> 1) - INDICATOR;
   y1 = rasterItem->itemRect.y - (BOXBORDER >> 1) - INDICATOR;
   x2 = x1 +INDICATOR + BOXBORDER + rsDataPtr->rasterWidth + BOXBORDER;
   y2 = y1 +INDICATOR + BOXBORDER + rsDataPtr->rasterHeight + BOXBORDER;

   _XrLine (windowId, GContext, x1, y1, x2, y1);
   _XrLine (windowId, GContext, x2, y1, x2, y2);
   _XrLine (windowId, GContext, x2, y2, x1, y2);
   _XrLine (windowId, GContext, x1, y2, x1, y1);
}


/*************************************<->*************************************
 *
 *  INT32
 *  processRSelect (rasterSelect, event, returnEvent)
 *
 *     xrEditor     * rasterSelect;
 *     XButtonEvent * event;
 *     xrEvent      * returnEvent;
 *
 *   Description:
 *   -----------
 *     This is the event processing routine for the raster select editor.
 *     It takes an event, and determines which, if any, of the raster
 *     select items the event occurred within.  If one of the items was
 *     selected, then it will be redrawn as active, and its index will
 *     be returned to the application, along with the index of the 
 *     previously active item.
 *
 *
 *   Inputs:
 *   ------
 *     rasterSelect = Instance pointer for the instance in which the event
 *                    occurred.
 *
 *     event = Points to the event to be processed.
 *
 *     returnEvent = Points to a partially filled out X-ray event
 *                   structure.  It can be used by this routine when it
 *                   needs to push a return event onto the input queue.
 *                   Every field is already filled, except for the 'value'
 *                   fields.
 * 
 *   Outputs:
 *   -------
 *     Although a value is not directly returned, an input event will be
 *         pushed onto the input queue, telling the application which
 *         part of the instance was selected.
 *
 *   Procedures Called
 *   -----------------
 *   XrSetPt()  [calc.c]
 *   setUpGCs()
 *   drawIndicator()
 *
 *************************************<->***********************************/

static
INT32
processRSelect (rasterSelect, event, returnEvent)

            xrEditor     * rasterSelect;
            XButtonEvent * event;
   register xrEvent      * returnEvent;

{
   register xrRasterSelectData  * rsDataPtr;
   register xrRasterSelectItem  * itemData;
   register INT16            i;
            POINT            spritePt;

   /*
    * Determine if the select occurred within one
    * of the raster select boxes.
    */
   rsDataPtr = (xrRasterSelectData *) rasterSelect->editorData;
   XrSetPt (&spritePt, event->x, event->y);
   returnEvent->value1 = NULL;

   for (i = 0, itemData = rsDataPtr->rasterData;
        i < rsDataPtr->rasterCount;
        i++, itemData++)
   {
      if (XrPtInRect (&spritePt, &itemData->itemRect))
      {
         setUpGCs (rsDataPtr);
        
         /* Remove the old indicator */
         if (i != rsDataPtr->lastActive)
            drawIndicator (rasterSelect->editorWindowId,
                           rsDataPtr,
                           &(rsDataPtr->rasterData[rsDataPtr->lastActive]),
                           xrEditorGC4);

         /* Draw the new indicator */
         drawIndicator (rasterSelect->editorWindowId, rsDataPtr, 
                        itemData, xrEditorGC3);

         /* Update the application's active index */
         *rsDataPtr->activeRaster = i;
         returnEvent->value3 = rsDataPtr->lastActive;
         rsDataPtr->lastActive = i;

         /* Set up the return event information */
         returnEvent->value2 = i;
         returnEvent->value1 = XrSELECT;
      }
   }
}

