/*
 *	$Source: /u1/Xr/src/Xrlib/Dialog/RCS/MenuEdit.c,v $
 *	$Header: MenuEdit.c,v 1.1 86/12/17 08:58:05 swick Exp $
 */

#ifndef lint
static char *rcsid_MenuEdit_c = "$Header: MenuEdit.c,v 1.1 86/12/17 08:58:05 swick Exp $";
#endif	lint

#include <Xr/xr-copyright.h>

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

static char rcsid[] = "$Header: MenuEdit.c,v 1.1 86/12/17 08:58:05 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        MenuEdit.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: X-ray Toolbox Menu Editor
 **
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	MenuEdit.c,v $
 * Revision 1.1  86/12/17  08:58:05  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:27:56  08:27:56  ed ()
 * Final QA release
 * 
 * Revision 6.1  86/11/12  21:08:38  21:08:38  ed ()
 * Fixed:  Explicitly set title info to NULL if no title bar.
 * 
 * Revision 6.0  86/11/10  15:37:15  15:37:15  ed ()
 * QA #2 release
 * 
 * Revision 5.2  86/11/07  14:09:52  14:09:52  ed ()
 * Added procedure headers, new copyright message.
 * 
 * Revision 5.1  86/11/06  11:33:18  11:33:18  ed ()
 * Fixed space padding for keyboard equivalents.
 * 
 * Revision 5.0  86/10/28  08:25:13  08:25:13  ed ()
 * QA #1.1 release
 * 
 * Revision 4.0  86/10/20  12:07:59  12:07:59  ed ()
 * QA #1 release
 * 
 * Revision 3.9  86/10/19  14:17:03  14:17:03  ed ()
 * Linted, register variables, prepared for Beta release.
 * 
 * Revision 3.8  86/10/18  16:58:40  16:58:40  ed ()
 * Fixed cascade anomolieamlies
 * Tuned line placement
 * 
 * Revision 3.7  86/10/15  21:43:16  21:43:16  ed ()
 * Memory management changes
 * 
 * Revision 3.6  86/10/14  16:45:24  16:45:24  ed ()
 * Added item functs and item events
 * 
 * Revision 3.5  86/10/13  20:43:32  20:43:32  ed ()
 * Keyboard equivalents (added drawing).
 * 
 * Revision 3.4  86/10/10  08:57:10  08:57:10  ed ()
 * More drawing changes.
 * 
 * Revision 3.2  86/10/09  15:49:40  15:49:40  ed ()
 * Many editor drawing changes. Color, lines...
 * 
 * Revision 3.1  86/10/08  08:43:15  08:43:15  ed ()
 * Rearranged MSG_NEW, MSG_EDIT, added new XrMapButton
 * 
 * Revision 3.0  86/10/02  16:03:34  16:03:34  ed ()
 * Alpha Release set to 3.0
 * 
 * Revision 1.2  86/09/29  15:39:29  15:39:29  ed ()
 * Removed code that created dithering pixmap.
 * Now using global.
 * 
 * 
 * Revision 1.1  86/09/28  19:15:43  19:15:43  ed ()
 * Initial revision
 * 
 *****************************************************************************
 *************************************<+>*************************************/




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

extern INT32 createMenuEdit();
extern INT32 drawMenuEdit();
extern INT32 processMenuEdit();
extern INT32 highlightItem();
extern INT32 menuState();


static xrTitleBarInfo titleSizeInfo = {0,
                                  {0,0,0,0},
                                   0,0,0,
                                   NULL,
                                   NULL,
                                   NULL,
                                   NULL};

