/****************************************************************************
**
**  Name:  ldlgbox.c
**
**  Description:
**     Dynamically create the Tools Select dialog box.  Uses the global
**     toolNameTbl[] table.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/arcppc/l695/ldlgbox.c_v  $
** 
**    Rev 1.0   17 Jan 1997 09:21:10   kevin
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:32:10   gene
** Initial revision.
** 
**    Rev 1.3   03 Aug 1993 17:36:52   nghia
** Removed LERR_xxxx to use standard error codes.
** 
**    Rev 1.2   22 Jul 1993 16:21:26   ron
** pprs 8378, 8379, 8380: select compiler used dialog needs less whitespace,
** help button, shortcut keys.
** 
**    Rev 1.1   12 Apr 1993 18:02:10   nghia
** Added space between Compiler and Used.
** Adjusted the vertical space between dialog items.
** 
**    Rev 1.0   08 Mar 1993 10:12:16   nghia
** Initial revision.
**
**  $Header:   S:/tbird/arcppc/l695/ldlgbox.c_v   1.0   17 Jan 1997 09:21:10   kevin  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <mem.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef __ERR__
#include "err.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef __LPROFILE__
#include "lprofile.h"
#endif;

#ifndef _HLPENTRY_
#include "hlpentry.h"
#endif;


/* IMPORTANT:
** This module must be compiled with BYTE aligment.
** Only support Borland compiler for now. Any other compiler needs to check
** for options to compile with BYTE alignment.
*/
#ifdef __BORLANDC__
#pragma option -a-
#endif
                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

/* DLGTEMPLATE & DLGITEMTEMPLATE structs and their pointers */
typedef struct  {
   S32   style;            // Dialog style flags
   BYTE  nItems;           // Number of items in dialog.
   S16   x,y,cx,cy;        // Position and size of dialog box
   // CHAR  menuName[];    // Actual length is variable and dynamically allocate
   // CHAR  className[];   // ditto
   // CHAR  CaptionText[]; // ditto
} DLGTEMPLATE, FAR *LPDLGTEMPLATE;

typedef struct {
   S16   x, y, cx, cy;     // Position and size of control
   S16   id;               // ID of control
   S32   style;            // Style flags
   // CHAR  className[];   // Dynamically allocate.
   // CHAR  text[];
   // BYTE  extraBytes;
}  DLGITEMTEMPLATE, FAR *LPDLGITEMTEMPLATE;

STATIC U16 nBytesInTemplate = 0;

/* Dialog CAPTION text */
#define DLG_CAPTION "Select Compiler Used"

/* Dialog Styles */
#define DLGBOX_STYLE (WS_VISIBLE | WS_POPUPWINDOW | DS_MODALFRAME | WS_DLGFRAME)
#define DLGITEM_STYLE (WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_AUTORADIOBUTTON | WS_GROUP)
#define DLGBUTTON_STYLE (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP)

/*
** MACRO MakeFarPointer() to use with DLL
** Convert a near pointer "N" to FAR F
*/
// #define MakeFarPointer(N, F) \
//  sizeof(PSTR) == sizeof(LPSTR) ? (LONG)N : MAKELONG((WORD)N, HIWORD((LONG)F)))

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern CHAR *toolNameTbl[MAX_NUM_TOOLS_SUPPORT];
extern U8 numToolsSupport;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
RETCODE SetupDlgTemplate(HANDLE *hDlgTemplate, S32 iStyle, S16 ix, S16 iy, S16 icx, S16 icy,
   LPSTR menuName, LPSTR className, LPSTR captionText);

RETCODE AddControlToDlg(HANDLE *hDlgTemplate, S32 iStyle, S16 ix, S16 iy, S16 icx,
S16 icy, S16 controlID, LPSTR className, LPSTR text, BYTE dataBytes, LPBYTE data);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/* Dialog box units */
#define HSPACE cx
#define VSPACE cy
#define LINE_HEIGHT 1.75*cy
#define LINE_TEXT_HEIGHT  1.5*cy
#define IDD_ITEM(I) I+IDD_UNKNOWN
#define MAX_LETTERS 26
#define MAX_TOOLS 16
#define MAX_TOOL_NAMELEN 16
static CHAR toolStrings[MAX_TOOLS][MAX_TOOL_NAMELEN];

