/*
 *	$Source: /u1/Xr/src/Xrlib/Editor/RCS/MsgItem.c,v $
 *	$Header: MsgItem.c,v 1.1 86/12/17 09:00:07 swick Exp $
 */

#ifndef lint
static char *rcsid_MsgItem_c = "$Header: MsgItem.c,v 1.1 86/12/17 09:00:07 swick Exp $";
#endif	lint


#include <Xr/xr-copyright.h>

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

static char rcsid[] = "$Header: MsgItem.c,v 1.1 86/12/17 09:00:07 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        MsgItem.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **         This file contains a series of message handler routines which
 **         are useful to multiple entity type field editors.  The messages
 **         for which handlers are provided here are: MSG_GETITEMSTATES,
 **         MSG_SETITEMSTATES, MSG_GETITEMCOUNT, MSG_GETITEMRECTS,
 **         MSG_MOVE and MSG_SIZE.  It should be noted that there are
 **         some conditions which must be met before a field editor can
 **         use these routines:
 **
 **         1) The first 9 fields of the editor's internal 'data'
 **            structure must match that of the structure 'xrDataTemplate,
 **            since these routines expect certain data fields to reside
 **            in a fixed location.  Refer to the include file 
 **            "Xr/in_types.h" for the definition of this structure.
 **
 **         2) The array containing the individual entity information,
 **            such as a button's rectangle, state, value, etc, must
 **            be an array of 'xrItemData' structures; again, this is
 **            because these routines need the data they will be accessing
 **            to be in fixed locations.  Refer to the include file
 **            "Xr/in_types.h" for the definition of this structure.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	MsgItem.c,v $
 * Revision 1.1  86/12/17  09:00:07  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:21:59  08:21:59  fred ()
 * Final QA Release
 * 
 * Revision 6.0  86/11/10  15:27:21  15:27:21  fred ()
 * QA #2 release
 * 
 * Revision 5.2  86/11/07  14:18:59  14:18:59  fred ()
 * Added new copyright message.
 * 
 * Revision 5.1  86/10/30  13:23:20  13:23:20  fred ()
 * Added a check in _MsgSize() for numCols <= 0.
 * 
 * Revision 5.0  86/10/28  08:26:53  08:26:53  fred ()
 * QA #1.1 release
 * 
 * Revision 4.0  86/10/20  12:08:05  12:08:05  fred ()
 * QA #1 release
 * 
 * Revision 3.1  86/10/16  09:13:51  09:13:51  fred ()
 * Performance enhanced: added use of register variables.
 * 
 * Revision 3.0  86/10/02  15:58:21  15:58:21  fred ()
 * Alpha release set to 3.0
 * 
 * Revision 2.3  86/09/22  13:10:11  13:10:11  fred ()
 * Added calls to XrEditorGroup().
 * 
 * Revision 2.2  86/09/19  07:09:37  07:09:37  fred ()
 * Added a check for XrVISIBLE before doing any drawing.
 * 
 * Revision 2.1  86/09/17  07:53:07  07:53:07  fred ()
 * Filled in procedure headers.
 * Fixed MsgSize(), so that it checks the 'numFields' value, before
 * attempting to allocate temporay work space.
 * 
 * Revision 2.0  86/09/16  08:04:05  08:04:05  fred ()
 * No change; simply upgraded to release 2.0 to match other source files.
 * 
 * Revision 1.1  86/09/03  13:56:20  13:56:20  fred ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



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


/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgGetItemStates (instance, data)
 *
 *     xrEditor * instance;
 *     INT8     * data;
 *
 *   Description:
 *   -----------
 *     This routine will fill the array pointed to by the 'data' parameter
 *     with the individual state flag settings for the specified field
 *     editor instance.  The array is filled such that the state flags for
 *     entity 'x' are saved in 'data[x]'.  The array pointed to by the 
 *     'data' parameter must be large enough to hold all of the state
 *     flag settings; this routine will assume it is.
 *
 *
 *   Inputs:
 *   ------
 *     instance = The instance pointer, which indicates which editor
 *                instance is to be queried.
 *
 *     data = Pointer to the array in which the state flags are returned.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the instance pointer will be returned,
 *          and the 'data' array will be filled.
 *
 *     Upon failure, NULL will be returned, and xrErrno will be set.  
 *          This request will fail if if either the 'instance' or 'data' 
 *          parameters are set to NULL.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgGetItemStates (instance, data)

   xrEditor * instance;
   INT8     * data;

