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

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


#include <Xr/xr-copyright.h>

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

static char rcsid[] = "$Header: MsgCommon.c,v 1.1 86/12/17 08:59:38 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        MsgCommon.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **          This file contains the source code for some utility routines
 **          used by most field editors.  It includes common message
 **          handlers for the following messages:
 **
 **          MSG_NEW, MSG_FREE, MSG_GETSTATE, MSG_SETSTATE, MSG_REDRAW
 **          MSG_EDIT
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	MsgCommon.c,v $
 * Revision 1.1  86/12/17  08:59:38  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:21:25  08:21:25  fred ()
 * Final QA Release
 * 
 * Revision 6.0  86/11/10  15:27:05  15:27:05  fred ()
 * QA #2 release
 * 
 * Revision 5.1  86/11/07  14:18:31  14:18:31  fred ()
 * Added new copyright message.
 * 
 * Revision 5.0  86/10/28  08:25:48  08:25:48  fred ()
 * QA #1.1 release
 * 
 * Revision 4.0  86/10/20  12:07:46  12:07:46  fred ()
 * QA #1 release
 * 
 * Revision 3.2  86/10/16  09:13:35  09:13:35  fred ()
 * Performance enhanced: added use of register variables.
 * 
 * Revision 3.1  86/10/07  16:49:31  16:49:31  fred ()
 * Upgraded to use new XrMapButton() calling sequence.
 * 
 * Revision 3.0  86/10/02  15:57:55  15:57:55  fred ()
 * Alpha release set to 3.0
 * 
 * Revision 2.2  86/09/19  07:09:00  07:09:00  fred ()
 * Added a check for XrVISIBLE before doing any drawing.
 * 
 * Revision 2.1  86/09/16  10:19:34  10:19:34  fred ()
 * Fixed a bug in _MsgEdit(), where it was still using an xrEvent
 * structure to check for a SELECT UP, instead of XrMapButton().
 * 
 * Revision 2.0  86/09/16  08:03:23  08:03:23  fred ()
 * Updated _MsgEdit() to match new SELECT strategy.
 * 
 * Revision 1.3  86/09/16  05:45:02  05:45:02  fred ()
 * Modified _MsgEdit() to swallow a select up event.
 * 
 * Revision 1.2  86/09/15  07:59:32  07:59:32  fred ()
 * Filled in procedure headers
 * 
 * Revision 1.1  86/09/03  13:56:06  13:56:06  fred ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



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


/*************************************<->*************************************
 *
 *  xrEditor *
 *  _MsgNew (instance, infoPtr, dataStructSize, createFunct,
 *           drawFunct, freeFunct, editorHandler, drawOption)
 *
 *   Description:
 *   -----------
 *     This routine is capable of creating a new editor instance for
 *     most field editors.  It relies upon the fact that the steps for
 *     creating a new instance are identical, regardless of which editor
 *     is being created.  The only differences are how the editor's
 *     internal structures are initialized (by the createFunct()), how
 *     the instance is drawn (by the drawFunct()), and how the editor
 *     cleans up when a fatal error occurs (by the freeFunct()).  This
 *     modules allows for this, by allowing the editor to specify it's
 *     own create, draw and free functions.
 *
 *     The steps for creating a new editor instance are as follows:
 *
 *     - Validate parameters.
 *     - Allocate space for the editor's internal data structure.
 *     - Allocate space for the editor instance structure.
 *     - Call the editor's create function, which fills the internal struct.
 *     - Initialize the editor instance structure.
 *     - Attach the editor instance to the specified window.
 *     - Draw the editor instance.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is not really used by this call.
 *     
 *     infoPtr  = This points to an 'info' structure describing the
 *                new instance; this structure differs between editors.
 *
 *     dataStructSize = This describes the size of the editor's internal
 *                      data structure.  It is needed, so that we can
 *                      allocate the structure here, without having to
 *                      know what the structure looks like.
 *
 *     createFunct = This is a pointer to the editor's create function.
 *                   This function should validate all parameters, and
 *                   then fill in the editor's internal structure.  It
 *                   should return TRUE if all goes well, otherwise FALSE.
 *
 *     drawFunct = This is a pointer to the editor's draw function.  This
 *                 function will be invoked, and passed the 'drawOption'
 *                 value.  This should force the editor to draw the complete
 *                 instance, if the XrVISIBLE state flag is set.
 *
 *     freeFunct = This is a pointer to the editor's error recovery routine.
 *                 If an error occurs after the createFunct was called, then
 *                 this routine will be called, to allow the editor to free
 *                 up any memory the createFunct might have allocated.
 *
 *     editorHandler = A pointer to the editor's main handler routine.
 *
 *     drawOption = The option passed to the drawFunct.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the instance pointer for the new
 *          instance is returned.  If the request fails, then 'NULL' is
 *          returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *
 *   _XrInitEditorStruct()  [editorUtil.c]
 *   XrEditor()             [editor.c]
 *
 *************************************<->***********************************/

