/*************************************************************************
**
**    OLE 2 Sample Code
**
**    dialogs.c
**
**    This file contains dialog functions and support function
**
**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
**
*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

static OLECHAR  g_szBuf[MAXSTRLEN+1];
static LPSTR g_lpszDlgTitle;

// REVIEW: should use string resource for messages
static OLECHAR ErrMsgInvalidRange[] = OLESTR("Invalid Range entered!");
static OLECHAR ErrMsgInvalidValue[] = OLESTR("Invalid Value entered!");
static OLECHAR ErrMsgInvalidName[] = OLESTR("Invalid Name entered!");
static OLECHAR ErrMsgNullName[] = OLESTR("NULL string disallowed!");
static OLECHAR ErrMsgNameNotFound[] = OLESTR("Name doesn't exist!");

/* InputTextDlg
 * ------------
 *
 *      Put up a dialog box to allow the user to edit text
 */
BOOL InputTextDlg(HWND hWnd, LPSTR lpszText, LPSTR lpszDlgTitle)
{
   int nResult;

   g_lpszDlgTitle = lpszDlgTitle;
   A2W (lpszText, g_szBuf, MAXSTRLEN+1);  // preload dialog with input text

   nResult = DialogBox(g_lpApp->m_hInst, (LPSTR)"AddEditLine", hWnd,
                  (DLGPROC)AddEditDlgProc);
   if (nResult) {
      W2A(g_szBuf, lpszText, MAXSTRLEN+1);
      return TRUE;
   } else {
      return FALSE;
   }
}



/* AddEditDlgProc
 * --------------
 *
 * This procedure is associated with the dialog box that is included in
 * the function name of the procedure. It provides the service routines
 * for the events (messages) that occur because the end user operates
 * one of the dialog box's buttons, entry fields, or controls.
 */
BOOL CALLBACK EXPORT AddEditDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
   HWND hEdit;
   char szAnsiString[256];

   switch(Message) {
      case WM_INITDIALOG:
         /* initialize working variables */
         hEdit=GetDlgItem(hDlg,IDD_EDIT);
         SendMessage(hEdit,EM_LIMITTEXT,(WPARAM)MAXSTRLEN,0L);
         SetWindowText(hDlg, g_lpszDlgTitle);
         W2A (g_szBuf, szAnsiString, 256);
         SetDlgItemText(hDlg,IDD_EDIT, szAnsiString);
         break; /* End of WM_INITDIALOG */

      case WM_CLOSE:
         /* Closing the Dialog behaves the same as Cancel */
         PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);
         break; /* End of WM_CLOSE */

      case WM_COMMAND:
         switch (wParam) {
            case IDOK:
               /* save data values entered into the controls
               ** and dismiss the dialog box returning TRUE
               */
               GetDlgItemText(hDlg,IDD_EDIT,(LPSTR)g_szBuf,MAXSTRLEN+1);
               EndDialog(hDlg, TRUE);
               break;

            case IDCANCEL:
               /* ignore data values entered into the controls
               ** and dismiss the dialog box returning FALSE
               */
               EndDialog(hDlg, FALSE);
               break;
         }
         break;    /* End of WM_COMMAND */

      default:
         return FALSE;
   }

   return TRUE;
} /* End of AddEditDlgProc */


/* SetLineHeightDlgProc
 * --------------------
 *
 *      Dialog procedure for set line height
 */
BOOL CALLBACK EXPORT SetLineHeightDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
   BOOL    fTranslated;
   BOOL    fEnable;
   static LPINT    lpint;
   int     nHeight;
   static int nMaxHeight;

   switch (Message) {
      case WM_INITDIALOG:
      {
         char cBuf[80];

         nMaxHeight = XformHeightInPixelsToHimetric(NULL,
                        LISTBOX_HEIGHT_LIMIT);
         lpint = (LPINT)lParam;
         SetDlgItemInt(hDlg, IDD_EDIT, *lpint, FALSE);
         wsprintf(cBuf, "Maximum value is %d units", nMaxHeight);
         SetDlgItemText(hDlg, IDD_LIMIT, (LPSTR)cBuf);
         break;
      }

      case WM_COMMAND:
         switch (wParam) {
            case IDOK:
               if (IsDlgButtonChecked(hDlg, IDD_CHECK)) {
                  *lpint = -1;
               }
               else {
                  /* save the value in the edit control */
                  nHeight = GetDlgItemInt(hDlg, IDD_EDIT,
                        (BOOL FAR*)&fTranslated, FALSE);
                  if (!fTranslated || !nHeight || (nHeight>nMaxHeight)){
                     OutlineApp_ErrorMessage(g_lpApp,
                           ErrMsgInvalidValue);
                     break;
                  }
                  *lpint = nHeight;
               }
               EndDialog(hDlg, TRUE);
               break;

            case IDCANCEL:
               *lpint = 0;
               EndDialog(hDlg, FALSE);
               break;


            case IDD_CHECK:
               fEnable = !IsDlgButtonChecked(hDlg, IDD_CHECK);
               EnableWindow(GetDlgItem(hDlg, IDD_EDIT), fEnable);
               EnableWindow(GetDlgItem(hDlg, IDD_TEXT), fEnable);
               break;
         }
         break;  /* WM_COMMAND */

      case WM_CLOSE:  /* Closing the Dialog behaves the same as Cancel */
         PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);
         break; /* End of WM_CLOSE */

      default:
         return FALSE;
   }

   return TRUE;

} /* end of SetLineHeightProc */