/*************************************<->*************************************
 *
 *  XrMenuEdit(menuEdit, message, data)
 *
 *     xrEditor   * menuEdit
 *     INT32        message;
 *     INT8       * data;
 *
 *   Description:
 *   -----------
 *   This is the MenuEdit field editor.  This editor was written for
 *   the menu manager.  It does not abide by all the rules of 
 *   standard editors and should not be used as one.  This editor
 *   is in charge of the visual and semantic aspects of menu items.
 *   It is called by the menu manager.
 *
 *
 *   Inputs:
 *   ------
 *     menu = This value indicates to the menuEdit editor,
 *                    which editor should be dealt with.
 *
 *     message = Contains the command to be executed.
 *
 *     data    = Varies depending on the message, But is generally
 *               a pointer to a structure.
 *
 * 
 *   Outputs:
 *   -------
 *     menuEdit = Returned from MSG_NEW.
 *
 *     TRUE    = Returned upon successful completion of a message.
 *
 *     NULL    = Returned if something went wrong.
 *
 *     xrError = The error variable is set to one of several values
 *               upon failure of this routine.
 *
 *   Procedures Called
 *   -----------------
 *   MSG_NEW:
 *     (* xrMalloc)()
 *     (* xrFree)()
 *     createMenuEdit()
 *     _XrInitEditorStruct()  - editorUtil.c
 *     
 *  MSG_FREE:
 *    XrTitleBar()            - TitleBar.c
 *    XFreePixmap()           - XLib
 *    (* xrFree)()
 *
 *  MSG_EDIT:
 *    XrSetPt()               - calc.c
 *    processMenuEdit()
 *    XrInput()               - input.c
 *
 *  MSG_SIZE:
 *    XrStringWidth()         - editorUtil.c
 *    _XrTextInfo()           - editorUtil.c
 *    XrTitleBar()            - TitleBar.c
 *
 *
 *
 *
 *************************************<->***********************************/


