/*
 *	$Source: /u1/Xr/src/Xrlib/Editor/RCS/TitleBar.c,v $
 *	$Header: TitleBar.c,v 1.1 86/12/17 09:06:08 swick Exp $
 */

#ifndef lint
static char *rcsid_TitleBar_c = "$Header: TitleBar.c,v 1.1 86/12/17 09:06:08 swick Exp $";
#endif	lint


#include <Xr/xr-copyright.h>

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

static char rcsid[] = "$Header: TitleBar.c,v 1.1 86/12/17 09:06:08 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        TitleBar.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **         Source code for the X-ray TitleBar field editor.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	TitleBar.c,v $
 * Revision 1.1  86/12/17  09:06:08  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:29:23  08:29:23  fred ()
 * Final QA Release
 * 
 * Revision 6.0  86/11/10  15:37:54  15:37:54  fred ()
 * QA #2 release
 * 
 * Revision 5.3  86/11/07  14:24:59  14:24:59  fred ()
 * Added new copyright message.
 * 
 * Revision 5.2  86/11/04  09:04:28  09:04:28  fred ()
 * Fixed a bug dealing with the generation of a fake select up event.
 * The detail bits were being masked off.
 * 
 * Revision 5.1  86/10/30  13:32:26  13:32:26  fred ()
 * Changed input processing routine to not swallow select up events.
 * 
 * Revision 5.0  86/10/28  08:38:41  08:38:41  fred ()
 * QA #1.1 release
 * 
 * Revision 4.2  86/10/23  09:11:37  09:11:37  fred ()
 * Removed unused variables.
 * 
 * Revision 4.1  86/10/22  08:23:26  08:23:26  fred ()
 * Filled in procedure headers.
 * 
 * Revision 4.0  86/10/20  12:15:30  12:15:30  fred ()
 * QA #1 release
 * 
 * Revision 3.4  86/10/16  09:21:43  09:21:43  fred ()
 * Performance enhanced: added use of register variables.
 * 
 * Revision 3.3  86/10/13  10:10:59  10:10:59  fred ()
 * Added use of the default tile, if needed.
 * 
 * Revision 3.2  86/10/09  07:56:58  07:56:58  fred ()
 * Added default color check to create routine.
 * 
 * Revision 3.1  86/10/07  16:08:43  16:08:43  fred ()
 * Added check for invalid rectangle height.
 * 
 * Revision 3.0  86/10/02  16:03:21  16:03:21  fred ()
 * Alpha release set to 3.0
 * 
 * Revision 2.2  86/09/22  13:12:31  13:12:31  fred ()
 * Added calls to XrEditorGroup().
 * 
 * Revision 2.1  86/09/19  07:13:56  07:13:56  fred ()
 * Added a check for XrVISIBLE before doing any drawing.
 * 
 * Revision 2.0  86/09/16  08:13:31  08:13:31  fred ()
 * Updated input processing routine to use new SELECT strategy.
 * 
 * Revision 1.3  86/09/16  05:51:49  05:51:49  fred ()
 * Modified to swallow a select up event.
 * 
 * Revision 1.2  86/09/10  11:49:55  11:49:55  fred ()
 * Fixed bug in createTitleBar(), where if the XMakePixmap()
 * request failed, it automatically freed the title string
 * memory, even if no memory was allocated.
 * 
 * Revision 1.1  86/09/03  13:59:00  13:59:00  fred ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



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

extern INT32 createTitleBar();
extern INT32 drawTitleBar();
extern INT32 processTitleBar();
extern INT32 tbFreeMemory();


/*
 * This array contains the x offsets used to draw the vertical lines
 * in the titlebar header.
 */
static INT16 xOffsets[] = {1, 3, 5, 8, 12, 17, -1, -3, -5, -8, -12, -17};



