home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / dlgedit / addctrl.c next >
C/C++ Source or Header  |  1997-10-05  |  34KB  |  1,175 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: addctrl.c
  14. *
  15. * Contains routines for adding (creating) and deleting controls.
  16. *
  17. * Functions:
  18. *
  19. *    AddNewDialog()
  20. *    DropControl()
  21. *    AddControl()
  22. *    CreateControl()
  23. *    CreateDlgFont()
  24. *    MyGetCharDimensions()
  25. *    AdjustDefaultSizes()
  26. *    DeleteControl()
  27. *    DeleteDialog()
  28. *    DeleteControl2()
  29. *    FreeCTYPE()
  30. *
  31. * Comments:
  32. *
  33. ****************************************************************************/
  34.  
  35. #include "dlgedit.h"
  36. #include "dlgfuncs.h"
  37. #include "dlgextrn.h"
  38. #include "dialogs.h"
  39.  
  40. #include <stdlib.h>
  41. #include <string.h>
  42.  
  43. STATICFN HFONT CreateDlgFont(HWND hwnd, LPTSTR pszFontName,
  44.     INT nPointSize);
  45. STATICFN INT MyGetCharDimensions(HWND hwnd, HFONT hFont,
  46.     PTEXTMETRIC ptm);
  47. STATICFN VOID AdjustDefaultSizes(VOID);
  48. STATICFN VOID DeleteControl2(NPCTYPE npcDel);
  49. STATICFN VOID FreeCTYPE(NPCTYPE npc);
  50.  
  51. int CALLBACK GetFontCharSetEnumFunc(LPLOGFONT,LPTEXTMETRIC,int,LPARAM);
  52. STATICFN BYTE NEAR GetFontCharSet(LPTSTR);
  53.  
  54.  
  55. /************************************************************************
  56. * AddNewDialog
  57. *
  58. * High level function to add a new dialog to the current resource.
  59. * Any existing dialog will be saved away in the resource buffer.
  60. * The dialog is created at a default position and size with default
  61. * styles.
  62. *
  63. ************************************************************************/
  64.  
  65. VOID AddNewDialog(VOID)
  66. {
  67.     RECT rc;
  68.  
  69.     if (gfEditingDlg) {
  70.         if (!SynchDialogResource())
  71.             return;
  72.  
  73.         DeleteDialog(FALSE);
  74.     }
  75.  
  76.     /*
  77.      * Now drop a new dialog window.
  78.      */
  79.     SetRect(&rc, DEFDIALOGXPOS, DEFDIALOGYPOS,
  80.             DEFDIALOGXPOS + awcd[W_DIALOG].cxDefault,
  81.             DEFDIALOGYPOS + awcd[W_DIALOG].cyDefault);
  82.     DropControl(&awcd[W_DIALOG], &rc);
  83. }
  84.  
  85.  
  86.  
  87. /************************************************************************
  88. * DropControl
  89. *
  90. * This function drops a new control of Type at the specified
  91. * location.  The default style and text of the control is
  92. * determined from the awcd table based on its type.  The control
  93. * is selected after being dropped.
  94. *
  95. *
  96. * Arguments:
  97. *   PWINDOWCLASSDESC pwcd - Describes the type of new control.
  98. *   PRECT prc             - Rectangle of the new control (in dialog units).
  99. *
  100. ************************************************************************/
  101.  
  102. VOID DropControl(
  103.     PWINDOWCLASSDESC pwcd,
  104.     PRECT prc)
  105. {
  106.     ORDINAL ordIcon;
  107.     ORDINAL ordDlg;
  108.     LPTSTR pszText;
  109.     NPCTYPE npcNew;
  110.     INT idCtrl;
  111.     DIALOGINFO di;
  112.  
  113.     /*
  114.      * Get the next available id to use for the new control.
  115.      */
  116.     idCtrl = NextID((pwcd->iType == W_DIALOG) ? NEXTID_DIALOG : NEXTID_CONTROL,
  117.             plInclude, 0);
  118.  
  119.     if (pwcd->iType == W_ICON) {
  120.         /*
  121.          * For icon controls, the text is really an ordinal or name
  122.          * of the icon resource to display.  We get the next available
  123.          * id (skipping the id we just got for the control itself) to
  124.          * use as an ordinal.
  125.          */
  126.         WriteOrd(&ordIcon, NextID(NEXTID_CONTROL, plInclude, idCtrl));
  127.         pszText = (LPTSTR)&ordIcon;
  128.     }
  129.     else {
  130.         pszText = pwcd->pszTextDefault;
  131.     }
  132.  
  133.     /*
  134.      * Make the control.
  135.      */
  136.     if (pwcd->iType == W_DIALOG) {
  137.         /*
  138.          * Pick a default name for the dialog.
  139.          */
  140.         WriteOrd(&ordDlg, NextID(NEXTID_DIALOG, plInclude, 0));
  141.  
  142.         di.fResFlags = DEFDLGMEMFLAGS;
  143. //      di.wLanguage = GetUserDefaultLangID();
  144.     di.wLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  145.         di.pszClass = NULL;
  146.         di.pszMenu = NULL;
  147.         di.DataVersion = 0;
  148.         di.Version = 0;
  149.         di.Characteristics = 0;
  150.         di.nPointSize = DEFPOINTSIZE;
  151.         lstrcpy(di.szFontName, ids(IDS_DEFFONTNAME));
  152.  
  153.         npcNew = AddControl(pwcd, pszText,
  154.                 pwcd->flStyles, pwcd->flExtStyle, idCtrl,
  155.                 prc->left, prc->top,
  156.                 prc->right - prc->left, prc->bottom - prc->top,
  157.                 (LPTSTR)&ordDlg, &di);
  158.     }
  159.     else {
  160.         npcNew = AddControl(pwcd, pszText,
  161.                 pwcd->flStyles, pwcd->flExtStyle, idCtrl,
  162.                 prc->left, prc->top,
  163.                 prc->right - prc->left, prc->bottom - prc->top,
  164.                 NULL, NULL);
  165.     }
  166.  
  167.     if (!npcNew)
  168.         return;
  169.  
  170.     /*
  171.      * If we just dropped a dialog, we need to now show it.
  172.      * It it was some other control, mark the dialog as having
  173.      * been changed.
  174.      */
  175.     if (pwcd->iType == W_DIALOG) {
  176.         ShowWindow(npcNew->hwnd, SW_SHOWNA);
  177.         ToolboxOnTop();
  178.     }
  179.     else {
  180.         gfDlgChanged = TRUE;
  181.     }
  182.  
  183.     SelectControl(npcNew, FALSE);
  184.  
  185.     gfResChged = TRUE;
  186.     ShowFileStatus(FALSE);
  187.  
  188.     /*
  189.      * Now we determine if one of the fields in the status ribbon
  190.      * should be given the focus initially.  The assumption is that
  191.      * there are some things that a user will always want to change
  192.      * when dropping a new control, such as the text in a push
  193.      * button, for example.
  194.      */
  195.     idCtrl = 0;
  196.     switch (pwcd->iType) {
  197.         case W_ICON:
  198.             /*
  199.              * For icons, the first thing the user will
  200.              * probably want to do is to change the name.
  201.              */
  202.             idCtrl = DID_STATUSNAME;
  203.             break;
  204.  
  205.         default:
  206.             /*
  207.              * If this control has text, they will probably want
  208.              * to change it.  This includes the caption if the
  209.              * control is a dialog.
  210.              */
  211.             if (pwcd->fHasText)
  212.                 idCtrl = DID_STATUSTEXT;
  213.  
  214.             break;
  215.     }
  216.  
  217.     if (idCtrl) {
  218.         SendDlgItemMessage(hwndStatus, idCtrl,
  219.          EM_SETSEL, (WPARAM)(0), (LONG)(-1));
  220.         SetFocus(GetDlgItem(hwndStatus, idCtrl));
  221.     }
  222. }
  223.  
  224.  
  225.  
  226. /************************************************************************
  227. * AddControl
  228. *
  229. * This function is used to add a new control.  CreateControl() does
  230. * half the work.
  231. *
  232. * Arguments:
  233. *   PWINDOWCLASSDESC pwcd - Window class structure.  Describes the
  234. *                           type of control to add.
  235. *   LPTSTR pszText        - Text for the new control.
  236. *   DWORD style           - Style of the new control.
  237. *   DWORD flExtStyle      - Extended style of the new control.
  238. *   INT id                - ID for the new control.
  239. *   INT x                 - X location of the new control.
  240. *   INT y                 - Y location of the new control.
  241. *   INT cx                - Width of the new control.
  242. *   INT cy                - Height of the new control.
  243. *   LPTSTR pszDlgName     - For dialogs, has dialog name.
  244. *   PDIALOGINFO pdi       - Ptr to additional dialog info (NULL for controls).
  245. *
  246. * Returns:
  247. *     A pointer to the CTYPE structure for the new control.
  248. *     NULL if it couldn't create the control.
  249. *
  250. ************************************************************************/
  251.  
  252. NPCTYPE AddControl(
  253.     PWINDOWCLASSDESC pwcd,
  254.     LPTSTR pszText,
  255.     DWORD style,
  256.     DWORD flExtStyle,
  257.     INT id,
  258.     INT x,
  259.     INT y,
  260.     INT cx,
  261.     INT cy,
  262.     LPTSTR pszDlgName,
  263.     PDIALOGINFO pdi)
  264. {
  265.     NPCTYPE npcNew;
  266.     NPCTYPE npcT;
  267.     NPCTYPE *npnpcLast;
  268.     HWND hwndBehind;
  269.  
  270.     if (!(npcNew = (NPCTYPE)MyAlloc(sizeof(CTYPE))))
  271.         return NULL;
  272.  
  273.     /*
  274.      * These are checked later if a failure occurs,
  275.      * so we null them out now.
  276.      */
  277.     npcNew->hwnd = NULL;
  278.     npcNew->hwndDrag = NULL;
  279.     npcNew->text = NULL;
  280.  
  281.     /*
  282.      * Set up some fields and create the control.
  283.      */
  284.     npcNew->npcNext = NULL;
  285.     npcNew->pwcd = pwcd;
  286.     npcNew->fSelected = FALSE;
  287.     SetRect(&npcNew->rc, x, y, x + cx, y + cy);
  288.  
  289.     if (pwcd->iType == W_DIALOG)
  290.         hwndBehind = (HWND)NULL;
  291.     else
  292.         hwndBehind = (HWND)1;
  293.  
  294.     if (!CreateControl(npcNew, pszText, style, flExtStyle, id, &npcNew->rc,
  295.             hwndBehind, pdi))
  296.         goto CreateFailed;
  297.  
  298.     /*
  299.      * Create the drag window, unless this is the dialog.
  300.      */
  301.     if (pwcd->iType != W_DIALOG) {
  302.         npcNew->hwndDrag = CreateWindow(
  303.                 szDragClass,
  304.                 NULL,
  305.                 WS_CHILD,
  306.                 0, 0, 0, 0,
  307.                 gcd.npc->hwnd,
  308.                 NULL,
  309.                 ghInst,
  310.                 NULL);
  311.  
  312.         /*
  313.          * Store the CTYPE pointer into the control's drag window.
  314.          * This will be used by PCFROMHWND later.
  315.          */
  316.         SETPCINTOHWND(npcNew->hwndDrag, npcNew);
  317.  
  318.         /*
  319.          * Move the drag window to the top of the Z-Order.
  320.          */
  321.         SetWindowPos(npcNew->hwndDrag, NULL, 0, 0, 0, 0,
  322.                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
  323.  
  324.         SizeDragToControl(npcNew);
  325.     }
  326.  
  327.     /*
  328.      * Did we just create a dialog?
  329.      */
  330.     if (pwcd->iType == W_DIALOG) {
  331.         /*
  332.          * First, copy the new name (it can be an ordinal!).
  333.          */
  334.         if (!(gcd.pszDlgName = MyAlloc(NameOrdLen(pszDlgName))))
  335.             goto CreateFailed;
  336.  
  337.         NameOrdCpy(gcd.pszDlgName, pszDlgName);
  338.  
  339.         /*
  340.          * Now, setup some other globals.  We clear the gcd.prl pointer,
  341.          * because we are assuming that this dialog was not created
  342.          * from a res link (it was dropped instead).  The routines
  343.          * that call AddControl when creating a dialog from a res
  344.          * link are  responsible for setting this global later.
  345.          */
  346.         gcd.prl = NULL;
  347.         gcd.npc = npcNew;
  348.         gfEditingDlg = TRUE;
  349.     }
  350.     else {
  351.         /*
  352.          * Search for the last control in the list.
  353.          */
  354.         npnpcLast = &npcHead;
  355.         for (npcT = npcHead; npcT; npcT = npcT->npcNext)
  356.             npnpcLast = &npcT->npcNext;
  357.  
  358.         /*
  359.          * Link in the new control at the end of the list.
  360.          */
  361.         *npnpcLast = npcNew;
  362.         cWindows++;
  363.     }
  364.  
  365.     return npcNew;
  366.  
  367. CreateFailed:
  368.     FreeCTYPE(npcNew);
  369.     return NULL;
  370. }
  371.  
  372.  
  373.  
  374. /************************************************************************
  375. * CreateControl
  376. *
  377. * Creates a control.  Some styles may be masked off of the actual
  378. * control created.  This function can also create the dialog box.
  379. *
  380. * If the control created is the dialog box, it will not be made visible.
  381. * This must be done by the caller.  This allows the caller to first add
  382. * all the controls to the dialog before showing it.
  383. *
  384. * The x, y, cx and cy coordinates are all in dialog units.  For a
  385. * type of W_DIALOG, this will be relative to the apps client.  For a
  386. * control, this will be relative to the "client" area of the dialog.
  387. *
  388. * Arguments:
  389. *   NPCTYPE npc       - The CTYPE pointer to the new control.  The hwnd
  390. *                       fields of the npc will be set.
  391. *   LPTSTR pszText    - The window text.
  392. *   DWORD flStyle     - The style to use.
  393. *   DWORD flExtStyle  - Extended style of the new control.
  394. *   INT id            - ID for the control.
  395. *   PRECT prc         - The size and location of the new control.
  396. *   HWND hwndBehind   - Put new control behind this hwnd in Z-order.
  397. *   PDIALOGINFO pdi   - Pointer to additional dialog info (NULL for controls).
  398. *
  399. * Returns:
  400. *     Handle of the control created.
  401. *     NULL if control was not created.
  402. *
  403. ************************************************************************/
  404.  
  405. HWND CreateControl(
  406.     NPCTYPE npc,
  407.     LPTSTR pszText,
  408.     DWORD flStyle,
  409.     DWORD flExtStyle,
  410.     INT id,
  411.     PRECT prc,
  412.     HWND hwndBehind,
  413.     PDIALOGINFO pdi)
  414. {
  415.     HWND hwnd;
  416.     HWND hwndChild;
  417.     WNDPROC lpfnChild;
  418.     RECT rcT;
  419.     TEXTMETRIC tm;
  420.     LPTSTR pszCreateClass;
  421.     LPTSTR pszTextOld;
  422.     INT iType = npc->pwcd->iType;
  423.  
  424.     /*
  425.      * Set the text field.  Remember that it can be an ordinal
  426.      * (for icon controls).
  427.      */
  428.     pszTextOld = npc->text;
  429.     if (pszText && *pszText) {
  430.         if (!(npc->text = MyAlloc(NameOrdLen(pszText))))
  431.             return NULL;
  432.  
  433.         NameOrdCpy(npc->text, pszText);
  434.     }
  435.     else {
  436.         npc->text = NULL;
  437.     }
  438.  
  439.     /*
  440.      * If there was text before on this control, free it now.
  441.      * This should be done after the new text is allocated and
  442.      * copied, because it is common to pass this routine the same
  443.      * pointer, and we don't want to free the text before we have
  444.      * copied it!
  445.      */
  446.     if (pszTextOld)
  447.         MyFree(pszTextOld);
  448.  
  449.     /*
  450.      * Also set some other values in the CTYPE structure.
  451.      */
  452.     npc->id = id;
  453.     npc->flStyle = flStyle;
  454.     npc->flExtStyle = flExtStyle;
  455.  
  456.     /*
  457.      * If this is a dialog and it has the WS_CHILD style, remove
  458.      * it and make it WS_POPUP instead.  This prevents some problems
  459.      * when editing the dialog.
  460.      */
  461.     if (iType == W_DIALOG && (flStyle & WS_CHILD)) {
  462.         flStyle &= ~WS_CHILD;
  463.         flStyle |= WS_POPUP;
  464.     }
  465.  
  466.     /*
  467.      * If this is an emulated custom control, we always make it with the
  468.      * default styles no matter what the user has specified.  If not,
  469.      * remove any styles that can cause problems for a control of this
  470.      * type, such as OWNERDRAW styles.
  471.      */
  472.     if (npc->pwcd->fEmulated)
  473.         flStyle = awcd[W_CUSTOM].flStyles;
  474.     else
  475.         flStyle &= ~npc->pwcd->flStylesBad;
  476.  
  477.     if (iType == W_DIALOG) {
  478.         /*
  479.          * If the style includes the DS_MODALFRAME bit, set the appropriate
  480.          * extended style bit.
  481.          */
  482.         if (flStyle & DS_MODALFRAME)
  483.             flExtStyle |= WS_EX_DLGMODALFRAME;
  484.  
  485.         /*
  486.          * Create the dialog, but don't show it yet.
  487.          */
  488.         hwnd = CreateWindowEx(
  489.                 flExtStyle,
  490.                 MAKEINTRESOURCE(DIALOGCLASS),
  491.                 npc->text,
  492.                 flStyle & ~WS_VISIBLE,
  493.                 0, 0, 0, 0,
  494.                 ghwndSubClient,
  495.                 0,
  496.                 ghInst,
  497.                 NULL);
  498.     }
  499.     else {
  500.         /*
  501.          * Get the size of the control.
  502.          */
  503.         rcT = *prc;
  504.  
  505.         /*
  506.          * Map the dialog unit rectangle to window coords.
  507.          */
  508.         DUToWinRect(&rcT);
  509.  
  510.         /*
  511.          * If this is an icon, the text field is actually going
  512.          * to be an ordinal that has the resource id.  We must map this to
  513.          * an id of our own or when we create the control it will cause a
  514.          * "Resource not found" error.
  515.          */
  516.         if (iType == W_ICON)
  517.             pszText = (LPTSTR)&gordIcon;
  518.         else
  519.             pszText = npc->text;
  520.  
  521.         /*
  522.          * Get the class name to use.  In the case of custom controls,
  523.          * if the control is emulated, use the special emulator class.
  524.          * Otherwise, it is an installed custom control, and we can use
  525.          * it's real class string.
  526.          */
  527.         if (iType == W_CUSTOM) {
  528.             if (npc->pwcd->fEmulated)
  529.                 pszCreateClass = szCustomClass;
  530.             else
  531.                 pszCreateClass = npc->pwcd->pszClass;
  532.         }
  533.         else {
  534.             pszCreateClass = ids(acsd[awcd[iType].iClass].idsClass);
  535.         }
  536.  
  537.         /*
  538.          * Create the control.  We always create it visible in work mode,
  539.          * even if the style says it isn't.
  540.          */
  541.         hwnd = CreateWindowEx(
  542.                 flExtStyle,
  543.                 pszCreateClass,
  544. #ifdef JAPAN
  545.                 // pszText is ordnum for icon control.
  546.                 iType == W_ICON ? pszText : TEXT(""),
  547. #else
  548.                 pszText,
  549. #endif
  550.                 flStyle | WS_VISIBLE,
  551.                 rcT.left, rcT.top,
  552.                 rcT.right - rcT.left,
  553.                 rcT.bottom - rcT.top,
  554.                 gcd.npc->hwnd,
  555.                 0,
  556.                 ghInst,
  557.                 NULL);
  558. #ifdef JAPAN
  559.         // It isn't necessary for ICON control to handle accel in text.
  560.         if( iType != W_ICON ) {
  561.             TCHAR   szTmp[CCHTEXTMAX];
  562.  
  563.             KKExpandCopy(szTmp, pszText, CCHTEXTMAX);
  564.             SetWindowText(hwnd, szTmp);
  565.         }
  566. #endif
  567.     }
  568.  
  569.     if (!hwnd) {
  570.         Message(MSG_CREATECTRLERROR, pszCreateClass);
  571.         return NULL;
  572.     }
  573.  
  574.     if (iType == W_DIALOG) {
  575.         /*
  576.          * Did they specify a font?
  577.          */
  578.         if (*pdi->szFontName) {
  579.             gcd.hFont = CreateDlgFont(hwnd, pdi->szFontName, pdi->nPointSize);
  580.             lstrcpy(gcd.di.szFontName, pdi->szFontName);
  581.             gcd.di.nPointSize = pdi->nPointSize;
  582.             gcd.fFontSpecified = TRUE;
  583.         }
  584.         else {
  585.             gcd.hFont = NULL;
  586.             *gcd.di.szFontName = CHAR_NULL;
  587.             gcd.di.nPointSize = 0;
  588.             gcd.fFontSpecified = FALSE;
  589.         }
  590.  
  591.         /*
  592.          * Get the dimensions of the font.  It is a possible case that
  593.          * they specified a font but it could not be created, so in
  594.          * that case we use the system font as well as if they didn't
  595.          * specify a font at all.
  596.          */
  597.         if (gcd.hFont) {
  598.             gcd.cxChar = MyGetCharDimensions(hwnd, gcd.hFont, &tm);
  599.             gcd.cyChar = tm.tmHeight;
  600.         }
  601.         else {
  602.             gcd.cxChar = gcxSysChar;
  603.             gcd.cyChar = gcySysChar;
  604.         }
  605.  
  606.         /*
  607.          * Now that we know what font we are using, adjust some entries
  608.          * in the awcd (array of window class data) table for default 
  609.          * sizing of controls.
  610.          */
  611.         AdjustDefaultSizes();
  612.     }
  613.  
  614.     /*
  615.      * If there is a valid user specified font, inform the control
  616.      * of it.  Once the font has been set into the dialog, it
  617.      * must not be destroyed, because the dialog window will
  618.      * clean it up when it is destroyed.
  619.      */
  620.     if (gcd.hFont)
  621.         SendMessage(hwnd, WM_SETFONT, (WPARAM)gcd.hFont, 0L);
  622.  
  623.     /*
  624.      * Move the window into the requested Z-Order.
  625.      */
  626.     SetWindowPos(hwnd, hwndBehind, 0, 0, 0, 0,
  627.             SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
  628.  
  629.     /*
  630.      * Store the CTYPE pointer into the control's hwnd.
  631.      * This will be used by PCFROMHWND later.
  632.      */
  633.     SETPCINTOHWND(hwnd, npc);
  634.  
  635.     /*
  636.      * Subclass the control.
  637.      */
  638.     npc->pwcd->pfnOldWndProc =
  639.             (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC,
  640.             (iType == W_DIALOG) ? (DWORD)DialogCtrlWndProc :
  641.             (DWORD)CtrlWndProc);
  642.  
  643.     /*
  644.      * Be sure double-clicks are enabled for this control.
  645.      */
  646.     (UINT)SetClassLong((hwnd), GCL_STYLE, (LONG)((UINT)GetClassLong((hwnd), GCL_STYLE) | CS_DBLCLKS));
  647.  
  648.     /*
  649.      * Subclass any children this control may have.
  650.      */
  651.     for (hwndChild = GetTopWindow(hwnd); hwndChild;
  652.             hwndChild = GetNextWindow(hwndChild, GW_HWNDNEXT)) {
  653.         lpfnChild = (WNDPROC)SetWindowLong(hwndChild,
  654.                 GWL_WNDPROC, (DWORD)ChildWndProc);
  655.         SETCHILDPROC(hwndChild, lpfnChild);
  656.     }
  657.  
  658.     /*
  659.      * Did we just create a dialog?
  660.      */
  661.     if (iType == W_DIALOG) {
  662.         /*
  663.          * Now that the dialog is created, we can figure out how to
  664.          * size it.  We start by mapping the dialog units to window
  665.          * coordinates,
  666.          */
  667.         rcT = *prc;
  668.         DUToWinRect(&rcT);
  669.  
  670.         /*
  671.          * We now have the rectangle for the client area.  Expand it
  672.          * to account for the frame controls.
  673.          */
  674.         AdjustWindowRectEx(&rcT, flStyle, FALSE, flExtStyle);
  675.  
  676.         /*
  677.          * Now we can map the rect from the apps client area
  678.          * to the desktop, then we set the dialogs position.
  679.          */
  680.         ClientToScreenRect(ghwndSubClient, &rcT);
  681.         SetWindowPos(hwnd, NULL,
  682.                 rcT.left, rcT.top,
  683.                 rcT.right - rcT.left, rcT.bottom - rcT.top,
  684.                 SWP_NOZORDER | SWP_NOACTIVATE);
  685.  
  686.         SaveDlgClientRect(hwnd);
  687.  
  688.         /*
  689.          * Save the class name, if any.
  690.          */
  691.         if (pdi->pszClass && *pdi->pszClass) {
  692.             if (!(gcd.di.pszClass = MyAlloc(NameOrdLen(pdi->pszClass)))) {
  693.                 DestroyWindow(hwnd);
  694.                 return (HWND)NULL;
  695.             }
  696.  
  697.             NameOrdCpy(gcd.di.pszClass, pdi->pszClass);
  698.         }
  699.         else {
  700.             gcd.di.pszClass = NULL;
  701.         }
  702.  
  703.         /*
  704.          * Save the menu name, if any.
  705.          */
  706.         if (pdi->pszMenu && *pdi->pszMenu) {
  707.             if (!(gcd.di.pszMenu = MyAlloc(NameOrdLen(pdi->pszMenu)))) {
  708.                 DestroyWindow(hwnd);
  709.                 return (HWND)NULL;
  710.             }
  711.  
  712.             NameOrdCpy(gcd.di.pszMenu, pdi->pszMenu);
  713.         }
  714.         else {
  715.             gcd.di.pszMenu = NULL;
  716.         }
  717.  
  718.         /*
  719.          * Set some other fields in the additional dialog info structure.
  720.          */
  721.         gcd.di.fResFlags = pdi->fResFlags;
  722.         gcd.di.wLanguage = pdi->wLanguage;
  723.         gcd.di.DataVersion = pdi->DataVersion;
  724.         gcd.di.Version = pdi->Version;
  725.         gcd.di.Characteristics = pdi->Characteristics;
  726.     }
  727.  
  728.     npc->hwnd = hwnd;
  729.     return hwnd;
  730. }
  731.  
  732.  
  733.  
  734. /************************************************************************
  735. * CreateDlgFont
  736. *
  737. * This function creates a font with the given face name and point size
  738. * and returns a handle to it.
  739. *
  740. * Arguments:
  741. *   HWND hwnd           - Dialog window handle.
  742. *   LPTSTR pszFontName  - Name of the font (for example: "Helv").
  743. *   INT nPointSize      - Point size of the font (for example: 8 or 12).
  744. *
  745. * Returns:
  746. *   A handle to the created font, or NULL if it could not be created.
  747. *
  748. ************************************************************************/
  749.  
  750. static BYTE bSystemCharset;
  751.  
  752. STATICFN HFONT CreateDlgFont(
  753.     HWND hwnd,
  754.     LPTSTR pszFontName,
  755.     INT nPointSize)
  756. {
  757.     HFONT hFont;
  758.     HFONT hFontOld;
  759.     HDC hDC;
  760.     LOGFONT lf;
  761.     TCHAR szFaceName[LF_FACESIZE];
  762.     CHARSETINFO csi;
  763.     DWORD dw = GetACP();
  764.  
  765.     if (TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE))
  766.     bSystemCharset = csi.ciCharset;
  767.     else
  768.         bSystemCharset = ANSI_CHARSET;
  769.  
  770.     /*
  771.      * Initialize the logical font structure.  Note that filling the
  772.      * structure with zeros gives it all the default settings.
  773.      */
  774.     memset(&lf, 0, sizeof(LOGFONT));
  775.     lf.lfHeight = (SHORT)-PointSizeToPixels(nPointSize);
  776.     if ((lf.lfCharSet = GetFontCharSet(pszFontName)) != bSystemCharset)
  777.         lf.lfWeight = FW_BOLD; // allow boldface on non ShiftJIS fonts
  778.     lstrcpy(lf.lfFaceName, pszFontName);
  779.  
  780.     if (!(hFont = CreateFontIndirect(&lf)))
  781.         return NULL;
  782.  
  783.     /*
  784.      * If we didn't get the face name that was requested, delete the
  785.      * new font and return NULL.  This will effectively select the
  786.      * system font for this dialog.
  787.      */
  788.     hDC = GetDC(hwnd);
  789.     if (hFontOld = SelectObject(hDC, hFont)) {
  790.         GetTextFace(hDC, LF_FACESIZE, szFaceName);
  791.         SelectObject(hDC, hFontOld);
  792.  
  793.         if (lstrcmpi(szFaceName, pszFontName) != 0) {
  794.             DeleteObject(hFont);
  795.             hFont = NULL;
  796.         }
  797.     }
  798.     else {
  799.         DeleteObject(hFont);
  800.         hFont = NULL;
  801.     }
  802.  
  803.     ReleaseDC(hwnd, hDC);
  804.  
  805.     return hFont;
  806. }
  807.  
  808.  
  809.  
  810. /************************************************************************
  811. * MyGetCharDimensions
  812. *
  813. * This function calculates the average character width of the given
  814. * font for the given window.  This must be used instead of
  815. * simply using the tmAveCharWidth field of the text metrics, because
  816. * this value is not correct for proportional fonts.  
  817. *
  818. * Arguments:
  819. *   HWND hwnd       - The window handle.
  820. *   HFONT hFont     - The font handle.
  821. *   PTEXTMETRIC ptm - Where to return the text metrics.
  822. *
  823. * Returns:
  824. *   The average character width.  The text metrics are returned in
  825. *   the TEXTMETRIC structure pointed to by ptm.
  826. *
  827. ************************************************************************/
  828.  
  829. STATICFN INT MyGetCharDimensions(
  830.     HWND hwnd,
  831.     HFONT hFont,
  832.     PTEXTMETRIC ptm)
  833. {
  834.     register INT i;
  835.     HDC hDC;
  836.     SIZE size;
  837.     INT iWidth;
  838.     TCHAR szAveCharWidth[52];
  839.     HFONT hFontOld;
  840.  
  841.     hDC = GetDC(hwnd);
  842.     hFontOld = SelectObject(hDC, hFont);
  843.  
  844.     GetTextMetrics(hDC, ptm);
  845.  
  846.     /*
  847.      * Is this a variable pitch font?
  848.      */
  849.     if (ptm->tmPitchAndFamily & 0x01) {
  850.         for (i = 0; i < 26; i++)
  851.             szAveCharWidth[i] = (TCHAR)(i + CHAR_A);
  852.  
  853.         for (i = 0; i < 26; i++)
  854.             szAveCharWidth[i + 26] = (TCHAR)(i + CHAR_CAP_A);
  855.  
  856.         GetTextExtentPoint(hDC, szAveCharWidth, 52, &size);
  857.         iWidth = (INT)size.cx / 26;
  858.  
  859.         //
  860.         // Round it up.
  861.         //
  862.         iWidth = (iWidth + 1) / 2;
  863.     }
  864.     else {
  865.         iWidth = ptm->tmAveCharWidth;
  866.     }
  867.  
  868.     SelectObject(hDC, hFontOld);
  869.     ReleaseDC(hwnd, hDC);
  870.  
  871.     return iWidth;
  872. }
  873.  
  874.  
  875.  
  876. /************************************************************************
  877. * AdjustDefaultSizes
  878. *
  879. * This functions adjusts some default size entries in the awcd (array of
  880. * window class data) table.
  881. * This must be done at run time, because the actual values depend on the
  882. * system that dlgedit is being run on and the font of the current dialog.
  883. *
  884. * This function should be called any time that a dialog is created,
  885. * or its font is changed.
  886. *
  887. ************************************************************************/
  888.  
  889. STATICFN VOID AdjustDefaultSizes(VOID)
  890. {
  891.     awcd[W_ICON].cxDefault =
  892.             (((GetSystemMetrics(SM_CXICON) * 4) * 2) + gcd.cxChar)
  893.             / (gcd.cxChar * 2);
  894.  
  895.     awcd[W_ICON].cyDefault =
  896.             (((GetSystemMetrics(SM_CYICON) * 8) * 2) + gcd.cyChar)
  897.             / (gcd.cyChar * 2);
  898.  
  899.     awcd[W_VERTSCROLL].cxDefault =
  900.             (((GetSystemMetrics(SM_CXVSCROLL) * 4) * 2) + gcd.cxChar)
  901.             / (gcd.cxChar * 2);
  902.  
  903.     awcd[W_HORZSCROLL].cyDefault =
  904.             (((GetSystemMetrics(SM_CYHSCROLL) * 8) * 2) + gcd.cyChar)
  905.             / (gcd.cyChar * 2);
  906. }
  907.  
  908.  
  909.  
  910. /************************************************************************
  911. * DeleteControl
  912. *
  913. * This deletes all selected controls from the dialog being edited
  914. * (or the dialog itself, if it is selected).
  915. *
  916. ************************************************************************/
  917.  
  918. VOID DeleteControl(VOID)
  919. {
  920.     if (gfDlgSelected) {
  921.         if (Message(MSG_DELETEDIALOG) == IDYES)
  922.             /*
  923.              * Delete the dialog, including the resource for it.
  924.              */
  925.             DeleteDialog(TRUE);
  926.     }
  927.     else {
  928.         while (gnpcSel)
  929.             DeleteControl2(gnpcSel);
  930.  
  931.         gfDlgChanged = TRUE;
  932.     }
  933.  
  934.     gfResChged = TRUE;
  935.     ShowFileStatus(FALSE);
  936.     StatusUpdate();
  937.     StatusSetEnable();
  938. }
  939.  
  940.  
  941.  
  942. /************************************************************************
  943. * DeleteControl2
  944. *
  945. * This deletes a control by destroying its window and removing it
  946. * from the linked list of controls associated with the dialog box.
  947. * The control is destroyed and the window is unlinked and the CTYPE free'd.
  948. *
  949. ************************************************************************/
  950.  
  951. STATICFN VOID DeleteControl2(
  952.     NPCTYPE npcDel)
  953. {
  954.     register NPCTYPE npcT;
  955.     register NPCTYPE *npnpcLast;
  956.  
  957.     UnSelectControl(npcDel);
  958.  
  959.     /*
  960.      * Search for the control, unlink it from the list and free it.
  961.      */
  962.     npcT = npcHead;
  963.     npnpcLast = &npcHead;
  964.     while (npcT) {
  965.         if (npcT == npcDel) {
  966.             *npnpcLast = npcT->npcNext;
  967.             FreeCTYPE(npcT);
  968.             cWindows--;
  969.             break;
  970.         }
  971.  
  972.         npnpcLast = &npcT->npcNext;
  973.         npcT = npcT->npcNext;
  974.     }
  975. }
  976.  
  977.  
  978.  
  979. /************************************************************************
  980. * DeleteDialog
  981. *
  982. * This deletes the dialog box being worked on and sets globals
  983. * and the Status Window appropriately.  All CTYPEs are freed, the
  984. * status window is updated and the dialog window is destroyed.
  985. *
  986. * Arguments:
  987. *   BOOL fResAlso - If TRUE, delete the dialog resource also.
  988. *
  989. ************************************************************************/
  990.  
  991. VOID DeleteDialog(
  992.     BOOL fResAlso)
  993. {
  994.     register NPCTYPE npcT;
  995.     register NPCTYPE npcNext;
  996.  
  997.     CancelSelection(FALSE);
  998.  
  999.     /*
  1000.      * If they requested that the dialog resource be deleted also,
  1001.      * do it first while some globals are still set.
  1002.      */
  1003.     if (fResAlso)
  1004.         DeleteDialogResource();
  1005.  
  1006.     /*
  1007.      * Hide the window for better painting speed.
  1008.      */
  1009.     ShowWindow(gcd.npc->hwnd, SW_HIDE);
  1010.  
  1011.     /*
  1012.      * Free all the controls.
  1013.      */
  1014.     npcT = npcHead;
  1015.     while (npcT) {
  1016.         npcNext = npcT->npcNext;
  1017.         FreeCTYPE(npcT);
  1018.         npcT = npcNext;
  1019.     }
  1020.     npcHead = NULL;
  1021.     cWindows = 0;
  1022.  
  1023.     /*
  1024.      * Free the dialog itself.
  1025.      */
  1026.     FreeCTYPE(gcd.npc);
  1027.  
  1028.     if (gcd.pszDlgName) {
  1029.         MyFree(gcd.pszDlgName);
  1030.         gcd.pszDlgName = NULL;
  1031.     }
  1032.  
  1033.     if (gcd.di.pszClass) {
  1034.         MyFree(gcd.di.pszClass);
  1035.         gcd.di.pszClass = NULL;
  1036.     }
  1037.  
  1038.     if (gcd.di.pszMenu) {
  1039.         MyFree(gcd.di.pszMenu);
  1040.         gcd.di.pszMenu = NULL;
  1041.     }
  1042.  
  1043.     if (gcd.hFont) {
  1044.         DeleteObject(gcd.hFont);
  1045.         gcd.hFont = NULL;
  1046.     }
  1047.  
  1048.     gcd.fFontSpecified = FALSE;
  1049.     *gcd.di.szFontName = CHAR_NULL;
  1050.  
  1051.     /*
  1052.      * Set these globals back to the system font values so that
  1053.      * workers like WinToDUPoint will still work.
  1054.      */
  1055.     gcd.cxChar = gcxSysChar;
  1056.     gcd.cyChar = gcySysChar;
  1057.  
  1058.     gcd.prl = NULL;
  1059.  
  1060.     gcd.npc = NULL;
  1061.     gfEditingDlg = FALSE;
  1062.     gfDlgChanged = FALSE;
  1063.  
  1064.     ToolboxSelectTool(W_NOTHING, FALSE);
  1065.     StatusUpdate();
  1066.     StatusSetEnable();
  1067. }
  1068.  
  1069.  
  1070.  
  1071. /************************************************************************
  1072. * FreeCTYPE
  1073. *
  1074. * This function frees an allocated CTYPE.  The associated control or
  1075. * dialog window is destroyed, and memory for the text and/or class
  1076. * is freed, followed by freeing the actual CTYPE structure itself.
  1077. *
  1078. * If the hwnd in the CTYPE is NULL, only the text (if not NULL) is
  1079. * assumed to be valid and will be freed, followed by the CTYPE structure
  1080. * itself.  This allows FreeCTYPE to be called when the CTYPE is only
  1081. * partially initialized.  This is a little dependant on the order that
  1082. * a CTYPE is allocated and initialized in AddControl().
  1083. *
  1084. * Arguments:
  1085. *     NPCTYPE npc = The CTYPE to free.
  1086. *
  1087. ************************************************************************/
  1088.  
  1089. STATICFN VOID FreeCTYPE(
  1090.     NPCTYPE npc)
  1091. {
  1092.     if (npc->hwnd)
  1093.         DestroyWindow(npc->hwnd);
  1094.  
  1095.     if (npc->hwndDrag)
  1096.         DestroyWindow(npc->hwndDrag);
  1097.  
  1098.     if (npc->text)
  1099.         MyFree(npc->text);
  1100.  
  1101.     MyFree(npc);
  1102. }
  1103.  
  1104. /************************************************************************
  1105. *
  1106. *
  1107. *
  1108. ************************************************************************/
  1109.  
  1110. int CALLBACK GetFontCharSetEnumFunc(LPLOGFONT lpLf,
  1111.                     LPTEXTMETRIC lpTm,
  1112.                     int nFontType,
  1113.                     LPARAM lParam)
  1114. {
  1115.     LPBYTE lpB = (LPBYTE)lParam;
  1116.     *lpB = lpTm->tmCharSet;
  1117.     return 0; // no more enum
  1118. }
  1119.  
  1120. /************************************************************************
  1121. *
  1122. *
  1123. *
  1124. ************************************************************************/
  1125.  
  1126. STATICFN BYTE NEAR GetFontCharSet(LPTSTR lpStr)
  1127. {
  1128.     HDC hDC;
  1129.     BYTE cbCharset = bSystemCharset;
  1130.     FONTENUMPROC lpEFCB = (FONTENUMPROC)MakeProcInstance(
  1131.                               (FARPROC)GetFontCharSetEnumFunc,
  1132.                               ghInst);
  1133.     if (hDC = GetDC(ghwndMain)) {
  1134.         EnumFonts(hDC, lpStr, lpEFCB, (LPARAM)&cbCharset);
  1135.         ReleaseDC(ghwndMain,hDC);
  1136.     }
  1137.     FreeProcInstance(lpEFCB);
  1138.     return cbCharset;
  1139. }
  1140.  
  1141. #ifdef JAPAN
  1142. /************************************************************************
  1143. * Copy strings to the buffer. Codes \036 and \037 are expanded to
  1144. * text strings "\036" and "\037" respectively. t-Yoshio
  1145. ************************************************************************/
  1146.  
  1147. VOID KDExpandCopy(LPTSTR pszDest, LPTSTR pszSrc, WORD wLimit)
  1148. {
  1149.     int  i;
  1150.     LPTSTR p = pszSrc;
  1151.  
  1152.     wLimit--;
  1153.     for (i = 0; i < wLimit && p && *p; i++) {
  1154.         if (*p == 036 || *p == 037) {
  1155.             if (i < wLimit-4) {
  1156.                 lstrcpy(&pszDest[i], (*p == 036) ? TEXT("\\036") : TEXT("\\037"));
  1157.                 i += 3;
  1158.             } else {
  1159.                 break;
  1160.                 }
  1161.         } else {
  1162.             pszDest[i] = *p;
  1163.             }
  1164.         if (IsDBCSLeadByte((BYTE)*p)) {
  1165.             if (i == wLimit - 1) {
  1166.                 break;
  1167.             }
  1168.             pszDest[++i] = *(p+1);
  1169.         }
  1170.         p = CharNext(p);
  1171.     }
  1172.     pszDest[i] = '\0';
  1173. }
  1174. #endif
  1175.