xrEditor * 
XrMenuEdit (menuEdit, message, data)
register xrEditor   * menuEdit;
         INT32        message;
         INT8       * data;
{

  /******************************************************************
   *
   *   Process the messages sent to the menu editor.
   *
   ******************************************************************/


   switch (message) {

   case MSG_NEW:
   {
      xrEditor  * mnuEdit;
      register xrMenuEditor * menuInfo = (xrMenuEditor *) data;
      INT8 * dataPtr;


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

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

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

      



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

      /* Initialize the instance's data structures */
      _XrInitEditorStruct (mnuEdit, menuInfo, dataPtr, XrMenuEdit);

      /* Create request was successful */
      return (mnuEdit);


      break;

    }

   case MSG_FREE:
   {
      register xrMenuData *   menuData;

      menuData = (xrMenuData *) menuEdit -> editorData;
      
      XrTitleBar(menuData -> menuTitleBar, MSG_FREE, NULL);
 
      XFreePixmap(menuData -> menuTile);
 
      (* xrFree)(menuData -> popupMenu);
      (* xrFree)(menuData -> itemFunct);
      (* xrFree)(menuData -> itemEvent);
      (* xrFree)(menuData -> itemPosy);

      (* xrFree)(menuData);
      (* xrFree)(menuEdit);

      return((xrEditor *) TRUE);
      break;
   }


   case MSG_EDIT:
   {
      xrEvent        returnEvent;

      /*
       * Fill out the return keystroke.
       * The editor itself must fill out the value1 field.
       */

      returnEvent.type = XrXRAY;
      returnEvent.source = menuEdit -> editorWindowId;
      returnEvent.inputType = XrEDITOR;
      returnEvent.inputCode = XrMENUEDIT;
      returnEvent.valuePtr = (INT32) menuEdit;
      XrSetPt (&returnEvent.valuePt, 0, 0);

      /* Process the keystroke */
      processMenuEdit (menuEdit, &returnEvent);

   
      /* Push the xrEvent structure onto the input queue */
      XrInput (NULL, MSG_PUSHEVENT, &returnEvent);

      return (menuEdit);
      break;


   }
      

   case MSG_GETSTATE:
   {
      return((xrEditor *) _MsgGetState(menuEdit, data));
      break;
   }

   case MSG_SETSTATE:
   {
      return((xrEditor *) _MsgSetState(menuEdit, data, drawMenuEdit, NULL));
      break;
   }

   case MSG_REDRAW:
   {
      return((xrEditor *) _MsgRedraw(menuEdit, data, drawMenuEdit, NULL));
      break;
   }

   case MSG_RESET:
   {
       xrMenuData   * meDataPtr;

       meDataPtr = (xrMenuData *) menuEdit -> editorData;       

       meDataPtr -> menuArea = -1;
       meDataPtr -> menuItem = -1;

       return((xrEditor *)TRUE);
       break;
   }

   case MSG_SIZE:
   {
       register xrMenuEditor   * menuInfo;
       INT32  currentWidth, currentHeight, stringWidth, tmpWidth;
       register INT32 i;
       register INT32 pad;
       xrTextInfo  textInfo;
       INT32 lineThick, lineHeight, dlineHeight;

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


      menuInfo = (xrMenuEditor *) data;

      if (menuInfo == NULL) 
      {
         xrErrno = XrINVALIDPTR;
         return((xrEditor *) NULL);
      }


      menuInfo -> editorRect.x = 0;
      menuInfo -> editorRect.y = 0;

       /* 
        * Determine the width of the menu.
        *
        * width = pad * 2 +               (left margin)
        *         width of longest item + (item length)
        *         pad +                   (middle margin)
        *         fontinfo.width * 2 +    (arrow, kbd equiv marks)
        *         pad * 2;                (right margin)
        */

       /* width of the left margin */

       pad = menuInfo -> editorFont -> width;
       currentWidth = pad * 2;

       /* width of the widest item */
       
       stringWidth = 0;
       for (i=0; i < menuInfo -> numItems; i++)
       {
          if (menuInfo -> itemTypes[i] == XrSTRING ||
              menuInfo -> itemTypes[i] == XrUSTRING)
          {
             tmpWidth = XrStringWidth(
                                   menuInfo -> editorFont,
                                   menuInfo -> menuStrings[i],
                                   * (menuInfo -> stringLengths + i),
                                   0,
                                   0);
             if (stringWidth < tmpWidth)
                stringWidth = tmpWidth;
           }
        }

        currentWidth += stringWidth;

        /* middle margin, arrow, kbd equivs, right margin */

        currentWidth += pad;
        currentWidth += (pad * 2);
        currentWidth += pad * 2;

        menuInfo -> editorRect.width = currentWidth;


       /* 
        * Determine the height of the menu.
        *
        * width = height of titlebar +         (title height)
        *         leading +                    (top margin)
        *         sum of item heights +        (item heights)
        *         leading;                     (bottom margin)
        */


        /* top margin                                   */

        _XrTextInfo(menuInfo -> editorFont, &textInfo);
        currentHeight = textInfo.leading;


        /* height of the title bar                      */

        if (menuInfo -> menuTitle != NULL)
        {
           titleSizeInfo.editorFont = menuInfo -> editorFont;
           titleSizeInfo.titleName = menuInfo -> menuTitle;

           if (!(XrTitleBar(NULL, MSG_SIZE, &titleSizeInfo)))
              return((xrEditor *) NULL);

           if (titleSizeInfo.editorRect.width > menuInfo -> editorRect.width)
              menuInfo -> editorRect.width = titleSizeInfo.editorRect.width;

           currentHeight += titleSizeInfo.editorRect.height;
        }

        /* sum the item heights                         */

       lineThick = textInfo.leading/3;
       if(lineThick == 0)
         lineThick = 1;

       lineHeight = lineThick * 4 + lineThick;

       dlineHeight = lineThick * 4 + lineThick * 3;

       for (i=0; i < menuInfo -> numItems; i++)
       {
          switch (menuInfo -> itemTypes[i])
          {
          case XrSTRING:
          case XrUSTRING:
             currentHeight += (menuInfo -> editorFont -> height);
             break;

          case XrLINE:
             currentHeight += lineHeight;
             break;

          case XrDBLINE:
             currentHeight += dlineHeight;
             break;

          default:
             break;
          }


        }

        /* Bottom margin                                */

        currentHeight += textInfo.leading;

        menuInfo -> editorRect.height = currentHeight;

     return((xrEditor *) TRUE);
     break;
   } /* end MSG_SIZE */


   default:
      xrErrno = XrINVALIDMSG;
      return((xrEditor *) NULL);
      break;
   
   } /* end switch */

   return((xrEditor *) NULL);
}



