/*
 *	$Source: /u1/Xr/src/Xrlib/Editor/RCS/CheckBox.c,v $
 *	$Header: CheckBox.c,v 1.1 86/12/17 08:59:21 swick Exp $
 */

#ifndef lint
static char *rcsid_CheckBox_c = "$Header: CheckBox.c,v 1.1 86/12/17 08:59:21 swick Exp $";
#endif	lint


#include <Xr/xr-copyright.h>

/* $Header: CheckBox.c,v 1.1 86/12/17 08:59:21 swick Exp $ */
/* Copyright 1986, Hewlett-Packard Company */
/* Copyright 1986, Massachussetts Institute of Technology */

static char rcsid[] = "$Header: CheckBox.c,v 1.1 86/12/17 08:59:21 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        CheckBox.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **         Source code for the X-ray CheckBox field editor.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	CheckBox.c,v $
 * Revision 1.1  86/12/17  08:59:21  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:20:10  08:20:10  fred ()
 * Final QA Release
 * 
 * Revision 6.0  86/11/10  15:23:09  15:23:09  fred ()
 * QA #2 release
 * 
 * Revision 5.2  86/11/07  14:18:00  14:18:00  fred ()
 * Added new copyright message.
 * 
 * Revision 5.1  86/10/30  13:22:00  13:22:00  fred ()
 * Added a check for numCols = 0.
 * 
 * Revision 5.0  86/10/28  08:25:08  08:25:08  fred ()
 * QA #1.1 release
 * 
 * Revision 4.1  86/10/22  10:05:21  10:05:21  fred ()
 * Filled in the procedure headers.
 * 
 * Revision 4.0  86/10/20  12:04:42  12:04:42  fred ()
 * QA #1 release
 * 
 * Revision 3.4  86/10/16  09:13:00  09:13:00  fred ()
 * Performance enhanced: added use of register variables.
 * 
 * Revision 3.3  86/10/13  10:04:47  10:04:47  fred ()
 * Added use of the default tile, if needed.
 * 
 * Revision 3.2  86/10/09  07:43:27  07:43:27  fred ()
 * Added default color check to create routine.
 * 
 * Revision 3.1  86/10/07  16:03:43  16:03:43  fred ()
 * Added check for invalid rectangle size
 * 
 * Revision 3.0  86/10/02  15:57:24  15:57:24  fred ()
 * Alpha release set to 3.0
 * 
 * Revision 2.3  86/10/01  06:53:33  06:53:33  fred ()
 * Changed default label padding from font's maxWidth to avgWidth.
 * 
 * Revision 2.2  86/09/22  13:09:43  13:09:43  fred ()
 * Added calls to XrEditorGroup().
 * 
 * Revision 2.1  86/09/19  07:08:12  07:08:12  fred ()
 * Added a check for XrVISIBLE before doing any drawing.
 * 
 * Revision 2.0  86/09/16  08:01:58  08:01:58  fred ()
 * Updated the input processing routine to match new select strategy.
 * 
 * Revision 1.4  86/09/16  05:44:15  05:44:15  fred ()
 * Modified to swallow a select up event.
 * 
 * Revision 1.3  86/09/10  07:24:50  07:24:50  fred ()
 * Changed numRows to numCols in all data structures.
 * 
 * Revision 1.2  86/09/09  13:06:40  13:06:40  fred ()
 * Changed some variables from INT32 to INT16
 * 
 * Revision 1.1  86/09/03  13:55:43  13:55:43  fred ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



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

extern INT32 createCBoxes();
extern INT32 drawCBoxes();
extern INT32 processCBoxes();
extern INT32 cbFreeMemory();
extern INT32 calcComponents();