{
   /* Return the state flags for the individual editor items */
   register xrDataTemplate * instanceData;
   register xrItemData     * itemData;
   register INT8           * stateFlags;
   register INT32            i;

   /* Validate all pointers, before using them */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (data == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }

   /* Get a pointer to the instance's item array */
   instanceData = (xrDataTemplate *) instance->editorData;
   itemData = instanceData->fields;
   stateFlags = (INT8 *) data;

   /* Copy out the state flags */
   for (i = 0; i < instanceData->numFields; i++, itemData++, stateFlags++)
      *stateFlags = itemData->state;

   return (instance);
}


/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgSetItemStates (instance, data, drawFunct)
 *
 *     xrEditor * instance;
 *     INT8     * data;
 *     INT32      (*drawFunct)();
 *
 *   Description:
 *   -----------
 *     This routine takes an array of state flag setting, pointed to by
 *     the 'data' parameter, and assigns them to the individual items
 *     within a field editor instance.  The values in the array are
 *     assigned such that the state flags in 'data[x]' are assigned to
 *     item 'x'.  This routine will assume that the array contains
 *     enough values for all of the items in the instance.  While the
 *     new state flags are being assigned, a check is made to see if
 *     they are different than the old state flags for that item; if
 *     they are, then after the new flags have been copied, the item
 *     will be redrawn - otherwise the item is not redrawn.  The field
 *     editor is responsible for providing a pointer to the redraw
 *     routine; it will be invoked as follows: 
 *
 *               redrawRoutine (instance, itemNumber);
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is the instance pointer, which indicates which
 *                editor instance is to be modified.
 *
 *     data = This is a pointer to an array of 8 bit quantities, containing
 *            the new state flag setting for the items.
 *
 *     drawFunct = This is a pointer to a redraw function.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the instance pointer will be returned,
 *          and the new state flag values assigned.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.  This request
 *          will fail if either the 'instance' or 'data' parameter are
 *          set to NULL.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgSetItemStates (instance, data, drawFunct)

   register xrEditor * instance;
            INT8     * data;
            INT32     (*drawFunct)();

{
   /*
    * Set the states for the individual editor items; redraw 
    * only those whose state has then changed.
    */
   register xrDataTemplate * instanceData;
   register xrItemData     * itemData;
   register INT8           * stateFlags;
   register INT32            i;
   register INT8             instanceVisible;

   /* Validate all pointers before referencing them */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (data == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }

   /* Get a pointer to the instance's item array */
   instanceData = (xrDataTemplate *) instance->editorData;
   itemData = instanceData->fields;
   stateFlags = (INT8 *) data;
   instanceVisible = instance->editorState & XrVISIBLE;

   /* Copy in the new state flags */
   for (i = 0; i < instanceData->numFields; i++, itemData++, stateFlags++)
   {
      /* Check for different state flags */
      if (*stateFlags != itemData->state)
      {
         /* Redraw this item */
         itemData->state = *stateFlags;
         if (instanceVisible)
            (*drawFunct) (instance, i);
      }
   }

   return (instance);
}


/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgGetItemCount (instance, data)
 *
 *     xrEditor * instance;
 *     INT8     * data;
 *
 *   Description:
 *   -----------
 *     This routine servers as the MSG_GETITEMCOUNT handler, and will
 *     return to the application the number of items defined in the
 *     specified field editor instance.  This piece of information is
 *     extracted from the instance's internal 'data' structure, and is
 *     contained in the 'numFields' field.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is an editor instance pointer, indicating which
 *                editor instance is to be queried.
 *
 *     data = This is a pointer to an integer value, in which the item
 *            count value will be returned.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer is returned,
 *          and the number of items is returned in the integer pointed to
 *          by the 'data' parameter.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.  This request
 *          will fail if either the 'instance' or 'data' parameters are
 *          set to NULL.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgGetItemCount (instance, data)

   xrEditor * instance;
   INT8     * data;