/*************************************<->*************************************
 *
 *  createMenuEdit(meDataPtr, meInfoPtr)
 *    xrMenuData    * meDataPtr;
 *    xrMenuEditor  * meInfoPtr;
 *
 *   Description:
 *   -----------
 *    This routine take an editor info structure and creates the
 *    internal data structure.
 *
 *
 *   Inputs:
 *   ------
 *     meDataPtr = A pointer to the internal menu structure.
 *     meInfoPtr = A pointer to the info structure to be used.
 * 
 *   Outputs:
 *   -------
 *     meDataPtr = a filled out xrMenuData structure.
 *
 *   Procedures Called
 *   -----------------
 *     (* xrMalloc)()
 *     (* xrFree)()
 *     XrCopyRect()  - calc.c
 *     XrTitleBar()  - TitleBar.c
 *     XrResource()  - resource.c
 *     XMakePixmap() - XLib
 *     _XrTextInfo() - editorUtil.c
 *     
 *
 *************************************<->***********************************/
static
INT32
createMenuEdit(meDataPtr, meInfoPtr)
   register xrMenuData * meDataPtr;
   register xrMenuEditor * meInfoPtr;

{
   register INT32 i;
   register INT32 pad;

   INT32 currentYPos, lineThick, lineHeight, dlineHeight;
   xrResourceInfo  resourceInfo;

      if ((meDataPtr -> itemEvent = 
        (xrEvent **) (*xrMalloc)(sizeof(xrEvent *) * (meInfoPtr -> numItems))) 
        == NULL) {
        xrErrno = XrOUTOFMEM;
        return (NULL);
      }

      if ((meDataPtr -> itemFunct = 
        (xrPFI *) (*xrMalloc)(sizeof(xrPFI) * (meInfoPtr -> numItems))) 
        == NULL) {
        xrErrno = XrOUTOFMEM;
        (* xrFree)(meDataPtr -> itemEvent);
        return (NULL);
      }

      if ((meDataPtr -> popupMenu = 
        (xrMenu **) (*xrMalloc)(sizeof(xrMenu *) * (meInfoPtr -> numItems))) 
        == NULL) {
        xrErrno = XrOUTOFMEM;
        (* xrFree)(meDataPtr -> itemFunct);
        (* xrFree)(meDataPtr -> itemEvent);
        return (NULL);
      }

      if ((meDataPtr -> itemPosy = 
        (INT32 *) (*xrMalloc)(sizeof(INT32) * (meInfoPtr -> numItems))) 
        == NULL) {
        xrErrno = XrOUTOFMEM;
        (* xrFree)(meDataPtr -> popupMenu);
        (* xrFree)(meDataPtr -> itemFunct);
        (* xrFree)(meDataPtr -> itemEvent);
        return (NULL);
      }


   /* Create title bar if a title string is given.   */

   XrCopyRect(&xrZeroRect, &titleSizeInfo.editorRect);
   if (meInfoPtr -> menuTitle)
   {
      titleSizeInfo.editorWindowId = meInfoPtr -> editorWindowId;
      titleSizeInfo.editorState = XrVISIBLE | XrSENSITIVE;
      titleSizeInfo.editorFGColor = 
                    meInfoPtr -> editorFGColor;
      titleSizeInfo.editorBGColor =
                    meInfoPtr -> editorBGColor;
      titleSizeInfo.editorFont = 
                    meInfoPtr -> editorFont;
      titleSizeInfo.titleName = meInfoPtr -> menuTitle;
      XrTitleBar(NULL, MSG_SIZE, &titleSizeInfo);
      titleSizeInfo.editorRect.width = meInfoPtr -> editorRect.width;
      meDataPtr -> menuTitleBar = XrTitleBar(NULL, MSG_NEW, &titleSizeInfo);
    }
    else
    {
       meDataPtr -> menuTitleBar = NULL;
    }
      
   /* Copy the elements of the info structure to the data structure */

   meDataPtr -> meFGColor = meInfoPtr -> editorFGColor;
   meDataPtr -> meBGColor = meInfoPtr -> editorBGColor;

   resourceInfo.resourceType = XrTYPE_BITMAPID;
   resourceInfo.resourceId = XrPERCENT50;
   XrResource (MSG_FIND, &resourceInfo);
   meDataPtr -> menuTile = 
              XMakePixmap (((xrBitmapId *)resourceInfo.resourceObject)
              -> bitmapId, meDataPtr -> meFGColor, meDataPtr -> meBGColor);
   

   meDataPtr -> numItems = meInfoPtr -> numItems;
   meDataPtr -> itemTypes = meInfoPtr -> itemTypes;
   meDataPtr -> menuStrings = meInfoPtr -> menuStrings;
   meDataPtr -> stringLengths = meInfoPtr -> stringLengths;
   meDataPtr -> keybdEquiv = meInfoPtr -> keybdEquiv;

   /* fill out the dataPtr elements used to draw the menu */

   _XrTextInfo(meInfoPtr -> editorFont, &meDataPtr -> menuTextInfo);


   pad = meInfoPtr -> editorFont -> width;

   meDataPtr -> highlightStart = 2;
   meDataPtr -> highlightLength = meInfoPtr -> editorRect.width -4;
   meDataPtr -> itemPosx = pad * 2;
   meDataPtr -> kbdeqPosx = meInfoPtr -> editorRect.width - (pad * 4);
   meDataPtr -> popupPosx = meInfoPtr -> editorRect.width - 
                            (meInfoPtr -> editorRect.width / 3);

   /*  Figure the y locations for each item in the menu   */

    
    currentYPos = titleSizeInfo.editorRect.height +
                  meDataPtr -> menuTextInfo.leading + 1;

    meDataPtr -> stringHeight = meInfoPtr -> editorFont -> height;

    lineThick = meDataPtr -> menuTextInfo.leading/3;
    if(lineThick == 0)
       lineThick = 1;

    lineHeight = lineThick * 4 + lineThick;
    dlineHeight = lineThick * 4 + lineThick * 3;
    meDataPtr -> lineThickness = lineThick;

    for (i=0; i < meDataPtr -> numItems; i++)
    {
          meDataPtr -> itemFunct[i] = NULL;
          meDataPtr -> itemEvent[i] = NULL;
          meDataPtr -> popupMenu[i] = NULL;
          switch (meDataPtr -> itemTypes[i])
          {
          case XrSTRING:
          case XrUSTRING:
             meDataPtr -> itemPosy[i] = currentYPos;
             currentYPos += (meInfoPtr -> editorFont -> height);
             break;

          case XrLINE:
             meDataPtr -> itemPosy[i] = currentYPos;
             currentYPos += lineHeight;
             break;

          case XrDBLINE:
             meDataPtr -> itemPosy[i] = currentYPos;
             currentYPos += dlineHeight;
             break;

          default:
             break;
          }

    }

    meDataPtr -> menuArea = -1;
    meDataPtr -> menuItem = -1;

return(TRUE);
}