/*************************************<->*************************************
 *
 *  xrEditor *
 *  XrCheckBox (checkBox, message, data)
 *
 *     xrEditor * checkBoxr;
 *     INT32      message;
 *     INT8     * data;
 *
 *   Description:
 *   -----------
 *     This is the main entry point an dmessage handler for the checkbox
 *     field editor.  It takes all message requests, and passes them
 *     onto the appropriate handler; invalid messages will fail and
 *     return an error.
 *
 *
 *   Inputs:
 *   ------
 *     checkBox = 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.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   _MsgNew()            [MsgCommon.c]
 *   _MsgFree()           [MsgCommon.c]
 *   _MsgGetState()       [MsgCommon.c]
 *   _MsgSetState()       [MsgCommon.c]
 *   _MsgRedraw()         [MsgCommon.c]
 *   _MsgEdit()           [MsgCommon.c]
 *   _MsgSize()           [MsgItem.c]
 *   _MsgGetItemStates()  [MsgItem.c]
 *   _MsgSetItemStates()  [MsgItem.c]
 *   _MsgGetItemCount()   [MsgItem.c]
 *   _MsgGetItemRects()   [MsgItem.c]
 *   _MsgMove()           [MsgItem.c]
 *   XrCopyRect()         [calc.c]
 *   _XrMakeInvisible()   [editorUtil.c]
 *   XrEditorGroup()      [group.c]
 *   createCBoxes()
 *   drawCBoxes()
 *
 *************************************<->***********************************/

xrEditor *
XrCheckBox (checkBox, message, data)

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

