/*
 *	$Source: /u1/Xr/src/Xrlib/Intrinsic/RCS/editor.c,v $
 *	$Header: editor.c,v 1.1 86/12/17 09:07:56 swick Exp $
 */

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

#include <Xr/xr-copyright.h>

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

static char rcsid[] = "$Header: editor.c,v 1.1 86/12/17 09:07:56 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        editor.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: Handle all of the editor list functions needed
 **                for a window.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	editor.c,v $
 * Revision 1.1  86/12/17  09:07:56  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:19:34  08:19:34  rick ()
 * Final QA release
 * 
 * Revision 6.0  86/11/10  15:21:23  15:21:23  rick ()
 * QA #2 release
 * 
 * Revision 5.2  86/11/07  14:01:32  14:01:32  rick ()
 * Added the copyright message.
 * 
 * Revision 5.1  86/11/07  11:09:01  11:09:01  rick ()
 * Fixed a REMOVE bug -- made sure that the group rect gets zero'ed.
 * 
 * Revision 5.0  86/10/28  08:22:13  08:22:13  rick ()
 * QA #1.1 release
 * 
 * Revision 4.0  86/10/20  12:08:03  12:08:03  rick ()
 * QA 1 release
 * 
 * Revision 3.3  86/10/17  12:22:52  12:22:52  rick ()
 * Linted
 * 
 * Revision 3.2  86/10/16  11:19:57  11:19:57  rick ()
 * Added register variables.
 * 
 * Revision 3.1  86/10/07  16:43:09  16:43:09  rick ()
 * Changed the call to XrMapButton in MSG_PROCESSKEY to reflect the
 * the new functionality.
 * 
 * Revision 3.0  86/10/02  15:58:16  15:58:16  rick ()
 *  Alpha release set to 3.0
 * 
 * Revision 2.5  86/10/01  07:57:47  07:57:47  rick ()
 * Added a check in PROCESSKEY for a return value of NULL from an editor.
 * 
 * Revision 2.4  86/09/22  11:35:49  11:35:49  rick ()
 * Added a call to XrEditorGroup - MSG_ADJUSTGROUPRECT to recalculate
 * the group rectangle when an editor is removed.
 * 
 * Revision 2.3  86/09/18  16:42:09  16:42:09  rick ()
 * Added checks for NULL data parameters in several messages.
 * 
 * Revision 2.2  86/09/18  10:43:24  10:43:24  rick ()
 * Added a check for SENSITIVE groups in message PROCESSKEY.
 * 
 * Revision 2.1  86/09/17  10:43:46  10:43:46  rick ()
 * Changed the check of the XButtonEvent to a call to XrMapButton
 * 
 * Revision 2.0  86/09/16  07:57:40  07:57:40  rick ()
 * *** empty log message ***
 * 
 * Revision 1.4  86/09/16  07:43:40  07:43:40  rick ()
 * Changed input to MSG_PROCESSKEY to an X Button Event input.
 * 
 * Revision 1.3  86/09/11  08:04:07  08:04:07  rick ()
 * Changed all of the messages to add editor group traversal.
 * 
 * Revision 1.2  86/09/04  11:59:54  11:59:54  rick ()
 * Added a check in MSG_REMOVE in case the editor is not in the list.
 * 
 * Revision 1.1  86/09/03  13:35:05  13:35:05  rick ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/


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


static xrResourceInfo resourceInfo =
   { XrTYPE_REGWINDOW, 0, 0, XrMEMORY, NULL };



/*************************************<->*************************************
 *
 *  Window
 *  XrEditor (windowId, message, data)
 *  INT32  windowId;
 *  INT32  message;
 *  INT8 * data;
 *
 *
 *   Description:
 *   -----------
 *     This routine provides for the editor list management needed
 *     by Input, Editors, Forms, etc..  Refer to the XrEditor() man
 *     page and the X-ray toolbox manual for a complete description.
 *
 *
 *   Inputs:
 *   ------
 *     message = Contains the message which describes the capability
 *               to be executed.
 *
 *     data    = Contains a pointer to a structure necessary for the
 *               completion of the message.
 *
 *     For a complete description of XrEditor()'s messages and data
 *     parameters, refer to XrEditor(3XR) and the X-ray toolbox manual.
 * 
 *   Outputs:
 *   -------
 *     windowId = Returned as the value of the function if the message 
 *                succeeds.
 *
 *     FALSE = Returned as the value of the function if the message fails.
 *
 *     xrError = The error variable is set to one several values upon
 *               failure of this routine.
 *
 *     For a complete description of the values returned in data, 
 *     refer to XrEditor(3XR) and the X-ray toolbox manual.
 *
 *
 *   Procedures Called
 *   -----------------
 *     XrResource()  -  resource.c
 *     XrPtInRect()  -  calc.c
 *     XrSectRect()  -  calc.c
 *     XrEmptyRect() -  calc.c
 *     XrCopyRect()  -  calc.c
 *     XrUnionRect() -  calc.c
 *     XrEqualRect() -  calc.c
 *     XrMapButton() -  utilities.c
 *
 *************************************<->***********************************/