/*************************************<->*************************************
 *
 *  drawMenuEdit(menuEdit, drawOption)
 *    xrMenuEditor  * meInfoPtr;
 *    INT32           drawOption;
 *
 *   Description:
 *   -----------
 *    This routine take an editor structure and draws the
 *    menu in the given window.
 *
 *
 *   Inputs:
 *   ------
 *     meInfoPtr = A pointer to the info structure to be used.
 * 
 *   Outputs:
 *   -------
 *     None
 *
 *   Procedures Called
 *   -----------------
 *     XrTitleBar()  - TitleBar.c
 *     XText()       - XLib
 *     XTileFill()   - XLib
 *     XTextPad()    - XLib
 *     XPixSet()     - XLib
 *     
 *     
 *
 *************************************<->***********************************/

static
INT32
drawMenuEdit(menuEdit, drawOption)
register xrEditor * menuEdit;
INT32      drawOption;
{
   register xrMenuData * menuData;
   register INT32 i;
   static char * popupMark = "->";
   static char * kbdMark = "^ ";
   register char * mark;



   menuData = (xrMenuData *) (menuEdit -> editorData);

   XrTitleBar(menuData -> menuTitleBar, MSG_REDRAW,
                            XrREDRAW_ALL);


   for (i=0; i < menuData -> numItems; i++)
   {
      mark = NULL;
      if (menuData -> popupMenu[i] != NULL)
         mark = popupMark;

      if (menuData -> keybdEquiv[i] != NULL)
      {
           kbdMark[1] = (INT8) menuData -> keybdEquiv[i];
           mark = kbdMark;
      }

      switch (menuData -> itemTypes[i])
      {

      case XrSTRING:
      {

         XText(menuEdit -> editorWindowId, 
                       menuData -> itemPosx,
                       menuData -> itemPosy[i],
                       menuData -> menuStrings[i],
                       menuData -> stringLengths[i],
                       menuData -> menuTextInfo.fontInfo -> id,
                       menuData -> meFGColor,
                       menuData -> meBGColor);

         if (mark)
         {
            XText(menuEdit -> editorWindowId, 
                       menuData -> kbdeqPosx,
                       menuData -> itemPosy[i],
                       mark,
                       2,
                       menuData -> menuTextInfo.fontInfo -> id,
                       menuData -> meFGColor,
                       menuData -> meBGColor);
          }


         break;
       }

      case XrUSTRING:
      {
         
         XText (menuEdit -> editorWindowId, 
                    menuData -> itemPosx,
                    menuData -> itemPosy[i],
                    menuData -> menuStrings[i],
                    menuData -> stringLengths[i],
                    menuData -> menuTextInfo.fontInfo -> id,
                    AllPlanes,
                    0);



         XTileFill (menuEdit -> editorWindowId,
                       menuData -> itemPosx,
                       menuData -> itemPosy[i],
                       XrStringWidth(menuData -> menuTextInfo.fontInfo,
                                     menuData -> menuStrings[i],
                                     menuData -> stringLengths[i],
                                     0,0),
                       menuData -> menuTextInfo.fontInfo -> height,
                       menuData -> menuTile, 0, GXand, AllPlanes);


         XTextPad (menuEdit -> editorWindowId, 
                       menuData -> itemPosx,
                       menuData -> itemPosy[i],
                       menuData -> menuStrings[i],
                       menuData -> stringLengths[i],
                       menuData -> menuTextInfo.fontInfo -> id,
                       0,0,
                       BlackPixel,
                       menuData -> meBGColor,
                       GXor,
                       AllPlanes);

         if (mark)
         {
            XText(menuEdit -> editorWindowId, 
                       menuData -> kbdeqPosx,
                       menuData -> itemPosy[i],
                       mark,
                       2,
                       menuData -> menuTextInfo.fontInfo -> id,
                       AllPlanes,
                       0);

            XTileFill (menuEdit -> editorWindowId,
                       menuData -> kbdeqPosx,
                       menuData -> itemPosy[i],
                       XrStringWidth(menuData -> menuTextInfo.fontInfo,
                                     mark,
                                     2,
                                     0,0),
                       menuData -> menuTextInfo.fontInfo -> height,
                       menuData -> menuTile, 0, GXand, AllPlanes);

            XTextPad (menuEdit -> editorWindowId, 
                       menuData -> kbdeqPosx,
                       menuData -> itemPosy[i],
                       mark,
                       2,
                       menuData -> menuTextInfo.fontInfo -> id,
                       0,0,
                       BlackPixel,
                       menuData -> meBGColor,
                       GXor,
                       AllPlanes);

          }



         break;
      }

      case XrLINE:
         XPixSet(menuEdit -> editorWindowId,
                     menuEdit -> editorRect.x,
                     menuData -> itemPosy[i] + menuData -> lineThickness * 2,
                     menuEdit -> editorRect.width,
                     menuData -> lineThickness,
                     menuData -> meFGColor);
         break;

      case XrDBLINE:
         XPixSet(menuEdit -> editorWindowId,
                     menuEdit -> editorRect.x,
                     menuData -> itemPosy[i] + menuData -> lineThickness * 2,
                     menuEdit -> editorRect.width,
                     menuData -> lineThickness,
                     menuData -> meFGColor);

         XPixSet(menuEdit -> editorWindowId,
                     menuEdit -> editorRect.x,
                     menuData -> itemPosy[i] + (menuData->lineThickness * 4),
                     menuEdit -> editorRect.width,
                     menuData -> lineThickness,
                     menuData -> meFGColor);
         break;

      default:
         break;
      }

   }

return(TRUE);
}