xrEditor *
_MsgNew (instance, infoPtr, dataStructSize, createFunct, drawFunct,
        freeFunct, editorHandler, drawOption)

   register xrEditor         * instance;
   register xrEditorTemplate * infoPtr;
            INT32              dataStructSize;
            INT32              (*createFunct)();
            INT32              (*drawFunct)();
            INT32              (*freeFunct)();
            INT32              (*editorHandler)();
            INT32              drawOption;

{
   /* Create a new instance of an editor */
   INT8 * dataPtr;

   /* Validate the pointer to the info for the new editor instance */
   if (infoPtr == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *) NULL);
   }
   else if (infoPtr->editorWindowId == 0)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }

   /* Allocate some data area, to hold the instance specific data */
   if ((dataPtr = (*xrMalloc) (dataStructSize)) == NULL)
   {
      xrErrno = XrOUTOFMEM;
      return ((xrEditor *) NULL);
   }

   /* Allocate some space for the editor structure */
   if ((instance = (xrEditor *)(*xrMalloc)(sizeof(xrEditor))) == NULL)
   {
      (*xrFree) (dataPtr);
      xrErrno = XrOUTOFMEM;
      return ((xrEditor *) NULL);
   }

   /* Call the routine responsible for creating the instance */
   if ((*createFunct) (dataPtr, infoPtr, MSG_NEW) == FALSE)
   {
      /* Create failed; xrErrno is set by the create function */
      (*xrFree) (dataPtr);
      (*xrFree) (instance);
      return ((xrEditor *)NULL);
   }

   /* Initialize the instance's data structures */
   _XrInitEditorStruct (instance, infoPtr, dataPtr, editorHandler);

   /* Attach this editor instance to the specified window */
   if (XrEditor (infoPtr->editorWindowId, MSG_ADD, instance)==FALSE)
   {
      /* Draw request failed; xrErrno is set by XrEditor() */
      /* freeFunct() frees any memory allocated by createFunct() */
      if (freeFunct)
         (*freeFunct) (dataPtr);
      (*xrFree) (dataPtr);
      (*xrFree) (instance);
      return ((xrEditor *)NULL);
   }

   /* Lastly, draw the editor instance */
   if (instance->editorState & XrVISIBLE)
      (*drawFunct) (instance, drawOption);

   /* Create request was successful */
   return (instance);
}


/*************************************<->*************************************
 *
 *  _MsgFree (instance, freeFunct)
 *
 *      xrEditor * instance;
 *      INT32      (*freeFunct)();
 *
 *   Description:
 *   -----------
 *     This is the common MSG_FREE handler.  It performs the following
 *     tasks:
 *
 *     - Make the instance invisible.
 *     - Call freeFunct(), to allow the editor to free up any
 *       memory it might have allocated during MSG_NEW.
 *     - Free up the editor's internal data structures.
 *     - Unattach the editor instance from the window to which 
 *       it's attached.
 *     - Free up the editor instance structure.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This points to the editor instance structure for the
 *                instance which is to be destroyed.
 *
 *     freeFunct = A pointer to a function, which will deallocate any
 *                 memory previously allocated by the editor's createFunct
 *                 at the time the instance was created.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer is returned;
 *          if the request fails, then NULL is returned and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   _XrMakeInvisible()  [editorUtil.c]
 *   XrEditor()          [editor.c]
 *
 *************************************<->***********************************/