Window
XrEditor (windowId, message, data)
Window   windowId;
INT32    message;
INT8   * data;

{
   register xrEditor  * editStruct;
   register xrEditor  * editorPtr;
   register xrEditorGroup * groupPtr;
   XButtonEvent  * editorInput;
   POINT       inputPt;
   xrWindow  * window;
   RECTANGLE * dataRect;
   RECTANGLE   workRect;


   /*
    *  Set up a switch to handle each of the messages.
    */

   switch (message)
   {

      /*
       *  Add the editor structure pointed at by data into the window's
       *  active group.  Adjust the group rectangle to make sure the
       *  editor is within it.
       */

      case MSG_ADD:
         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         editStruct = (xrEditor *) data;
         editStruct -> nextEditor = NULL;

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
            return ((Window) FALSE);

         window = (xrWindow *) resourceInfo.resourceObject;

         groupPtr = window -> activeGroup;
         editorPtr = groupPtr -> editorList;

         if (editorPtr == NULL)
            groupPtr -> editorList = editStruct;
         else
         {
            while (editorPtr -> nextEditor != NULL)
               editorPtr = editorPtr -> nextEditor;

            editorPtr -> nextEditor = editStruct;
         }

         if (XrEmptyRect (&groupPtr -> groupRect))
            XrCopyRect (&editStruct -> editorRect, &groupPtr -> groupRect);
         else
            XrUnionRect (&groupPtr -> groupRect, &editStruct -> editorRect,
                         &groupPtr -> groupRect);

         return (windowId);
      break;


      /*
       *  Find the group an editor is attached to and remove it from
       *  the editor list.  Make the checks by first comparing the
       *  group rectangle with the editor rectangle and then checking
       *  each editor instance within the group.
       */

      case MSG_REMOVE:		/*  Remove an editor from the list  */

         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         editStruct = (xrEditor *) data;

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
            return ((Window) FALSE);

         window = (xrWindow *) resourceInfo.resourceObject;
         groupPtr = &(window -> groupList);


         /*
          *  Loop through the group list, first seeing if the editor
          *  resides in the group and if so, loop through the editor
          *  list to see if the editor is in the list.  If found, 
          *  remove the editor and return.  If not found go and check
          *  the next group.
          */

         while (groupPtr != NULL)
         {
            XrSectRect (&groupPtr -> groupRect, 
                        &editStruct -> editorRect, &workRect);

            if (XrEqualRect (&editStruct -> editorRect, &workRect))
            {
               editorPtr = groupPtr -> editorList;

               if (editorPtr == editStruct)
               {
                  groupPtr -> editorList = editorPtr -> nextEditor;
                  XrEditorGroup (groupPtr, MSG_SETGROUPRECT, NULL);
                  return (windowId);
               }
               else
               {
                  while (editorPtr -> nextEditor != NULL)
                  {
                     if (editorPtr -> nextEditor == editStruct)
                     {
                        editorPtr -> nextEditor = 
                        editorPtr -> nextEditor -> nextEditor;
                        XrEditorGroup (groupPtr, MSG_SETGROUPRECT, NULL);
                        return (windowId);
                     }
                     editorPtr = editorPtr -> nextEditor;
                  }
               }
            }
            groupPtr = groupPtr -> nextGroup;
         }

         return ((Window) FALSE);
      break;


      /*
       *  Process the event pointed at by data by locating the editor
       *  it is to go to and calling the editor.
       */

      case MSG_PROCESSKEY:
         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         editorInput = (XButtonEvent *) data;

         if (XrMapButton (XrSELECT, editorInput) == FALSE)
         {
            xrErrno = XrINVALIDPARM;
            return (FALSE);
         }

         inputPt.x = editorInput -> x;
         inputPt.y = editorInput -> y;

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
            return (FALSE);

         window = (xrWindow *) resourceInfo.resourceObject;
         groupPtr = &(window -> groupList);


         /*
          *  Loop through the set of groups, checking each VISIBLE and
          *  SENSITIVE group to see if the input falls within the group.  
          *  If so, loop through the set of editors attached to the group
          *  checking each VISIBLE and SENSITIVE editor to see if the
          *  input falls within it.  When an editor is found, call
          *  it with MSG_EDIT and return.
          */

         while (groupPtr != NULL)
         {
            if (groupPtr -> groupState & XrVISIBLE   &&
                groupPtr -> groupState & XrSENSITIVE &&
                XrPtInRect (&inputPt, &groupPtr -> groupRect))
            {
               editorPtr = groupPtr -> editorList;

               while (editorPtr != NULL)
               {
                  if (editorPtr -> editorState & XrVISIBLE &&
                      editorPtr -> editorState & XrSENSITIVE &&
                      XrPtInRect (&inputPt, &editorPtr -> editorRect))
                  {
                     if ((*editorPtr -> editorFunct)
                          (editorPtr, MSG_EDIT, editorInput))
                        ;
                     else
                        XrInput (0, MSG_PUSHEVENT, editorInput);
                     return (windowId);
                  }
                  editorPtr = editorPtr -> nextEditor;
               }
            }

            groupPtr = groupPtr -> nextGroup;
         }

         xrErrno = XrINVALIDPARM;
         return ((Window) FALSE);
      break;


      /*
       *  Redraw all of the editors of active groups which
       *  intersect with the rectangle pointed at by data.
       */

      case MSG_REDRAW:
         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         dataRect = (RECTANGLE *) data;

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
            return (FALSE);

         window = (xrWindow *) resourceInfo.resourceObject;
         groupPtr = &(window -> groupList);

         while (groupPtr != NULL)
         {
            if (groupPtr -> groupState & XrVISIBLE &&
                XrSectRect (&groupPtr -> groupRect, dataRect, &workRect))
            {
               editorPtr = groupPtr -> editorList;
         
               while (editorPtr != NULL)
               {
                  if (editorPtr -> editorState & XrVISIBLE &&
                      XrSectRect(&editorPtr->editorRect, dataRect, &workRect))
                     *(editorPtr -> editorFunct)
                      (editorPtr, MSG_REDRAW, XrREDRAW_ALL);
   
                  editorPtr = editorPtr -> nextEditor;
               }
            }

            groupPtr = groupPtr -> nextGroup;
         }

         return (windowId);
      break;



      /*
       *  Redraw all of the editors of all of the active groups.
       */

      case MSG_REDRAWALL:
         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
            return (FALSE);

         window = (xrWindow *) resourceInfo.resourceObject;
         groupPtr = &(window -> groupList);

         while (groupPtr != NULL)
         {
            if (groupPtr -> groupState & XrVISIBLE)
            {
               editorPtr = groupPtr -> editorList;
         
               while (editorPtr != NULL)
               {
                  if (editorPtr -> editorState & XrVISIBLE)
                     *(editorPtr -> editorFunct) 
                      (editorPtr, MSG_REDRAW, XrREDRAW_ALL);

                  editorPtr = editorPtr -> nextEditor;
               }
            }

            groupPtr = groupPtr -> nextGroup;
         }

         return (windowId);
      break;


      /*
       *  Set the state of all of the editors within all of 
       *  the active groups.
       */

      case MSG_SETSTATE:
         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
            return (FALSE);

         window = (xrWindow *) resourceInfo.resourceObject;
         groupPtr = &(window -> groupList);

         while (groupPtr != NULL)
         {
            if (groupPtr -> groupState & XrVISIBLE)
            {
               editorPtr = groupPtr -> editorList;
         
               while (editorPtr != NULL)
               {
                  *(editorPtr -> editorFunct) (editorPtr, MSG_SETSTATE, data);
                  editorPtr = editorPtr -> nextEditor;
               }
            }
            groupPtr = groupPtr -> nextGroup;
         }

         return (windowId);
      break;


      default:
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;
   }
}