/*************************************<->*************************************
 *
 *  processMenuEdit(menuEdit, returnEvent)
 *    xrEditor      * menuEdit;
 *    xrEvent       * returnEvent;
 *
 *   Description:
 *   -----------
 *     This routine processes input from the user while a menu is posted.
 *     It informs the menu manager what is happening with a particular
 *     posted menu.
 *
 *
 *   Inputs:
 *   ------
 *     menuEdit = The editor instance to process.
 *     returnEvent = A return parameter.
 * 
 *   Outputs:
 *   -------
 *     returnEvent = Filled out with the result of the menu editing
 *                   session.
 *
 *   Procedures Called
 *   -----------------
 *     XrInput()
 *     XrMapButton()
 *     highlightItem()
 *     menuState()
 *     
 *     
 *
 *************************************<->***********************************/


static
INT32
processMenuEdit(menuEdit, returnEvent)

   register xrEditor     * menuEdit;
            xrEvent      * returnEvent;

{

   register xrMenuData   * menuData;
   register INT32          currentArea, currentItem;
            INT32          newArea, newItem, stateChange;
   xrEvent        key;
   XEvent       * menuEvent;


   menuData = (xrMenuData *) (menuEdit -> editorData);
   currentArea = menuData -> menuArea;
   currentItem = menuData -> menuItem;
   
   while (1)
   {
      returnEvent -> value3 = NULL;
      if (XrInput (NULL, MSG_NONBLKREAD, &key))
      {
         if(XrMapButton(XrMENUITEMSELECT,&key))
         {
            returnEvent -> value1 = menuData -> menuArea = currentArea;
            returnEvent -> value2 = menuData -> menuItem = currentItem;
            returnEvent -> value3 = XrMENUITEMSELECT;
            return (TRUE);
          }
          else

          {
            /*  check for leaving window keystroke */
             menuEvent = (XEvent *) (& key);
             if ((menuEvent -> type == LeaveWindow) &&
                 (menuEvent -> window == menuEdit -> editorWindowId))
             {
                returnEvent -> value1 = menuData -> menuArea = XrOUTSIDEMENU;
                returnEvent -> value2 = menuData -> menuItem =  -1;
                highlightItem(menuEdit, currentItem, FALSE);
                return (TRUE); 
              }
           }
       }

       menuState(menuEdit, currentArea, currentItem, 
                 &newArea, &newItem, &stateChange);

       switch (stateChange)
       {
          case XrNOCHANGE:
            break;

          case XrITEMCHANGE:
            if (currentItem != -1) 
            {
                highlightItem(menuEdit, currentItem, FALSE);
                if (currentArea == XrPOPUPAREA)
                {
                  returnEvent -> value1 = menuData -> menuArea = XrEXITPOPUP;
                  returnEvent -> value2 = menuData -> menuItem = currentItem;
                  return(TRUE);
                }
             }
                   
            if (newItem != -1)
                highlightItem(menuEdit, newItem, TRUE);
            currentItem = newItem;
            break;

          case XrAREACHANGE:
            if (currentArea == XrPOPUPAREA)
            {
               returnEvent -> value1 = menuData -> menuArea = XrEXITPOPUP;
               returnEvent -> value2 = menuData -> menuItem = currentItem;
               return(TRUE);
            }

            if (newArea == XrPOPUPAREA)
            {
               returnEvent -> value1 = menuData -> menuArea = newArea;
               returnEvent -> value2 = menuData -> menuItem = currentItem;
               return(TRUE);
            }

            currentArea = newArea;
            break;

          case XrBOTHCHANGE:
            if (currentArea == XrPOPUPAREA)
            {
               returnEvent -> value1 =  menuData -> menuArea = XrEXITPOPUP;
               returnEvent -> value2 =  menuData -> menuItem = currentItem;
               return(TRUE);
            }

            if (currentItem != -1)
                highlightItem(menuEdit, currentItem, FALSE);
            if (newItem != -1)
                highlightItem(menuEdit, newItem, TRUE);
            currentItem = newItem;


            if (newArea == XrPOPUPAREA)
            {
               returnEvent -> value1 = menuData -> menuArea = newArea;
               returnEvent -> value2 = menuData -> menuItem = currentItem;
               return(TRUE);
            }

            currentArea = newArea;
            break;

        }
 
   }/* while end */

}





