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

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


#include <Xr/xr-copyright.h>

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

static char rcsid[] = "$Header: RasterEdit.c,v 1.1 86/12/17 09:03:45 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        RasterEdit.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **         This file contains all of the source code (minus the
 **         field editor utility routines) for the raster edit
 **         field editor.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	RasterEdit.c,v $
 * Revision 1.1  86/12/17  09:03:45  swick
 * Initial revision
 * 
 * Revision 6.1  86/11/13  12:57:58  12:57:58  fred ()
 * Fixed scrollbar event bug
 * 
 * Revision 6.0  86/11/10  15:34:15  15:34:15  fred ()
 * QA #2 release
 * 
 * Revision 5.2  86/11/07  14:21:41  14:21:41  fred ()
 * Added new copyright message.
 * 
 * Revision 5.1  86/11/04  08:57:37  08:57:37  fred ()
 * Added continuous scrolling, and fixed a bug in MSG_SETSTATE.
 * 
 * Revision 5.0  86/10/28  08:31:09  08:31:09  fred ()
 * QA #1.1 release
 * 
 * Revision 4.1  86/10/23  09:07:31  09:07:31  fred ()
 * Removed unused variables.
 * 
 * Revision 4.0  86/10/20  12:12:26  12:12:26  fred ()
 * QA #1 release
 * 
 * Revision 3.2  86/10/16  09:16:31  09:16:31  fred ()
 * Performance enhanced: added use of register variables.
 * 
 * Revision 3.1  86/10/09  07:46:52  07:46:52  fred ()
 * Added default color check to create routine.
 * 
 * Revision 3.0  86/10/02  16:00:12  16:00:12  fred ()
 * Alpha release set to 3.0
 * 
 * Revision 2.7  86/10/01  08:13:31  08:13:31  fred ()
 * Fixed a bug where if only a single scrollbar was needed,
 * it ended up getting displayed on top of the editing region,
 * instead of next to it.
 * 
 * Revision 2.6  86/09/22  12:37:35  12:37:35  fred ()
 * Changed xrPixMap structure to xrPixmap, and
 * added calls to XrEditorGroup().
 * 
 * Revision 2.5  86/09/19  10:09:06  10:09:06  fred ()
 * Fixed a bug where I was generating a fake "
 * Select event instead of a SELECTUP event.
 * 
 * Revision 2.4  86/09/19  07:11:24  07:11:24  fred ()
 * Added a check for XrVISIBLE before doing any drawing.
 * 
 * Revision 2.3  86/09/18  10:02:32  10:02:32  fred ()
 * Fixed scrollbar processing, so that a fake select up event is
 * pushed after the scrollbar processing, thus preventing _MsgEdit()
 * from hanging, waiting for a non-existant select up event.
 * 
 * Revision 2.2  86/09/18  07:40:57  07:40:57  fred ()
 * Filled in procedure headers.
 * 
 * Revision 2.1  86/09/17  08:16:24  08:16:24  fred ()
 * Fixed a but in paintREdit(), where the input queue was only read
 * when the cursor was within the editing region.
 * 
 * Revision 2.0  86/09/16  08:08:18  08:08:18  fred ()
 * Updated input processing routine to use new SELECT strategy.
 * 
 * Revision 1.6  86/09/16  05:48:08  05:48:08  fred ()
 * Modified to swallow a select up event.
 * 
 * Revision 1.5  86/09/09  10:43:19  10:43:19  fred ()
 * Added a line algorithm to the drawing routine, so
 * that pixels are not skipped during drag operation.
 * 
 * Revision 1.4  86/09/09  07:09:27  07:09:27  fred ()
 * Added the view origin data to the event information returned
 * when the view region is scrolled by the user.
 * 
 * Revision 1.3  86/09/08  06:50:17  06:50:17  fred ()
 * Broke up large functions into several smaller functions.
 * 
 * Revision 1.2  86/09/05  15:05:31  15:05:31  fred ()
 * Added handling of all message requests.
 * This is the first complete version of this editor.
 * 
 * Revision 1.1  86/09/03  13:57:33  13:57:33  fred ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



#include <X/Xlib.h>
#include <Xr/defs.h>
#include <Xr/types.h>
#include <Xr/in_types.h>
#ifdef BSD
#include <sys/time.h>
#else
#include <time.h>
#endif


extern INT32 createREdit();
extern INT32 drawREdit();
extern INT32 processREdit();
extern INT32 reFreeMemory();
extern xrEditor * moveREdit();
extern xrEditor * resizeREdit();
extern xrEditor * positionREdit();



/*************************************<->*************************************
 *
 *  xrEditor *
 *  XrRasterEdit (rasterEdit, message, data)
 *
 *     xrEditor * rasterEdit;
 *     INT32      message;
 *     INT8     * data;
 *
 *   Description:
 *   -----------
 *     This is the entry point into the raster edit field editor.
 *     All requests (in the form of a message) are received here,
 *     and processed accordingly.  Refer to the raster editor manual
 *     page for a complete description of the messages handled here,
 *     along with the meaning of the 'data' parameter.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This is a pointer to the editor instance structure,
 *                  returned when an instance was created.
 * 
 *     message = This is one of the raster editor messages.
 *
 *     data = This parameter is message specific.  Depending upon the
 *            'message' parameter, this may contain a scalar value, or
 *            it may contain a pointer to a structure.  The exact format
 *            of this parameter is discussed below, in the handling code
 *            for each message.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion of processing a message, the editor
 *          instance pointer will be returned.  Other information may
 *          also be returned by means of the 'data' parameter; if this
 *          is the case, then it will be discussed in the handling code
 *          for each message.
 *
 *     Upon failure, NULL will be returned, and xrErrno set. 
 *
 *   Procedures Called
 *   -----------------
 *   _MsgNew()       [MsgCommon.c]
 *   _MsgFree()      [MsgCommon.c]
 *   _MsgGetState()  [MsgCommon.c]
 *   _MsgRedraw()    [MsgCommon.c]
 *   _MsgEdit()      [MsgCommon.c]
 *   XrScrollBar()   [ScrollBar.c]
 *   sizeREdit()
 *   moveREdit()
 *   resizeREdit()
 *   positionREdit()
 *
 *************************************<->***********************************/

xrEditor *
XrRasterEdit (rasterEdit, message, data)

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

{
   /* Determine the action being requested */
   switch (message)
   {
      case MSG_NEW:
      {
           /*
            * Create a new instance of the editor.
            * The 'rasterEdit' parameter is unused.
            * The 'data' parameter must point to an instance of
            * the xrRasterEditInfo structure.
            */
           return ((xrEditor *) _MsgNew (rasterEdit, data,
                                         sizeof(xrRasterEditData),
                                         createREdit, drawREdit,
                                         reFreeMemory, XrRasterEdit,
                                         NULL));
      }

      case MSG_FREE:
      {
           /*
            * Destroy the specified editor instance.
            * The 'rasterEdit' parameter must point to the editor
            * instance structure associated with the instance to
            * be freed.  The 'data' parameter is unused.
            */
           return ((xrEditor *) _MsgFree (rasterEdit, reFreeMemory));
      }

      case MSG_GETSTATE:
      {
           /*
            * Return the state flags for an editor instance.
            * The 'rasterEdit' parameter specifies the instance
            * to be queried, while the 'data' parameter must point
            * to an INT8 value, into which the state flags are returned.
            */
           return ((xrEditor *) _MsgGetState (rasterEdit, data));
      }

      case MSG_SETSTATE:
      {
           /*
            * Change the state flags for an editor instance.
            * The 'rasterEdit' parameter specifies the instance to
            * be modified.  The 'data' parameter is interpreted as
            * an INT8 value, containing the new state flags.
            */
           register xrRasterEditData * reDataPtr;
           register INT8 oldState;
           register INT8 stateFlags = (INT8) data;

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

           oldState = rasterEdit->editorState;
           rasterEdit->editorState = stateFlags;

           /*
            * Redraw the instance if either the XrVISIBLE flag has changed,
            * or if the instance is visible and the XrSENSITIVE flag has
            * changed.
            */
           if (((oldState & XrVISIBLE) != (stateFlags & XrVISIBLE)) ||
              ((stateFlags & XrVISIBLE) && 
              ((oldState & XrSENSITIVE) != (stateFlags & XrSENSITIVE))))
           {
              if ((oldState & XrVISIBLE) != (stateFlags & XrVISIBLE))
                 drawREdit (rasterEdit, NULL);

              /* Update the scrollbar states */
              reDataPtr = (xrRasterEditData *) rasterEdit->editorData;
              if (reDataPtr->vScrollbar)
                 XrScrollBar (reDataPtr->vScrollbar, MSG_SETSTATE, data);
              if (reDataPtr->hScrollbar)
                 XrScrollBar (reDataPtr->hScrollbar, MSG_SETSTATE, data);

            }
            return (rasterEdit);
      }

      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 'rasterEdit' 
            * parameter is unused.  The 'data' parameter must point to 
            * an instance of the 'xrRasterEditInfo' structure.  The
            * calculated rectangle is returned in the 'editorRect'
            * field within this structure.
	    */
           xrRasterEditInfo * reInfoPtr;

           reInfoPtr = (xrRasterEditInfo *)data;

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

           return ((xrEditor *) TRUE);
      }

      case MSG_REDRAW:
      {
         /*
          * Redraw an instance of this editor.
          * The 'rasterEdit' parameter specifies the instance to be
          * redrawn.  The 'data' parameter is interpreted as an INT32
          * value, specifying the type of redraw to perform; this editor
          * only supports the XrREDRAW_ALL option.
          */
         register xrRasterEditData * reDataPtr;

         if (_MsgRedraw (rasterEdit, data, drawREdit, NULL))
         {
            /* Redraw the scrollbars */
            reDataPtr = (xrRasterEditData *) rasterEdit->editorData;
            if (reDataPtr->vScrollbar)
               XrScrollBar (reDataPtr->vScrollbar, MSG_REDRAW, XrREDRAW_ALL);
            if (reDataPtr->hScrollbar)
               XrScrollBar (reDataPtr->hScrollbar, MSG_REDRAW, XrREDRAW_ALL);

            return (rasterEdit);
         }

         return ((xrEditor *) NULL);
      }

      case MSG_MOVE:
      {
         /*
          * Reposition the origin of an instance's editorRect.
          * The 'rasterEdit' parameter specifies the instance which is
          * to be moved.  The 'data' parameter must point to a POINT
          * structure, specifying the new origin.
          */
         return (moveREdit (rasterEdit, data));
      }

      case MSG_RESIZE:
      {
         /*
          * Resize an existing raster editor instance.
          * The 'rasterEdit' parameter specifies the instance which
          * is to be resized.  The 'data' parameter must point to an
          * instance of the RECTANGLE structure, containing the new
          * size and origin information.
          */
         return (resizeREdit (rasterEdit, data));
      }

      case MSG_POSITION:
      {
         /*
          * Change the portion of the raster image to be displayed
          * within the view region. 
          * The 'rasterEdit' parameter specifies the instance which is
          * to be modified.  The 'data' parameter must point to an
          * instance of the POINT structure, which contains the
          * coordinates of the pixel which should be displayed in
          * the upper left hand corner of the view region.
          */
         return (positionREdit (rasterEdit, data));
      }

      case MSG_SETCOLOR:
      {
         /*
          * Set a new pixel editing color.
          * The 'rasterEdit' parameter indicates which instance
          * is being referenced.  The 'data' parameter is interpreted
          * as a 32 bit integer value containing the new editing color.
          */
         if (rasterEdit == NULL)
         {
            xrErrno = XrINVALIDID;
            return ((xrEditor *) NULL);
         }

         ((xrRasterEditData *)rasterEdit->editorData)->pixelColor =
               (INT32) data;

         return (rasterEdit);
      }

      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 'rasterEdit' parameter specifies the instance to which
          * the event is to be applied.  The 'data' parameter is assumed
          * to point to an XEvent structure.
	  */
         return ((xrEditor *) _MsgEdit (rasterEdit, data,
                                        processREdit, XrRASTEREDIT));
      }

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

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