/*************************************<->*************************************
 *
 *  xrEditor *
 *  XrTitleBar (titleBar, message, data)
 * 
 *     xrEditor * titleBar;
 *     INT32      message;
 *     INT8     * data;
 *
 *   Description:
 *   -----------
 *     This is the main entry point and message handler for the titlebar
 *     field editor.  It takes all message request, and passes them onto
 *     the appropriate handler; invalid messages will fail and return an
 *     error.
 *
 *
 *   Inputs:
 *   ------
 *     titleBar = For all messages but MSG_NEW and MSG_SIZE, this contains
 *                the instance pointer for the instance being acted upon.
 *
 *     message = This indicates which action the editor should perform.
 *
 *     data = This is the message specific data.  It's usage depends upon
 *            the 'message' parameter, and may be a scalar or a pointer.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion of a command, the instance pointer
 *          is returned; additional information may be returned by means
 *          of the 'data' parameter.
 *
 *     Upon failure, NULL is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   _MsgNew()           [MsgCommon.c]
 *   _MsgFree()          [MsgCommon.c]
 *   _MsgGetState()      [MsgCommon.c]
 *   _MsgSetState()      [MsgCommon.c]
 *   _MsgRedraw()        [MsgCommon.c]
 *   _MsgEdit()          [MsgCommon.c]
 *   XrCopyRect()        [calc.c]
 *   XrOffsetRect()      [calc.c]
 *   _XrMakeInvisible()  [editorUtil.c]
 *   XrEditorGroup()     [group.c]
 *   createTitleBar()
 *   drawTitleBar()
 *   sizeTitleBar()
 *
 *************************************<->***********************************/

xrEditor *
XrTitleBar (titleBar, message, data)

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

{
   /* Determine the action being requested */
   switch (message)
   {
      case MSG_NEW:
      {
           /*
            * Create a new titlebar instance.
            * The only parameter of interest is the 'data' parameter,
            * which is a pointer to a filled instance of the
            * xrTitleBarInfo structure.
            */
           return ((xrEditor *) _MsgNew (titleBar, data,
                                         sizeof(xrTitleBarData),
                                         createTitleBar, drawTitleBar,
                                         tbFreeMemory, XrTitleBar, NULL));
      }

      case MSG_FREE:
      {
           /*
            * Destroy the specified titlebar instance.
            * The 'titleBar' parameter specifies the instance to
            * be destroyed; the 'data' parameter is unused.
            */
           return ((xrEditor *) _MsgFree (titleBar, tbFreeMemory));
      }

      case MSG_GETSTATE:
      {
           /*
            * Return the settings of the state flags for the specified
            * titlebar instance.  The 'titleBar' parameter specifies the
            * instance to be queried, while the 'data' parameter must
            * point to an INT8 value, into which the state flags will be
            * placed.
            */
           return ((xrEditor *) _MsgGetState (titleBar, data));
      }

      case MSG_SETSTATE:
      {
           /*
            * Change the state flag settings for the specified titlebar
            * instance.  The 'titleBar' parameter specifies the instance
            * to be modified, and the 'data' parameter is interpreted as
            * an INT8 value, containing the new state flag settings.
            */
           return ((xrEditor *) _MsgSetState (titleBar, data,
                                              drawTitleBar, NULL));
      }

      case MSG_MINSIZE:
      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 'data'
            * parameter must point to a partially filled out instance
            * of the 'xrTitleBarInfo' structure; upon completion, the
            * 'editorRect' field of the 'info' structure will be filled.
	    */
           xrTitleBarInfo *tbInfoPtr = (xrTitleBarInfo *)data;

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

           return ((xrEditor *) TRUE);
      }

      case MSG_REDRAW:
      {
         /*
          * Redraw a titlebar instance.
          * The 'titleBar' parameter specifies the instance to be redrawn,
          * while the 'data' parameter is interpreted as an INT32 value,
          * specifying the type of redraw to perform.
          */
         return ((xrEditor *) _MsgRedraw (titleBar, data, drawTitleBar, NULL));
      }

      case MSG_MOVE:
      {
         /*
          * Relocate a titlebar instance to a new location.
          * The 'titleBar' parameter specifies the isntance to be moved,
          * while the 'data' parameter must point to a POINT structure,
          * containing the new editor rectangle origin.
          */
         register xrTitleBarData * tbDataPtr;
                  RECTANGLE        workRect;
                  POINT          * ptPtr = (POINT *) data;
         register INT16            xDelta;
         register INT16            yDelta;

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

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

         /* Relocate each component */
         XrOffsetRect (&titleBar->editorRect, xDelta, yDelta);
         if (tbDataPtr->titleName)
         {
            XrOffsetRect (&tbDataPtr->titleRect, xDelta, yDelta);
            tbDataPtr->titleLoc.x += xDelta;
            tbDataPtr->titleLoc.y += yDelta;
         }
         if (tbDataPtr->gadgetIcon1)
         {
            XrOffsetRect (&tbDataPtr->gadgetRect1, xDelta, yDelta);
            tbDataPtr->iconLoc1.x += xDelta;
            tbDataPtr->iconLoc1.y += yDelta;
         }
         if (tbDataPtr->gadgetIcon2)
         {
            XrOffsetRect (&tbDataPtr->gadgetRect2, xDelta, yDelta);
            tbDataPtr->iconLoc2.x += xDelta;
            tbDataPtr->iconLoc2.y += yDelta;
         }

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

            /* Redisplay the instance */
            drawTitleBar (titleBar, NULL);
         }

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

      case MSG_RESIZE:
      {
         /*
          * Resize an existing titlebar instance.
          * The 'titleBar' parameter specifies the instance to be
          * resized, while the 'data' parameter must point to a
          * RECTANGLE structure, containing the new editor rectangle.
          */
         register xrTitleBarData * tbDataPtr;
                  xrTitleBarInfo   tbInfo;
                  RECTANGLE        workRect;

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

         /* Create a pseudo Info structure */
         tbDataPtr = (xrTitleBarData *) titleBar->editorData;
         XrCopyRect (&titleBar->editorRect, &workRect);
         XrCopyRect ((RECTANGLE *) data, &tbInfo.editorRect);
         tbInfo.editorFont = tbDataPtr->titleFont.fontInfo;
         tbInfo.editorWindowId = titleBar->editorWindowId;
         tbInfo.titleName = tbDataPtr->titleName;
         tbInfo.gadgetIcon1 = tbDataPtr->gadgetIcon1;
         tbInfo.gadgetIcon2 = tbDataPtr->gadgetIcon2;

         if (createTitleBar (tbDataPtr, &tbInfo, MSG_RESIZE)==FALSE)
            /* xrErrno is set by createTitleBar() */
            return ((xrEditor *) NULL);

         /* Save the new rectangle definition */
         XrCopyRect (&tbInfo.editorRect, &titleBar->editorRect);

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

            /* Redisplay the instance */
            drawTitleBar (titleBar, NULL);
         }

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

      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 'data' parameter must point
          * to the event which is to be processed.
	  */
         return ((xrEditor *) _MsgEdit (titleBar, data,
                                        processTitleBar, XrTITLEBAR));
      }

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

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