/*************************************<->*************************************
 *
 *  highLightItem()
 *
 *   Description:
 *   -----------
 *    This procedure highlights a particular item in a given menu.
 *
 *************************************<->***********************************/


static
INT32
highlightItem(menuEdit, item, mode)
register xrEditor    * menuEdit;
register INT32         item;
register INT32         mode;
{

   register xrMenuData      * menuData;
   register INT32             foreGround, backGround;
   static char * popupMark = "->";
   static char * kbdMark = "^ ";
   char * mark;


   menuData = (xrMenuData *) (menuEdit -> editorData);

      mark = NULL;
      if (menuData -> popupMenu[item] != NULL)
         mark = popupMark;

      if (menuData -> keybdEquiv[item] != NULL)
      {
           kbdMark[1] = (INT8) menuData -> keybdEquiv[item];
           mark = kbdMark;
      }


   if ((menuData -> itemTypes[item]) == XrSTRING)
   {

      if (mode)
      {
        foreGround = menuData -> meBGColor;
        backGround = menuData -> meFGColor;
      }
      else
      {
        foreGround = menuData -> meFGColor;
        backGround = menuData -> meBGColor;
      }
              
      XPixSet(menuEdit -> editorWindowId, 
              menuData -> highlightStart,
              menuData -> itemPosy[item],
              menuData -> highlightLength,
              menuData -> stringHeight,
              backGround);

      XText (menuEdit -> editorWindowId, 
                    menuData -> itemPosx,
                    menuData -> itemPosy[item],
                    menuData -> menuStrings[item],
                    menuData -> stringLengths[item],
                    menuData -> menuTextInfo.fontInfo -> id,
                    foreGround, backGround
                    );

      if (mark)
      {
         XText(menuEdit -> editorWindowId, 
                       menuData -> kbdeqPosx,
                       menuData -> itemPosy[item],
                       mark,
                       2,
                       menuData -> menuTextInfo.fontInfo -> id,
                       foreGround,
                       backGround);
       }
      }
}