{
   /* Return the number of items in the specified instance */
   INT32 * countPtr = (INT32 *) data;

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

   *countPtr =((xrDataTemplate *)(instance->editorData))->numFields;

   return (instance);
}


/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgGetItemRects (instance, rectPtr)
 *
 *     xrEditor  * instance;
 *     RECTANGLE * rectPtr;
 *     
 *
 *   Description:
 *   -----------
 *     This routine serves as the MSG_GETITEMRECTS handler for a multiple
 *     entity field editor.  It will return, in the array pointed to by
 *     the 'rectPtr' parameter, the rectangle definition describing the
 *     size and location of each item within the specified editor instance.
 *     The information is returned such that the rectangle for item 'x' is
 *     returned in 'rectPtr[x]'.  It is assumed that the array pointed to
 *     by the 'rectPtr' parameter is large enough to hold all of the
 *     rectangle definitions.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is the editor instance pointer, which indicates
 *                which field editor instance is to be queried.
 *
 *     rectPtr = This is a pointer to an array of RECTANGLE structures.
 *               The item rectangles will be returned here.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer will be
 *          returned, and the array pointed to by the 'rectPtr' parameter
 *          will be filled.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.  This request
 *          will fail if either the 'instance' or 'data' parameters are
 *          set to NULL.
 *
 *   Procedures Called
 *   -----------------
 *   XrCopyRect()  [calc.c]
 *
 *************************************<->***********************************/

xrEditor *
_MsgGetItemRects (instance, rectPtr)

            xrEditor  * instance;
   register RECTANGLE * rectPtr;

{
   /*
    * Fill the array passed in by the application, with the rectangle
    * information describing each item in the specified instance.
    */
   register xrDataTemplate * instanceData;
   register xrItemData     * itemData;
   register INT32            i;

   /* Validate all pointers, before referencing them */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (rectPtr == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }

   /* Get a pointer to the instance's item data */
   instanceData = (xrDataTemplate *) instance->editorData;
   itemData = instanceData->fields;

   for (i = 0; i < instanceData->numFields; i++, rectPtr++, itemData++)
      XrCopyRect (&itemData->rectangle, rectPtr);

   return (instance);
}


/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgMove (instance, pointPtr, drawFunct)
 *
 *     xrEditor  * instance;
 *     POINT     * pointPtr;
 *     INT32       (*drawFunct)();
 *
 *   Description:
 *   -----------
 *     This routine servers as the MSG_MOVE handler for a multiple entity
 *     field editor.  It will move an existing field editor instance, so
 *     that the origin of the instance's editor rectangle (the upper left
 *     corner) is positioned at the point specified by the 'pointPtr'
 *     parameter.  Besides relocating the instance's editor rectangle,
 *     each component of each item (the label location, the item rectangle
 *     and the item sub-rectangle) must also be relocated.  After the
 *     relocation operation has been completed, a check will be made to
 *     see if the instance is currently visible; if it is, then the
 *     instance will be remove from its old location in the window, and
 *     will be redrawn at its new location.  The routine used to draw
 *     the instance must be supplied by the editor using this routine.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is the editor instance pointer, which indicates
 *                which editor instance is to be moved.
 *
 *     pointPtr = This points to a POINT structure, containing the new
 *                origin for the editor instance.
 *
 *     drawFunct = This is a pointer to a drawing function supplied by
 *                 the field editor; it will be invoked in the following
 *                 manner, after the instance has been moved:
 *
 *                 (*drawFunct) (instance, XrALLBUTTONS);
 * 
 *   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.  This routine
 *          will fail if either the 'instance' or 'pointPtr' parameters
 *          are set to NULL.
 *
 *   Procedures Called
 *   -----------------
 *   XrCopyRect()        [calc.c]
 *   XrOffsetRect()      [calc.c]
 *   _XrMakeInvisible()  [editorUtil.c]
 *
 *************************************<->***********************************/

xrEditor *
_MsgMove (instance, pointPtr, drawFunct)

            POINT    * pointPtr;
   register xrEditor * instance;
            INT32      (*drawFunct)();