/*************************************<->*************************************
 *
 *  INT32
 *  tbFreeMemory (tbDataPtr)
 *
 *     xrTitleBarData * tbDataPtr;
 *
 *   Description:
 *   -----------
 *     This routine is called both when an existing instance is freed,
 *     and when a MSG_NEW request fails after createTitleBar() has
 *     been called.  It will free up all resources which createTitleBar()
 *     allocated for the instance.
 *
 *
 *   Inputs:
 *   ------
 *     tbDataPtr = Points to the instance's internal 'data' structure.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   XFreePixmap()  [libX.a]
 *
 *************************************<->***********************************/

static
INT32
tbFreeMemory (tbDataPtr)

   xrTitleBarData * tbDataPtr;

{
   if (tbDataPtr->titleTileId != xrDefaultTile)
      XFreePixmap (tbDataPtr->titleTileId);
   if (tbDataPtr->titleName)
      (*xrFree) (tbDataPtr->titleName);
}


/*************************************<->*************************************
 *
 *  INT32
 *  sizeTitleBar (tbInfoPtr, rectPtr, sizeType)
 *
 *     xrTitleBarInto * tbInfoPtr;
 *     RECTANGLE      * rectPtr;
 *     INT32            sizeType
 *
 *   Description:
 *   -----------
 *     This routine calculates the size of the rectangle needed to contain
 *     the hypothetical titlebar instance described by the 'tbInfoPtr'
 *     structure.  If 'sizeType' is set to MSG_SIZE, then the rectangle
 *     will be the minimal rectangle needed to contain the gadget boxes and
 *     the complete title string.
 *     If 'sizeType' is set to MSG_MINSIZE, then the rectangle will be
 *     the minimal rectangle needed to contain the gadget boxes and only
 *     the first letter within the title string.
 *
 *
 *   Inputs:
 *   ------
 *     tbInfoPtr = Points to a partially filled out instance of the
 *                 xrTitleBarInfo structure, which contains the description
 *                 of the hypothetical instance being sized.
 *
 *     rectPtr = Points to a RECTANGLE structure, into which the rectangle
 *               definition will be placed.
 *
 *     sizeType = Can be set to MSG_SIZE or MSG_MINSIZE, as described above.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE is returned, and the editor
 *          rectangle is returned.
 *
 *     Upon failure, FALSE is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   _XrTextInfo()  [textUtil.c]
 *
 *************************************<->***********************************/