/*************************************<->*************************************
 *
 *  reFreeMemory (reDataPtr)
 *
 *     xrRasterEditData * reDataPtr;
 *
 *   Description:
 *   -----------
 *     This routine will free up the scrollbars associated with a
 *     particular instance (if they are defined), and will also
 *     free up the pixel extraction instance used to extract the data
 *     from the raster image being edited.  It is invoked either when
 *     a MSG_FREE is received, or when a MSG_NEW request fails at a point
 *     after createREdit() has been called.
 *
 *
 *   Inputs:
 *   ------
 *     reDataPtr = This is a pointer to an instance's internal 'data'
 *                 structure.  It contains the scrollbar instance pointers,
 *                 along with the pixel extraction instance pointer.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   XrScrollBar()      [ScrollBar.c]
 *   _XrPixelExtract()  [pixelExt.c]
 *
 *************************************<->***********************************/

static
INT32
reFreeMemory (reDataPtr)

   register xrRasterEditData * reDataPtr;

{
   /* 
    * If either a horizontal or vertical scrollbar was created,
    * then instruct the scrollbar editor to destroy them.
    */
   if (reDataPtr->vScrollbar)
      XrScrollBar (reDataPtr->vScrollbar, MSG_FREE, NULL);
   if (reDataPtr->hScrollbar)
      XrScrollBar (reDataPtr->hScrollbar, MSG_FREE, NULL);

   /* Release the pixel extraction resources */
   _XrPixelExtract (reDataPtr->extractionData, MSG_FREE, NULL);
}


/*************************************<->*************************************
 *
 *  sizeREdit (reInfoPtr, rectPtr)
 *
 *     xrRasterEditInfo * reInfoPtr;
 *     RECTANGLE        * rectPtr;
 *
 *   Description:
 *   -----------
 *     Given a raster image size, a view region size, and a pixel 
 *     expansion factor, this routine will calculate the minimally
 *     sized 0-based rectangle needed to completely contain the
 *     described instance.
 *
 *
 *   Inputs:
 *   ------
 *     reInfoPtr = This must point to an instance of the xrRasterEditInfo 
 *                 structure, which defines a hypothetical raster edit
 *                 instance.
 *
 *     rectPtr = This must point to an instance of a RECTANGLE structure.
 *               The 0-based rectangle calculated by this procedure will
 *               be returned in that RECTANGLE structure.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, a value of TRUE is returned, and the
 *          0-based rectangle definition is returned in the structure
 *          pointed to by the 'rectPtr' parameter.
 *
 *     Upon failure, FALSE is returned, an xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XrCopyRect()  [calc.c]
 *
 *************************************<->***********************************/

static
sizeREdit (reInfoPtr, rectPtr)

   register xrRasterEditInfo  * reInfoPtr;
   register RECTANGLE         * rectPtr;