/* DefineNameDlgProc
 * -----------------
 *
 *      Dialog procedure for define name
 */
BOOL CALLBACK EXPORT DefineNameDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
   static HWND hCombo;
   static LPOUTLINEDOC lpOutlineDoc = NULL;
   static LPOUTLINENAMETABLE lpOutlineNameTable = NULL;
   LPOUTLINENAME lpOutlineName = NULL;
   UINT nIndex;
   LINERANGE lrSel;
   BOOL fTranslated;
   char szAnsiString[256];

   switch(Message) {
      case WM_INITDIALOG:
      /* initialize working variables */
         hCombo=GetDlgItem(hDlg,IDD_COMBO);
         lpOutlineDoc = (LPOUTLINEDOC) lParam;
         lpOutlineNameTable = OutlineDoc_GetNameTable(lpOutlineDoc);

         SendMessage(hCombo,CB_LIMITTEXT,(WPARAM)MAXNAMESIZE,0L);
         NameDlg_LoadComboBox(lpOutlineNameTable, hCombo);

         OutlineDoc_GetSel(lpOutlineDoc, (LPLINERANGE)&lrSel);
         lpOutlineName = OutlineNameTable_FindNamedRange(
               lpOutlineNameTable,
               &lrSel
         );

         /* if current selection already has a name, hilight it */
         if (lpOutlineName) {
            nIndex = (int) SendMessage(
                  hCombo,
                  CB_FINDSTRINGEXACT,
                  (WPARAM)0xffff,
                  (LPARAM)(LPCSTR)lpOutlineName->m_szName
            );
            if (nIndex != CB_ERR) {
               SendMessage(hCombo, CB_SETCURSEL, (WPARAM)nIndex, 0L);
            }
         }

         SetDlgItemInt(hDlg, IDD_FROM, (UINT)lrSel.m_nStartLine+1,FALSE);
         SetDlgItemInt(hDlg, IDD_TO, (UINT)lrSel.m_nEndLine+1, FALSE);

         break; /* End of WM_INITDIALOG */

      case WM_CLOSE:
      /* Closing the Dialog behaves the same as Cancel */
         PostMessage(hDlg, WM_COMMAND, IDD_CLOSE, 0L);
         break; /* End of WM_CLOSE */

      case WM_COMMAND:
         switch(wParam) {
            case IDOK:
               GetDlgItemText(hDlg,IDD_COMBO,(LPSTR)g_szBuf,MAXNAMESIZE);
               if(! SendMessage(hCombo,WM_GETTEXTLENGTH,0,0L)) {
                  W2A (ErrMsgNullName, szAnsiString, 256);
                  MessageBox(
                        hDlg,
                        szAnsiString,
                        NULL,
                        MB_ICONEXCLAMATION
                  );
                  break;
               } else if(SendMessage(hCombo,CB_GETCURSEL,0,0L)==CB_ERR &&
                     wcschr(g_szBuf, ' ')) {
                  W2A (ErrMsgInvalidName, szAnsiString, 256);
                  MessageBox(
                        hDlg,
                        szAnsiString,
                        NULL,
                        MB_ICONEXCLAMATION
                  );
                  break;
               } else {
                  nIndex = (int) SendMessage(hCombo,CB_FINDSTRINGEXACT,
                     (WPARAM)0xffff,(LPARAM)(LPCSTR)g_szBuf);

                  /* Line indices are 1 less than the number in
                  **    the row heading
                  */
                  lrSel.m_nStartLine = GetDlgItemInt(hDlg, IDD_FROM,
                        (BOOL FAR*)&fTranslated, FALSE) - 1;
                  if(! fTranslated) {
                     OutlineApp_ErrorMessage(g_lpApp,
                           ErrMsgInvalidRange);
                     break;
                  }
                  lrSel.m_nEndLine = GetDlgItemInt(hDlg, IDD_TO,
                        (BOOL FAR*)&fTranslated, FALSE) - 1;
                  if (!fTranslated ||
                     (lrSel.m_nStartLine < 0) ||
                     (lrSel.m_nEndLine < lrSel.m_nStartLine) ||
                     (lrSel.m_nEndLine >= OutlineDoc_GetLineCount(
                           lpOutlineDoc))) {
                     OutlineApp_ErrorMessage(g_lpApp,
                           ErrMsgInvalidRange);
                     break;
                  }

                  if(nIndex != CB_ERR) {
                     NameDlg_UpdateName(
                           hCombo,
                           lpOutlineDoc,
                           nIndex,
                           g_szBuf,
                           &lrSel
                     );
                  } else {
                     NameDlg_AddName(
                           hCombo,
                           lpOutlineDoc,
                           g_szBuf,
                           &lrSel
                     );
                  }
               }
               // fall through

            case IDD_CLOSE:
               /* Ignore data values entered into the controls */
               /* and dismiss the dialog window returning FALSE */
               EndDialog(hDlg,0);
               break;

            case IDD_DELETE:
               GetDlgItemText(hDlg,IDD_COMBO,(LPSTR)szAnsiString,MAXNAMESIZE);
               if((nIndex=(int)SendMessage(hCombo,CB_FINDSTRINGEXACT,
               (WPARAM)0xffff,(LPARAM)(LPCSTR)szAnsiString))==CB_ERR) {
                  W2A (ErrMsgNameNotFound, szAnsiString, 256);
                  MessageBox(hDlg, szAnsiString, NULL, MB_ICONEXCLAMATION);
               }
               else {
                  NameDlg_DeleteName(hCombo, lpOutlineDoc, nIndex);
               }
               break;

            case IDD_COMBO:
               if(HIWORD(lParam) == CBN_SELCHANGE) {
                  nIndex=(int)SendMessage(hCombo, CB_GETCURSEL, 0, 0L);
                  lpOutlineName = (LPOUTLINENAME)SendMessage(
                        hCombo,
                        CB_GETITEMDATA,
                        (WPARAM)nIndex,
                        0L
                  );
                  SetDlgItemInt(
                        hDlg,
                        IDD_FROM,
                        (UINT) lpOutlineName->m_nStartLine + 1,
                        FALSE
                  );
                  SetDlgItemInt(
                        hDlg,
                        IDD_TO,
                        (UINT) lpOutlineName->m_nEndLine + 1,
                        FALSE
                  );
               }
         }
         break;    /* End of WM_COMMAND */

      default:
         return FALSE;
   }

   return TRUE;
} /* End of DefineNameDlgProc */