static
INT32
sizeTitleBar (tbInfoPtr, rectPtr, sizeType)

   register xrTitleBarInfo  * tbInfoPtr;
   register RECTANGLE       * rectPtr;
            INT32             sizeType;

{
   INT8       * titleName = tbInfoPtr->titleName;
   INT8       * gadget1   = tbInfoPtr->gadgetIcon1;
   INT8       * gadget2   = tbInfoPtr->gadgetIcon2;
   INT16        width;
   FontInfo   * fontPtr;
   xrTextInfo   fontData;
   INT16        tbSize;

   /* Verify the titleType parameter; empty titlebars are not allowed */
   if ((!titleName || !strlen(titleName)) && (!gadget1 || !strlen(gadget1)) &&
      (!gadget2 || !strlen(gadget2)))
   {
      xrErrno = XrINVALIDPARM;
      return (FALSE);
   }
 
   /* Get a pointer to the font description */
   fontPtr= (tbInfoPtr->editorFont) ? tbInfoPtr->editorFont : xrBaseFontInfo;
   _XrTextInfo (fontPtr, &fontData);

   /* Set the rectangle coordinates */
   rectPtr->x = 0;
   rectPtr->y = 0;

   /*
    * height = 1 pixel of border + leading/2 of padding +
    *          2 more pixels of padding (for gadget boxes) +
    *          the font height + leading/2 of padding +
    *          2 more pixels of padding (for gadget boxes) +
    *          1 pixel of border.
    */
   rectPtr->height = 1 + fontData.leading + fontData.ascent +
                      fontData.descent + 2 + 1 + 2;

   /* Don't allow the title bar height to be less than 11 */
   if (rectPtr->height < XrTB_MIN_HEIGHT)
      rectPtr->height = XrTB_MIN_HEIGHT;

   /* Calculate the width of the titlebar */
   /* Take into account the 2 pixels of border */
   width = 2;

   if (titleName)
   {
      if (sizeType == MSG_SIZE)
         tbSize = XrStringWidth (fontPtr, titleName, XrNULLTERMINATED, 0, 0);
      else
         tbSize = XrStringWidth (fontPtr, titleName, 1, 0, 0);

      /*
       * width += 5 pixels of padding on each end +
       *          23 pixels of title border on each side +
       *          width of the title string.
       */
      width += 5 + 23 + tbSize + 23 + 5;
   }

   if (gadget1 || gadget2)
   {
      if ((sizeType == MSG_MINSIZE) && !titleName)
         width += 5 + 4 + 5 + (2*(fontData.ascent + fontData.descent)) + 4 + 5;
      else
         width += 5 + 4 + (2*(fontData.ascent + fontData.descent)) + 4 + 5;
   }

   rectPtr->width = width;

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  INT32
 *  createTitleBar (tbDataPtr, tbInfoPtr, message)
 *
 *     xrTitleBarData * tbDataPtr;
 *     xrTitleBarInfo * tbInfoPtr;
 *     INT32            message;
 *
 *   Description:
 *   -----------
 *   if (message == MSG_NEW)
 *   This routine is responsible for creating a new titlebar instance.
 *   The description of the new instance is contained within the structure
 *   pointed to by the 'tbInfoPtr' parameter.  Besides allocating the
 *   resources needed for the new instance, this procedure will also fill
 *   in the structure pointed to by the 'tbDataPtr' parameter with the
 *   state information for the new instance.
 *
 *   if (message == MSG_RESIZE)
 *   This routine will take the information contained within the 
 *   'tbInfoPtr' structure, and will recalculate the location of each
 *   component within an existing titlebar instance, to match the new
 *   data.  This will do no resource allocation.
 *
 *
 *   Inputs:
 *   ------
 *     tbDataPtr = Points to the 'data' structure for the instance being
 *                 created or resized.
 *
 *     tbInfoPtr = Points to the 'info' structure, which describes how
 *                 the instance is to be laid out.
 *
 *     message = This can be set to MSG_NEW or MSG_RESIZE.
 * 
 *   Outputs:
 *   -------
 *     Upon successful completion, TRUE is returned, and the 'tbDataPtr'
 *          structure is filled out.
 *
 *     Upon failure, FALSE is returned, and xrErrno is set.
 *
 *   Procedures Called
 *   -----------------
 *   XQueryWindow()   [libX.a]
 *   XMakePixmap()    [libX.a]
 *   XrCopyRect()     [calc.c]
 *   _XrTextInfo()    [textUtil.c]
 *   XrStringWidth()  [utilities.c]
 *   XrResource()     [resource.c]
 *   sizeTitleBar()
 *
 *************************************<->***********************************/

static
INT32
createTitleBar (tbDataPtr, tbInfoPtr, message)

   register xrTitleBarData * tbDataPtr;
   register xrTitleBarInfo * tbInfoPtr;
            INT32            message;

{
            RECTANGLE      * editorRect = &tbInfoPtr->editorRect;
   register xrTextInfo     * fontPtr    = &tbDataPtr->titleFont;
            INT8           * titleName  = tbInfoPtr->titleName;
            INT8           * gadget1    = tbInfoPtr->gadgetIcon1;
            INT8           * gadget2    = tbInfoPtr->gadgetIcon2;
            WindowInfo       winfo;
            RECTANGLE        workRect, tempRect;
            INT16            regionWidth;
            INT16            stringWidth;
            INT32            i;
            xrResourceInfo   bitmapInfo;

   /* Verify the titleType parameter; empty titlebars are not allowed */
   if ((!titleName || !strlen(titleName)) && (!gadget1 || !strlen(gadget1)) &&
      (!gadget2 || !strlen(gadget2)))
   {
      xrErrno = XrINVALIDPARM;
      return (FALSE);
   }

   /*
    * If the application has set the editorRect to (0,0,0,0), then
    * calculate the editorRect, such that the titlebar will run the
    * full extend of the top of the window; otherwise, make sure the
    * editorRect specified is large enough to hold the instance.
    */
   if ((editorRect->x == 0) && (editorRect->y == 0) &&
       (editorRect->height == 0) && (editorRect->width == 0))
   {
      /* Calculate the rectangle for the application */
      sizeTitleBar (tbInfoPtr, editorRect, MSG_SIZE);
      if (XQueryWindow (tbInfoPtr->editorWindowId, &winfo) == 0)
      {
         xrErrno = XrXCALLFAILED;
         return (FALSE);
      }
      editorRect->width = winfo.width;
   }
   else
   {
      /* Make sure the editorRect is large enough to hold the instance */
      sizeTitleBar (tbInfoPtr, &workRect, MSG_MINSIZE);
      XrCopyRect (editorRect, &tempRect);
      if ((tempRect.height != workRect.height) ||
          (tempRect.width < workRect.width))
      {
         xrErrno = XrINVALIDRECT;
         return (FALSE);
      }
   }

   /* 
    * Now that we know all of the parameters are valid, we can start
    * filling in the structure pointed to by 'tbDataPtr'.
    */

   if (message == MSG_NEW)
   {
      /* Copy some of the information from the 'tbInfoPtr' structure */
      if (tbInfoPtr->editorFont)
         _XrTextInfo (tbInfoPtr->editorFont, fontPtr);
      else
         _XrTextInfo (xrBaseFontInfo, fontPtr);

      tbDataPtr->tbFGColor = (tbInfoPtr->editorFGColor == -1) ?
                 xrForegroundColor : tbInfoPtr->editorFGColor;
      tbDataPtr->tbBGColor = (tbInfoPtr->editorBGColor == -1) ?
                 xrBackgroundColor : tbInfoPtr->editorBGColor;
      tbDataPtr->gadgetIcon1 = tbInfoPtr->gadgetIcon1;
      tbDataPtr->gadgetIcon2 = tbInfoPtr->gadgetIcon2;
   }

   /*
    * Determine the size of gadget box 1 rectangle
    *
    *   x origin = left of editorRect + 1 pixel ER border + 5 pixels padding.
    *   y origin = top of editorRect + 1 pixel ER border + leading/2 padding.
    *   width    = font height + 2 pixels padding + 2 pixels of border.
    *   height   = font height + 2 pixels padding + 2 pixels of border.
    */
   tempRect.x = editorRect->x + 1 + 5;
   tempRect.y = editorRect->y + 1 + (fontPtr->leading >> 1);
   tempRect.width = fontPtr->ascent + fontPtr->descent + 2 + 2;
   tempRect.height =fontPtr->ascent + fontPtr->descent + 2 + 2;
   XrCopyRect (&tempRect, &tbDataPtr->gadgetRect1);

   /*
    * Determine the size of gadget box 2 rectangle
    *
    *   x origin = right of editorRect - 1 pixel ER border - 5 pixels padding -
    *              width of gadget box - 2 pixels of border - 2 pixels of
    *              padding + 1 adjustment pixel.
    *   y origin = top of editorRect + 1 pixel border + leading/2 padding.
    *   width    = font height + 2 pixels padding + 2 pixels of border.
    *   height   = font height + 2 pixels padding + 2 pixels of border.
    */
   tempRect.x = (editorRect->x + editorRect->width - 1) - 1 - 5
                - (fontPtr->ascent + fontPtr->descent) - 2 - 2 + 1;
   tempRect.y = editorRect->y + 1 + (fontPtr->leading >> 1);
   tempRect.width = fontPtr->ascent + fontPtr->descent + 2 + 2;
   tempRect.height = fontPtr->ascent + fontPtr->descent + 2 + 2;
   XrCopyRect (&tempRect, &tbDataPtr->gadgetRect2);

   /*
    * Before determining the titleRect, determine how much space is
    * available for the title string, and then determine how much of
    * the title string will fit.
    */
   if (titleName)
   {
      if (gadget1 || gadget2)
         /*
          * width = width between the two gadget boxes
          *         - 5 pixels padding between gadgets and title borders
          *         - 23 pixels of title border on each end.
          */
         regionWidth = tbDataPtr->gadgetRect2.x - 1 - 
                   (tbDataPtr->gadgetRect1.x + tbDataPtr->gadgetRect1.width - 1)
                   - 10 - 46;
      else
         /*
          * width = width of editorRect - 2 pixels of border
          *         - 5 pixels padding on each end
          *         - 23 pixels of title border on each end.
          */
         regionWidth = tbInfoPtr->editorRect.width - 10 - 46 - 2;

      /* Allocate some space for the title string */
      if (message == MSG_NEW)
      {
         if ((tbDataPtr->titleName =(char *)(*xrMalloc)(strlen(titleName) + 1)) 
             == NULL)
         {
            xrErrno = XrOUTOFMEM;
            return (FALSE);
         }

         /* Copy over the title string to the new buffer */
         strcpy (tbDataPtr->titleName, titleName);
      }

      /* Determine how much of the string we can use */
      titleName = tbDataPtr->titleName;
      stringWidth = XrStringWidth (fontPtr->fontInfo, titleName,
                    XrNULLTERMINATED, 0, 0);
      for (i = strlen(titleName); i > 0; i--)
      {
         stringWidth = XrStringWidth (fontPtr->fontInfo, titleName,
                                      i, 0, 0);
         if (stringWidth <= regionWidth)
            break;
      }
      tbDataPtr->titleLen = i;

      /* Now, we can determine the size of the title string rectangle */
      tempRect.x = editorRect->x + (editorRect->width >> 1) - 
                   (stringWidth>>1) - 23;
      tempRect.y = editorRect->y;
      tempRect.width = 23 + stringWidth + 23;
      tempRect.height = editorRect->height;
      XrCopyRect (&tempRect, &tbDataPtr->titleRect);

      /* Determine the pen position for the title string */
      tbDataPtr->titleLoc.x = tempRect.x + 23;
      tbDataPtr->titleLoc.y = editorRect->y + (fontPtr->leading >> 1) + 3; 
                              /* + fontPtr->ascent ; */
   }
   else
      tbDataPtr->titleName = NULL;

   /* Lastly, determine the pen position for the icons in the gadget boxes */
   if (gadget1)
   {
      stringWidth = XrStringWidth (fontPtr->fontInfo, tbDataPtr->gadgetIcon1,
                                   1, 0, 0);
      tbDataPtr->iconLoc1.x = tbDataPtr->gadgetRect1.x - (stringWidth >> 1) +
                   (tbDataPtr->gadgetRect1.width >> 1);
      tbDataPtr->iconLoc1.y = tbDataPtr->gadgetRect1.y + 2; 
                              /* fontPtr->ascent ; */
   }

   if (gadget2)
   {
      stringWidth = XrStringWidth (fontPtr->fontInfo, tbDataPtr->gadgetIcon2,
                                1, 0, 0);
      tbDataPtr->iconLoc2.x = tbDataPtr->gadgetRect2.x - (stringWidth >> 1) +
                      (tbDataPtr->gadgetRect2.width >> 1);
      tbDataPtr->iconLoc2.y = tbDataPtr->gadgetRect2.y + 2; 
                              /* fontPtr->ascent ; */
   }

   /* Create the 50% tile used as the background for the titlebar */
   if (message == MSG_NEW)
   {
      if ((tbInfoPtr->editorFGColor == -1) &&
          (tbInfoPtr->editorBGColor == -1))
      {
         /* Use the default 50% tile */
         tbDataPtr->titleTileId = xrDefaultTile;
      }
      else
      {
         bitmapInfo.resourceType = XrTYPE_BITMAPID;
         bitmapInfo.resourceId = XrPERCENT50;
         if ((XrResource (MSG_FIND, &bitmapInfo) == FALSE) ||
            ((tbDataPtr->titleTileId = 
             XMakePixmap (((xrBitmapId *)bitmapInfo.resourceObject)->bitmapId,
                                       tbDataPtr->tbFGColor,
                                       tbDataPtr->tbBGColor)) == 0))
         {
            if (tbDataPtr->titleName)
               (*xrFree) (tbDataPtr->titleName);
            xrErrno = XrXCALLFAILED;
            return (FALSE);
         }
      }
   }

   return (TRUE);
}


/*************************************<->*************************************
 *
 *  INT32
 *  drawTitleBar (titleBar, drawOption)
 *
 *     xrEditor * titleBar;
 *     INT32      drawOption;
 *
 *   Description:
 *   -----------
 *     This routine will display a titlebar instance.
 *
 *
 *   Inputs:
 *   ------
 *     titleBar = Points to the editor instance structure.
 *
 *     drawOption = Not used; this parameter is present so that _MsgNew()
 *                  can call this procedure.
 * 
 *   Outputs:
 *   -------
 *
 *   Procedures Called
 *   -----------------
 *   _XrMakeInvisible()        [editorUtil.c]
 *   _XrInitEditorGCs()        [gcUtil.c]
 *   _XrCopyGC()               [gcUtil.c]
 *   _XrChangeGC()             [gcUtil.c]
 *   _XrBorderFillRectangle()  [rectUtil.c]
 *   _XrFillRectangle()        [rectUtil.c]
 *   _XrLine()                 [rectUtil.c]
 *   _XrImageText8()           [textUtil.c]
 *
 *************************************<->***********************************/

static
INT32
drawTitleBar (titleBar, drawOption)

   register xrEditor * titleBar;
            INT32      drawOption;

{
   register xrTitleBarData  * tbDataPtr;
            INT8              sensitive;
   register INT32             i;
            INT16             x1, y1, x2, y2;
   register Window            windowId = titleBar->editorWindowId;
            INT32             changeList[21];
            INT32             changeMask;

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

   /* Initialize the graphic contexts we will be using */
   _XrInitEditorGCs (tbDataPtr->tbFGColor, tbDataPtr->tbBGColor,
                     tbDataPtr->titleFont.fontInfo->id);

   /*
    * Initialize another graphics context, which we will use
    * to tile fill the background area within a sensitive titlebar.
    */
   changeList[XrFILLSTYLEVAL] = Tiled;
   changeList[XrTILEVAL] = tbDataPtr->titleTileId;
   changeMask = (XrFILLSTYLE | XrTILE);
   _XrCopyGC (xrDefaultGC, xrEditorGC3);
   _XrChangeGC (xrEditorGC3, changeMask, changeList);

   sensitive = (titleBar->editorState & XrSENSITIVE) ? TRUE : FALSE;

   /* Draw the titleBar instance */
   if (! sensitive)
   {
      /*
       * The titlebar instance is insensitive, therefore
       * draw a bordered rectangle, filled with the background color 
       * and then display the title string.
       */
      _XrBorderFillRectangle (windowId, xrEditorGC1, xrEditorGC2,
                              &titleBar->editorRect);

      /* Display just the title string */
      if (tbDataPtr->titleName)
      {
         _XrImageText8 (windowId, xrEditorGC1, tbDataPtr->titleLen,
                        tbDataPtr->titleLoc.x, tbDataPtr->titleLoc.y,
                        tbDataPtr->titleName);
      }
   }
   else
   {
      /* Draw a bordered rectangle, with 50% tile fill */
      _XrBorderFillRectangle (windowId, xrEditorGC1, xrEditorGC3,
                              &titleBar->editorRect);

      if (tbDataPtr->titleName)
      {
         /* Draw the title borders */
         _XrFillRectangle (windowId, xrEditorGC1, &tbDataPtr->titleRect);

         /* Draw the highlight lines */
         y1 = tbDataPtr->titleRect.y + 1;
         y2 = tbDataPtr->titleRect.y + tbDataPtr->titleRect.height - 2;

         for (i = 0; i < 12; i++)
         {
            if (i < 6)
               x1 = tbDataPtr->titleRect.x + xOffsets[i];
            else
               x1 = (tbDataPtr->titleRect.x +
                    tbDataPtr->titleRect.width - 1) + xOffsets[i];
            x2 = x1;
            _XrLine (windowId, xrEditorGC2, x1, y1, x2, y2);
         }
   
         /* Display the title string */
         _XrImageText8 (windowId, xrEditorGC2, tbDataPtr->titleLen,
                        tbDataPtr->titleLoc.x, tbDataPtr->titleLoc.y,
                        tbDataPtr->titleName);
      }

      /* Display gadget box 1 */
      if (tbDataPtr->gadgetIcon1)
      {
         /* Draw a bordered gadget box */
         _XrBorderFillRectangle (windowId, xrEditorGC1, xrEditorGC2,
                                 &tbDataPtr->gadgetRect1);

         /* Display the icon character */
         _XrImageText8 (windowId, xrEditorGC1, 1, tbDataPtr->iconLoc1.x,
                        tbDataPtr->iconLoc1.y, tbDataPtr->gadgetIcon1);
      }

      /* Display gadget box 2 */
      if (tbDataPtr->gadgetIcon2)
      {
         /* Draw a bordered gadget box */
         _XrBorderFillRectangle (windowId, xrEditorGC1, xrEditorGC2,
                                 &tbDataPtr->gadgetRect2);

         /* Display the icon character */
         _XrImageText8 (windowId, xrEditorGC1, 1, tbDataPtr->iconLoc2.x,
                        tbDataPtr->iconLoc2.y, tbDataPtr->gadgetIcon2);
      }

   }
}


/*************************************<->*************************************
 *
 *  INT32
 *  processTitleBar (titleBar, input, returnEvent)
 *
 *     xrEditor     * titleBar;
 *     XButtonEvent * input;
 *     xrEvent      * returnEvent;
 *
 *   Description:
 *   -----------
 *     This is the event processing routine for the titlebar editor.
 *     It takes an event, and determines which of the titlebar components
 *     the select occurred within.  In return, a return event is generated
 *     which will tell the application which components was selected.
 *
 *
 *   Inputs:
 *   ------
 *     titleBar = Instance pointer for the titlebar instance in which the
 *                event occurred.
 *
 *     input = Points to the event to be processed.
 *
 *     returnEvent = Points to a partially filled out X-ray event structure,
 *                   It can be used by this routine when it needs to 
 *                   generate a return event.
 * 
 *   Outputs:
 *   -------
 *     Although a value is not directly returned, an input event will be
 *         generated, telling the application which part of the instance 
 *         was selected.
 *
 *   Procedures Called
 *   -----------------
 *   XrSetPt()     [calc.c]
 *   XrPtInRect()  [calc.c]
 *
 *************************************<->***********************************/

static
INT32
processTitleBar (titleBar, input, returnEvent)

   xrEditor     * titleBar;
   XButtonEvent * input;
   xrEvent      * returnEvent;

{
   register xrTitleBarData  * tbDataPtr;
            POINT             spritePt;
            xrWindowEvent     windowEvent;
            XButtonEvent      selectUp;

   tbDataPtr = (xrTitleBarData *) titleBar->editorData;
   XrSetPt (&spritePt, input->x, input->y);
   returnEvent->value1 = NULL;

   /*
    * Determine which region was selected 
    */

   /* Check for a select in gadget box 1 region */
   if ((tbDataPtr->gadgetIcon1) &&
       XrPtInRect (&spritePt, &(tbDataPtr->gadgetRect1)))
   {
      returnEvent->value1 = XrGADGET_BOX1;
   }

   /* Check for a select in gadget box 2 region */
   else if ((tbDataPtr->gadgetIcon2) &&
       XrPtInRect (&spritePt, &(tbDataPtr->gadgetRect2)))
   {
      returnEvent->value1 = XrGADGET_BOX2;
   }

   /* Check for a select in the title string region */
   else if ((tbDataPtr->titleName) &&
       XrPtInRect (&spritePt, &(tbDataPtr->titleRect)))
   {
      returnEvent->value1 = XrTITLE_REGION;
   }

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