{
   INT16 vHeight = reInfoPtr->viewRegion.height; 
   INT16 vWidth = reInfoPtr->viewRegion.width;  
   INT16 rHeight = reInfoPtr->rasterData.height;
   INT16 rWidth = reInfoPtr->rasterData.width;
   INT32 pixelSize = reInfoPtr->pixelSize;

   /*
    * Make sure the view region is at least 16 x 16, and
    * also that the view region is NOT larger than the
    * raster image.
    */
   if ((vHeight < 16) || (vWidth < 16) ||
       (vHeight > rHeight) || (vWidth > rWidth))
   {
      xrErrno = XrINVALIDPARM;
      return (FALSE);
   }
   else if (pixelSize < 4)
   {
      xrErrno = XrPARMOUTOFRANGE;
      return (FALSE);
   }

   /*
    * The preliminary height of the editor rectangle is calculated
    * using the following formula:
    *
    *  ht = (viewRegion height * pixelSize) + (viewRegion height + 1)
    *       [ the second component takes the grid into account ]
    */
   XrCopyRect (&xrZeroRect, rectPtr);
   rectPtr->height = (vHeight * pixelSize) + (vHeight + 1);

   /*
    * The preliminary width of the editor rectangle is calculated
    * using the following formula:
    *
    *   width = (viewRegion width * pixelSize) + (viewRegion Width + 1)
    *           [ the second component take the grid into account ]
    */
   rectPtr->width = (vWidth * pixelSize) + (vWidth + 1);

   /*
    * If the raster image width is larger than the view region width,
    * then we need to take into account a horizontal scrollbar.
    */
   if (rWidth > vWidth)
      rectPtr->height += XrMIN_SCROLLBAR_HT + 2 + (pixelSize / 10);

   /*
    * If the raster image height is larger than the view region
    * height, then we need to take into account a vertical scrollbar.
    */
   if (rHeight > vHeight)
      rectPtr->width += XrMIN_SCROLLBAR_WID + 2 + (pixelSize / 10);

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  createREdit (reDataPtr, reInfoPtr, message)
 *
 *     xrRasterEditData * reDataPtr;
 *     xrRasterEditInfo * reInfoPtr;
 *     INT32              message;
 *
 *   Description:
 *   -----------
 *     This routine takes a raster editor definition, contained in the
 *     structure pointed to by the 'reInfoPtr' parameter, and constructs
 *     all of the components necessary to create that instance.  This
 *     includes filling in the structure pointed to by the 'reDataPtr'
 *     parameter, allocating a pixel extraction instance, and creating
 *     any needed scrollbars.
 *
 *
 *   Inputs:
 *   ------
 *     reDataPtr = This is a pointer to an instance of the xrRasterEditData
 *                 structure, which will be filled in by this routine.
 *
 *     reInfoPtr = This is a pointer to an instance of the xrRasterEditInfo
 *                 structure, which must be completely filled out.  The
 *                 reDataPtr structure is filled out using information
 *                 contained within this structure.
 *
 *     message = This parameter is unused by this procedure.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, a value of TRUE is returned, and the
 *          fields in the structure pointed to by the reDataPtr parameter
 *          will be filled.
 *
 *     Upon failure, FALSE will be returned, and xrErrno set.
 *
 *   Procedures Called
 *   -----------------
 *   XrCopyPt()         [calc.c]
 *   _XrPixelExtract()  [pixelExt.c]
 *   sizeREdit()
 *   createVScrollBar() 
 *   createHScrollBar()
 *
 *************************************<->***********************************/

static
INT32
createREdit (reDataPtr, reInfoPtr, message)

   register xrRasterEditData * reDataPtr;
   register xrRasterEditInfo * reInfoPtr;
            INT32              message;

{
   INT32     depth;
   RECTANGLE workRect;

   /* Validate all parameters */
   if (((depth = reInfoPtr->rasterData.depth) != XrBIT1) &&
        (depth != XrBYTE1) && (depth != XrBYTE2) &&
        (depth != XrBYTE3) && (depth != XrBYTE4))
   {
      xrErrno = XrINVALIDDEPTH;
      return (FALSE);
   }
   else if (reInfoPtr->rasterData.raster == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return (FALSE);
   }

   /* Make sure a valid editor rectangle was specified */
   if (sizeREdit (reInfoPtr, &workRect) == FALSE)
   {
      /* xrErrno is set by sizeREdit() */
      return (FALSE);
   }
   else if ((reInfoPtr->editorRect.height < workRect.height) ||
           (reInfoPtr->editorRect.width < workRect.width))
   {
      xrErrno = XrINVALIDRECT;
      return (FALSE);
   }

   /* Initialize the pixel extraction routine */
   if ((reDataPtr->extractionData = (xrPixelData *)
       _XrPixelExtract (NULL, MSG_NEW, &reInfoPtr->rasterData)) == NULL)
   {
      /* xrErrno has already been set by _XrPixelExtract() */
      return (FALSE);
   }

   /* Copy the rest of the information describing the instance */
   reDataPtr->reFGColor = (reInfoPtr->editorFGColor == -1) ?
               xrForegroundColor : reInfoPtr->editorFGColor;
   reDataPtr->reBGColor = (reInfoPtr->editorBGColor == -1) ?
               xrBackgroundColor : reInfoPtr->editorBGColor;
   reDataPtr->pixelColor = reInfoPtr->pixelColor;
   reDataPtr->pixelSize = reInfoPtr->pixelSize;
   reDataPtr->vScrollbar = NULL;
   reDataPtr->hScrollbar = NULL;
   XrCopyPt (&xrZeroPt, &reDataPtr->viewOrigin);
   _Xrmemcpy(&reDataPtr->viewRegion, &reInfoPtr->viewRegion, sizeof (SIZE));
   _Xrmemcpy(&reDataPtr->rasterData, &reInfoPtr->rasterData, sizeof (xrPixmap));

   /*
    * Define the rectangle containing ONLY the editing region.
    * It it tied to the upper left corner of the editor rectangle.
    *   width = Number of grid lines + (view width * pixelSize)
    *   height = Number of grid lines + (view height * pixelSize)
    */
   reDataPtr->reRectangle.x = reInfoPtr->editorRect.x;
   reDataPtr->reRectangle.y = reInfoPtr->editorRect.y;
   reDataPtr->reRectangle.height = (reInfoPtr->viewRegion.height + 1) +
            (reInfoPtr->viewRegion.height * reInfoPtr->pixelSize);
   reDataPtr->reRectangle.width = (reInfoPtr->viewRegion.width + 1) +
            (reInfoPtr->viewRegion.width * reInfoPtr->pixelSize);

   /*
    * If the height of the raster image is larger than the height
    * of the view region, then create a vertical scrollbar.  Tie its
    * origin to the right edge of the editor rectangle.
    */
   if (reInfoPtr->rasterData.height > reInfoPtr->viewRegion.height)
   {
      if (createVScrollBar (reInfoPtr, reDataPtr) == FALSE)
      {
         reFreeMemory (reDataPtr);
         return (FALSE);
      }
   }

   /*
    * If the width of the raster image is larger than the width
    * of the view region, then create a horizontal scrollbar.  Tie
    * its origin to the bottom of the editor rectangle.
    */
   if (reInfoPtr->rasterData.width > reInfoPtr->viewRegion.width)
   {
      if (createHScrollBar (reInfoPtr, reDataPtr) == FALSE)
      {
         reFreeMemory (reDataPtr);
         return (FALSE);
      }
   }
      
   return (TRUE);
}


/*************************************<->*************************************
 *
 *  xrEditor *
 *  moveREdit (rasterEdit, ptPtr)
 *
 *     xrEditor * rasterEdit;
 *     POINT    * ptPtr;
 *
 *   Description:
 *   -----------
 *     This routine will relocate all components of a raster editor
 *     instance.  The new origin for the instance is specified in the
 *     POINT structure pointed to by the 'ptPtr' parameter.  The
 *     components which must be moved are the editor rectangle, the
 *     editing region rectangle, and the scrollbars.  If the instance
 *     is currently visible, then it will be redrawn at its new location
 *     after the move is complete.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This is the instance pointer, and indicates which
 *                  editor instance is to be moved.
 *
 *     ptPtr = This is a pointer to a POINT structure, and contains the
 *             new editor rectangle origin.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer is returned,
 *          and the editor instance is moved.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XrCopyRect()        [calc.c]
 *   XrOffsetRect()      [calc.c]
 *   XrScrollBar()       [ScrollBar.c]
 *   _XrMakeInvisible()  [editorUtil.c]
 *   drawREdit()
 *
 *************************************<->***********************************/

static
xrEditor *
moveREdit (rasterEdit, ptPtr)

   register xrEditor * rasterEdit;
            POINT    * ptPtr;

{
   register xrRasterEditData * reDataPtr;
            RECTANGLE          workRect;
   register INT16              xDelta;
   register INT16              yDelta;
            POINT              sbOrigin;

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

   /* Determine how much to relocate the instance by */
   reDataPtr = (xrRasterEditData *) rasterEdit->editorData;
   XrCopyRect (&rasterEdit->editorRect, &workRect);
   xDelta = ptPtr->x - rasterEdit->editorRect.x;
   yDelta = ptPtr->y - rasterEdit->editorRect.y;

   /* Relocate each component of the raster editor instance */
   XrOffsetRect (&rasterEdit->editorRect, xDelta, yDelta);
   XrOffsetRect (&reDataPtr->reRectangle, xDelta, yDelta);
   if (reDataPtr->vScrollbar)
   {
      if (rasterEdit->editorState & XrVISIBLE)
         XrScrollBar (reDataPtr->vScrollbar, MSG_SETSTATE, 0);
      sbOrigin.x = reDataPtr->vScrollbar->editorRect.x + xDelta;
      sbOrigin.y = reDataPtr->vScrollbar->editorRect.y + yDelta;
      XrScrollBar (reDataPtr->vScrollbar, MSG_MOVE, &sbOrigin);
   }
   if (reDataPtr->hScrollbar)
   {
      if (rasterEdit->editorState & XrVISIBLE)
         XrScrollBar (reDataPtr->hScrollbar, MSG_SETSTATE, 0);
      sbOrigin.x = reDataPtr->hScrollbar->editorRect.x + xDelta;
      sbOrigin.y = reDataPtr->hScrollbar->editorRect.y + yDelta;
      XrScrollBar (reDataPtr->hScrollbar, MSG_MOVE, &sbOrigin);
   }

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

      /* Redisplay the instance, if it was visible */
      drawREdit (rasterEdit, NULL);
   }

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


/*************************************<->*************************************
 *
 *  xrEditor *
 *  resizeREdit (rasterEdit, rectPtr)
 *
 *     xrEditor  * rasterEdit;
 *     RECTANGLE * rectPtr;
 *
 *   Description:
 *   -----------
 *     This routine will resize an existing raster edit instance.  The
 *     application passes in a new editor rectangle definition, and the
 *     instance will be recalculated, such that it now fits within the
 *     new region; the same size restrictions which applied when the
 *     instance was created will apply.  Resizing an instance involves
 *     moving the origin of the editor rectangle and the editing region
 *     rectangle; it also involves telling the scrollbar editor to
 *     move the scrollbar instances; they will continue to be tied to
 *     top right and bottom left corners of the editor rectangle.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This is the instance pointer for the editor instance
 *                  which is to be resized.
 *
 *     rectPtr = This is a pointer to a RECTANGLE structure, containing
 *               the new size and location information for the instance.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer will be
 *          returned, and the instance will have been resized, and
 *          redrawn (if it was visible).
 *
 *     Upon failure, NULL is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XrScrollBar()       [ScrollBar.c]
 *   _XrMakeInvisible()  [editorUtil.c]
 *   XrSetPt()           [calc.c]
 *   drawREdit()
 *   sizeREdit()
 *
 *************************************<->***********************************/

static
xrEditor *
resizeREdit (rasterEdit, rectPtr)

   register xrEditor  * rasterEdit;
   register RECTANGLE * rectPtr;

{
            RECTANGLE          tempRect;
            xrRasterEditInfo   reInfo;
            POINT              vSBOrigin;
            POINT              hSBOrigin;
   register xrRasterEditData * reDataPtr;

   /* Check for invalid parameters */
   if (rasterEdit == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (rectPtr == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }

   /* Set up a pseudo info structure to pass to sizeREdit() */
   reDataPtr = (xrRasterEditData *) rasterEdit->editorData;
   reInfo.pixelSize = reDataPtr->pixelSize;
   reInfo.viewRegion.height = reDataPtr->viewRegion.height;
   reInfo.viewRegion.width = reDataPtr->viewRegion.width;
   reInfo.rasterData.height = reDataPtr->rasterData.height;
   reInfo.rasterData.width = reDataPtr->rasterData.width;

   /* Check for an invalid editor rectangle definition */
   if (sizeREdit (&reInfo, &tempRect) == FALSE)
   {
      /* This better not ever fail here !! */
      return ((xrEditor *) NULL);
   }
   else if ((rectPtr->height < tempRect.height) ||
            (rectPtr->width < tempRect.width))
   {
      xrErrno = XrINVALIDRECT;
      return ((xrEditor *) NULL);
   }

   /* Remove the old instance, if visible */
   if (rasterEdit->editorState & XrVISIBLE)
   {
      XrScrollBar (reDataPtr->vScrollbar, MSG_SETSTATE,
                   rasterEdit->editorState & ~XrVISIBLE);
      XrScrollBar (reDataPtr->hScrollbar, MSG_SETSTATE,
                   rasterEdit->editorState & ~XrVISIBLE);
      _XrMakeInvisible (rasterEdit->editorWindowId, 
                        &rasterEdit->editorRect, TRUE);
   }

   /* Move each component in the raster editor instance */

   /* Move the editor rectangle */
   rasterEdit->editorRect.x = rectPtr->x;
   rasterEdit->editorRect.y = rectPtr->y;
   rasterEdit->editorRect.height = rectPtr->height;
   rasterEdit->editorRect.width = rectPtr->width;

   /* Move the editing region rectangle */
   reDataPtr->reRectangle.x = rectPtr->x;
   reDataPtr->reRectangle.y = rectPtr->y;

   /* Move the vertical scrollbar */
   if (reDataPtr->vScrollbar)
   {
      XrSetPt (&vSBOrigin, (rectPtr->x + rectPtr->width - 1) - 
               reDataPtr->vScrollbar->editorRect.width,
               rectPtr->y);
      XrScrollBar (reDataPtr->vScrollbar, MSG_MOVE, &vSBOrigin);
   }

   /* Move the horizontal scrollbar */
   if (reDataPtr->hScrollbar)
   {
      XrSetPt (&hSBOrigin, rectPtr->x,
               (rectPtr->y + rectPtr->height - 1) - 
               reDataPtr->hScrollbar->editorRect.height);
      XrScrollBar (reDataPtr->hScrollbar, MSG_MOVE, &hSBOrigin);
   }

   /* Redraw the instance, if visible */
   if (rasterEdit->editorState & XrVISIBLE)
      drawREdit (rasterEdit, NULL);

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


/*************************************<->*************************************
 *
 *  xrEditor *
 *  positionREdit (rasterEdit, position)
 *
 *   Description:
 *   -----------
 *     This routine allow a new view origin to be specified; the view
 *     origin is the coordinates of the pixel which is displayed in the
 *     upper left corner of the editing region.  The value will be
 *     ignored if it meant that the visible portion of the raster image
 *     is smaller than the view region.  After setting the new view
 *     origin, the instance will be redrawn, if it was visible.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the editor instance structure for the
 *                  instance which is to be modified.
 *
 *     position = This points to a POINT structure, which contains the
 *                new view origin point.  This point will be displayed
 *                in the upper left square in the editing region.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer is returned,
 *          the new view origin is set, and the instance is redraw, if it
 *          was visible.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XrCopyPt()       [calc.c]
 *   XrScrollBar()    [calc.c]
 *   drawColorBoxes()
 *
 *************************************<->***********************************/

static
xrEditor *
positionREdit (rasterEdit, position)

            xrEditor * rasterEdit;
   register POINT    * position;

{
   register xrRasterEditData * reDataPtr;

   if (rasterEdit == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (position == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }

   /*
    * Verify the location falls within the bounds of the raster image,
    * and also still allows the complete view region to be filled.
    */
   reDataPtr = (xrRasterEditData *) rasterEdit->editorData;

   if ((position->x < 0) || (position->y < 0) ||
       (position->x > (reDataPtr->rasterData.width - 
       reDataPtr->viewRegion.width) ||
       (position->y > (reDataPtr->rasterData.height - 
       reDataPtr->viewRegion.height))))
   {
      xrErrno = XrINVALIDPARM;
      return ((xrEditor *) NULL);
   }

   XrCopyPt (position, &reDataPtr->viewOrigin);

   /* Reposition scrollbar, and redraw the instance */
   if (reDataPtr->vScrollbar)
   {
      reDataPtr->vSBParameters.slidePosition = reDataPtr->viewOrigin.y;
      XrScrollBar (reDataPtr->vScrollbar, MSG_SETPARAMETERS,
                   &reDataPtr->vSBParameters);
   }
   if (reDataPtr->hScrollbar)
   {
      reDataPtr->hSBParameters.slidePosition = reDataPtr->viewOrigin.x;
      XrScrollBar (reDataPtr->hScrollbar, MSG_SETPARAMETERS,
                   &reDataPtr->hSBParameters);
   }

   if (rasterEdit->editorState & XrVISIBLE)
      drawColorBoxes (rasterEdit, reDataPtr->viewOrigin.x, 
         reDataPtr->viewOrigin.y,
         reDataPtr->viewOrigin.x + reDataPtr->viewRegion.width -1,
         reDataPtr->viewOrigin.y + reDataPtr->viewRegion.height - 1);

   return (rasterEdit);
}


/*************************************<->*************************************
 *
 *  createVScrollBar (reInfoPtr, reDataPtr)
 *
 *     xrRasterEditInfo * reInfoPtr;
 *     xrRasterEditData * reDataPtr;
 *
 *   Description:
 *   -----------
 *     This routine attempts to create a vertical scrollbar, whose height
 *     is equal to the height of the raster editing region.  The scroll
 *     units are calculated with a min value of 0, and a max value equal
 *     the to raster image height - the view region height.  The scrollbar
 *     is created invisible, so that the raster editor can draw it at the
 *     proper time.  After the scrollbar is created, it is unattached from
 *     the window's editor list, so that XrInput() will not ever pass
 *     input events to it; only the raster editor should pass input events
 *     to it.
 *
 *
 *   Inputs:
 *   ------
 *     reInfoPtr = This is a pointer to the 'info' structure for the
 *                 raster edit instance being created.  It is used by
 *                 this routine to calculate the size and scroll unit
 *                 values for the scrollbar being created.
 *
 *     reDataPtr = This is a pointer to the internal 'data' structure
 *                 for the raster edit instance being created.  Both
 *                 the editor instance pointer for the new scrollbar
 *                 and the scrollbar configuration values will be
 *                 stored in this structure.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE will be returned, and a vertical
 *          scrollbar will be created.
 *
 *     Upon failure, FALSE will be returned, and xrErrno set.
 *
 *   Procedures Called
 *   -----------------
 *   XrScrollBar()  [ScrollBar.c]
 *   XrEditor()     [editor.c]
 *
 *************************************<->***********************************/

static
INT32
createVScrollBar (reInfoPtr, reDataPtr)

   register xrRasterEditInfo * reInfoPtr;
   register xrRasterEditData * reDataPtr;

{
            xrScrollBarInfo   sbInfo;
   register xrSBParameters  * config;

   /* Fill out the 'info' structure used to create the scrollbar */
   sbInfo.editorWindowId = reInfoPtr->editorWindowId;
   sbInfo.editorState = 0;
   sbInfo.editorFGColor = reInfoPtr->editorFGColor;
   sbInfo.editorBGColor = reInfoPtr->editorBGColor;
   sbInfo.orientation = XrVERTICAL;

   /* Fill the 'configuration' portion of the 'init' structure */
   config = &sbInfo.configuration;
   config->components = XrSCROLLARROWS | XrSLIDEBOX;
   config->min = 0;
   config->max = reInfoPtr->rasterData.height - 
                 reInfoPtr->viewRegion.height;
   config->slidePosition = 0;
   config->slideSize = config->max / 10;
   if (config->slideSize <= 0) config->slideSize = 1;
   config->handler = NULL;
   _Xrmemcpy (&reDataPtr->vSBParameters, config, sizeof (xrSBParameters));

   /* Calculate the editor rectangle for this instance */
   sbInfo.editorRect.width = XrMIN_SCROLLBAR_WID + 2 +
                             (reDataPtr->pixelSize / 10);
   XrScrollBar (NULL, MSG_SIZE, &sbInfo);
   sbInfo.editorRect.x = reInfoPtr->editorRect.x +
                         reInfoPtr->editorRect.width - 1 - 
                         sbInfo.editorRect.width;
   sbInfo.editorRect.y = reInfoPtr->editorRect.y;
   sbInfo.editorRect.height = reDataPtr->reRectangle.height;
   
   /* Create the editor instance */
   if ((reDataPtr->vScrollbar = XrScrollBar (NULL, MSG_NEW, &sbInfo)) == NULL)
      return (FALSE);

   XrEditor (reInfoPtr->editorWindowId, MSG_REMOVE, reDataPtr->vScrollbar);

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  createHScrollBar (reInfoPtr, reDataPtr)
 *
 *     xrRasterEditInfo * reInfoPtr;
 *     xrRasterEditData * reDataPtr;
 *
 *   Description:
 *   -----------
 *     This routine attempts to create a horizontal scrollbar, whose width
 *     is equal to the width of the raster editing region.  The scroll
 *     units are calculated with a min value of 0, and a max value equal
 *     the to raster image width - the view region width.  The scrollbar
 *     is created invisible, so that the raster editor can draw it at the
 *     proper time.  After the scrollbar is created, it is unattached from
 *     the window's editor list, so that XrInput() will not ever pass
 *     input events to it; only the raster editor should pass input events
 *     to it.
 *
 *
 *   Inputs:
 *   ------
 *     reInfoPtr = This is a pointer to the 'info' structure for the
 *                 raster edit instance being created.  It is used by
 *                 this routine to calculate the size and scroll unit
 *                 values for the scrollbar being created.
 *
 *     reDataPtr = This is a pointer to the internal 'data' structure
 *                 for the raster edit instance being created.  Both
 *                 the editor instance pointer for the new scrollbar
 *                 and the scrollbar configuration values will be
 *                 stored in this structure.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE will be returned, and a horizontal
 *          scrollbar will be created.
 *
 *     Upon failure, FALSE will be returned, and xrErrno set.
 *
 *   Procedures Called
 *   -----------------
 *   XrScrollBar()  [ScrollBar.c]
 *   XrEditor()     [editor.c]
 *
 *************************************<->***********************************/

static
INT32
createHScrollBar (reInfoPtr, reDataPtr)

   register xrRasterEditInfo * reInfoPtr;
   register xrRasterEditData * reDataPtr;

{
            xrScrollBarInfo   sbInfo;
   register xrSBParameters  * config;

   /* Fill out the 'info' structure used to create the scrollbar */
   sbInfo.editorWindowId = reInfoPtr->editorWindowId;
   sbInfo.editorState = 0;
   sbInfo.editorFGColor = reInfoPtr->editorFGColor;
   sbInfo.editorBGColor = reInfoPtr->editorBGColor;
   sbInfo.orientation = XrHORIZONTAL;

   /* Fill the 'configuration' portion of the 'init' structure */
   config = &sbInfo.configuration;
   config->components = XrSCROLLARROWS | XrSLIDEBOX;
   config->min = 0;
   config->max = reInfoPtr->rasterData.width - 
                 reInfoPtr->viewRegion.width;
   config->slidePosition = 0;
   config->slideSize = config->max / 10;
   if (config->slideSize <= 0) config->slideSize = 1;
   config->handler = NULL;
   _Xrmemcpy (&reDataPtr->hSBParameters, config, sizeof (xrSBParameters));

   /* Calculate the editor rectangle for this instance */
   sbInfo.editorRect.height = XrMIN_SCROLLBAR_HT + 2 +
                              (reDataPtr->pixelSize / 10);
   XrScrollBar (NULL, MSG_SIZE, &sbInfo);
   sbInfo.editorRect.x = reInfoPtr->editorRect.x;
   sbInfo.editorRect.y = reInfoPtr->editorRect.y +
                         reInfoPtr->editorRect.height - 1 - 
                         sbInfo.editorRect.height;
   sbInfo.editorRect.width = reDataPtr->reRectangle.width;
   
   /* Create the editor instance */
   if ((reDataPtr->hScrollbar = XrScrollBar (NULL, MSG_NEW, &sbInfo)) == NULL)
      return (FALSE);

   XrEditor (reInfoPtr->editorWindowId, MSG_REMOVE, reDataPtr->hScrollbar);

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  drawREdit (rasterEdit, drawOption)
 *
 *   Description:
 *   -----------
 *     This routine is responsible for drawing a raster editor instance,
 *     if it is visible, or for covering it with the window's background
 *     tile if it is not visible.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This is a pointer to the editor instance structure,
 *                  which contains all the data needed to draw the raster
 *                  edit instance.
 *
 *     drawOption = This parameter is unused.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrMakeInvisible()  [editorUtil.c]
 *   XrScrollBar()       [ScrollBar.c]
 *   drawGrid()
 *   drawColorBoxes()
 *
 *************************************<->***********************************/

static
INT32
drawREdit (rasterEdit, drawOption)

   register xrEditor * rasterEdit;
            INT32      drawOption;

{
   register xrRasterEditData  * reDataPtr;
            Window              windowId = rasterEdit->editorWindowId;

   reDataPtr = (xrRasterEditData *) rasterEdit->editorData;

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

   /* Initialize the graphics context we will be needing */
   _XrInitEditorGCs (reDataPtr->reFGColor, reDataPtr->reBGColor, -1);

   /* Draw the editing region grid */
   drawGrid (rasterEdit, reDataPtr);

   /* Fill the editing rectangles */
   drawColorBoxes (rasterEdit, reDataPtr->viewOrigin.x, 
              reDataPtr->viewOrigin.y,
              reDataPtr->viewOrigin.x + reDataPtr->viewRegion.width - 1,
              reDataPtr->viewOrigin.y + reDataPtr->viewRegion.height - 1);

   /* Draw the scrollbars */
   if (reDataPtr->vScrollbar)
      XrScrollBar (reDataPtr->vScrollbar, MSG_SETSTATE, 
                   XrSENSITIVE | XrVISIBLE);

   if (reDataPtr->hScrollbar)
      XrScrollBar (reDataPtr->hScrollbar, MSG_SETSTATE, 
                   XrSENSITIVE | XrVISIBLE);

}


/*************************************<->*************************************
 *
 *  drawGrid (rasterEdit, reDataPtr)
 *
 *   Description:
 *   -----------
 *     This routine will draw the editing region grid.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the editor instance structure.  The
 *                  window Id is extracted from it.
 *
 *     reDataPtr = This is a pointer to the editor instance's internal
 *                 'data' structure.  The editing region dimensions, and
 *                 the pixel size values are obtained from it.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrLine()  [rectUtil.c]
 *
 *************************************<->***********************************/

static
INT32
drawGrid (rasterEdit, reDataPtr)

   register xrEditor         * rasterEdit;
   register xrRasterEditData * reDataPtr;

{
   register INT32 x1, x2, y1, y2;
   
   /* Draw the horizontal grid lines */
   for (x1 = reDataPtr->reRectangle.x, 
        x2 = x1 + reDataPtr->reRectangle.width - 1,
        y1 = reDataPtr->reRectangle.y;
        y1 < reDataPtr->reRectangle.y + reDataPtr->reRectangle.height; 
        y1 += reDataPtr->pixelSize + 1)
   {
      _XrLine (rasterEdit->editorWindowId, xrEditorGC1, x1, y1, x2, y1);
   }

   /* Draw the vertical grid lines */
   for (y1 = reDataPtr->reRectangle.y, 
        y2 = y1 + reDataPtr->reRectangle.height - 1,
        x1 = reDataPtr->reRectangle.x;
        x1 < reDataPtr->reRectangle.x + reDataPtr->reRectangle.width; 
        x1 += reDataPtr->pixelSize + 1)
   {
      _XrLine (rasterEdit->editorWindowId, xrEditorGC1, x1, y1, x1, y2);
   }
}


/*************************************<->*************************************
 *
 *  drawColorBoxes (rasterEdit, xStart, yStart, xEnd, yEnd)
 *
 *     xrEditor * rasterEdit;
 *     INT32      xStart, yStart;
 *     INT32      xEnd, yEnd;
 *
 *   Description:
 *   -----------
 *     This routine updates a rectangular region of the the raster
 *     editing region.  The four Start/End parameters specify the
 *     starting and ending row/columns which are to be updated.
 *     These values refer to a row and column within the raster image;
 *     not within the editing region.  The colors are automatically
 *     mapped to their proper location within the editing region.  It
 *     is up to the routine calling this to make sure that the region
 *     being drawn lies completely within the view region.  
 *     If xStart = xEnd and yStart = yEnd, then only a single pixel is
 *     drawn.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the instance's editor structure.
 *
 *     xStart, yStart = This specifies the starting column and row.
 *
 *     xEnd, yEnd = This specifies the ending column and row.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   XPixSet()          [libX.a]
 *   XrSetPt()          [calc.c]
 *   _XrPixelExtract()  [pixelExt.c]
 *
 *************************************<->***********************************/

static
INT32
drawColorBoxes (rasterEdit, xStart, yStart, xEnd, yEnd)

   xrEditor * rasterEdit;
   INT32      xStart;
   INT32      yStart;
   INT32      xEnd;
   INT32      yEnd;

{
            Window             windowId;
   register xrRasterEditData * reDataPtr;
            INT32              pixelSize;
            POINT              extractionLoc;
            INT32              pixelValue;
   register INT32              i, j;
   register INT32              xOrigin;
   register INT32              yOrigin;
   register xrPixelData *      instance;

   /* Initialize variables */
   windowId = rasterEdit->editorWindowId;
   reDataPtr = (xrRasterEditData *) rasterEdit->editorData;
   pixelSize = reDataPtr->pixelSize;
   instance = reDataPtr->extractionData;

   /* Redraw the request region, one row at a time */
   yOrigin = reDataPtr->reRectangle.y + 1 + 
             ((yStart - reDataPtr->viewOrigin.y) * (pixelSize + 1));

   for (i = yStart; i <= yEnd; i++)
   {
      /* Set the pixel extraction location */
      XrSetPt (&extractionLoc, xStart, i);
      _XrPixelExtract (instance, MSG_LOCATION, &extractionLoc);

      xOrigin = reDataPtr->reRectangle.x + 1 + 
                ((xStart - reDataPtr->viewOrigin.x) * (pixelSize + 1));

      /* Redraw one row */
      for (j = xStart; j <= xEnd; j++)
      {
         _XrPixelExtract (instance, MSG_GETVALUE, &pixelValue);
         XPixSet (windowId, xOrigin, yOrigin, pixelSize, 
                  pixelSize, pixelValue);
         xOrigin += pixelSize + 1;
      }

      yOrigin += pixelSize + 1;
   }
}


/*************************************<->*************************************
 *
 *  scrollImage (windowId, reDataPtr, scrollDirection)
 *
 *     Window             windowId;
 *     xrRasterEditData * reDataPtr;
 *     INT32              scrollDirection;
 *
 *   Description:
 *   -----------
 *     This routine will scroll the pixels within the editing region
 *     one pixel in any direction, as specified by the 'scrollDirection'
 *     parameter.  Fast scrolling is accomplished by using the XMoveArea()
 *     library routine to move the area of the editing region which is
 *     not changing, except for its location, and then only redrawing the
 *     new row or column which just became visible; note: only the scrolling
 *     is done here; the redrawing of the new row/column is done elsewhere.
 *
 *
 *   Inputs:
 *   ------
 *     windowId = This is the window Id for the window in which the raster
 *                editor instance resides.
 *
 *     reDataPtr = This points to the instance's internal 'data' structure.
 *
 *     scrollDirection = The direction in which the editing region data is
 *                       to be scrolled.  It can be assigned any of the
 *                       following values: XrSCROLL_UP, XrSCROLL_DOWN,
 *                       XrSCROLL_LEFT or XrSCROLL_RIGHT.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   XMoveArea()  [libX.a]
 *
 *************************************<->***********************************/

static
INT32
scrollImage (windowId, reDataPtr, scrollDirection)

            Window             windowId;
   register xrRasterEditData * reDataPtr;
            INT32              scrollDirection;
{
   INT32 srcX, srcY;
   INT32 dstX, dstY;
   INT32 height;
   INT32 width;
   INT32 pixelSize = reDataPtr->pixelSize;

   /* Do a fast scroll, by moving an area of the window */
   switch (scrollDirection)
   {
      case XrSCROLL_UP:
      {
         srcX = reDataPtr->reRectangle.x;
         srcY = reDataPtr->reRectangle.y;
         dstX = reDataPtr->reRectangle.x;
         dstY = reDataPtr->reRectangle.y + pixelSize + 1;
         height = (pixelSize + 1) * (reDataPtr->viewRegion.height - 1);
         width = (pixelSize + 1) * reDataPtr->viewRegion.width;
         break;
      }

      case XrSCROLL_DOWN:
      {
         srcX = reDataPtr->reRectangle.x;
         srcY = reDataPtr->reRectangle.y + pixelSize + 1;
         dstX = reDataPtr->reRectangle.x;
         dstY = reDataPtr->reRectangle.y;
         height = (pixelSize + 1) * (reDataPtr->viewRegion.height - 1);
         width = (pixelSize + 1) * reDataPtr->viewRegion.width;
         break;
      }

      case XrSCROLL_LEFT:
      {
         srcX = reDataPtr->reRectangle.x;
         srcY = reDataPtr->reRectangle.y;
         dstX = reDataPtr->reRectangle.x + pixelSize + 1;
         dstY = reDataPtr->reRectangle.y;
         height = (pixelSize + 1) * reDataPtr->viewRegion.height;
         width = (pixelSize + 1) * (reDataPtr->viewRegion.width - 1);
         break;
      }

      case XrSCROLL_RIGHT:
      {
         srcX = reDataPtr->reRectangle.x + pixelSize + 1;
         srcY = reDataPtr->reRectangle.y;
         dstX = reDataPtr->reRectangle.x;
         dstY = reDataPtr->reRectangle.y;
         height = (pixelSize + 1) * reDataPtr->viewRegion.height;
         width = (pixelSize + 1) * (reDataPtr->viewRegion.width - 1);
         break;
      }
   }

   XMoveArea (windowId, srcX, srcY, dstX, dstY, width, height);
}


/*************************************<->*************************************
 *
 *  processREdit (rasterEdit, event, returnEvent)
 *
 *     xrEditor       * rasterEdit;
 *     XButtonEvent   * event;
 *     xrEvent        * returnEvent;
 *
 *   Description:
 *   -----------
 *     This is the main event processing routine for the raster edit editor.
 *     It is invoked anytime an XrSELECT event occurs within a raster edit
 *     instance.  It will determine which region of the raster editor the
 *     event occurred in (editing region, scrollbars or background), and
 *     will then call the appropriate handling routine.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the instance's editor structure.
 *
 *     event = This is the X select event.
 *
 *     returnEvent = This is a pointer to the xrEvent structure which will
 *                   be returned to the application upon completion of our
 *                   processing of the received X event.
 * 
 *   Outputs:
 *   -------
 *     The value1 field within the return event will be filled.
 *
 *   Procedures Called
 *   -----------------
 *   XrPtInRect()  [calc.c]
 *   XrSetPt()     [calc.c]
 *   XrCopyRect()  [calc.c]
 *   paintREdit()
 *   processVScrollbar()
 *   processHScrollbar()
 *
 *************************************<->***********************************/

static
INT32
processREdit (rasterEdit, event, returnEvent)

   xrEditor     * rasterEdit;
   XButtonEvent * event;
   xrEvent      * returnEvent;

{
   register xrRasterEditData * reDataPtr;
            POINT              spritePt;
            RECTANGLE          workRect;

   /* Initialize variables */
   reDataPtr = (xrRasterEditData *) rasterEdit->editorData;
   XrSetPt (&spritePt, event->x, event->y);

   /* Exclude the bottom and right grid lines */
   XrCopyRect (&reDataPtr->reRectangle, &workRect);
   workRect.height -= 1;
   workRect.width -= 1;

   /*
    * Determine which component of the raster editor the
    * select occurred in, and process it accordingly.
    */

   if (XrPtInRect (&spritePt, &workRect))
   {
      paintREdit (rasterEdit, reDataPtr, &spritePt, &workRect);
      returnEvent->value1 = XrSELECT;
   }
   else if ((reDataPtr->vScrollbar) &&
            (XrPtInRect (&spritePt, &reDataPtr->vScrollbar->editorRect)))
   {
      processVScrollbar (rasterEdit, reDataPtr, event, returnEvent);
      returnEvent->value1 = XrSCROLLBAR;
   }
   else if ((reDataPtr->hScrollbar) &&
            (XrPtInRect (&spritePt, &reDataPtr->hScrollbar->editorRect)))
   {
      processHScrollbar (rasterEdit, reDataPtr, event, returnEvent);
      returnEvent->value1 = XrSCROLLBAR;
   }
   else
      /* Unimportant region */
      returnEvent->value1 = NULL;
}


/*************************************<->*************************************
 *
 *  processVScrollbar (rasterEdit, reDataPtr, event, returnEvent)
 *
 *     xrEditor         * rasterEdit;
 *     xrRasterEditData * reDataPtr;
 *     XButtonEvent     * event;
 *     xrEvent          * returnEvent;
 *
 *   Description:
 *   -----------
 *     This routine will process any select events which occur within the
 *     vertical scrollbar.  This is done by passing the event to the
 *     scrollbar editor, then grabbing the event generated by the scrollbar
 *     editor.  Using the scroll information within the event, it will either
 *     scroll the raster area 1 pixel up or down, or it will redraw the
 *     whole editing region if the user moved the slide box or selected
 *     a location within the slide region.  Upon completion of the scroll
 *     operation, the new view region origin will be copied into the
 *     'valuePt' field within the xrEvent structure pointed to by the
 *     'returnEvent' parameter.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the instance's editor structure.
 *
 *     reDataPtr = This points to the instance's internal 'data' structure.
 *
 *     event = This points to the X select event.
 *
 *     returnEvent = This points to the xrEvent structure which will be
 *                   returned to the application upon completion of the
 *                   scroll operation.
 * 
 *   Outputs:
 *   -------
 *     The 'valuePt' field within the structure pointed to by the
 *         'returnEvent' parameter will be filled with the new view origin.
 *
 *   Procedures Called
 *   -----------------
 *   XrScrollBar()  [ScrollBar.c]
 *   XrInput()      [input.c]
 *   XrCopyPt()     [calc.c]
 *   scrollImage()
 *   drawColorBoxes()
 *
 *************************************<->***********************************/

static
INT32
processVScrollbar (rasterEdit, reDataPtr, event, returnEvent)

            xrEditor         * rasterEdit;
   register xrRasterEditData * reDataPtr;
            XButtonEvent     * event;
            xrEvent          * returnEvent;

{
            Window    windowId = rasterEdit->editorWindowId;
            xrEvent   scrollEvent;
   register POINT     * viewOrigin = &reDataPtr->viewOrigin;
   register SIZE      * viewRegion = &reDataPtr->viewRegion;
            xrEvent   input;
   struct   timeval   origTime;
   struct   timeval   newTime;
            INT16     firstPass;
            xrWindowEvent windowEvent;
            XButtonEvent  selectUp;

   /* Let the scrollbar editor handle the event */
   XrScrollBar (reDataPtr->vScrollbar, MSG_EDIT, event);

   /* Process the event generated by the scrollbar editor */
   XrInput (NULL, MSG_NONBLKREAD, &scrollEvent);
   XrInput (NULL, MSG_GETTIMEOUT, &origTime);
   newTime.tv_sec = 0;
   newTime.tv_usec = 500000;
   firstPass = TRUE;

   switch (scrollEvent.value1)
   {
      case XrSCROLL_UP:
      {
         /* Scroll the raster image down 1 pixel */
         XrInput (NULL, MSG_SETTIMEOUT, &newTime);
         while (1)
         {
            if (viewOrigin->y > 0)
            {
               viewOrigin->y -= 1;
               reDataPtr->vSBParameters.slidePosition = viewOrigin->y;
               XrScrollBar (reDataPtr->vScrollbar, MSG_SETPARAMETERS,
                            &reDataPtr->vSBParameters);
               scrollImage (windowId, reDataPtr, XrSCROLL_UP);
               drawColorBoxes (rasterEdit, viewOrigin->x, viewOrigin->y,
                               viewOrigin->x + viewRegion->width - 1,
                               viewOrigin->y);
            }

            if (XrInput (NULL, MSG_BLKREAD, &input) != FALSE)
            {
               XrInput (NULL, MSG_PUSHEVENT, &input);
               break;
            }
            else if (firstPass)
            {
               newTime.tv_sec = 0;
               newTime.tv_usec = 100000;
               XrInput (NULL, MSG_SETTIMEOUT, &newTime);
               firstPass = FALSE;
            }
         }
         break;
      }
      
      case XrSCROLL_DOWN:
      {
         /* Scroll the raster image up 1 pixel */
         XrInput (NULL, MSG_SETTIMEOUT, &newTime);
         while (1)
         {
            if (viewOrigin->y < 
                (reDataPtr->rasterData.height - viewRegion->height)) 
            {
               viewOrigin->y += 1;
               reDataPtr->vSBParameters.slidePosition = viewOrigin->y;
               XrScrollBar (reDataPtr->vScrollbar, MSG_SETPARAMETERS,
                            &reDataPtr->vSBParameters);
               scrollImage (windowId, reDataPtr, XrSCROLL_DOWN);
               drawColorBoxes (rasterEdit, viewOrigin->x, 
                               viewOrigin->y + viewRegion->height - 1,
                               viewOrigin->x + viewRegion->width - 1,
                               viewOrigin->y + viewRegion->height - 1);
            }

            if (XrInput (NULL, MSG_BLKREAD, &input) != FALSE)
            {
               XrInput (NULL, MSG_PUSHEVENT, &input);
               break;
            }
            else if (firstPass)
            {
               newTime.tv_sec = 0;
               newTime.tv_usec = 100000;
               XrInput (NULL, MSG_SETTIMEOUT, &newTime);
               firstPass = FALSE;
            }
         }
         break;
      }

      case XrSCROLL_SLIDE:
      {
         /* Set the view origin to the selected position */
         viewOrigin->y = scrollEvent.value2;
         drawColorBoxes (rasterEdit, viewOrigin->x, viewOrigin->y,
                         viewOrigin->x + viewRegion->width -1,
                         viewOrigin->y + viewRegion->height - 1);

         /* Push on a fake select up event */
         XrGetWindowEvent (XrSELECTUP, &windowEvent);
         selectUp.type = windowEvent.inputType;
         selectUp.detail = windowEvent.inputCode;
         XrInput (NULL, MSG_PUSHEVENT, &selectUp);
         break;
      }

      case XrSCROLL_LESS:
      case XrSCROLL_MORE:
      {
         /* Set the view origin to the selected position */
         viewOrigin->y = scrollEvent.value3;
         reDataPtr->vSBParameters.slidePosition = viewOrigin->y;
         XrScrollBar (reDataPtr->vScrollbar, MSG_SETPARAMETERS,
                      &reDataPtr->vSBParameters);
         drawColorBoxes (rasterEdit, viewOrigin->x, viewOrigin->y,
                         viewOrigin->x + viewRegion->width -1,
                         viewOrigin->y + viewRegion->height - 1);

         /* Push on a fake select up event */
         XrGetWindowEvent (XrSELECTUP, &windowEvent);
         selectUp.type = windowEvent.inputType;
         selectUp.detail = windowEvent.inputCode;
         XrInput (NULL, MSG_PUSHEVENT, &selectUp);
         break;
      }
   }

   /* Set up the view origin return value */
   XrCopyPt (viewOrigin, &returnEvent->valuePt);
   XrInput (NULL, MSG_SETTIMEOUT, &origTime);
}


/*************************************<->*************************************
 *
 *  processHScrollbar (rasterEdit, reDataPtr, event, returnEvent)
 *
 *     xrEditor         * rasterEdit;
 *     xrRasterEditData * reDataPtr;
 *     XButtonEvent     * event;
 *     xrEvent          * returnEvent;
 *
 *   Description:
 *   -----------
 *     This routine will process any select events which occur within the
 *     horizontal scrollbar.  This is done by passing the event to the
 *     scrollbar editor, then grabbing the event generated by the scrollbar
 *     editor.  Using the scroll information within the event, it will either
 *     scroll the raster area 1 pixel right or left, or it will redraw the
 *     whole editing region if the user moved the slide box or selected
 *     a location within the slide region.  Upon completion of the scroll
 *     operation, the new view region origin will be copied into the
 *     'valuePt' field within the xrEvent structure pointed to by the
 *     'returnEvent' parameter.
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the instance's editor structure.
 *
 *     reDataPtr = This points to the instance's internal 'data' structure.
 *
 *     event = This points to the X select event.
 *
 *     returnEvent = This points to the xrEvent structure which will be
 *                   returned to the application upon completion of the
 *                   scroll operation.
 * 
 *   Outputs:
 *   -------
 *     The 'valuePt' field within the structure pointed to by the
 *         'returnEvent' parameter will be filled with the new view origin.
 *
 *   Procedures Called
 *   -----------------
 *   XrScrollBar()  [ScrollBar.c]
 *   XrInput()      [input.c]
 *   XrCopyPt()     [calc.c]
 *   scrollImage()
 *   drawColorBoxes()
 *
 *************************************<->***********************************/

static
INT32
processHScrollbar (rasterEdit, reDataPtr, event, returnEvent)

            xrEditor         * rasterEdit;
   register xrRasterEditData * reDataPtr;
            XButtonEvent     * event;
            xrEvent          * returnEvent;

{
            Window    windowId = rasterEdit->editorWindowId;
            xrEvent   scrollEvent;
   register POINT     * viewOrigin = &reDataPtr->viewOrigin;
   register SIZE      * viewRegion = &reDataPtr->viewRegion;
            xrEvent   input;
            INT16     firstPass;
   struct   timeval   origTime;
   struct   timeval   newTime;
            xrWindowEvent windowEvent;
            XButtonEvent  selectUp;

   /* Let the scrollbar editor handle the event */
   XrScrollBar (reDataPtr->hScrollbar, MSG_EDIT, event);

   /* Process the event generated by the scrollbar editor */
   XrInput (NULL, MSG_NONBLKREAD, &scrollEvent);
   XrInput (NULL, MSG_GETTIMEOUT, &origTime);
   newTime.tv_sec = 0;
   newTime.tv_usec = 500000;
   firstPass = TRUE;

   switch (scrollEvent.value1)
   {
      case XrSCROLL_LEFT:
      {
         /* Scroll the raster image left 1 pixel */
         XrInput (NULL, MSG_SETTIMEOUT, &newTime);
         while (1)
         {
            if (viewOrigin->x > 0)
            {
               viewOrigin->x -= 1;
               reDataPtr->hSBParameters.slidePosition = viewOrigin->x;
               XrScrollBar (reDataPtr->hScrollbar, MSG_SETPARAMETERS,
                            &reDataPtr->hSBParameters);
               scrollImage (windowId, reDataPtr, XrSCROLL_LEFT);
               drawColorBoxes (rasterEdit, viewOrigin->x, viewOrigin->y,
                               viewOrigin->x,
                               viewOrigin->y + viewRegion->height - 1);
            }

            if (XrInput (NULL, MSG_BLKREAD, &input) != FALSE)
            {
               XrInput (NULL, MSG_PUSHEVENT, &input);
               break;
            }
            else if (firstPass)
            {
               newTime.tv_sec = 0;
               newTime.tv_usec = 100000;
               XrInput (NULL, MSG_SETTIMEOUT, &newTime);
               firstPass = FALSE;
            }
         }
         break;
      }
      
      case XrSCROLL_RIGHT:
      {
         /* Scroll the raster image right 1 pixel */
         XrInput (NULL, MSG_SETTIMEOUT, &newTime);
         while (1)
         {
            if (viewOrigin->x < 
                (reDataPtr->rasterData.width - viewRegion->width)) 
            {
               viewOrigin->x += 1;
               reDataPtr->hSBParameters.slidePosition = viewOrigin->x;
               XrScrollBar (reDataPtr->hScrollbar, MSG_SETPARAMETERS,
                            &reDataPtr->hSBParameters);
               scrollImage (windowId, reDataPtr, XrSCROLL_RIGHT);
               drawColorBoxes (rasterEdit,viewOrigin->x+viewRegion->width - 1, 
                               viewOrigin->y,
                               viewOrigin->x + viewRegion->width - 1,
                               viewOrigin->y + viewRegion->height - 1);
            }

            if (XrInput (NULL, MSG_BLKREAD, &input) != FALSE)
            {
               XrInput (NULL, MSG_PUSHEVENT, &input);
               break;
            }
            else if (firstPass)
            {
               newTime.tv_sec = 0;
               newTime.tv_usec = 100000;
               XrInput (NULL, MSG_SETTIMEOUT, &newTime);
               firstPass = FALSE;
            }
         }
         break;
      }

      case XrSCROLL_SLIDE:
      {
         /* Set the view origin to the selected position */
         viewOrigin->x = scrollEvent.value2;
         drawColorBoxes (rasterEdit, viewOrigin->x, viewOrigin->y,
                         viewOrigin->x + viewRegion->width -1,
                         viewOrigin->y + viewRegion->height - 1);

         /* Push on a fake select up event */
         XrGetWindowEvent (XrSELECTUP, &windowEvent);
         selectUp.type = windowEvent.inputType;
         selectUp.detail = windowEvent.inputCode;
         XrInput (NULL, MSG_PUSHEVENT, &selectUp);
         break;
      }

      case XrSCROLL_LESS:
      case XrSCROLL_MORE:
      {
         /* Set the view origin to the selected position */
         viewOrigin->x = scrollEvent.value3;
         reDataPtr->hSBParameters.slidePosition = viewOrigin->x;
         XrScrollBar (reDataPtr->hScrollbar, MSG_SETPARAMETERS,
                      &reDataPtr->hSBParameters);
         drawColorBoxes (rasterEdit, viewOrigin->x, viewOrigin->y,
                         viewOrigin->x + viewRegion->width -1,
                         viewOrigin->y + viewRegion->height - 1);

         /* Push on a fake select up event */
         XrGetWindowEvent (XrSELECTUP, &windowEvent);
         selectUp.type = windowEvent.inputType;
         selectUp.detail = windowEvent.inputCode;
         XrInput (NULL, MSG_PUSHEVENT, &selectUp);
         break;
      }
   }

   /* Set up the view origin return value */
   XrCopyPt (viewOrigin, &returnEvent->valuePt);
   XrInput (NULL, MSG_SETTIMEOUT, &origTime);
}


/*************************************<->*************************************
 *
 *  paintREdit (rasterEdit, reDataPtr, spritePtr, editRect)
 *
 *     xrEditor         * rasterEdit;
 *     xrRasterEditData * reDataPtr;
 *     POINT            * spritePtr;
 *     RECTANGLE        * editRect;
 *
 *   Description:
 *   -----------
 *     This routine processes all select events which occur within the
 *     editing region.  When a select occurs in the editing region, this
 *     routine will continually poll the cursor position, and will change
 *     those pixels which lie in a line starting at the previous cursor
 *     position, and ending at the new cursor position.  This is done
 *     because the cursor polling facilities are SLOW, and if we only
 *     changed the pixels at the cursor location, lots of gaps appear
 *     when the user moves the cursor quickly.  When a select up, or any
 *     other X event is received, the painting operation will cease, and
 *     the event which caused us to terminate will be pushed back onto the
 *     front of the input queue; this is done so that the _MsgEdit() routine,
 *     which invoked our event processing routine, can strip the select up
 *     event, if it occurred.
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the instance's editor structure.
 *
 *     reDataPtr = This points to the instance's internal 'data' structure.
 *
 *     spritePtr = This contains the initial cursor position at the time
 *                 the select event occurred.
 *
 *     editRect = This contains the rectangle describing the editing region.
 * 
 *   Outputs:
 *   -------
 *     The event which caused us to terminate is pushed onto the front of
 *     the application's input queue.
 *
 *   Procedures Called
 *   -----------------
 *   XrPtInRect()   [calc.c]
 *   XrCopyPt()     [calc.c]
 *   XrEqualPt()    [calc.c]
 *   XrSetPt()      [calc.c]
 *   XrInput()      [input.c]
 *   XQueryMouse()  [libX.a]
 *   paintLine()
 *
 *************************************<->***********************************/

static
INT32
paintREdit (rasterEdit, reDataPtr, spritePtr, editRect)

            xrEditor         * rasterEdit;
            xrRasterEditData * reDataPtr;
            POINT            * spritePtr;
   register RECTANGLE        * editRect;

{
   register INT32   pixelSize;
   register POINT * viewOrigin;
            POINT   pixelLoc;
            POINT   oldPixelLoc;
            Window  subw;
            xrEvent tempEvent;
            INT32   x,y;
            Window  windowId;
            INT8    firstPass = TRUE;

   windowId = rasterEdit->editorWindowId;
   pixelSize = reDataPtr->pixelSize;
   viewOrigin = &reDataPtr->viewOrigin;

   /* Keep processing, until we receive another input event */
   while (TRUE)
   {
      /* Ignore, if outside the editing region */
      if (XrPtInRect (spritePtr, editRect))
      {
         pixelLoc.x = viewOrigin->x + 
                      ((spritePtr->x - editRect->x) / (pixelSize + 1));
         pixelLoc.y = viewOrigin->y + 
                      ((spritePtr->y - editRect->y) / (pixelSize + 1));

         if (firstPass)
            XrCopyPt (&pixelLoc, &oldPixelLoc);

         /* Redraw, only if in a new raster square */
         if (!XrEqualPt (&pixelLoc, &oldPixelLoc) || firstPass)
         {
            paintLine (rasterEdit, reDataPtr, pixelLoc.x, pixelLoc.y,
                       oldPixelLoc.x, oldPixelLoc.y);
            firstPass = FALSE;
         }

         XrCopyPt (&pixelLoc, &oldPixelLoc);
      }

      /* Stop, when an input event is received */
      if (XrInput (NULL, MSG_NONBLKREAD, &tempEvent))
      {
         /* 
          * Push the event back on the input queue; this
          * is done so that _MsgEdit(), which called us,
          * properly exits and strips the select up event.
          */
         XrInput (NULL, MSG_PUSHEVENT, &tempEvent);
         return;
      }

      /* Continue polling for the cursor position */
      XQueryMouse (windowId, &x, &y, &subw);
      XrSetPt (spritePtr, x, y);
   }
}


/*************************************<->*************************************
 *
 *  paintLine (rasterEdit, reDataPtr, x1, y1, x2, y2)
 *
 *     xrEditor        * rasterEdit;
 *     xrRsterEditData * reDataPtr;
 *     INT32             x1, y1;
 *     INT32             x2, y2;
 *
 *   Description:
 *   -----------
 *     This routine will set to the current editing color, those pixels
 *     in the editing region which line along the line starting at point
 *     (x1, y1) and ending at point (x2, y2).
 *
 *
 *   Inputs:
 *   ------
 *     rasterEdit = This points to the instance's editor structure.
 *
 *     reDataPtr = This points to the instance's internal 'data' structure.
 *
 *     x1, y1 = This specifies the starting point of the line.
 *
 *     x2, y2 = This specifies the ending point of the line.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   XrSetPt()          [calc.c]
 *   _XrPixelExtract()  [pixelExt.c]
 *   drawColorBoxes()
 *
 *************************************<->***********************************/

static
INT32
paintLine (rasterEdit, reDataPtr, x1, y1, x2, y2)

            xrEditor         * rasterEdit;
   register xrRasterEditData * reDataPtr;
   register INT32              x1;
   register INT32              y1;
   register INT32              x2;
   register INT32              y2;

{
   register INT16 d;
   register INT32 count;
            POINT location;
            INT16 xincr1, yincr1;
            INT16 xincr2, yincr2;
            INT16 a, b;
            INT32 xPtCount;
            INT32 yPtCount;


   /* Draw the first point */
   XrSetPt (&location, x1, y1);
   _XrPixelExtract (reDataPtr->extractionData, MSG_LOCATION, 
                    &location);
   _XrPixelExtract (reDataPtr->extractionData, MSG_SETVALUE,
                    reDataPtr->pixelColor); 
   drawColorBoxes (rasterEdit, x1, y1, x1, y1);

   /* Stop, if this is a single point line */
   if (x1 == x2 && y1 == y2)
      return;

   /*
    *  Initialize the incrementing values used to generate 
    *  the points within the segment
    */

   xPtCount = abs(x2 - x1);
   yPtCount = abs(y2 - y1);

   if (x2 > x1)
   {
      if (y2 > y1)
	 xincr2 = yincr2 = 1;
      else
      {
	 xincr2 = 1;
	 yincr2 = -1;
      }
   }
   else
   {
      if (y2 > y1)
      {
	 xincr2 = -1;
	 yincr2 = 1;
      }
      else
	 xincr2 = yincr2 = -1;
   }

   if (xPtCount > yPtCount)
   {
      count = xPtCount;
      xincr1 = xincr2;
      yincr1 = 0;
      b = yPtCount << 1;
      a = (xPtCount << 1) - b;
      d = b - xPtCount;
   }
   else
   {
      count = yPtCount;
      xincr1 = 0;
      yincr1 = yincr2;
      b = xPtCount << 1;
      a = (yPtCount << 1) - b;
      d = b - yPtCount;
   }

   do
   {
      if (d > 0)
      {
	 d -= a;
         x1 += xincr2;
         y1 += yincr2;
      }
      else
      {
	 d += b;
         x1 += xincr1;
         y1 += yincr1;
      }

      /* Set the specified pixel, and draw it */
      XrSetPt (&location, x1, y1);
      _XrPixelExtract (reDataPtr->extractionData, MSG_LOCATION, 
                       &location);
      _XrPixelExtract (reDataPtr->extractionData, MSG_SETVALUE,
                       reDataPtr->pixelColor); 
      drawColorBoxes (rasterEdit, x1, y1, x1, y1);
   }
   while (--count);
}