/* GotoNameDlgProc
 * ---------------
 *
 *      Dialog procedure for goto name
 */
BOOL CALLBACK EXPORT GotoNameDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
   static HWND hLBName;
   static LPOUTLINEDOC lpOutlineDoc = NULL;
   static LPOUTLINENAMETABLE lpOutlineNameTable = NULL;
   UINT nIndex;
   LINERANGE lrLineRange;
   LPOUTLINENAME lpOutlineName;

   switch(Message) {
      case WM_INITDIALOG:
      /* initialize working variables */
         lpOutlineDoc = (LPOUTLINEDOC) lParam;
         lpOutlineNameTable = OutlineDoc_GetNameTable(lpOutlineDoc);

         hLBName=GetDlgItem(hDlg,IDD_LINELISTBOX);
         NameDlg_LoadListBox(lpOutlineNameTable, hLBName);

         // highlight 1st item
         SendMessage(hLBName, LB_SETCURSEL, 0, 0L);
         // trigger to initialize edit control
         SendMessage(hDlg, WM_COMMAND, (WPARAM)IDD_LINELISTBOX,
            MAKELONG(hLBName, LBN_SELCHANGE));

         break; /* End of WM_INITDIALOG */

      case WM_CLOSE:
      /* Closing the Dialog behaves the same as Cancel */
         PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);
         break; /* End of WM_CLOSE */

      case WM_COMMAND:
         switch(wParam) {
            case IDD_LINELISTBOX:
               if(HIWORD(lParam) == LBN_SELCHANGE) {
                  // update the line range display
                  nIndex=(int)SendMessage(hLBName, LB_GETCURSEL, 0, 0L);
                  lpOutlineName = (LPOUTLINENAME)SendMessage(hLBName, LB_GETITEMDATA,
                                 (WPARAM)nIndex,0L);
                  if (lpOutlineName) {
                     SetDlgItemInt(
                           hDlg,
                           IDD_FROM,
                           (UINT) lpOutlineName->m_nStartLine + 1,
                           FALSE
                     );
                     SetDlgItemInt(
                           hDlg,
                           IDD_TO,
                           (UINT) lpOutlineName->m_nEndLine + 1,
                           FALSE
                     );
                  }
                  break;
               }
               // double click will fall through
               else if(HIWORD(lParam) != LBN_DBLCLK)
                  break;

            case IDOK:
               nIndex=(int)SendMessage(hLBName,LB_GETCURSEL,0,0L);
               if(nIndex!=LB_ERR) {
                  lpOutlineName = (LPOUTLINENAME)SendMessage(hLBName,
                        LB_GETITEMDATA, (WPARAM)nIndex, 0L);
                  lrLineRange.m_nStartLine=lpOutlineName->m_nStartLine;
                  lrLineRange.m_nEndLine = lpOutlineName->m_nEndLine;
                  OutlineDoc_SetSel(lpOutlineDoc, &lrLineRange);
               }   // fall through

            case IDCANCEL:
            /* Ignore data values entered into the controls */
            /* and dismiss the dialog window returning FALSE */
               EndDialog(hDlg,0);
               break;

         }
         break;    /* End of WM_COMMAND */

      default:
         return FALSE;
   }

   return TRUE;
} /* End of GotoNameDlgProc */