{
   /* Determine the action being requested */
   switch (message)
   {
      case MSG_NEW:
      {
           /*
            * Create a new instance of the checkbox editor.
            * The only parameter of interest is the 'data' parameter,
            * which is a pointer to a filled instance of the
            * 'xrCheckBoxInfo' structure.
            */
           return ((xrEditor *)_MsgNew (checkBox, data, 
                                        sizeof(xrCheckBoxData),
                                        createCBoxes, drawCBoxes,
                                        cbFreeMemory, XrCheckBox,
                                        XrALLBUTTONS));
      }

      case MSG_FREE:
      {
           /*
            * Destroy the specified checkbox instance.
            * The 'checkBox' parameter specifies the instance to
            * be destroyed; the 'data' parameter is unused.
            */
           return ((xrEditor *) _MsgFree (checkBox, cbFreeMemory));
      }

      case MSG_GETSTATE:
      {
           /*
            * Return the settings of the state flags for the
            * specified checkbox instance.  The 'checkBox'
            * 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 (checkBox, data));
      }

      case MSG_SETSTATE:
      {
           /*
            * Change the state flag settings for the specified
            * instance.  The 'checkBox' 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 (checkBox, data, drawCBoxes,
                                              XrALLBUTTONS));
      }

      case MSG_GETITEMSTATES:
      {
         /*
          * Return the state flags for the individual checkboxes. The
          * 'checkBox' parameter specifies the instance to be queried,
          * while the 'data' parameter must point to an array of INT8
          * values, into which the state flags will be returned.
          */
         return ((xrEditor *)_MsgGetItemStates(checkBox, data));
      }

      case MSG_SETITEMSTATES:
      {
         /*
          * Set the individual checkbox states; redraw only those
          * whose state has then changed.  The 'checkBox' parameter
          * specifies the instance to be modified, while the 'data'
          * parameter points to an array of INT8 values, containing
          * the new state flags.
          */
         return ((xrEditor *) _MsgSetItemStates (checkBox, data, drawCBoxes));
      }

      case MSG_GETITEMCOUNT:
      {
         /*
          * Return the number of checkboxes in the specified instance.
          * The 'checkBox' parameter specifies the instance to be
          * queried, while the 'data' parameter must point to an INT32
          * value, into which the item count will be placed.
          */
         return ((xrEditor *) _MsgGetItemCount (checkBox, data));
      }

      case MSG_GETITEMRECTS:
      {
         /*
          * Fill the array passed in by the application, with the
          * rectangle information describing each checkbox in
          * the specified instance.  The 'checkbox' parameter
          * indicates the instance to be queried, while the 'data'
          * parameter must point to an array of RECTANGLE structures,
          * into which the individual button rectangles will be placed.
          */
         return ((xrEditor *) _MsgGetItemRects (checkBox, data));
      }

      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 'xrCheckBoxInfo' structure; upon completion,
            * the 'editorRect' field of the 'info' structure will
            * be filled.
	    */
           return ((xrEditor *) _MsgSize (data, calcComponents));
      }

      case MSG_MOVE:
      {
         /*
          * Relocate an instance of checkboxes to a new location.
          * The 'checkBox' parameter specifies the instance to be
          * moved, while the 'data' parameter must point to a POINT
          * structure, containing the new editor rectangle origin.
          */
         return ((xrEditor *) _MsgMove (checkBox, data, drawCBoxes));
      }

      case MSG_RESIZE:
      {
         /*
          * Resize an existing instance of checkboxes.
          * The 'checkBox' parameter indicates the instance to be
          * resized, while the 'data' parameter must point to a
          * RECTANGLE structure, containing the new editor rectangle
          * definition.
          */
                  RECTANGLE        workRect;
                  xrCheckBoxInfo   cbInfo;
         register xrCheckBoxData * cbDataPtr;
         register xrCheckBoxInfo * cbInfoPtr;

         if (checkBox == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }
         else if (data == NULL)
         {
            xrErrno = XrINVALIDPTR;
            return ((xrEditor *) NULL);
         }

         /* Create a pseudo Info structure */
         cbDataPtr = (xrCheckBoxData *) checkBox->editorData;
         XrCopyRect (&checkBox->editorRect, &workRect);
         cbInfoPtr = &cbInfo;
         XrCopyRect ((RECTANGLE *) data, &cbInfoPtr->editorRect);
         cbInfoPtr->editorFont = cbDataPtr->cbFont.fontInfo;
         cbInfoPtr->numFields = cbDataPtr->cbNumFields;
         cbInfoPtr->numCols = cbDataPtr->cbNumCols;
         cbInfoPtr->labels = cbDataPtr->cbLabels;

         if (createCBoxes (cbDataPtr, cbInfoPtr, MSG_RESIZE) == FALSE)
            return ((xrEditor *) NULL);
         XrCopyRect (&cbInfoPtr->editorRect, &checkBox->editorRect);

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

            /* Redisplay the instance */
            drawCBoxes (checkBox, XrALLBUTTONS);
         }

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

      case MSG_REDRAW:
      {
         /*
          * Redraw a checkbox instance.
          * The 'checkBox' parameter specifies the instance to redraw,
          * while the 'data' parameter is interpreted as an INT32 value,
          * specifying the type of redraw to perform.
          */
         return ((xrEditor *) _MsgRedraw (checkBox, data, drawCBoxes,
                                          XrALLBUTTONS));
      }

      case MSG_EDIT:
      {
	 /*
          * Process the incoming keystroke, and generate a return
          * keystroke, 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 (checkBox, data, processCBoxes,
                                        XrCHECKBOX));
      }

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

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

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

static
INT32
cbFreeMemory (cbDataPtr)

   xrCheckBoxData * cbDataPtr;

{
   if (cbDataPtr->cbTileId != xrDefaultTile)
      XFreePixmap (cbDataPtr->cbTileId);
   (*xrFree) (cbDataPtr->cbFields);
}


/*************************************<->*************************************
 *
 *  INT32
 *  calcComponents (cbInfoPtr, fields, cmd)
 *
 *     xrCheckBoxInfo * cbInfoPtr;
 *     XrItemData     * fields;
 *     INT32            cmd;
 *
 *   Description:
 *   -----------
 *     If the 'cmd' parameter is set to MSG_SIZE, then this routine will
 *     calculate the size of the editor rectangle needed to contain the
 *     instance described by the structure pointed to by 'cbInfoPtr'; the
 *     editor rectangle information is returned in the 'editorRect' field
 *     within the structure pointed to by the 'cbInfoPtr' parameter.
 *     If the 'cmd' parameter is set to any other value, then this routine
 *     will calculate the location and size of each checkbox rectangle
 *     and corresponding checkbox label; this information is then stored
 *     in the structure pointed to by the 'fields' parameter.
 *
 *
 *   Inputs:
 *   ------
 *     cbInfoPtr = Points to an instance of the checkbox 'info' structure,
 *                 which describes the instance being sized or created.
 *
 *     fields = This must point to an array of structures, which will be
 *              used to store temporary information, if 'cmd' is set to
 *              MSG_SIZE, or will be used to store the component information,
 *              if 'cmd' is set to MSG_NEW.
 *
 *     cmd = This indicates whether just the size of the editor rectangle
 *           needs to be calculated (MSG_SIZE), or whether the size and
 *           location of each component must be calculated (MSG_NEW).
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE is returned, along with some
 *          additional information in either the 'cbInfoPtr' structure,
 *          or the 'fields' structure.
 *
 *     Upon failure, FALSE is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   _XrTextInfo()    [textUtil.c]
 *   XrStringWidth()  [utilities.c]
 *   XrCopyRect()     [calc.c]
 *   XrSetRect()      [calc.c]
 *   XrSetPt()        [calc.c]
 *
 *************************************<->***********************************/

static
INT32
calcComponents (cbInfoPtr, fields, cmd)

   register xrCheckBoxInfo  * cbInfoPtr;
   register xrItemData      * fields;
            INT32             cmd;

{
            INT16        numFields = cbInfoPtr->numFields;
            INT16        numCols = cbInfoPtr->numCols;
            INT16        numRows;
            RECTANGLE  * rectPtr = &(cbInfoPtr->editorRect);
            FontInfo   * fontPtr;
            xrTextInfo   fontData;
   register INT16        i, col;
            INT16        hPadding, vPadding;
            INT16        xPos, yPos;
            INT16        itemWidth, maxItemWidth;
            INT16        heightMin, widthMin;
            INT16        lineHt;

   /* Check for invalid dimensions */
   if ((numFields < numCols) || (numFields <= 0) || (numCols <= 0))
   {
      xrErrno = XrINVALIDPARM;
      return (FALSE);
   }

   /* Initialize variables we'll need for our calculations */
   numRows = (numFields + numCols - 1) / numCols;
   fontPtr = cbInfoPtr->editorFont ? cbInfoPtr->editorFont : xrBaseFontInfo;
   _XrTextInfo (fontPtr, &fontData);
   lineHt = fontData.ascent + fontData.descent;
   rectPtr = &(cbInfoPtr->editorRect);

   /*
    * Determine the preliminary size of the instance.  This is done by
    * using the following formulae:
    *
    *   height = number of Rows * height of a line
    *   width  = Sum of longest item in each column
    *
    * An item in a column is composed of a checkbox, some padding,
    * and an optional label.
    */

   heightMin = numRows * lineHt;
   for (widthMin = 0, col = 0; col < numCols; col++)
   {
      /* Keep track of longest item in each column */
      maxItemWidth = 0;

      /* Calculate the width of each item in the column */
      for (i = col; i < numFields; i += numCols)
      {
         /* Take into account the size of the checkbox */
         itemWidth = lineHt;

         /* Include the label and padding, if a label is defined */
         if ((cbInfoPtr->labels) && (cbInfoPtr->labels[i]))
            itemWidth += fontData.avgWidth + XrStringWidth (fontData.fontInfo,
                         cbInfoPtr->labels[i], XrNULLTERMINATED, 0, 0);

         /* See if this is the longest item encountered in the column */
         if (itemWidth > maxItemWidth)
            maxItemWidth = itemWidth;
      }

      /* Keep a running total of all the column width */
      widthMin += maxItemWidth;
   }

   /*
    * If this is being done in response to a MSG_SIZE request, then
    * take the height and width values calculated above, and add some
    * default padding values between each row and column; then return
    * the rectangle definition.  The following padding values are used:
    *
    *    hPadding = 2 * font leading     vPadding = font leading
    */

   if (cmd == MSG_SIZE)
   {
      /* Add the default padding */
      XrCopyRect (&xrZeroRect, rectPtr);
      rectPtr->height = heightMin + (numRows - 1) * fontData.leading;
      rectPtr->width = widthMin + (numCols - 1) * (fontData.leading << 1);
      return (TRUE);
   }

   /* If the rectangle passed in by the application is larger than the
    * preliminary rectangle calculated above, then use this extra space
    * as padding between the row and column items.
    */

   hPadding = (rectPtr->width - widthMin)/((numCols == 1) ? 1 : (numCols - 1));
   vPadding = (rectPtr->height - heightMin)/((numRows == 1) ? 1:(numRows - 1));

   /* Now, we can calculate the rectangle definition for each checkbox */

   for (xPos = rectPtr->x, col = 0; col < numCols; col++)
   {
      maxItemWidth = 0;
      yPos = rectPtr->y;

      for (i = col; i < numFields; i += numCols)
      {
         /* Keep track of the longest item in a column */
         itemWidth = lineHt;
         if ((cbInfoPtr->labels) && (cbInfoPtr->labels[i]))
            itemWidth += fontData.avgWidth + XrStringWidth (fontData.fontInfo,
                         cbInfoPtr->labels[i], XrNULLTERMINATED, 0, 0);
         if (itemWidth > maxItemWidth)
            maxItemWidth = itemWidth;

         /* Set the rectangle describing the complete checkbox */
         XrSetRect (&((fields+i)->subRectangle), xPos, yPos, itemWidth, lineHt);

         /* Set the rectangle describing just the checkbox; no label */
         XrSetRect (&((fields+i)->rectangle), xPos, yPos, lineHt, lineHt);

         /* Set the point describing where the label is displayed */
         XrSetPt (&((fields+i)->labelPt), xPos + lineHt + fontData.avgWidth,
                  yPos);

         /* Increment for the next checkbox in the column */
         yPos += lineHt + vPadding;
      }

      /* Increment for the start of the next column */
      xPos += maxItemWidth + hPadding;
   }

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  INT32
 *  createCBoxes (cbDataPtr, cbInfoPtr, message)
 *
 *     xrCheckBoxData * cbDataPtr;
 *     xrCheckBoxInfo * cbInfoPtr;
 *     INT32            message;
 *
 *   Description:
 *   -----------
 *     if (message == MSG_NEW)
 *     This routine is responsible for creating a new checkbox instance.
 *     The description of the new instance is contained within the structure
 *     pointed to by the 'cbInfoPtr' parameter.  Besides allocating the
 *     resources needed for the new instance, this routine will also fill
 *     in the structure pointed to by the 'cbDataPtr' parameter with the
 *     state information for the new instance.
 *
 *     if (message == MSG_RESIZE)
 *     This routine will take the information contained within the 'cbInfoPtr'
 *     structure, and will recalculate the location of each component within
 *     an existing instance of checkboxes, to match the new data.  This
 *     will do no resource allocation.
 *
 *
 *   Inputs:
 *   ------
 *     cbDataPtr = Points to the 'data' structure for the instance being
 *                 created or resized.
 *
 *     cbInfoPtr = 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 'cbDataPtr'
 *          structure is filled out.
 *
 *     Upon failure, FALSE is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XrResource()   [resource.c]
 *   XMakePixmap()  [libX.a]
 *   XrCopyRect()   [calc.c]
 *   XFreePixmap()  [libX.a]
 *   _XrTextInfo()  [textUtil.c]
 *   calcComponents()
 *
 *************************************<->***********************************/

static
INT32
createCBoxes (cbDataPtr, cbInfoPtr, message)

   register xrCheckBoxData * cbDataPtr;
   register xrCheckBoxInfo * cbInfoPtr;
            int              message;

{
            FontInfo     * fontPtr;
   register xrItemData   * aButton;
   register INT16          i;
            xrResourceInfo bitmapInfo;
            RECTANGLE      minRect;
            RECTANGLE      editorRect;
            xrItemData   * tempItems;

   /* Allocate some space to hold the rectangle calculations */
   if ((tempItems = (xrItemData *) (*xrMalloc) 
       (sizeof (xrItemData) * cbInfoPtr->numFields)) == NULL)
   {
      /* Unable to allocate the memory we need */
      xrErrno = XrOUTOFMEM;
      return (FALSE);
   }

   if (message == MSG_NEW)
   {
      /* Validate incoming parameters */
      if (cbInfoPtr->values == NULL)
      {
         (*xrFree)(tempItems);
         xrErrno = XrINVALIDPTR;
         return (FALSE);
      }

      /* Allocate space to hold the individual checkbox information */
      if ((cbDataPtr->cbFields = (xrItemData *) (*xrMalloc) 
          (sizeof (xrItemData) * cbInfoPtr->numFields)) == NULL)
      {
         /* Unable to allocate the memory we need */
         (*xrFree)(tempItems);
         xrErrno = XrOUTOFMEM;
         return (FALSE);
      }

      cbDataPtr->cbFGColor = (cbInfoPtr->editorFGColor == -1) ?
                        xrForegroundColor : cbInfoPtr->editorFGColor;
      cbDataPtr->cbBGColor = (cbInfoPtr->editorBGColor == -1) ?
                        xrBackgroundColor : cbInfoPtr->editorBGColor;

      /* Create the 50% tile we will need when drawing insensitive box */
      if ((cbInfoPtr->editorFGColor == -1) &&
          (cbInfoPtr->editorBGColor == -1))
      {
         /* Use the default 50% tile */
         cbDataPtr->cbTileId = xrDefaultTile;
      }
      else
      {
         bitmapInfo.resourceType = XrTYPE_BITMAPID;
         bitmapInfo.resourceId = XrPERCENT50;
         if ((XrResource (MSG_FIND, &bitmapInfo)== FALSE) ||
          ((cbDataPtr->cbTileId = 
            XMakePixmap (((xrBitmapId *)bitmapInfo.resourceObject)->bitmapId,
                    cbDataPtr->cbFGColor, cbDataPtr->cbBGColor)) == 0))
         {
            /* Unable to create the tile */
            (*xrFree)(tempItems);
            (*xrFree) (cbDataPtr->cbFields);
            xrErrno = XrXCALLFAILED;
            return (FALSE);
         }
      }
   }

   /* Check the rectangle size */
   XrCopyRect (&cbInfoPtr->editorRect, &editorRect);
   if (calcComponents (cbInfoPtr, tempItems, MSG_SIZE) == FALSE)
   {
      /* The application must have supplied invalid information */
      /* xrErrno is set by calcComponents */
      XrCopyRect (&editorRect, &cbInfoPtr->editorRect);
      (*xrFree)(tempItems);
      if (message == MSG_NEW)
      {
         if (cbDataPtr->cbTileId != xrDefaultTile)
            XFreePixmap (cbDataPtr->cbTileId);
         (*xrFree) (cbDataPtr->cbFields);
      }
      return (FALSE);
   }
   (*xrFree)(tempItems);
   XrCopyRect (&cbInfoPtr->editorRect, &minRect);
   XrCopyRect (&editorRect, &cbInfoPtr->editorRect);
   if ((editorRect.height < minRect.height) ||
      (editorRect.width < minRect.width))
   {
      /* The application has supplied an invalid rectangle */
      xrErrno = XrINVALIDRECT;
      if (message == MSG_NEW)
      {
         if (cbDataPtr->cbTileId != xrDefaultTile)
            XFreePixmap (cbDataPtr->cbTileId);
         (*xrFree) (cbDataPtr->cbFields);
      }
      return (FALSE);
   }

   /* Generate the location and size information associated with each button */
   calcComponents (cbInfoPtr, cbDataPtr->cbFields, MSG_NEW);

   if (message == MSG_NEW)
   {
      /* Fill in the rest of the fields in the checkbox structures */
      cbDataPtr->cbNumFields = cbInfoPtr->numFields;
      cbDataPtr->cbNumCols = cbInfoPtr->numCols;
      fontPtr = cbInfoPtr->editorFont ? cbInfoPtr->editorFont : xrBaseFontInfo;
      _XrTextInfo (fontPtr, &cbDataPtr->cbFont);
      cbDataPtr->cbLabels = cbInfoPtr->labels;
      cbDataPtr->cbValues = cbInfoPtr->values;
      cbDataPtr->cbStates = cbInfoPtr->stateFlags;
      aButton = cbDataPtr->cbFields;

      for (i = 0; i < cbDataPtr->cbNumFields; i++, aButton++)
      {
         /* Copy over each checkbox label */
         if (cbInfoPtr->labels)
            aButton->label = cbInfoPtr->labels[i];
         else
            aButton->label = NULL;
   
         /* Copy the initial value, and the state flags */
         aButton->value = &(cbInfoPtr->values[i]);
         if (cbInfoPtr->stateFlags)
            aButton->state = cbInfoPtr->stateFlags[i];
         else
            aButton->state =  (XrVISIBLE | XrSENSITIVE);
      }
   }

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  INT32
 *  drawCBoxes (checkBox, buttonNum)
 *
 *     xrEditor * checkBox;
 *     INT32      buttonNum;
 *
 *   Description:
 *   -----------
 *     This routine will display either a single checkbox, or all of
 *     the checkboxes, depending upon the vlaue specified in the
 *     'buttonNum' parameter.
 *
 *
 *   Inputs:
 *   ------
 *     checkBox = Points to the editor instance structure.
 *
 *     buttonNum = This can be set to the index of the checkbox to be
 *                 drawn, or to the define XrALLBUTTONS, if all the
 *                 checkboxex should be redrawn.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrMakeInvisible()        [editorUtil.c]
 *   _XrInitEditorGCs()        [gcUtil.c]
 *   _XrCopyGC()               [gcUtil.c]
 *   _XrChangeGC()             [gcUtil.c]
 *   XrCopyRect()              [calc.c]
 *   _XrFillRectangle()        [rectUtil.c]
 *   _XrBorderFillRectangle()  [rectUtil.c]
 *   _XrImageText8()           [textUtil.c]
 *
 *************************************<->***********************************/

static
INT32
drawCBoxes (checkBox, buttonNum)

   xrEditor * checkBox;
   INT32      buttonNum;

{
   register xrCheckBoxData   * cbDataPtr;
            Window             windowId;
            INT32              sensitive;
   register INT16              firstButton, lastButton;
   register xrItemData       * aButton;
            RECTANGLE          workRect;
   register RECTANGLE        * workRectPtr;
            INT32              changeList[21];
            INT8               makeGCFlag;

   /* Initialize variables */
   cbDataPtr = (xrCheckBoxData *) checkBox->editorData;
   windowId = checkBox->editorWindowId;
   workRectPtr = &workRect;
   makeGCFlag = TRUE;

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

   /* Initialize the standard graphic contexts we will be using */
   _XrInitEditorGCs (cbDataPtr->cbFGColor, cbDataPtr->cbBGColor,
                     cbDataPtr->cbFont.fontInfo->id);

   /* Initialize the graphics context used to draw insensitive checkboxes */
   _XrCopyGC (xrDefaultGC, xrEditorGC3);
   changeList[XrTILEVAL] = cbDataPtr->cbTileId;
   changeList[XrFILLSTYLEVAL] = Tiled;
   _XrChangeGC (xrEditorGC3, (XrTILE | XrFILLSTYLE), changeList);

   sensitive = (checkBox->editorState & XrSENSITIVE) ? TRUE : FALSE;

   /* Determine the range of checkboxes to be drawn */
   if (buttonNum == XrALLBUTTONS)
   {
      firstButton = 0;
      lastButton = cbDataPtr->cbNumFields - 1;
   }
   else
      firstButton = lastButton = buttonNum;

   while (firstButton <= lastButton)
   {
      aButton = (cbDataPtr->cbFields) + firstButton;
      XrCopyRect (&(aButton->rectangle), workRectPtr);

      /* Determine how to draw the button, depending upon it's state */
      if (aButton->state & XrVISIBLE)
      {
         if (sensitive && (aButton->state & XrSENSITIVE))
         {
            /* Determine if the button is active or inactive */
            if ( *(aButton->value))
            {
               /*
                * The state of the checkbox is 'ACTIVE', so draw
                * it as a filled square, using the foreground color.
                */
               _XrFillRectangle (windowId, xrEditorGC1, workRectPtr);
            }
            else
            {
               /*
                * The state of the checkbox is 'INACTIVE', so draw
                * draw the square with the border in the foreground
                * color, and the interior in the background color.
                */
               _XrBorderFillRectangle (windowId, xrEditorGC1,
                                       xrEditorGC2, workRectPtr);
            }
         }
         else
         {
            /*
             * The checkbox is insensitive, so we will draw it as a
             * filled square, using the 50% tile.
             */
            _XrBorderFillRectangle (windowId, xrEditorGC1,
                                    xrEditorGC3, workRectPtr);
         }

         /* If the checkbox has a label, then we will draw that now. */
         if ((aButton->label) && (strlen(aButton->label) > 0))
            _XrImageText8 (windowId, xrEditorGC1, strlen(aButton->label),
                           aButton->labelPt.x, aButton->labelPt.y,
                           aButton->label);
      }
      else
      {
         /*
          * The checkbox is not visible, so fill the area it would occupy
          * with the window's background color.
          */
         _XrMakeInvisible (windowId, &(aButton->subRectangle), makeGCFlag);
          makeGCFlag = FALSE;
      }

      /* Go on and process the next checkBox */
      firstButton++;
   }
}


/*************************************<->*************************************
 *
 *  INT32
 *  processCBoxes (checkBox, input, returnEvent)
 *
 *     xrEditor     * checkBox;
 *     XButtonEvent * input;
 *     xrEvent      * returnEvent;
 *
 *   Description:
 *   -----------
 *     This is the event processing routine for the checkbox editor.
 *     It takes an event, and determines which, if any, of the checkboxes
 *     the event occurred within.  If a checkbox 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 checkbox.
 *
 *
 *   Inputs:
 *   ------
 *     checkBox = Instance pointer for the instance in which the event
 *                occurred.
 *
 *     input = This points to the event to be processed.
 *
 *     returnEvent = This points to a partially filled out X-ray event
 *                   structure.  It can be used by this routine when it
 *                   needs to generate a return event for the application.
 *                   All fields, except for the 'value' fields, are already
 *                   filled out.
 * 
 *   Outputs:
 *   -------
 *     Although a value is not directly returned, an input event will be
 *     generated, telling the application which checkbox was selected.
 *
 *   Procedures Called
 *   -----------------
 *   XrSetPt()  [calc.c]
 *   drawCBoxes
 *
 *************************************<->***********************************/

static
INT32
processCBoxes (checkBox, input, returnEvent)

   xrEditor     * checkBox;
   XButtonEvent * input;
   xrEvent      * returnEvent;

{
   register xrCheckBoxData  * cbDataPtr;
            POINT             spritePt;
   register INT16             i;
   register xrItemData      * aButton;

   cbDataPtr = (xrCheckBoxData *) checkBox->editorData;
   XrSetPt (&spritePt, input->x, input->y);
   returnEvent->value1 = NULL;

   /* Check each checkbox to see if one was selected */
   for (i = 0; i < cbDataPtr->cbNumFields; i++)
   {
      aButton = (cbDataPtr->cbFields) + i;

      if (XrPtInRect (&spritePt, &(aButton->rectangle)) &&
         ((aButton->state & (XrVISIBLE | XrSENSITIVE)) ==
         (XrVISIBLE | XrSENSITIVE)))
      {
         /* A checkbox was selected; modify its value and redraw it */
         *(aButton->value) = *(aButton->value) ? FALSE : TRUE;
         drawCBoxes (checkBox, i);
  
         /* Save the index of the checkbox which changed, and return */
         returnEvent->value2 = i;
         returnEvent->value1 = XrSELECT;
      }
   }
}