/*************************************<->*************************************
 *
 *  menuState()
 *
 *   Description:
 *   -----------
 *    This procedure gives the current state of the cursor in a menu.
 *
 *************************************<->***********************************/


static
INT32
menuState(menuEdit, currentArea, currentItem, newArea, newItem, change)
xrEditor    * menuEdit;
INT32         currentArea;
INT32         currentItem;
INT32       * newArea;
register INT32       * newItem;
register INT32       * change;

{
   Window         subw;
   INT32          cursorX, cursorY, menuItem;
   POINT          cursorPt;
   register xrMenuData      * menuData;
   register INT32          i;


   menuData = (xrMenuData *) (menuEdit -> editorData);

   menuItem = TRUE;
   XQueryMouse(menuEdit -> editorWindowId, &cursorX, &cursorY, &subw);
   XrSetPt(&cursorPt, cursorX, cursorY);
   if(!(XrPtInRect(&cursorPt, &menuEdit -> editorRect)))
   {
      menuItem = FALSE;
      * newArea = XrOUTSIDEMENU;
      * newItem = -1;
   }

   if (cursorY < menuData -> itemPosy[0])
   {
      menuItem = FALSE;
      * newArea = XrNULLAREA;
      * newItem = -1;
   }

   /*  The locator is over an item, determine which one, and   */
   /*  then if it is in the popup area of an item.              */
   
   if (menuItem)
   {
      i = (menuData -> numItems) - 1;
      while ( cursorY < menuData -> itemPosy[i])
         i--;

      * newItem = i;

      if ((menuData -> itemTypes[i]) == XrSTRING)
      {
         if (cursorX >= menuData -> popupPosx)
            * newArea = XrPOPUPAREA;
         else
            * newArea = XrITEMAREA;
      }
      else
      {
         * newArea = XrUITEMAREA;
      }
   }

   if ((*newArea != currentArea) && (*newItem != currentItem))
   {
     *change = XrBOTHCHANGE;
     return(TRUE);
   }

   if (*newArea != currentArea)
   {
      *change = XrAREACHANGE;
      return(TRUE);
   }

   if (*newItem != currentItem)
   {
      *change = XrITEMCHANGE;
      return(TRUE);
   }

   *change = XrNOCHANGE;
   return(TRUE);
     

}