/* NameDlg_LoadComboBox
 * --------------------
 *
 *      Load defined names into combo box
 */
void NameDlg_LoadComboBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hCombo)
{
   LPOUTLINENAME lpOutlineName;
   int i, nIndex;
   int nCount;

   nCount=OutlineNameTable_GetCount((LPOUTLINENAMETABLE)lpOutlineNameTable);
   if(!nCount) return;

   SendMessage(hCombo,WM_SETREDRAW,(WPARAM)FALSE,0L);
   for(i=0; i<nCount; i++) {
      lpOutlineName=OutlineNameTable_GetName((LPOUTLINENAMETABLE)lpOutlineNameTable,i);
      nIndex = (int)SendMessage(
            hCombo,
            CB_ADDSTRING,
            0,
            (LPARAM)(LPCSTR)lpOutlineName->m_szName
      );
      SendMessage(hCombo,CB_SETITEMDATA,(WPARAM)nIndex,(LPARAM)lpOutlineName);
   }
   SendMessage(hCombo,WM_SETREDRAW,(WPARAM)TRUE,0L);
}


/* NameDlg_LoadListBox
 * -------------------
 *
 *      Load defined names into list box
 */
void NameDlg_LoadListBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hListBox)
{
   int i;
   int nCount;
   int nIndex;
   LPOUTLINENAME lpOutlineName;

   nCount=OutlineNameTable_GetCount((LPOUTLINENAMETABLE)lpOutlineNameTable);

   SendMessage(hListBox,WM_SETREDRAW,(WPARAM)FALSE,0L);
   for(i=0; i<nCount; i++) {
      lpOutlineName=OutlineNameTable_GetName((LPOUTLINENAMETABLE)lpOutlineNameTable,i);
      nIndex = (int)SendMessage(
            hListBox,
            LB_ADDSTRING,
            0,
            (LPARAM)(LPCSTR)lpOutlineName->m_szName
      );
      SendMessage(hListBox,LB_SETITEMDATA,(WPARAM)nIndex,(LPARAM)lpOutlineName);
   }
   SendMessage(hListBox,WM_SETREDRAW,(WPARAM)TRUE,0L);
}


/* NameDlg_AddName
 * ---------------
 *
 *      Add a name to the name table corresponding to the name dialog
 *      combo box.
 */
void NameDlg_AddName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, LPOLESTR lpszName, LPLINERANGE lplrSel)
{
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
   LPOUTLINENAME lpOutlineName;

   lpOutlineName = OutlineApp_CreateName(lpOutlineApp);

   if (lpOutlineName) {
      OLESTRCPY(lpOutlineName->m_szName, lpszName);
      lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;
      lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;
      OutlineDoc_AddName(lpOutlineDoc, lpOutlineName);
   } else {
      // REVIEW: do we need error message here?
   }
}