/******************************************************************************
**
**  CreateDlgTemplate
**
**  Status: CODED | REVIEWED | TESTED
**
**  Description: Create a dialog box with the numToolsSupport checkbox in
**  a global memory block pointed to by the hDlgTemplate variable.  It also
**  compute the size and position of the dialog box automatically.
**
**  Parameters:
**     input:
**        none.
**     output:
**        hDlgTemplate     Handle of a DLGTEMPLATE struct.
**
******************************************************************************/
RETCODE CreateDlgTemplate(HANDLE *hDlgTemplate) {
   RETCODE err;
   S16 cx = 4, cy = 8;   /* character average width & height in dialog units */
   S16 itemTitleX = HSPACE;
   S16 firstItemY = VSPACE;
   S16 buttonY, buttonWidth = 8 * cx;
   S16 y, boxX = 10, boxY = 10;
   S16 x;
   S16 boxWidth, boxHeight, centerX;
   U16 maxTextWidth = 0;
   U16 maxTitleWidth = 0;
   CHAR captionText[] = DLG_CAPTION;
   LOOP_VAR i, j, k;
   U16 nameLen;
   HDC hDC;
   TEXTMETRIC tm;
   HFONT hFont;
   CHAR underlinesUsed[MAX_LETTERS];
   CHAR letter, lletter;
   BOOLEAN underLined;

   /* Setup Windows environment */
   hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
   hFont = GetStockObject(SYSTEM_FONT);
   SelectObject(hDC, hFont);
   GetTextMetrics(hDC, &tm);
   
   for (i = 0; i < MAX_LETTERS; i++) {
      underlinesUsed[i] = 0;
   }
   /* 
    * Compute the maxTextWidth of all items in the toolNameTbl[] 
    * and figure out which character to underline as the accelerator.
    */
   underlinesUsed['o' - 'a'] = TRUE; /* reserve 'o' for &OK */
   underlinesUsed['c' - 'a'] = TRUE; /* reserve 'c' for &Cancel */
   underlinesUsed['h' - 'a'] = TRUE; /* reserve 'h' for &Help */
   for (i = 0; i < numToolsSupport && i < MAX_TOOLS; i++) {
      /* Use GetTextExtent to get system font (logical units)
		width of string */
      maxTitleWidth = max(maxTitleWidth, LOWORD(GetTextExtent(hDC,
         (LPSTR)toolNameTbl[i], (nameLen = lstrlen((LPSTR)toolNameTbl[i])))));
      underLined = FALSE;
      for (j = 0, k = 0; j < nameLen && j < MAX_TOOL_NAMELEN; j++) {
         letter = ((LPSTR)toolNameTbl[i])[j];
         if (!underLined && isalpha(letter)) {
            lletter = tolower(letter);
            if (!underlinesUsed[lletter - 'a']) {
               underlinesUsed[lletter - 'a'] = TRUE;
               toolStrings[i][k++] = '&';
               underLined = TRUE;
            }
         }
         toolStrings[i][k++] = letter;
      }
   }
   /* Include the caption title for the maxTextWidth */
   maxTextWidth = max(maxTitleWidth, LOWORD(GetTextExtent(hDC,
      (LPSTR) captionText, lstrlen((LPSTR)captionText))));

   /* Convert maxTextWidth from logical units to dialog unit */
   maxTextWidth = ceil(((double)maxTextWidth *  (double)cx) /
      (double)tm.tmAveCharWidth);
   DeleteDC(hDC);

   /* Calculate Dialog box position and size */
   buttonY   = firstItemY + (((numToolsSupport + 1) / 2) *LINE_HEIGHT)+VSPACE;
   boxWidth  = max((maxTitleWidth * 2), 3*buttonWidth + 6*HSPACE);
   boxHeight = buttonY + LINE_HEIGHT+(.5*VSPACE);
   centerX   = boxWidth / 2;

   /* Setup dialog box in Template */
   if ((err = SetupDlgTemplate(hDlgTemplate, DLGBOX_STYLE,
      boxX, boxY, boxWidth, boxHeight,
      "", "", captionText)) != GOOD)
      return(err);

   /* Add each tool support to the dialog */
   for (i = 0; i < numToolsSupport; i++) {
      /* Increment y position for every other button */
      y = firstItemY + (i / 2) * LINE_HEIGHT;
      if ((i % 2) == 0) {
         x = itemTitleX + HSPACE;
      }
      else {
         x = centerX + (2 * HSPACE);
      }
      /* Add item to dialog box */
      if ((err = AddControlToDlg(hDlgTemplate, DLGITEM_STYLE,
            x, y, centerX - HSPACE, LINE_TEXT_HEIGHT,
            IDD_ITEM(i), "BUTTON", (LPSTR)toolStrings[i], 0, NULL)) != GOOD) {
         GlobalFree(*hDlgTemplate);
         return(err);
      }
   }
   /* Add OK and CANCEL Buttons */
   if ((err = AddControlToDlg(hDlgTemplate,
         (DLGBUTTON_STYLE | BS_DEFPUSHBUTTON),
         centerX - buttonWidth - (3 * HSPACE) - (buttonWidth / 2), buttonY,
         buttonWidth, LINE_TEXT_HEIGHT,
         IDD_OK, "BUTTON", "&OK", 0, NULL)) != GOOD) {
      GlobalFree(*hDlgTemplate);
      return(err);
   }
   if ((err = AddControlToDlg(hDlgTemplate,
         (DLGBUTTON_STYLE | BS_PUSHBUTTON),
         centerX - (buttonWidth / 2), buttonY,
         buttonWidth, LINE_TEXT_HEIGHT,
         IDD_CANCEL, "BUTTON", "&Cancel", 0, NULL)) != GOOD) {
      GlobalFree(*hDlgTemplate);
      return(err);
   }
   if ((err = AddControlToDlg(hDlgTemplate,
         (DLGBUTTON_STYLE | BS_PUSHBUTTON),
         centerX + (buttonWidth / 2) + (3 * HSPACE), buttonY,
         buttonWidth, LINE_TEXT_HEIGHT,
         IDHELP, "BUTTON", "&Help", 0, NULL)) != GOOD) {
      GlobalFree(*hDlgTemplate);
      return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  SetupDlgTemplate
**
**  Status: CODED | REVIEWED | TESTED
**
**  Description:
**     Setup a dialog box according to the specified arguments.
**
**  Parameters:
**     input:
**        none.
**     output:
**        hDlgTemplate     pointer to hanlde of dialog template.
**
******************************************************************************/
RETCODE SetupDlgTemplate(HANDLE *hDlgTemplate, S32 iStyle, S16 ix, S16 iy,
      S16 icx, S16 icy, LPSTR menuName, LPSTR className, LPSTR captionText) {

   LPDLGTEMPLATE lpDlg;
   LPSTR lpText;
   S16 menuNameSize = lstrlen(menuName) + 1; // include null terminator
   S16 classNameSize = lstrlen(className) + 1;
   S16 captionTextSize = lstrlen(captionText) + 1;

   /* Compute the total bytes in DLGTEMPLATE */
   nBytesInTemplate = (sizeof(DLGTEMPLATE) + menuNameSize + classNameSize+
      captionTextSize);
   // GlobalFree(*hDlgTemplate);
   if ((*hDlgTemplate = GlobalAlloc(GHND, nBytesInTemplate)) == NULL)
      return(ER_NO_MEMORY);
   if ((lpDlg = (LPDLGTEMPLATE) GlobalLock(*hDlgTemplate)) == NULL)
      return(ER_WINDOWS_MEMLOCK);
   /* Set Dialog template attributes and position */
   lpDlg->style   = iStyle;
   lpDlg->nItems  = 0;
   lpDlg->x       = ix;
   lpDlg->y       = iy;
   lpDlg->cx      = icx;
   lpDlg->cy      = icy;

   /* Append menuName, className and captionText strings to template */
   lpText = ((LPSTR) lpDlg) + sizeof(DLGTEMPLATE);
   _fmemcpy(lpText, (LPSTR)menuName, menuNameSize);
   lpText += menuNameSize;
   _fmemcpy(lpText, (LPSTR)className, classNameSize);
   lpText += classNameSize;
   _fmemcpy(lpText, (LPSTR)captionText, captionTextSize);
   GlobalUnlock(*hDlgTemplate);
   return(GOOD);
}

/******************************************************************************
**
**  AddControlToDlg
**
**  Status: CODED | REVIEWED | TESTED
**
**  Description:
**     Add the specified control to dialog template - hDlgTemplate.
**
**  Parameters:
**     input:
**        iStyle           Control style.
**     output:
**        hDlgTemplate     pointer to handle of dialog template.
**
******************************************************************************/
RETCODE AddControlToDlg(HANDLE *hDlgTemplate, S32 iStyle, S16 ix, S16 iy,
								S16 icx, S16 icy, S16 controlID, LPSTR className,
								LPSTR text, BYTE dataBytes, LPBYTE data) {
   LPDLGTEMPLATE lpDlg;
   LPDLGITEMTEMPLATE lpItem;
   LPSTR lpText;
   S16 oldnBytes;
   S16 classNameSize = lstrlen(className) + 1;
   S16 textSize      = lstrlen(text) + 1;

   /* Save the number of bytes in the template */
   oldnBytes = nBytesInTemplate;
   /* Compute total bytes for an DLGITEMTEMPLATE struct */
   nBytesInTemplate += (sizeof(DLGITEMTEMPLATE) + classNameSize + textSize +
         sizeof(BYTE) + dataBytes);
   if ((*hDlgTemplate = GlobalReAlloc(*hDlgTemplate,
												  nBytesInTemplate, GHND)) == NULL) {
      return(ER_NO_MEMORY);
   }
   if ((lpDlg = (LPDLGTEMPLATE) GlobalLock(*hDlgTemplate)) == NULL)
      return(ER_WINDOWS_MEMLOCK);

   lpDlg->nItems++;

   /* Append item template to dialog template block */
   lpItem = (LPDLGITEMTEMPLATE) (((LPSTR) lpDlg) + oldnBytes);
   /* Set dialog item attributes and position */
   lpItem->x      = ix;
   lpItem->y      = iy;
   lpItem->cx     = icx;
   lpItem->cy     = icy;
   lpItem->id     = controlID;
   lpItem->style  = iStyle;
   /* Append text part to it */
   lpText = ((LPSTR) lpItem) + sizeof(DLGITEMTEMPLATE);
   _fmemcpy(lpText, (LPSTR)className, classNameSize);
   lpText += classNameSize;
   _fmemcpy(lpText, (LPSTR)text, textSize);
   lpText += textSize;
   *lpText = dataBytes;
   lpText += sizeof(BYTE);
   _fmemcpy(lpText, (LPSTR)data, dataBytes);
   GlobalUnlock(*hDlgTemplate);
   return(GOOD);
}
 
/******************************** E O F ***********************************/