xrEditor *
_MsgFree (instance, freeFunct)

   register xrEditor * instance;
            INT32      (*freeFunct)();

{
   /* Destroy the specified editor instance */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *)NULL);
   }

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

   /* Free up any space allocated by the field editor */
   if (freeFunct)
      (*freeFunct) (instance->editorData);

   /* Unattach the editor from the window */
   (*xrFree) (instance->editorData);
   XrEditor (instance->editorWindowId, MSG_REMOVE, instance);
   (*xrFree) (instance);
   return (instance);
}


/*************************************<->*************************************
 *
 *  _MsgGetState (instance, stateFlags)
 *
 *     xrEditor * instance;
 *     INT8     * stateFlags
 *
 *   Description:
 *   -----------
 *     Returns the current state flags for the specified editor instance.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is a pointer to the editor instance structure, 
 *                and indicates which editor instance is to be queried.
 *
 *     stateFlags = A pointer to an 8 bit integer value, into which the
 *                  current state flag values will be placed.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer is returned,
 *          and the current state flags will be returned in the value
 *          pointed to by the 'stateFlags' parameter; if the request fails,
 *          then NULL is returned, and xrErrno is set
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgGetState (instance, stateFlags)

   xrEditor * instance;
   INT8     * stateFlags;

{
   /* Return some info describing current state of editor */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *)NULL);
   }
   else if (stateFlags == NULL)
   {
      xrErrno = XrINVALIDPTR;
      return ((xrEditor *)NULL);
   }

   *stateFlags = instance->editorState;
   return (instance);
}

/*************************************<->*************************************
 *
 *  _MsgSetState (instance, stateFlags, drawFunct, drawOption)
 *
 *     xrEditor * instance;
 *     INT8       stateFlags;
 *     INT32      (*drawFunct)();
 *     INT32      drawOption;
 *
 *   Description:
 *   -----------
 *     This routine sets the state flags for the specified editor isntance
 *     to the value specified in the 'stateFlags' parameter.  After setting
 *     the new state flags, the editor's drawing function will be called,
 *     and passed the redraw option specified by the 'drawOption' parameter.
 *     If the instance is visible, then the draw function should redraw
 *     the specified instance, to match the new state flags.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is the editor instance pointer, and indicates which
 *                editor instance is to have its state flags modified.
 *
 *     stateFlags = This contains the new editor state flags.
 *
 *     drawFunct = This points to the editors drawing function.
 *
 *     drawOption = This specifies the option which should be passed to
 *                  the editor's draw function, such that the whole
 *                  editor instance will be redraw.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer will be
 *          returned; if the call fails, then NULL will be returned and
 *          xrErrno set.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgSetState (instance, stateFlags, drawFunct, drawOption)

   register xrEditor * instance;
            INT8       stateFlags;
            INT32      (*drawFunct)();
            INT32      drawOption;

{
   /* Change the state of this editor instance */
   INT8 oldState;

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

   oldState = instance->editorState;
   instance->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))))
   {
      (*drawFunct) (instance, drawOption);
   }
   return (instance);
}


/*************************************<->*************************************
 *
 *  _MsgRedraw (instance, redrawMode, drawFunct, drawOption)
 *
 *   Description:
 *   -----------
 *     This routine is capable of handling a MSG_REDRAW request for those
 *     field editors which understand only the XrREDRAW_ALL option.  After
 *     verifying the parameters, the editor's drawing function will be
 *     invoked, and passed the specified 'drawOption'; this option should
 *     tell the drawing routine to draw the complete editor instance.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is the editor instance pointer, and indicates which
 *                instance is to be redrawn.
 *
 *     redrawMode = This is the redraw mode specified with the MSG_REDRAW
 *                  request; any redraw mode other than XrREDRAW_ALL will
 *                  cause this request to fail.
 *
 *     drawFunct = This is a pointer to the editor's drawing function.
 *
 *     drawOption = This value is passed to the editor's drawing function,
 *                  and should instruct the drawing routine to draw the
 *                  complete editor instance.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, the editor instance pointer will be
 *          returned; if the request fails, then NULL is returned and
 *          xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *
 *************************************<->***********************************/