/* NameDlg_UpdateName
 * ------------------
 *
 *      Update a name in the name table corresponding to a name in
 *      the name dialog combo box.
 */
void NameDlg_UpdateName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, int nIndex, LPOLESTR lpszName, LPLINERANGE lplrSel)
{
   LPOUTLINENAME lpOutlineName;

   lpOutlineName = (LPOUTLINENAME)SendMessage(
         hCombo,
         CB_GETITEMDATA,
         (WPARAM)nIndex,
         0L
   );

   OutlineName_SetName(lpOutlineName, lpszName);
   OutlineName_SetSel(lpOutlineName, lplrSel, TRUE /* name modified */);
   OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
}


/* NameDlg_DeleteName
 * ------------------
 *
 *      Delete a name from the name dialog combo box and corresponding
 *      name table.
 */
void NameDlg_DeleteName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, UINT nIndex)
{
   SendMessage(hCombo,CB_DELETESTRING,(WPARAM)nIndex,0L);
   OutlineDoc_DeleteName(lpOutlineDoc, nIndex);
}

/* PlaceBitmap
 * -----------
 *
 *      Places a bitmap centered in the specified control in the dialog on the
 *      specified DC.
 *
 */

PlaceBitmap(HWND hDlg, int control, HDC hDC, HBITMAP hBitmap)
{
   BITMAP bm;
   HDC hdcmem;
   HBITMAP hbmOld;
   RECT rcControl;     // Rect of dialog control
   int width, height;

   GetObject(hBitmap, sizeof(BITMAP), &bm);

   hdcmem= CreateCompatibleDC(hDC);
   hbmOld = SelectObject(hdcmem, hBitmap);

   // Get rect of control in screen coords, and translate to our dialog
   // box's coordinates
   GetWindowRect(GetDlgItem(hDlg, control), &rcControl);
   MapWindowPoints(NULL, hDlg, (LPPOINT)&rcControl, 2);

   width  = rcControl.right - rcControl.left;
   height = rcControl.bottom - rcControl.top;

   BitBlt(hDC, rcControl.left + (width - bm.bmWidth) / 2,
            rcControl.top + (height - bm.bmHeight) /2,
            bm.bmWidth, bm.bmHeight,
            hdcmem, 0, 0, SRCCOPY);

   SelectObject(hdcmem, hbmOld);
   DeleteDC(hdcmem);
   return 1;
}



/* AboutDlgProc
 * ------------
 *
 *      Dialog procedure for the About function
 */
BOOL CALLBACK EXPORT AboutDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
   int  narrVersion[2];
   static HBITMAP hbmLogo;
   char   szAnsiString[256];

   switch(Message) {

      case WM_INITDIALOG:
         // get version number of app
         W2A (APPNAME, szAnsiString, 256);
         wsprintf(szAnsiString, "About %s", (LPCSTR)szAnsiString);
         SetWindowText(hDlg, (LPCSTR)szAnsiString);
         OutlineApp_GetAppVersionNo(g_lpApp, narrVersion);
         wsprintf(szAnsiString, "%s version %d.%d", (LPSTR) APPDESC,
            narrVersion[0], narrVersion[1]);
         SetDlgItemText(hDlg, IDD_APPTEXT, (LPCSTR)szAnsiString);

         // Load bitmap for displaying later
         hbmLogo = LoadBitmap(g_lpApp->m_hInst, "LogoBitmap");
         TraceDebug(hDlg, IDD_BITMAPLOCATION);
         ShowWindow(GetDlgItem(hDlg, IDD_BITMAPLOCATION), SW_HIDE);
         break;

      case WM_PAINT:
         {
         PAINTSTRUCT ps;
         BeginPaint(hDlg, &ps);

         // Display bitmap in IDD_BITMAPLOCATION control area
         PlaceBitmap(hDlg, IDD_BITMAPLOCATION, ps.hdc, hbmLogo);
         EndPaint(hDlg, &ps);
         }
         break;

      case WM_CLOSE :
         PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
         break;

      case WM_COMMAND :
         switch(wParam) {
            case IDOK:
            case IDCANCEL:
               if (hbmLogo) DeleteObject(hbmLogo);
               EndDialog(hDlg,0);
               break;
         }
         break;

      default :
         return FALSE;

   }
   return TRUE;
}
