home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / ppgfont.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  27KB  |  1,096 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFXCTL_PAGE_SEG
  14. #pragma code_seg(AFXCTL_PAGE_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CFontPropPage implementation
  26.  
  27. BEGIN_MESSAGE_MAP(CFontPropPage, CStockPropPage)
  28.     //{{AFX_MSG_MAP(CFontPropPage)
  29.     ON_WM_PAINT()
  30.     ON_CBN_SELCHANGE(AFX_IDC_FONTPROP, OnSelchangeFontprop)
  31.     ON_CBN_EDITUPDATE(AFX_IDC_FONTNAMES, OnEditupdateFontnames)
  32.     ON_CBN_EDITUPDATE(AFX_IDC_FONTSIZES, OnEditupdateFontsizes)
  33.     ON_CBN_SELCHANGE(AFX_IDC_FONTNAMES, OnSelchangeFontnames)
  34.     ON_CBN_SELCHANGE(AFX_IDC_FONTSIZES, OnSelchangeFontsizes)
  35.     ON_CBN_SELCHANGE(AFX_IDC_FONTSTYLES, OnSelchangeFontstyles)
  36.     ON_CBN_EDITCHANGE(AFX_IDC_FONTSTYLES, OnEditchangeFontstyles)
  37.     ON_BN_CLICKED(AFX_IDC_STRIKEOUT, OnStrikeout)
  38.     ON_BN_CLICKED(AFX_IDC_UNDERLINE, OnUnderline)
  39.     //}}AFX_MSG_MAP
  40. END_MESSAGE_MAP()
  41.  
  42. CFontPropPage::CFontPropPage() :
  43.     CStockPropPage(IDD, AFX_IDS_FONT_PPG_CAPTION)
  44. {
  45.     //{{AFX_DATA_INIT(CFontPropPage)
  46.     //}}AFX_DATA_INIT
  47. }
  48.  
  49. BOOL _AfxStringFromCy(CString& str, CY& cy)
  50. {
  51.     VARIANTARG varCy;
  52.     VARIANTARG varBstr;
  53.     AfxVariantInit(&varCy);
  54.     AfxVariantInit(&varBstr);
  55.     V_VT(&varCy) = VT_CY;
  56.     V_CY(&varCy) = cy;
  57.     if (FAILED(VariantChangeType(&varBstr, &varCy, 0, VT_BSTR)))
  58.     {
  59.         VariantClear(&varCy);
  60.         VariantClear(&varBstr);
  61.         return FALSE;
  62.     }
  63.     str = V_BSTR(&varBstr);
  64.     VariantClear(&varCy);
  65.     VariantClear(&varBstr);
  66.     return TRUE;
  67. }
  68.  
  69. BOOL _AfxCyFromString(CY& cy, LPCTSTR psz)
  70. {
  71.     USES_CONVERSION;
  72.  
  73.     VARIANTARG varBstr;
  74.     VARIANTARG varCy;
  75.     AfxVariantInit(&varBstr);
  76.     AfxVariantInit(&varCy);
  77.     V_VT(&varBstr) = VT_BSTR;
  78.     V_BSTR(&varBstr) = SysAllocString(T2COLE(psz));
  79.     if (FAILED(VariantChangeType(&varCy, &varBstr, 0, VT_CY)))
  80.     {
  81.         VariantClear(&varBstr);
  82.         VariantClear(&varCy);
  83.         return FALSE;
  84.     }
  85.     cy = V_CY(&varCy);
  86.     VariantClear(&varBstr);
  87.     VariantClear(&varCy);
  88.     return TRUE;
  89. }
  90.  
  91. #define DSx     0x00660046L
  92. #define DSna    0x00220326L
  93.  
  94. void _AfxDrawMaskedBitmap(CDC* pDC, CBitmap* pbmp, CBitmap* pbmpMask,
  95.     int x, int y, int cx, int cy)
  96. {
  97.     COLORREF oldBkColor = pDC->SetBkColor(RGB(255, 255, 255));
  98.     COLORREF oldTextColor = pDC->SetTextColor(RGB(0, 0, 0));
  99.  
  100.     CDC dcCompat;
  101.     dcCompat.CreateCompatibleDC(pDC);
  102.     CBitmap* pbmpSave = dcCompat.SelectObject(pbmp);
  103.     pDC->BitBlt(x, y, cx, cy, &dcCompat, 0, 0, DSx);
  104.     dcCompat.SelectObject(pbmpMask);
  105.     pDC->BitBlt(x, y, cx, cy, &dcCompat, 0, 0, DSna);
  106.     dcCompat.SelectObject(pbmp);
  107.     pDC->BitBlt(x, y, cx, cy, &dcCompat, 0, 0, DSx);
  108.     dcCompat.SelectObject(pbmpSave);
  109.  
  110.     pDC->SetBkColor(oldBkColor);
  111.     pDC->SetTextColor(oldTextColor);
  112. }
  113.  
  114. void _AfxInitMaskFromBitmap(CBitmap* pbmp, CBitmap* pbmpMask)
  115. {
  116.     BITMAP bmp;
  117.     pbmp->GetObject(sizeof (BITMAP), &bmp);
  118.     pbmpMask->CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
  119.  
  120.     CDC dcDst;
  121.     dcDst.CreateCompatibleDC(NULL);
  122.     CDC dcSrc;
  123.     dcSrc.CreateCompatibleDC(NULL);
  124.     CBitmap* pOldDst = dcDst.SelectObject(pbmpMask);
  125.     CBitmap* pOldSrc = dcSrc.SelectObject(pbmp);
  126.  
  127.     COLORREF oldBkColor = dcSrc.SetBkColor(dcSrc.GetPixel(0, 0));
  128.     dcDst.BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &dcSrc, 0, 0, NOTSRCCOPY);
  129.     dcSrc.SetBkColor(oldBkColor);
  130.  
  131.     dcDst.SelectObject(pOldDst);
  132.     dcSrc.SelectObject(pOldSrc);
  133. }
  134.  
  135. void CFontPropPage::DoDataExchange(CDataExchange* pDX)
  136. {
  137.     //{{AFX_DATA_MAP(CFontPropPage)
  138.     DDX_Control(pDX, AFX_IDC_FONTPROP, m_FontProp);
  139.     DDX_Control(pDX, AFX_IDC_SAMPLEBOX, m_SampleBox);
  140.     DDX_Control(pDX, AFX_IDC_FONTSTYLES, m_FontStyles);
  141.     DDX_Control(pDX, AFX_IDC_FONTSIZES, m_FontSizes);
  142.     DDX_Control(pDX, AFX_IDC_FONTNAMES, m_FontNames);
  143.     //}}AFX_DATA_MAP
  144.  
  145.     if (pDX->m_bSaveAndValidate)
  146.     {
  147.         FONTOBJECT fobj;
  148.         fobj.strName = m_FontNames.GetCurrentName();
  149.  
  150.         if (fobj.strName.IsEmpty())
  151.             return;
  152.  
  153.         m_FontSizes.GetPointSize(fobj.cySize);
  154.  
  155.         if (m_nCurrentStyle & NTM_REGULAR)
  156.             fobj.sWeight = FW_REGULAR;
  157.         if (m_nCurrentStyle & NTM_BOLD)
  158.         {
  159.             fobj.sWeight = FW_BOLD;
  160.             fobj.bBold = TRUE;
  161.         }
  162.         else
  163.             fobj.bBold = FALSE;
  164.         if (m_nCurrentStyle & NTM_ITALIC)
  165.             fobj.bItalic = TRUE;
  166.         else
  167.             fobj.bItalic = FALSE;
  168.         fobj.bUnderline = m_bUnderline;
  169.         fobj.bStrikethrough = m_bStrikeOut;
  170.  
  171.         SetFontProps(pDX, fobj, m_strPropName);
  172.     }
  173.     else
  174.     {
  175.         FONTOBJECT fobj;
  176.         MERGEOBJECT mobj;
  177.         if (!m_strPropName.IsEmpty() && GetFontProps(pDX, &fobj, m_strPropName, &mobj))
  178.         {
  179.             if (fobj.bBold && fobj.bItalic)
  180.                 m_nCurrentStyle = NTM_BOLD | NTM_ITALIC;
  181.             else if (fobj.bBold)
  182.                 m_nCurrentStyle = NTM_BOLD;
  183.             else if (fobj.bItalic)
  184.                 m_nCurrentStyle = NTM_ITALIC;
  185.             else
  186.                 m_nCurrentStyle = NTM_REGULAR;
  187.             m_nActualStyle = m_nCurrentStyle;
  188.             m_bUnderline = fobj.bUnderline;
  189.             m_bStrikeOut = fobj.bStrikethrough;
  190.  
  191.             mobj.bNameOK = TRUE;
  192.             mobj.bSizeOK = TRUE;
  193.             mobj.bStyleOK = TRUE;
  194.             mobj.bUnderlineOK = TRUE;
  195.             mobj.bStrikethroughOK = TRUE;
  196.  
  197.             _AfxStringFromCy(m_strFontSize, fobj.cySize);
  198.             SelectFontFromList(fobj.strName, &mobj);
  199.         }
  200.     }
  201. }
  202.  
  203. BOOL CFontPropPage::SetFontProps(CDataExchange* pDX, FONTOBJECT fobj, LPCTSTR pszPropName)
  204. {
  205.     USES_CONVERSION;
  206.  
  207.     BOOL bStatus = FALSE;
  208.     COleDispatchDriver PropDispDriver;
  209.  
  210.     // Set the properties for all the objects
  211.     ASSERT_KINDOF(COlePropertyPage, pDX->m_pDlgWnd);
  212.     COlePropertyPage* propDialog = (COlePropertyPage*)(pDX->m_pDlgWnd);
  213.  
  214.     ULONG nObjects;
  215.     LPDISPATCH* ppDisp = GetObjectArray(&nObjects);
  216.  
  217.     for (ULONG i = 0; i < nObjects; i++)
  218.     {
  219.         DISPID dwDispID;
  220.  
  221.         // Get the Dispatch ID for the property and if successful set the value
  222.         LPCOLESTR lpOleStr = T2COLE(pszPropName);
  223.         if (SUCCEEDED(ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr,
  224.             1, m_lcid, &dwDispID)))
  225.         {
  226.             LPDISPATCH pFontDisp = NULL;
  227.  
  228.             // Get property
  229.             PropDispDriver.AttachDispatch(ppDisp[i], FALSE);
  230.             TRY
  231.                 PropDispDriver.GetProperty(dwDispID, VT_DISPATCH, &pFontDisp);
  232.             END_TRY
  233.             PropDispDriver.DetachDispatch();
  234.  
  235.             if (pFontDisp == NULL)
  236.                 continue;
  237.  
  238.             // Get font interface
  239.             IFont * pFont;
  240.             HRESULT hresult = pFontDisp->QueryInterface(IID_IFont, (void**)&pFont);
  241.             if (hresult == S_OK)
  242.             {
  243.                 // Set font characteristics
  244.                 if (propDialog->GetControlStatus(AFX_IDC_FONTNAMES))
  245.                 {
  246.                     BSTR bstrName = fobj.strName.AllocSysString();
  247.                     pFont->put_Name(bstrName);
  248.                     SysFreeString(bstrName);
  249.                 }
  250.                 if (propDialog->GetControlStatus(AFX_IDC_FONTSIZES))
  251.                     pFont->put_Size(fobj.cySize);
  252.                 if (propDialog->GetControlStatus(AFX_IDC_FONTSTYLES))
  253.                 {
  254.                     pFont->put_Bold(fobj.bBold);
  255.                     pFont->put_Italic(fobj.bItalic);
  256.                     pFont->put_Weight(fobj.sWeight);
  257.                 }
  258.                 if (propDialog->GetControlStatus(AFX_IDC_UNDERLINE))
  259.                     pFont->put_Underline(fobj.bUnderline);
  260.                 if (propDialog->GetControlStatus(AFX_IDC_STRIKEOUT))
  261.                     pFont->put_Strikethrough(fobj.bStrikethrough);
  262.  
  263.                 // Release the font interface
  264.                 RELEASE(pFont);
  265.                 bStatus = TRUE;
  266.             }
  267.  
  268.             // Release the font dispatch interface
  269.             RELEASE(pFontDisp);
  270.         }
  271.     }
  272.     return bStatus;
  273. }
  274.  
  275. BOOL CFontPropPage::GetFontProps(CDataExchange* /* pDX */,
  276.     FONTOBJECT* pfobj, LPCTSTR pszPropName, MERGEOBJECT* pmobj)
  277. {
  278.     USES_CONVERSION;
  279.     BOOL bStatus = FALSE;
  280.  
  281.     COleDispatchDriver PropDispDriver;
  282.  
  283.     ULONG nObjects;
  284.     LPDISPATCH* ppDisp = GetObjectArray(&nObjects);
  285.  
  286.     for (ULONG i = 0; i < nObjects; i++)
  287.     {
  288.         DISPID dwDispID;
  289.  
  290.         // Get the Dispatch ID for the property and if successful get the value
  291.         LPCOLESTR lpOleStr = T2COLE(pszPropName);
  292.         if (SUCCEEDED(ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr,
  293.             1, m_lcid, &dwDispID)))
  294.         {
  295.             LPDISPATCH pFontDisp;
  296.  
  297.             // Get property
  298.             PropDispDriver.AttachDispatch(ppDisp[i], FALSE);
  299.             PropDispDriver.GetProperty(dwDispID, VT_DISPATCH, &pFontDisp);
  300.             PropDispDriver.DetachDispatch();
  301.  
  302.             if (pFontDisp == NULL)
  303.                 continue;
  304.  
  305.             // Get font interface
  306.             IFont * pFont;
  307.             HRESULT hresult = pFontDisp->QueryInterface(IID_IFont, (void**)&pFont);
  308.             if (hresult == S_OK)
  309.             {
  310.                 BOOL bTemp;
  311.  
  312.                 // Set font characteristics
  313.                 OLECHAR *pszName;
  314.                 pFont->get_Name(&pszName);
  315.                 if (lstrcmp(OLE2CT(pszName), pfobj->strName) != 0 && i != 0)
  316.                     pmobj->bNameOK = FALSE;
  317.                 pfobj->strName = pszName;
  318.                 SysFreeString(pszName);
  319.  
  320.                 CY cyTemp;
  321.                 pFont->get_Size(&cyTemp);
  322.                 if ((cyTemp.Lo != pfobj->cySize.Lo || cyTemp.Hi != pfobj->cySize.Hi) && i != 0)
  323.                     pmobj->bSizeOK = FALSE;
  324.                 pfobj->cySize = cyTemp;
  325.  
  326.                 pFont->get_Bold(&bTemp);
  327.                 if (pfobj->bBold != bTemp && i != 0)
  328.                     pmobj->bStyleOK = FALSE;
  329.                 pfobj->bBold = bTemp;
  330.  
  331.                 pFont->get_Italic(&bTemp);
  332.                 if (pfobj->bItalic != bTemp && i != 0)
  333.                     pmobj->bStyleOK = FALSE;
  334.                 pfobj->bItalic = bTemp;
  335.  
  336.                 pFont->get_Underline(&bTemp);
  337.                 if (pfobj->bUnderline != bTemp && i != 0)
  338.                     pmobj->bUnderlineOK = FALSE;
  339.                 pfobj->bUnderline = bTemp;
  340.  
  341.                 pFont->get_Strikethrough(&bTemp);
  342.                 if (pfobj->bStrikethrough != bTemp && i != 0)
  343.                     pmobj->bStrikethroughOK = FALSE;
  344.                 pfobj->bStrikethrough = bTemp;
  345.  
  346.                 short sTemp;
  347.  
  348.                 pFont->get_Weight(&sTemp);
  349.                 if (pfobj->sWeight != sTemp && i != 0)
  350.                     pmobj->bStyleOK = FALSE;
  351.                 pfobj->sWeight = sTemp;
  352.  
  353.                 // Release the font interface
  354.                 RELEASE(pFont);
  355.                 bStatus = TRUE;
  356.             }
  357.  
  358.             // Release font interface
  359.             RELEASE(pFontDisp);
  360.         }
  361.     }
  362.     return bStatus;
  363. }
  364.  
  365. BOOL CFontPropPage::OnInitDialog()
  366. {
  367.     CStockPropPage::OnInitDialog();
  368.     OnObjectsChanged();
  369.     IgnoreApply(AFX_IDC_FONTPROP);
  370.  
  371.     return TRUE;  // return TRUE  unless you set the focus to a control
  372. }
  373.  
  374. void CFontPropPage::FillFacenameList()
  375. {
  376.     // Clear the list
  377.     m_FontNames.ResetContent();
  378.  
  379.     // Create a DC to enumerate
  380.     CClientDC dc(NULL);
  381.     EnumFontFamilies(dc.GetSafeHdc(), (LPCTSTR) NULL,
  382.         (FONTENUMPROC)CFontPropPage::EnumFontFamiliesCallBack, (LPARAM) this);
  383.  
  384.     // Select the first one
  385.     if (m_FontNames.SetCurSel(0) != CB_ERR)
  386.     {
  387.         // Fill the size list
  388.         FillSizeList();
  389.     }
  390.     else
  391.     {
  392.         m_FontNames.EnableWindow(FALSE);
  393.         m_FontSizes.EnableWindow(FALSE);
  394.         m_FontStyles.EnableWindow(FALSE);
  395.         GetDlgItem(AFX_IDC_STRIKEOUT)->EnableWindow(FALSE);
  396.         GetDlgItem(AFX_IDC_UNDERLINE)->EnableWindow(FALSE);
  397.     }
  398. }
  399.  
  400. int CALLBACK CFontPropPage::EnumFontFamiliesCallBack(ENUMLOGFONT *lpelf, NEWTEXTMETRIC *, int FontType, LPARAM lParam)
  401. {
  402.     CFontPropPage *pDlg = (CFontPropPage *)lParam;
  403.     ASSERT(pDlg);
  404.     pDlg->m_FontNames.AddFont(&lpelf->elfLogFont, FontType);
  405.     return 1;
  406. }
  407.  
  408. AFX_STATIC_DATA int _afxTTDefaults[] = { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 };
  409.  
  410. void CFontPropPage::FillSizeList()
  411. {
  412.     // Clear the size list
  413.     m_FontSizes.ResetContent();
  414.     m_FontStyles.ResetContent();
  415.     m_nStyles = 0L;
  416.  
  417.     // Fill with "real" sizes
  418.     CString strFaceName;
  419.     m_FontNames.GetLBText(m_FontNames.GetCurSel(), strFaceName);
  420.     CClientDC dc(NULL);
  421.     EnumFontFamilies(dc.GetSafeHdc(), (LPCTSTR) strFaceName, (FONTENUMPROC) CFontPropPage::EnumFontFamiliesCallBack2, (LPARAM) this);
  422.  
  423.     // Check if we have a font that is either a vector or Truettype font
  424.     if (m_FontNames.GetFontType() != RASTER_FONTTYPE)
  425.     {
  426.         // Fill with "common" sizes
  427.         for (int i = 0; i < _countof(_afxTTDefaults); i++)
  428.             m_FontSizes.AddSize(_afxTTDefaults[i], 0);
  429.     }
  430.  
  431.     // See what fonts are native
  432.     BOOL    bRegular = (BOOL)(m_nStyles & NTM_REGULAR);
  433.     BOOL    bBold = (BOOL)(m_nStyles & NTM_BOLD);
  434.     BOOL    bItalic = (BOOL)(m_nStyles & NTM_ITALIC);
  435.     BOOL    bBoldItalic = (BOOL)((m_nStyles & NTM_BOLD) &&
  436.                                  (m_nStyles & NTM_ITALIC));
  437.  
  438.     // Allow for "synthesized" italic && bold variants
  439.     if (bRegular)
  440.         bBold = bItalic = TRUE;
  441.     if (bBold || bItalic)
  442.         bBoldItalic = TRUE;
  443.  
  444.     // Fill the styles list box
  445.     CString strStyle;
  446.  
  447.     int nEntry;
  448.     if (bRegular)
  449.     {
  450.         strStyle.LoadString(AFX_IDS_REGULAR);
  451.         nEntry = m_FontStyles.AddString(strStyle);
  452.         m_FontStyles.SetItemData(nEntry, (DWORD)NTM_REGULAR);
  453.     }
  454.     if (bBold)
  455.     {
  456.         strStyle.LoadString(AFX_IDS_BOLD);
  457.         nEntry = m_FontStyles.AddString(strStyle);
  458.         m_FontStyles.SetItemData(nEntry, (DWORD)NTM_BOLD);
  459.     }
  460.     if (bItalic)
  461.     {
  462.         strStyle.LoadString(AFX_IDS_ITALIC);
  463.         nEntry = m_FontStyles.AddString(strStyle);
  464.         m_FontStyles.SetItemData(nEntry, (DWORD)NTM_ITALIC);
  465.     }
  466.     if (bBoldItalic)
  467.     {
  468.         strStyle.LoadString(AFX_IDS_BOLDITALIC);
  469.         nEntry = m_FontStyles.AddString(strStyle);
  470.         m_FontStyles.SetItemData(nEntry, (DWORD)NTM_ITALIC|NTM_BOLD);
  471.     }
  472.  
  473.     // Set the point size
  474.     if (m_FontSizes.FindString(-1, m_strFontSize) != CB_ERR)
  475.     {
  476.         nEntry = m_FontSizes.SelectString(-1, m_strFontSize);
  477.         if (nEntry == CB_ERR)
  478.             return;
  479.     }
  480.     else
  481.     {
  482.         // Point size is not in the list so just fill the edit box
  483.         // and don't select anything from the list
  484.         m_FontSizes.SetCurSel(-1);
  485.         m_FontSizes.SetWindowText(m_strFontSize);
  486.     }
  487.  
  488.     // Set the styles combo box selection
  489.     BOOL bFound = FALSE;
  490.     int nMaxEntries = m_FontStyles.GetCount();
  491.     for (int nEntry3 = 0; nEntry3 < nMaxEntries; nEntry3++)
  492.     {
  493.         if (m_FontStyles.GetItemData(nEntry3) == m_nActualStyle)
  494.         {
  495.             m_FontStyles.SetCurSel(nEntry3);
  496.             bFound = TRUE;
  497.         }
  498.     }
  499.  
  500.     if (!bFound)
  501.     {
  502.         m_FontStyles.SetCurSel(0);      // Set style to regular
  503.         m_nCurrentStyle = NTM_REGULAR;
  504.     }
  505.     else
  506.         m_nCurrentStyle = m_nActualStyle;
  507.  
  508.     // Redraw the sample
  509.     UpdateSampleFont();
  510. }
  511.  
  512. int CALLBACK CFontPropPage::EnumFontFamiliesCallBack2(
  513.     ENUMLOGFONT* lpelf, NEWTEXTMETRIC* lpntm, int FontType, LPARAM lParam)
  514. {
  515.     CFontPropPage *pDlg = (CFontPropPage *)lParam;
  516.     ASSERT(pDlg != NULL);
  517.  
  518.     if (FontType & TRUETYPE_FONTTYPE)
  519.     {
  520.         if (!(lpntm->ntmFlags & (NTM_BOLD | NTM_ITALIC)))
  521.             pDlg->m_nStyles |= NTM_REGULAR;
  522.  
  523.         if (lpntm->ntmFlags & NTM_ITALIC)
  524.             pDlg->m_nStyles |= NTM_ITALIC;
  525.  
  526.         if (lpntm->ntmFlags & NTM_BOLD)
  527.             pDlg->m_nStyles |= NTM_BOLD;
  528.     }
  529.     else
  530.     {
  531.         if (FontType & RASTER_FONTTYPE)
  532.         {
  533.             int height = lpntm->tmHeight - lpntm->tmInternalLeading;
  534.             pDlg->m_FontSizes.AddSize(MulDiv(height, 72, afxData.cyPixelsPerInch), height);
  535.         }
  536.  
  537.         if (lpelf->elfLogFont.lfWeight >= FW_BOLD && lpelf->elfLogFont.lfItalic)
  538.             pDlg->m_nStyles |= NTM_BOLD | NTM_ITALIC;
  539.         else if (lpelf->elfLogFont.lfWeight >= FW_BOLD)
  540.             pDlg->m_nStyles |= NTM_BOLD;
  541.         else if (lpelf->elfLogFont.lfItalic)
  542.             pDlg->m_nStyles |= NTM_ITALIC;
  543.         else
  544.             pDlg->m_nStyles |= NTM_REGULAR;
  545.     }
  546.  
  547.     return 1;
  548. }
  549.  
  550. #define DX_BITMAP        20
  551. #define DY_BITMAP        12
  552.  
  553. /////////////////////////////////////////////////////////////////////////////
  554. // CFontComboBox
  555.  
  556. CFontComboBox::CFontComboBox() : CComboBox()
  557. {
  558.     m_bmpTrueType.LoadBitmap(AFX_IDB_TRUETYPE);
  559.     _AfxInitMaskFromBitmap(&m_bmpTrueType, &m_bmpMask);
  560. }
  561.  
  562. CFontComboBox::~CFontComboBox()
  563. {
  564. }
  565.  
  566. int CFontComboBox::AddFont(LOGFONT *pLF, DWORD FontType)
  567. {
  568.     int nEntry;
  569.     FONTITEM_PPG* pFontItem = NULL;
  570.  
  571.     // Font already in the combobox
  572.     if (FindString(-1, (LPCTSTR) pLF->lfFaceName) != CB_ERR)
  573.         return CB_ERR;
  574.  
  575.     // allocate some memory for the FONTITEM_PPG structure
  576.     TRY
  577.     {
  578.         pFontItem = new FONTITEM_PPG;
  579.     }
  580.     CATCH( CMemoryException, e )
  581.     {
  582.         return CB_ERR;
  583.     }
  584.     END_CATCH
  585.  
  586.     ASSERT( pFontItem );
  587.     pFontItem->lf = *pLF;
  588.     pFontItem->dwFontType = FontType;
  589.  
  590.     nEntry = AddString( (LPCTSTR) pFontItem->lf.lfFaceName );
  591.  
  592.     if (nEntry == CB_ERR)
  593.         delete pFontItem;
  594.     else
  595.         SetItemData( nEntry, (DWORD) pFontItem );
  596.  
  597.     return nEntry;
  598. }
  599.  
  600. FONTITEM_PPG* CFontComboBox::GetFontItem(int sel)
  601. {
  602.     if (sel == -1)
  603.         sel = GetCurSel();
  604.  
  605.     if (sel == -1)
  606.     {
  607.         CString str;
  608.  
  609.         GetWindowText( str );
  610.         sel = FindString( -1, str );
  611.         if (sel == CB_ERR)
  612.             sel = 0;
  613.     }
  614.  
  615.     ASSERT( GetItemData(sel) );
  616.     return (FONTITEM_PPG*) GetItemData(sel);
  617. }
  618.  
  619. LPLOGFONT CFontComboBox::GetLogFont(int sel)
  620. {
  621.     return &GetFontItem(sel)->lf;
  622. }
  623.  
  624. DWORD CFontComboBox::GetFontType(int sel)
  625. {
  626.     return GetFontItem(sel)->dwFontType;
  627. }
  628.  
  629. CString CFontComboBox::GetCurrentName()
  630. {
  631.     CString str;
  632.     GetWindowText(str);
  633.     return str;
  634. }
  635.  
  636. void CFontComboBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
  637. {
  638.     ASSERT( lpDIS->CtlType == ODT_COMBOBOX );
  639.  
  640.     // make sure this is a *real* item
  641.     if (lpDIS->itemID == -1)
  642.         return;
  643.  
  644.     CDC* pDC = CDC::FromHandle(lpDIS->hDC);
  645.     FONTITEM_PPG* pFI = (FONTITEM_PPG*)lpDIS->itemData;    // pointer to a FONTITEM storied in item data
  646.     LOGFONT* pLF = &pFI->lf;
  647.     COLORREF crBk, crText;
  648.     TEXTMETRIC tm;
  649.     int x, y;
  650.  
  651.     // Calculate the colors to use
  652.     crBk = pDC->SetBkColor(
  653.         GetSysColor(lpDIS->itemState & ODS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW) );
  654.     crText = pDC->SetTextColor(
  655.         GetSysColor(lpDIS->itemState & ODS_SELECTED ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT) );
  656.  
  657.     // Calculate the position of the text
  658.     pDC->GetTextMetrics( &tm );
  659.     x = LOWORD(GetDialogBaseUnits()) / 4;
  660.     y = (lpDIS->rcItem.bottom + lpDIS->rcItem.top - tm.tmHeight) / 2;
  661.  
  662.     // Draw the text
  663.     pDC->ExtTextOut(lpDIS->rcItem.left + DX_BITMAP + 2 * x, y, ETO_CLIPPED | ETO_OPAQUE,
  664.         &lpDIS->rcItem,(LPCTSTR) pLF->lfFaceName,
  665.         lstrlen((LPCTSTR) pLF->lfFaceName), NULL );
  666.  
  667.     // Put the colors back as they were
  668.     pDC->SetTextColor( crText );
  669.     pDC->SetBkColor( crBk );
  670.  
  671.     // Draw the TrueType bitmap
  672.     if (pFI->dwFontType & TRUETYPE_FONTTYPE)
  673.     {
  674.         int dy;
  675.         dy = ((lpDIS->rcItem.bottom - lpDIS->rcItem.top) - DY_BITMAP) / 2;
  676.         _AfxDrawMaskedBitmap(pDC, &m_bmpTrueType, &m_bmpMask,
  677.             x, lpDIS->rcItem.top + dy, DX_BITMAP, DY_BITMAP);
  678.     }
  679.  
  680.     // Draw the focus rect if needed
  681.     if (lpDIS->itemState & ODS_FOCUS)
  682.         pDC->DrawFocusRect( &lpDIS->rcItem );
  683. }
  684.  
  685. void CFontComboBox::DeleteItem(LPDELETEITEMSTRUCT lpDIS)
  686. {
  687.     FONTITEM_PPG* pFI;
  688.  
  689.     if (lpDIS->itemID == -1)
  690.         return;
  691.  
  692.     ASSERT( lpDIS->CtlType == ODT_COMBOBOX );
  693.  
  694.     pFI = GetFontItem(lpDIS->itemID);
  695.  
  696.     // Free the FONTITEM_PPG created in CFontComboBox::AddFont()
  697.     ASSERT(pFI);
  698.     delete pFI;
  699. }
  700.  
  701. /////////////////////////////////////////////////////////////////////////////
  702. // CSizeComboBox
  703.  
  704. int CSizeComboBox::AddSize(int PointSize, LONG lfHeight)
  705. {
  706.     if (lfHeight == 0)
  707.         lfHeight = MulDiv( -afxData.cyPixelsPerInch, PointSize, 72 );
  708.  
  709.     CString str;
  710.     wsprintf(str.GetBuffer(16), _T("%d"), PointSize);
  711.     str.ReleaseBuffer();
  712.  
  713.     int nMaxEntries = GetCount();
  714.     int nEntry;
  715.  
  716.     // we use positive height values for non-truetype fonts, negitive for true type
  717.     if (lfHeight > 0)
  718.     {
  719.         for (nEntry = 0; nEntry < nMaxEntries; nEntry++)
  720.         {
  721.             int iComp = (int)(lfHeight - GetHeight(nEntry));
  722.             if (!iComp)
  723.                 return CB_ERR;
  724.             if (iComp < 0)
  725.                 break;
  726.         }
  727.     }
  728.     else
  729.     {
  730.         for (nEntry = 0; nEntry < nMaxEntries; nEntry++)
  731.         {
  732.             int iComp = (int)(lfHeight - GetHeight(nEntry));
  733.             if (!iComp)
  734.                 return CB_ERR;
  735.             if (iComp > 0)
  736.                 break;
  737.         }
  738.     }
  739.  
  740.     if (nEntry == nMaxEntries)
  741.         nEntry = -1;
  742.     nEntry = InsertString(nEntry, str);
  743.     if (nEntry != CB_ERR)
  744.         SetItemData(nEntry, (DWORD)lfHeight);
  745.  
  746.     return nEntry;
  747. }
  748.  
  749. void CSizeComboBox::GetPointSize(CY& cy)
  750. {
  751.     TCHAR szText[20];
  752.     GetWindowText(szText, 20);
  753.     cy.Lo = 0;
  754.     cy.Hi = 0;
  755.     _AfxCyFromString(cy, szText);
  756. }
  757.  
  758. LONG CSizeComboBox::GetHeight(int sel)
  759. {
  760.     if (sel == -1)
  761.         sel = GetCurSel();
  762.  
  763.     if (sel == -1)
  764.     {
  765.         TCHAR szText[20];
  766.         GetWindowText(szText, 20);
  767.         sel = FindString( -1, szText);
  768.         if (sel == CB_ERR)
  769.         {
  770.             CY cyTmp;
  771.             cyTmp.Lo = 0;
  772.             cyTmp.Hi = 0;
  773.             _AfxCyFromString(cyTmp, szText);
  774.             int PointSize = (int)((cyTmp.Lo + 5000) / 10000);
  775.             if (PointSize != 0)
  776.                 return MulDiv(-afxData.cyPixelsPerInch, PointSize, 72);
  777.             else
  778.                 sel = 0;
  779.         }
  780.     }
  781.  
  782.     return (LONG) GetItemData(sel);
  783. }
  784.  
  785. void CSizeComboBox::UpdateLogFont( LPLOGFONT lpLF, int sel )
  786. {
  787.     ASSERT(lpLF);
  788.  
  789.     lpLF->lfHeight = (int)GetHeight(sel);
  790.     lpLF->lfWidth = 0;
  791. }
  792.  
  793. /////////////////////////////////////////////////////////////////////////////
  794. // CFontPropPage message handlers
  795.  
  796. void CFontPropPage::OnEditupdateFontnames()
  797. {
  798.     // When the users entry matches an entry in the list, select it
  799.     CString str;
  800.     m_FontNames.GetWindowText(str);
  801.     int nEntry = m_FontNames.FindStringExact(-1, str);
  802.     if (nEntry != CB_ERR)
  803.     {
  804.         m_FontNames.SetCurSel(nEntry);
  805.         m_FontNames.SetEditSel(-1, -1);
  806.  
  807.         // Re-fill the size list
  808.         FillSizeList();
  809.     }
  810. }
  811.  
  812. void CFontPropPage::OnEditupdateFontsizes()
  813. {
  814.     // when the users entry matches an entry in the list, select it
  815.     m_FontSizes.GetWindowText(m_strFontSize);
  816.     int nEntry = m_FontSizes.FindStringExact(-1, m_strFontSize);
  817.     if (nEntry != CB_ERR)
  818.     {
  819.         m_FontSizes.SetCurSel(nEntry);
  820.         m_FontSizes.SetEditSel(-1, -1);
  821.  
  822.         // Update the sample text
  823.         UpdateSampleFont();
  824.     }
  825. }
  826.  
  827. void CFontPropPage::OnSelchangeFontnames()
  828. {
  829.     FillSizeList();
  830. }
  831.  
  832. void CFontPropPage::UpdateSampleFont()
  833. {
  834.     ASSERT(m_FontNames.GetFontItem());
  835.  
  836.     LOGFONT lf = *m_FontNames.GetLogFont();
  837.     m_FontSizes.UpdateLogFont( &lf );
  838.  
  839.     // Handle styles
  840.     if (m_nCurrentStyle & NTM_BOLD)
  841.         lf.lfWeight = FW_BOLD;
  842.     else
  843.         lf.lfWeight = FW_REGULAR;
  844.     if (m_nCurrentStyle & NTM_ITALIC)
  845.         lf.lfItalic = TRUE;
  846.     else
  847.         lf.lfItalic = FALSE;
  848.  
  849.     lf.lfStrikeOut = (unsigned char)m_bStrikeOut;
  850.     lf.lfUnderline = (unsigned char)m_bUnderline;
  851.  
  852.     SampleFont.DeleteObject();
  853.     SampleFont.CreateFontIndirect( &lf );
  854.  
  855.     CRect rcSample;
  856.     m_SampleBox.GetWindowRect( &rcSample );
  857.     ScreenToClient( &rcSample );
  858.  
  859.     InvalidateRect( rcSample );
  860.     UpdateWindow();
  861. }
  862.  
  863. void CFontPropPage::OnPaint()
  864. {
  865.     CPaintDC dc(this);
  866.     CRect rcText;
  867.     CFont *oldFont;
  868.     CSize TextExtent;
  869.     COLORREF crText;
  870.     TEXTMETRIC tm;
  871.     int bkMode, len, x, y;
  872.     CString strSample;
  873.  
  874.     strSample.LoadString(AFX_IDS_SAMPLETEXT);
  875.  
  876.     // If there is no sample font abort
  877.     if (!SampleFont.GetSafeHandle())
  878.         return;
  879.  
  880.     // Get the bounding box
  881.     m_SampleBox.GetWindowRect( &rcText );
  882.     ScreenToClient( &rcText );
  883.  
  884.     // Select the new font and colors into the dc
  885.     oldFont = dc.SelectObject( &SampleFont );
  886.     crText = dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
  887.     bkMode = dc.SetBkMode(TRANSPARENT);
  888.  
  889.     // Calculate the position of the text
  890.     dc.GetTextMetrics( &tm );
  891.  
  892.     len = strSample.GetLength();
  893.     TextExtent = dc.GetTextExtent(strSample, len);
  894.     TextExtent.cy = tm.tmAscent - tm.tmInternalLeading;
  895.  
  896.     if ((TextExtent.cx >= (rcText.right - rcText.left)) ||
  897.             (TextExtent.cx <= 0))
  898.         x = rcText.left;
  899.     else
  900.         x = rcText.left + ((rcText.right - rcText.left) - TextExtent.cx) / 2;
  901.  
  902.     y = min(rcText.bottom,
  903.         rcText.bottom - ((rcText.bottom - rcText.top) - TextExtent.cy) / 2);
  904.  
  905.     // Draw it
  906.     dc.ExtTextOut(x, y - (tm.tmAscent), ETO_CLIPPED, &rcText,
  907.         strSample, len, NULL);
  908.  
  909.     // Put the DC back the way it was
  910.     dc.SetBkMode(bkMode);
  911.     dc.SetTextColor(crText);
  912.  
  913.     if (oldFont)
  914.         dc.SelectObject(oldFont);
  915. }
  916.  
  917. void CFontPropPage::OnSelchangeFontsizes()
  918. {
  919.     int nEntry = m_FontSizes.GetCurSel();
  920.     if (nEntry != CB_ERR)
  921.     {
  922.         m_FontSizes.GetLBText(nEntry, m_strFontSize);
  923.         UpdateSampleFont();
  924.     }
  925. }
  926. void CFontPropPage::OnSelchangeFontstyles()
  927. {
  928.     int nEntry = m_FontStyles.GetCurSel();
  929.     m_nCurrentStyle = m_FontStyles.GetItemData(nEntry);
  930.     m_nActualStyle = m_nCurrentStyle;
  931.  
  932.     // Update the sample font
  933.     UpdateSampleFont();
  934. }
  935.  
  936. void CFontPropPage::OnEditchangeFontstyles()
  937. {
  938.     // when the users entry matches an entry in the list, select it
  939.     CString str;
  940.     m_FontStyles.GetWindowText(str);
  941.     int nEntry = m_FontStyles.FindStringExact(-1, str);
  942.     if (nEntry != CB_ERR)
  943.     {
  944.         m_FontStyles.SetCurSel(nEntry);
  945.         m_FontStyles.SetEditSel(-1, -1);
  946.  
  947.         // Update the sample text
  948.         m_nCurrentStyle = m_FontStyles.GetItemData(nEntry);
  949.         m_nActualStyle = m_nCurrentStyle;
  950.         UpdateSampleFont();
  951.     }
  952. }
  953.  
  954. void CFontPropPage::SelectFontFromList(CString strFaceName, MERGEOBJECT* pmobj)
  955. {
  956.     // Set the effects buttons
  957.     CButton* pStrikeOut = (CButton*) GetDlgItem(AFX_IDC_STRIKEOUT);
  958.     if (!pmobj->bStrikethroughOK)
  959.         pStrikeOut->SetCheck(2);
  960.     else if (m_bStrikeOut)
  961.         pStrikeOut->SetCheck(1);
  962.     else
  963.         pStrikeOut->SetCheck(0);
  964.  
  965.     CButton* pUnderline = (CButton*) GetDlgItem(AFX_IDC_UNDERLINE);
  966.     if (!pmobj->bUnderlineOK)
  967.         pStrikeOut->SetCheck(2);
  968.     else if (m_bUnderline)
  969.         pUnderline->SetCheck(1);
  970.     else
  971.         pUnderline->SetCheck(0);
  972.  
  973.     // Set the font facename
  974.     if (pmobj->bNameOK)
  975.     {
  976.         int nEntry1 = m_FontNames.SelectString(-1, strFaceName);
  977.         if (nEntry1 == CB_ERR)
  978.             return;
  979.     }
  980.  
  981.     // Fill the size list appropriately
  982.     FillSizeList();
  983.  
  984.     // Set the styles combo box selection
  985.     BOOL bFound = FALSE;
  986.     int nMaxEntries = m_FontStyles.GetCount();
  987.     for (int nEntry3 = 0; nEntry3 < nMaxEntries; nEntry3++)
  988.     {
  989.         if (m_FontStyles.GetItemData(nEntry3) == m_nActualStyle)
  990.         {
  991.             m_FontStyles.SetCurSel(nEntry3);
  992.             bFound = TRUE;
  993.         }
  994.     }
  995.  
  996.     if (pmobj->bSizeOK)
  997.     {
  998.         if (!bFound)
  999.         {
  1000.             m_FontStyles.SetCurSel(0);      // Set style to regular
  1001.             m_nCurrentStyle = NTM_REGULAR;
  1002.         }
  1003.         else
  1004.             m_nCurrentStyle = m_nActualStyle;
  1005.     }
  1006.  
  1007.     UpdateSampleFont();
  1008. }
  1009.  
  1010. void CFontPropPage::OnStrikeout()
  1011. {
  1012.     CButton* pStrikeOut = (CButton*) GetDlgItem(AFX_IDC_STRIKEOUT);
  1013.     if (pStrikeOut->GetCheck() == 1)
  1014.         m_bStrikeOut = TRUE;
  1015.     else
  1016.         m_bStrikeOut = FALSE;
  1017.  
  1018.     UpdateSampleFont();
  1019. }
  1020.  
  1021. void CFontPropPage::OnUnderline()
  1022. {
  1023.     CButton* pUnderline = (CButton*) GetDlgItem(AFX_IDC_UNDERLINE);
  1024.     if (pUnderline->GetCheck() == 1)
  1025.         m_bUnderline = TRUE;
  1026.     else
  1027.         m_bUnderline = FALSE;
  1028.  
  1029.     UpdateSampleFont();
  1030. }
  1031.  
  1032. void CFontPropPage::OnSelchangeFontprop()
  1033. {
  1034.     OnSelchangePropname(m_FontProp);
  1035. }
  1036.  
  1037. BOOL CFontPropPage::OnEditProperty(DISPID dispid)
  1038. {
  1039.     return CStockPropPage::OnEditProperty(dispid, m_FontProp);
  1040. }
  1041.  
  1042. void CFontPropPage::OnObjectsChanged()
  1043. {
  1044.     ULONG nObjects;
  1045.     if (GetObjectArray(&nObjects) != NULL && m_hWnd != NULL)
  1046.     {
  1047.         FillPropnameList(IID_IFontDisp, 1, m_FontProp);
  1048.  
  1049.         if ( m_FontProp.GetCount() > 0 )
  1050.             FillFacenameList();
  1051.         else
  1052.         {
  1053.             m_FontNames.EnableWindow(FALSE);
  1054.             m_FontSizes.EnableWindow(FALSE);
  1055.             m_FontStyles.EnableWindow(FALSE);
  1056.             GetDlgItem(AFX_IDC_STRIKEOUT)->EnableWindow(FALSE);
  1057.             GetDlgItem(AFX_IDC_UNDERLINE)->EnableWindow(FALSE);
  1058.         }
  1059.     }
  1060.  
  1061.     if (m_hWnd != NULL)
  1062.         OnSelchangeFontprop();
  1063. }
  1064.  
  1065. /////////////////////////////////////////////////////////////////////////////
  1066. // Class factory for Font property page
  1067.  
  1068. #ifdef _AFXDLL
  1069.  
  1070. #ifdef AFXCTL_FACT_SEG
  1071. #pragma code_seg(AFXCTL_FACT_SEG)
  1072. #endif
  1073.  
  1074. IMPLEMENT_OLECREATE_EX(CFontPropPage, "OCxx.CFontPropPage",
  1075.     0x0be35200,0x8f91,0x11ce,0x9d,0xe3,0x00,0xaa,0x00,0x4b,0xb8,0x51)
  1076.  
  1077. BOOL CFontPropPage::CFontPropPageFactory::UpdateRegistry(BOOL bRegister)
  1078. {
  1079.     if (bRegister)
  1080.         return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),
  1081.             m_clsid, AFX_IDS_FONT_PPG);
  1082.     else
  1083.         return AfxOleUnregisterClass(m_clsid, NULL);
  1084. }
  1085.  
  1086. #endif //_AFXDLL
  1087.  
  1088. /////////////////////////////////////////////////////////////////////////////
  1089. // Force any extra compiler-generated code into AFX_INIT_SEG
  1090.  
  1091. #ifdef AFX_INIT_SEG
  1092. #pragma code_seg(AFX_INIT_SEG)
  1093. #endif
  1094.  
  1095. IMPLEMENT_DYNCREATE(CFontPropPage, CStockPropPage)
  1096.