xrEditor *
_MsgRedraw (instance, redrawMode, drawFunct, drawOption)

   register xrEditor * instance;
            INT32      redrawMode;
            INT32      (*drawFunct)();
            INT32      drawOption;

{
   /* Redraw the editor, to match new value */

   /* Validate the instance pointer & the redraw mode */
   if (instance == NULL)
   {
      xrErrno = XrINVALIDID;
      return ((xrEditor *) NULL);
   }
   else if (redrawMode != XrREDRAW_ALL)
   {
      xrErrno = XrINVALIDOPTION;
      return ((xrEditor *) NULL);
   }

   if (instance->editorState & XrVISIBLE)
      (*drawFunct) (instance, drawOption);

   return (instance);
}


/*************************************<->*************************************
 *
 *  _MsgEdit (instance, event, processFunct, inputCode)
 *
 *   Description:
 *   -----------
 *     This routine handles all MSG_EDIT requests for those field editors
 *     which accept only an XrSELECT event.  If the event pointed to by
 *     the 'event' parameter is an XrSELECT event, then the editor's
 *     input processing function will be invoked to handle it; in return
 *     the input processing function should fill out whatever fields in
 *     the returnEvent structure is wants to.  After the processing routine 
 *     has complete, the return event will be pushed onto the front of 
 *     the application's input queue.
 *
 *
 *   Inputs:
 *   ------
 *     instance = This is the editor instance pointer.
 *
 *     event = This is a pointer to an XEvent structure, containing the
 *             event information; this must be a button event.
 *
 *     processFunct = A pointer to the editor's event processing function.
 * 
 *     inputCode = This contains the editor's unique input code, which
 *                 is stored in the 'inputCode' field of the returned
 *                 event.
 * 
 *   Outputs:
 *   -------
 *     If the event is processed by the editor, then the editor instance
 *        pointer is returned, and an event is pushed on the front of the
 *        application's input queue; if the event is not processed, then
 *        NULL is returned.
 *
 *   Procedures Called
 *   -----------------
 *   _XrCatchableKey()  [editorUtil.c]
 *   XrInput()          [input.c]
 *
 *************************************<->***********************************/

xrEditor *
_MsgEdit (instance, event, processFunct, inputCode)

   xrEditor * instance;
   XEvent   * event;
   INT8       (*processFunct)();
   INT16      inputCode;

{
   /*
    * Process the incoming keystroke, and generate a return
    * keystroke, to indicate to the application program
    * how the editor instance was modified.
    */
   xrEvent        returnEvent;
   xrEvent        exitEvent;
   XButtonEvent * buttonEvent = (XButtonEvent *)event;
   
   if ((XrMapButton (XrSELECT, event) == FALSE) ||
       (!_XrCatchableKey (instance, event)))
   {
      /* xrErrno is not set; this is not an error condition */
      return ((xrEditor *)NULL);
   }

   /*
    * Fill out the return keystroke.
    * The editor itself must fill out the value1 field.
    */
   returnEvent.type = XrXRAY;
   returnEvent.source = buttonEvent->window;
   returnEvent.inputType = XrEDITOR;
   returnEvent.inputCode = inputCode;
   returnEvent.valuePtr = (INT32) instance;
   XrSetPt (&returnEvent.valuePt, buttonEvent->x, buttonEvent->y);

   /* Process the keystroke */
   (*processFunct) (instance, buttonEvent, &returnEvent);

   /* Swallow the select up event */
   while (XrInput (NULL, MSG_BLKREAD, &exitEvent) == FALSE);
   if (XrMapButton (XrSELECTUP, &exitEvent) == FALSE)
   {
      /* Not a select up event, so push back onto the input queue */
      XrInput (NULL, MSG_PUSHEVENT, &exitEvent);
   }
   
   /* Push the xrEvent structure onto the input queue */
   XrInput (NULL, MSG_PUSHEVENT, &returnEvent);

   return (instance);
}