{
            RECTANGLE        workRect;
   register xrDataTemplate * instanceData;
   register xrItemData     * itemData;
   register INT16            xDelta, yDelta;
   register INT32            i;

   /* Validate all pointers, before referencing them */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (pointPtr == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }

   /* Determine how much to relocate the instance */
   instanceData = (xrDataTemplate *) instance->editorData;
   XrCopyRect (&instance->editorRect, &workRect);
   xDelta = pointPtr->x - instance->editorRect.x;
   yDelta = pointPtr->y - instance->editorRect.y;

   /* Relocate each component of the instance */
   XrOffsetRect (&instance->editorRect, xDelta, yDelta);

   for (i = 0, itemData = instanceData->fields;
        i < instanceData->numFields; i++, itemData++)
   {
      XrOffsetRect (&itemData->rectangle, xDelta, yDelta);
      XrOffsetRect (&itemData->subRectangle, xDelta, yDelta);
      XrOffsetRect (&itemData->labelPt, xDelta, yDelta);
   }

   if (instance->editorState & XrVISIBLE)
   {
      /* Redisplay the instance */
      _XrMakeInvisible (instance->editorWindowId, &workRect, TRUE);
      (*drawFunct) (instance, XrALLBUTTONS);
   }

   /* Force the editor group rectangle to be recalculated */
   XrEditorGroup (NULL, MSG_ADJUSTGROUPRECT, instance);
   return (instance);
}

/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgSize (infoPtr, calcFunct)
 *
 *     xrCheckBoxInfo * infoPtr;
 *     INT32            (calcFunct)();
 *
 *   Description:
 *   -----------
 *     This routine serves as the MSG_SIZE message handler for a
 *     multiple entity field editor.  It will expect the field 
 *     editor to pass in one of its 'info' structures, along with a
 *     pointer to the editor's size calculation routine.  Before
 *     calling the calculation routine, this routine will first
 *     verify the 'infoPtr' pointer, and will then allocate a block
 *     of memory which may be used by the calculation routine; this
 *     block of memory is an array of 'xrItemData' structures, which
 *     the calculation routine can use as work space while doing its
 *     size calculations.  Upon completion of the calculations, the
 *     calculation routine must fill in the 'editorRect' field within
 *     the 'info' structure pointed to by 'infoPtr'.
 *
 *     The calculation routine is called as follows:
 *
 *        (*calcFunct) (infoPtr, fieldPtr, MSG_SIZE);
 *
 *
 *   Inputs:
 *   ------
 *     infoPtr = This is a pointer to the editor's 'info' structure,
 *               containing the information which the calculation
 *               routine will use to size the instance.
 *
 *     calcFunct = This is a pointer to the editor's size calculatio
 *                 routine.
 * 
 *   Outputs:
 *   -------
 *     Upon success completion, the editor instance pointer will be
 *          returned, and the 'editorRect' field within the 'info'
 *          structure pointed to by 'infoPtr' will be filled in with
 *          the 0-based size rectangle.
 *
 *     Upon failure, NULL will be returned, and xrErrno will be set.
 *          This routine will fail if 'infoPtr' is set to NULL, or
 *          if the 'numFields' field in the 'info' structure is less
 *          than or equal to 0.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgSize (infoPtr, calcFunct)

   register xrCheckBoxInfo * infoPtr;
            INT32            (*calcFunct)();

{
   /*
    * Return the size of the rectangle needed to enclose
    * an instance of this editor, using the specifications
    * passed in by the application program.
    */
   register xrItemData * fieldPtr;

   if (infoPtr == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }
   else if ((infoPtr->numFields <= 0) || (infoPtr->numCols <= 0))
   {
      xrErrno = XrINVALIDPARM;
      return ((xrEditor *) NULL);
   }

   /*
    * Allocate a temporary structure, to aid in calculating
    * the size of the editor rectangle.
    */
   if ((fieldPtr = (xrItemData *) (*xrMalloc) 
       (sizeof (xrItemData) * infoPtr->numFields)) == NULL)
   {
      xrErrno = XrOUTOFMEM;
      return ((xrEditor *) NULL);
   }

   if ((*calcFunct) (infoPtr, fieldPtr, MSG_SIZE) == FALSE)
   {
      /* Size request failed; xrErrno set by (*calcFunct) () */
      (*xrFree) (fieldPtr);
      return ((xrEditor *)NULL);
   }

   (*xrFree) (fieldPtr);
   return ((xrEditor *) TRUE);
}

