home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / ole / wordpad / formatba.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  21KB  |  806 lines

  1. // formatba.cpp : implementation file
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14.  
  15. #include "wordpad.h"
  16. #include "wordpdoc.h"
  17. #include "wordpvw.h"
  18. #include "formatba.h"
  19. #include "strings.h"
  20.  
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char BASED_CODE THIS_FILE[] = __FILE__;
  24. #endif
  25.  
  26. // reserve lobyte for charset
  27. #define PRINTER_FONT 0x0100
  28. #define TT_FONT 0x0200
  29. #define DEVICE_FONT 0x0400
  30.  
  31. #define BMW 16
  32. #define BMH 15
  33.  
  34. static int nFontSizes[] =
  35.     {8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72};
  36. int CLocalComboBox::m_nFontHeight = 0;
  37.  
  38. class CFontDesc
  39. {
  40. public:
  41.     CFontDesc(LPCTSTR lpszName, LPCTSTR lpszScript, BYTE nCharSet,
  42.         BYTE nPitchAndFamily, DWORD dwFlags);
  43.     CString m_strName;
  44.     CString m_strScript;
  45.     BYTE m_nCharSet;
  46.     BYTE m_nPitchAndFamily;
  47.     DWORD m_dwFlags;
  48. };
  49.  
  50. CFontDesc::CFontDesc(LPCTSTR lpszName, LPCTSTR lpszScript, BYTE nCharSet,
  51.     BYTE nPitchAndFamily, DWORD dwFlags)
  52. {
  53.     m_strName = lpszName;
  54.     m_strScript = lpszScript;
  55.     m_nCharSet = nCharSet;
  56.     m_nPitchAndFamily = nPitchAndFamily;
  57.     m_dwFlags = dwFlags;
  58. }
  59.  
  60. BEGIN_MESSAGE_MAP(CFormatBar, CToolBar)
  61.     //{{AFX_MSG_MAP(CFormatBar)
  62.     ON_WM_CREATE()
  63.     ON_WM_DESTROY()
  64.     //}}AFX_MSG_MAP
  65.     ON_CBN_DROPDOWN(IDC_FONTSIZE, OnFontSizeDropDown)
  66.     ON_CBN_KILLFOCUS(IDC_FONTNAME, OnFontNameKillFocus)
  67.     ON_CBN_KILLFOCUS(IDC_FONTSIZE, OnFontSizeKillFocus)
  68.     ON_CBN_SETFOCUS(IDC_FONTNAME, OnComboSetFocus)
  69.     ON_CBN_SETFOCUS(IDC_FONTSIZE, OnComboSetFocus)
  70.     ON_CBN_CLOSEUP(IDC_FONTNAME, OnComboCloseUp)
  71.     ON_CBN_CLOSEUP(IDC_FONTSIZE, OnComboCloseUp)
  72.     ON_REGISTERED_MESSAGE(CWordPadApp::m_nPrinterChangedMsg, OnPrinterChanged)
  73.     // Global help commands
  74. END_MESSAGE_MAP()
  75.  
  76. static CSize GetBaseUnits(CFont* pFont)
  77. {
  78.     ASSERT(pFont != NULL);
  79.     ASSERT(pFont->GetSafeHandle() != NULL);
  80.     pFont = theApp.m_dcScreen.SelectObject(pFont);
  81.     TEXTMETRIC tm;
  82.     VERIFY(theApp.m_dcScreen.GetTextMetrics(&tm));
  83.  
  84.     theApp.m_dcScreen.SelectObject(pFont);
  85. //  return CSize(tm.tmAveCharWidth, tm.tmHeight+tm.tmDescent);
  86.     return CSize(tm.tmAveCharWidth, tm.tmHeight);
  87. }
  88.  
  89. CFormatBar::CFormatBar()
  90. {
  91.     CFont fnt;
  92.     fnt.Attach(GetStockObject(theApp.m_nDefFont));
  93.     m_szBaseUnits = GetBaseUnits(&fnt);
  94.     CLocalComboBox::m_nFontHeight = m_szBaseUnits.cy;
  95. }
  96.  
  97. void CFormatBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  98. {
  99.     CToolBar::OnUpdateCmdUI(pTarget, bDisableIfNoHndler);
  100.     // don't update combo boxes if either one has the focus
  101.     if (!m_comboFontName.HasFocus() && !m_comboFontSize.HasFocus())
  102.         SyncToView();
  103. }
  104.  
  105. void CFormatBar::SyncToView()
  106. {
  107.     USES_CONVERSION;
  108.     // get the current font from the view and update
  109.     CHARHDR fh;
  110.     CHARFORMAT& cf = fh.cf;
  111.     fh.hwndFrom = m_hWnd;
  112.     fh.idFrom = GetDlgCtrlID();
  113.     fh.code = FN_GETFORMAT;
  114.     VERIFY(GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh));
  115.  
  116.     // the selection must be same font and charset to display correctly
  117.     if ((cf.dwMask & (CFM_FACE|CFM_CHARSET)) == (CFM_FACE|CFM_CHARSET))
  118.         m_comboFontName.MatchFont(A2T(cf.szFaceName), cf.bCharSet);
  119.     else
  120.         m_comboFontName.SetTheText(_T(""));
  121.  
  122.     // SetTwipSize only updates if different
  123.     // -1 means selection is not a single point size
  124.     m_comboFontSize.SetTwipSize( (cf.dwMask & CFM_SIZE) ? cf.yHeight : -1);
  125. }
  126.  
  127. void CFormatBar::OnFontSizeDropDown()
  128. {
  129.     CString str;
  130.     m_comboFontName.GetTheText(str);
  131.     LPCTSTR lpszName = NULL;
  132.     BOOL bPrinterFont;
  133.     int nIndex = m_comboFontName.FindStringExact(-1, str);
  134.     if (nIndex != CB_ERR)
  135.     {
  136.         CFontDesc* pDesc = (CFontDesc*)m_comboFontName.GetItemData(nIndex);
  137.         ASSERT(pDesc != NULL);
  138.         bPrinterFont = pDesc->m_dwFlags & PRINTER_FONT;
  139.         lpszName = pDesc->m_strName;
  140.     }
  141.  
  142.     int nSize = m_comboFontSize.GetTwipSize();
  143.     if (nSize == -2) // error
  144.     {
  145.         AfxMessageBox(IDS_INVALID_NUMBER, MB_OK|MB_ICONINFORMATION);
  146.         nSize = m_comboFontSize.m_nTwipsLast;
  147.     }
  148.     else if ((nSize >= 0 && nSize < 20) || nSize > 32760)
  149.     {
  150.         AfxMessageBox(IDS_INVALID_FONTSIZE, MB_OK|MB_ICONINFORMATION);
  151.         nSize = m_comboFontSize.m_nTwipsLast;
  152.     }
  153.  
  154.     if (bPrinterFont)
  155.         m_comboFontSize.EnumFontSizes(m_dcPrinter, lpszName);
  156.     else
  157.         m_comboFontSize.EnumFontSizes(theApp.m_dcScreen, lpszName);
  158.     m_comboFontSize.SetTwipSize(nSize);
  159. }
  160.  
  161. void CFormatBar::OnComboCloseUp()
  162. {
  163.     NotifyOwner(NM_RETURN);
  164. }
  165.  
  166. void CFormatBar::OnComboSetFocus()
  167. {
  168.     NotifyOwner(NM_SETFOCUS);
  169. }
  170.  
  171. void CFormatBar::OnFontNameKillFocus()
  172. {
  173.     USES_CONVERSION;
  174.     // get the current font from the view and update
  175.     NotifyOwner(NM_KILLFOCUS);
  176.  
  177.     CCharFormat cf;
  178.     cf.szFaceName[0] = NULL;
  179.  
  180.     // this will retrieve the font entered in the edit control
  181.     // it tries to match the font to something already present in the combo box
  182.     // this effectively ignores case of a font the user enters
  183.     // if a user enters arial, this will cause it to become Arial
  184.     CString str;
  185.     m_comboFontName.GetTheText(str);    // returns "arial"
  186.     m_comboFontName.SetTheText(str);                    // selects "Arial"
  187.     m_comboFontName.GetTheText(str);    // returns "Arial"
  188.  
  189.     // if font name box is not empty
  190.     if (str[0] != NULL)
  191.     {
  192.         cf.dwMask = CFM_FACE | CFM_CHARSET;
  193.         int nIndex = m_comboFontName.FindStringExact(-1, str);
  194.         if (nIndex != CB_ERR)
  195.         {
  196.             CFontDesc* pDesc = (CFontDesc*)m_comboFontName.GetItemData(nIndex);
  197.             ASSERT(pDesc != NULL);
  198.             ASSERT(pDesc->m_strName.GetLength() < LF_FACESIZE);
  199.             lstrcpynA(cf.szFaceName,
  200.                 T2A((LPTSTR) (LPCTSTR) pDesc->m_strName), LF_FACESIZE);
  201.             cf.bCharSet = pDesc->m_nCharSet;
  202.             cf.bPitchAndFamily = pDesc->m_nPitchAndFamily;
  203.         }
  204.         else // unknown font
  205.         {
  206.             ASSERT(str.GetLength() < LF_FACESIZE);
  207.             lstrcpynA(cf.szFaceName,
  208.                 T2A((LPTSTR) (LPCTSTR) str), LF_FACESIZE);
  209.             cf.bCharSet = DEFAULT_CHARSET;
  210.             cf.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  211.         }
  212.         SetCharFormat(cf);
  213.     }
  214. }
  215.  
  216. void CFormatBar::OnFontSizeKillFocus()
  217. {
  218.     NotifyOwner(NM_KILLFOCUS);
  219.     int nSize = m_comboFontSize.GetTwipSize();
  220.     if (nSize == -2)
  221.     {
  222.         AfxMessageBox(IDS_INVALID_NUMBER, MB_OK|MB_ICONINFORMATION);
  223.         nSize = m_comboFontSize.m_nTwipsLast;
  224.     }
  225.     else if ((nSize >= 0 && nSize < 20) || nSize > 32760)
  226.     {
  227.         AfxMessageBox(IDS_INVALID_FONTSIZE, MB_OK|MB_ICONINFORMATION);
  228.         nSize = m_comboFontSize.m_nTwipsLast;
  229.     }
  230.     else if (nSize > 0)
  231.     {
  232.         CCharFormat cf;
  233.         cf.dwMask = CFM_SIZE;
  234.         cf.yHeight = nSize;
  235.         SetCharFormat(cf);
  236.     }
  237. }
  238.  
  239. LONG CFormatBar::OnPrinterChanged(UINT, LONG)
  240. {
  241.     theApp.CreatePrinterDC(m_dcPrinter);
  242.     m_comboFontName.EnumFontFamiliesEx(m_dcPrinter);
  243.     return 0;
  244. }
  245.  
  246. int CFormatBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
  247. {
  248.     if (CToolBar::OnCreate(lpCreateStruct) == -1)
  249.         return -1;
  250.  
  251.     theApp.m_listPrinterNotify.AddTail(m_hWnd);
  252.  
  253.     CRect rect(0,0, (3*LF_FACESIZE*m_szBaseUnits.cx)/2, 200);
  254.     if (!m_comboFontName.Create(WS_TABSTOP|WS_VISIBLE|WS_TABSTOP|
  255.         WS_VSCROLL|CBS_DROPDOWN|CBS_SORT|CBS_AUTOHSCROLL|CBS_HASSTRINGS|
  256.         CBS_OWNERDRAWFIXED, rect, this, IDC_FONTNAME))
  257.     {
  258.         TRACE0("Failed to create fontname combo-box\n");
  259.         return -1;
  260.     }
  261.     m_comboFontName.LimitText(LF_FACESIZE);
  262.  
  263.     rect.SetRect(0, 0, 10*m_szBaseUnits.cx, 200);
  264.     if (!m_comboFontSize.Create(WS_TABSTOP|WS_VISIBLE|WS_TABSTOP|
  265.         WS_VSCROLL|CBS_DROPDOWN, rect, this, IDC_FONTSIZE))
  266.     {
  267.         TRACE0("Failed to create fontsize combo-box\n");
  268.         return -1;
  269.     }
  270.  
  271.     m_comboFontSize.LimitText(4);
  272.     m_comboFontName.EnumFontFamiliesEx(m_dcPrinter);
  273.  
  274.     return 0;
  275. }
  276.  
  277. void CFormatBar::OnDestroy()
  278. {
  279.     CToolBar::OnDestroy();
  280.     POSITION pos = theApp.m_listPrinterNotify.Find(m_hWnd);
  281.     ASSERT(pos != NULL);
  282.     theApp.m_listPrinterNotify.RemoveAt(pos);
  283. }
  284.  
  285. void CFormatBar::PositionCombos()
  286. {
  287.     CRect rect;
  288.     // make font name box same size as font size box
  289.     // this is necessary since font name box is owner draw
  290.     m_comboFontName.SetItemHeight(-1, m_comboFontSize.GetItemHeight(-1));
  291.  
  292.     m_comboFontName.GetWindowRect(&rect);
  293.     int nHeight = rect.Height();
  294.  
  295.     m_comboFontName.GetWindowRect(&rect);
  296.     SetButtonInfo(0, IDC_FONTNAME, TBBS_SEPARATOR, rect.Width());
  297.     GetItemRect(0, &rect); // FontName ComboBox
  298.     m_comboFontName.SetWindowPos(NULL, rect.left,
  299.         ((rect.Height() - nHeight) / 2) + rect.top, 0, 0,
  300.         SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
  301.  
  302.     m_comboFontSize.GetWindowRect(&rect);
  303.     SetButtonInfo(2, IDC_FONTSIZE, TBBS_SEPARATOR, rect.Width());
  304.     GetItemRect(2, &rect); // FontSize ComboBox
  305.     m_comboFontSize.SetWindowPos(NULL, rect.left,
  306.         ((rect.Height() - nHeight) / 2) + rect.top, 0, 0,
  307.         SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
  308. }
  309.  
  310. /////////////////////////////////////////////////////////////////////////////
  311. // CFontComboBox
  312.  
  313. BEGIN_MESSAGE_MAP(CFontComboBox, CLocalComboBox)
  314.     //{{AFX_MSG_MAP(CFontComboBox)
  315.     ON_WM_DESTROY()
  316.     //}}AFX_MSG_MAP
  317.     // Global help commands
  318. END_MESSAGE_MAP()
  319.  
  320. CFontComboBox::CFontComboBox()
  321. {
  322.     VERIFY(m_bmFontType.LoadBitmap(IDB_FONTTYPE));
  323. }
  324.  
  325. void CFontComboBox::OnDestroy()
  326. {
  327.     // destroy all the CFontDesc's
  328.     EmptyContents();
  329.     CLocalComboBox::OnDestroy();
  330. }
  331.  
  332. void CFontComboBox::EmptyContents()
  333. {
  334.     // destroy all the CFontDesc's
  335.     int nCount = GetCount();
  336.     for (int i=0;i<nCount;i++)
  337.         delete (CFontDesc*)GetItemData(i);
  338. }
  339.  
  340. void CFontComboBox::EnumFontFamiliesEx(CDC& dc, BYTE nCharSet)
  341. {
  342.     CMapStringToPtr map;
  343.     CString str;
  344.     GetTheText(str);
  345.  
  346.     EmptyContents();
  347.     ResetContent();
  348.     LOGFONT lf;
  349.     memset(&lf, 0, sizeof(LOGFONT));
  350.     lf.lfCharSet = nCharSet;
  351.  
  352.     if (dc.m_hDC != NULL)
  353.     {
  354.         if (theApp.m_bWin4)
  355.         {
  356.             ::EnumFontFamiliesEx(dc.m_hDC, &lf,
  357.                 (FONTENUMPROC) EnumFamPrinterCallBackEx, (LPARAM) this, NULL);
  358.         }
  359.         else
  360.         {
  361.             ::EnumFontFamilies(dc.m_hDC, NULL,
  362.                 (FONTENUMPROC) EnumFamPrinterCallBack, (LPARAM) this);
  363.         }
  364.     }
  365.     else
  366.     {
  367.         HDC hDC = theApp.m_dcScreen.m_hDC;
  368.         ASSERT(hDC != NULL);
  369.         if (theApp.m_bWin4)
  370.         {
  371.             ::EnumFontFamiliesEx(hDC, &lf,
  372.                 (FONTENUMPROC) EnumFamScreenCallBackEx, (LPARAM) this, NULL);
  373.         }
  374.         else
  375.         {
  376.             ::EnumFontFamilies(hDC, NULL,
  377.                 (FONTENUMPROC) EnumFamScreenCallBack, (LPARAM) this);
  378.         }
  379.     }
  380.     // now walk through the fonts and remove (charset) from fonts with only one
  381.  
  382.     int nCount = m_arrayFontDesc.GetSize();
  383.     // walk through fonts adding names to string map
  384.     // first time add value 0, after that add value 1
  385.     for (int i = 0; i<nCount;i++)
  386.     {
  387.         CFontDesc* pDesc = (CFontDesc*)m_arrayFontDesc[i];
  388.         void* pv = NULL;
  389.         if (map.Lookup(pDesc->m_strName, pv)) // found it
  390.         {
  391.             if (pv == NULL) // only one entry so far
  392.             {
  393.                 map.RemoveKey(pDesc->m_strName);
  394.                 map.SetAt(pDesc->m_strName, (void*)1);
  395.             }
  396.         }
  397.         else // not found
  398.             map.SetAt(pDesc->m_strName, (void*)0);
  399.     }
  400.  
  401.     for (i = 0; i<nCount;i++)
  402.     {
  403.         CFontDesc* pDesc = (CFontDesc*)m_arrayFontDesc[i];
  404.         CString str = pDesc->m_strName;
  405.         void* pv = NULL;
  406.         VERIFY(map.Lookup(str, pv));
  407.         if (pv != NULL && !pDesc->m_strScript.IsEmpty())
  408.         {
  409.             str += " (";
  410.             str += pDesc->m_strScript;
  411.             str += ")";
  412.         }
  413.  
  414.         int nIndex = AddString(str);
  415.         ASSERT(nIndex >=0);
  416.         if (nIndex >=0) //no error
  417.             SetItemData(nIndex, (DWORD)pDesc);
  418.     }
  419.  
  420.     SetTheText(str);
  421.     m_arrayFontDesc.RemoveAll();
  422. }
  423.  
  424. void CFontComboBox::AddFont(ENUMLOGFONT* pelf, DWORD dwType, LPCTSTR lpszScript)
  425. {
  426.     LOGFONT& lf = pelf->elfLogFont;
  427.     if (lf.lfCharSet == MAC_CHARSET) // don't put in MAC fonts, commdlg doesn't either
  428.         return;
  429.     // Don't display vertical font for FE platform
  430.     if ((GetSystemMetrics(SM_DBCSENABLED)) && (lf.lfFaceName[0] == '@'))
  431.         return;
  432.     // don't put in non-printer raster fonts
  433.     CFontDesc* pDesc = new CFontDesc(lf.lfFaceName, lpszScript,
  434.         lf.lfCharSet, lf.lfPitchAndFamily, dwType);
  435.     m_arrayFontDesc.Add(pDesc);
  436. }
  437.  
  438. BOOL CALLBACK AFX_EXPORT CFontComboBox::EnumFamScreenCallBack(ENUMLOGFONT* pelf,
  439.     NEWTEXTMETRICEX* /*lpntm*/, int FontType, LPVOID pThis)
  440. {
  441.     // don't put in non-printer raster fonts
  442.     if (FontType & RASTER_FONTTYPE)
  443.         return 1;
  444.     DWORD dwData = (FontType & TRUETYPE_FONTTYPE) ? TT_FONT : 0;
  445.     ((CFontComboBox *)pThis)->AddFont(pelf, dwData);
  446.     return 1;
  447. }
  448.  
  449. BOOL CALLBACK AFX_EXPORT CFontComboBox::EnumFamPrinterCallBack(ENUMLOGFONT* pelf,
  450.     NEWTEXTMETRICEX* /*lpntm*/, int FontType, LPVOID pThis)
  451. {
  452.     DWORD dwData = PRINTER_FONT;
  453.     if (FontType & TRUETYPE_FONTTYPE)
  454.         dwData |= TT_FONT;
  455.     else if (FontType & DEVICE_FONTTYPE)
  456.         dwData |= DEVICE_FONT;
  457.     ((CFontComboBox *)pThis)->AddFont(pelf, dwData);
  458.     return 1;
  459. }
  460.  
  461. BOOL CALLBACK AFX_EXPORT CFontComboBox::EnumFamScreenCallBackEx(ENUMLOGFONTEX* pelf,
  462.     NEWTEXTMETRICEX* /*lpntm*/, int FontType, LPVOID pThis)
  463. {
  464.     // don't put in non-printer raster fonts
  465.     if (FontType & RASTER_FONTTYPE)
  466.         return 1;
  467.     DWORD dwData = (FontType & TRUETYPE_FONTTYPE) ? TT_FONT : 0;
  468.     ((CFontComboBox *)pThis)->AddFont((ENUMLOGFONT*)pelf, dwData, CString(pelf->elfScript));
  469.     return 1;
  470. }
  471.  
  472. BOOL CALLBACK AFX_EXPORT CFontComboBox::EnumFamPrinterCallBackEx(ENUMLOGFONTEX* pelf,
  473.     NEWTEXTMETRICEX* /*lpntm*/, int FontType, LPVOID pThis)
  474. {
  475.     DWORD dwData = PRINTER_FONT;
  476.     if (FontType & TRUETYPE_FONTTYPE)
  477.         dwData |= TT_FONT;
  478.     else if (FontType & DEVICE_FONTTYPE)
  479.         dwData |= DEVICE_FONT;
  480.     ((CFontComboBox *)pThis)->AddFont((ENUMLOGFONT*)pelf, dwData, CString(pelf->elfScript));
  481.     return 1;
  482. }
  483.  
  484. void CFontComboBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
  485. {
  486.     ASSERT(lpDIS->CtlType == ODT_COMBOBOX);
  487.     int id = (int)(WORD)lpDIS->itemID;
  488.  
  489.     CDC *pDC = CDC::FromHandle(lpDIS->hDC);
  490.     CRect rc(lpDIS->rcItem);
  491.     if (lpDIS->itemState & ODS_FOCUS)
  492.         pDC->DrawFocusRect(rc);
  493.     int nIndexDC = pDC->SaveDC();
  494.  
  495.     CBrush brushFill;
  496.     if (lpDIS->itemState & ODS_SELECTED)
  497.     {
  498.         brushFill.CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT));
  499.         pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  500.     }
  501.     else
  502.         brushFill.CreateSolidBrush(pDC->GetBkColor());
  503.     pDC->SetBkMode(TRANSPARENT);
  504.     pDC->FillRect(rc, &brushFill);
  505.  
  506.     CFontDesc* pDesc= (CFontDesc*)lpDIS->itemData;
  507.     ASSERT(pDesc != NULL);
  508.     DWORD dwData = pDesc->m_dwFlags;
  509.     if (dwData & (TT_FONT|DEVICE_FONT)) // truetype or device flag set by SetItemData
  510.     {
  511.         CDC dc;
  512.         dc.CreateCompatibleDC(pDC);
  513.         CBitmap* pBitmap = dc.SelectObject(&m_bmFontType);
  514.         if (dwData & TT_FONT)
  515.             pDC->BitBlt(rc.left, rc.top, BMW, BMH, &dc, BMW, 0, SRCAND);
  516.         else // DEVICE_FONT
  517.             pDC->BitBlt(rc.left, rc.top, BMW, BMH, &dc, 0, 0, SRCAND);
  518.         dc.SelectObject(pBitmap);
  519.     }
  520.  
  521.     rc.left += BMW + 6;
  522.     CString strText;
  523.     GetLBText(id, strText);
  524.     pDC->TextOut(rc.left,rc.top,strText,strText.GetLength());
  525.  
  526.     pDC->RestoreDC(nIndexDC);
  527. }
  528.  
  529. void CFontComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
  530. {
  531.     ASSERT(lpMIS->CtlType == ODT_COMBOBOX);
  532.     ASSERT(m_nFontHeight > 0);
  533.     CRect rc;
  534.  
  535.     GetWindowRect(&rc);
  536.     lpMIS->itemWidth = rc.Width();
  537.     lpMIS->itemHeight = max(BMH, m_nFontHeight);
  538. }
  539.  
  540. int CFontComboBox::CompareItem(LPCOMPAREITEMSTRUCT lpCIS)
  541. {
  542.     ASSERT(lpCIS->CtlType == ODT_COMBOBOX);
  543.     int id1 = (int)(WORD)lpCIS->itemID1;
  544.     int id2 = (int)(WORD)lpCIS->itemID2;
  545.     CString str1,str2;
  546.     if (id1 == -1)
  547.         return -1;
  548.     if (id2 == -1)
  549.         return 1;
  550.     GetLBText(id1, str1);
  551.     GetLBText(id2, str2);
  552.     return str1.Collate(str2);
  553. }
  554.  
  555. // find a font with the face name and charset
  556. void CFontComboBox::MatchFont(LPCTSTR lpszName, BYTE nCharSet)
  557. {
  558.     int nFirstIndex = FindString(-1, lpszName);
  559.     if (nFirstIndex != CB_ERR)
  560.     {
  561.         int nIndex = nFirstIndex;
  562.         do
  563.         {
  564.             CFontDesc* pDesc = (CFontDesc*)GetItemData(nIndex);
  565.             ASSERT(pDesc != NULL);
  566.             // check the actual font name to avoid matching Courier western
  567.             // to Courier New western
  568.             if ((nCharSet == DEFAULT_CHARSET || pDesc->m_nCharSet == nCharSet) &&
  569.                 lstrcmp(lpszName, pDesc->m_strName)==0)
  570.             {
  571.                 //got a match
  572.                 if (GetCurSel() != nIndex)
  573.                     SetCurSel(nIndex);
  574.                 return;
  575.             }
  576.             nIndex = FindString(nIndex, lpszName);
  577.         } while (nIndex != nFirstIndex);
  578.         // loop until found or back to first item again
  579.     }
  580.     //enter font name
  581.     SetTheText(lpszName, TRUE);
  582. }
  583.  
  584. /////////////////////////////////////////////////////////////////////////////
  585. // CSizeComboBox
  586.  
  587. CSizeComboBox::CSizeComboBox()
  588. {
  589.     m_nTwipsLast = 0;
  590. }
  591.  
  592. void CSizeComboBox::EnumFontSizes(CDC& dc, LPCTSTR pFontName)
  593. {
  594.     ResetContent();
  595.     if (pFontName == NULL)
  596.         return;
  597.     if (pFontName[0] == NULL)
  598.         return;
  599.  
  600.     ASSERT(dc.m_hDC != NULL);
  601.     m_nLogVert = dc.GetDeviceCaps(LOGPIXELSY);
  602.  
  603.     ::EnumFontFamilies(dc.m_hDC, pFontName,
  604.         (FONTENUMPROC) EnumSizeCallBack, (LPARAM) this);
  605. }
  606.  
  607. void CSizeComboBox::TwipsToPointString(LPTSTR lpszBuf, int nTwips)
  608. {
  609.     ASSERT(lpszBuf != NULL);
  610.     lpszBuf[0] = NULL;
  611.     if (nTwips >= 0)
  612.     {
  613.         // round to nearest half point
  614.         nTwips = (nTwips+5)/10;
  615.         if ((nTwips%2) == 0)
  616.             _stprintf(lpszBuf, _T("%ld"), nTwips/2);
  617.         else
  618.             _stprintf(lpszBuf, _T("%.1f"), (float)nTwips/2.F);
  619.     }
  620. }
  621.  
  622. void CSizeComboBox::SetTwipSize(int nTwips)
  623. {
  624.     if (nTwips != GetTwipSize())
  625.     {
  626.         TCHAR buf[10];
  627.         TwipsToPointString(buf, nTwips);
  628.         SetTheText(buf, TRUE);
  629.     }
  630.     m_nTwipsLast = nTwips;
  631. }
  632.  
  633. int CSizeComboBox::GetTwipSize()
  634. {
  635.     // return values
  636.     // -2 -- error
  637.     // -1 -- edit box empty
  638.     // >=0 -- font size in twips
  639.     CString str;
  640.     GetTheText(str);
  641.     LPCTSTR lpszText = str;
  642.  
  643.     while (*lpszText == ' ' || *lpszText == '\t')
  644.         lpszText++;
  645.  
  646.     if (lpszText[0] == NULL)
  647.         return -1; // no text in control
  648.  
  649.     double d = _tcstod(lpszText, (LPTSTR*)&lpszText);
  650.     while (*lpszText == ' ' || *lpszText == '\t')
  651.         lpszText++;
  652.  
  653.     if (*lpszText != NULL)
  654.         return -2;   // not terminated properly
  655.  
  656.     return (d<0.) ? 0 : (int)(d*20.);
  657. }
  658.  
  659. BOOL CALLBACK AFX_EXPORT CSizeComboBox::EnumSizeCallBack(LOGFONT FAR* /*lplf*/,
  660.         LPNEWTEXTMETRIC lpntm, int FontType, LPVOID lpv)
  661. {
  662.     CSizeComboBox* pThis = (CSizeComboBox*)lpv;
  663.     ASSERT(pThis != NULL);
  664.     TCHAR buf[10];
  665.     if (
  666.         (FontType & TRUETYPE_FONTTYPE) ||
  667.         !( (FontType & TRUETYPE_FONTTYPE) || (FontType & RASTER_FONTTYPE) )
  668.         ) // if truetype or vector font
  669.     {
  670.         // this occurs when there is a truetype and nontruetype version of a font
  671.         if (pThis->GetCount() != 0)
  672.             pThis->ResetContent();
  673.  
  674.         for (int i = 0; i < 16; i++)
  675.         {
  676.             wsprintf(buf, _T("%d"), nFontSizes[i]);
  677.             pThis->AddString(buf);
  678.         }
  679.         return FALSE; // don't call me again
  680.     }
  681.     // calc character height in pixels
  682.     pThis->InsertSize(MulDiv(lpntm->tmHeight-lpntm->tmInternalLeading,
  683.         1440, pThis->m_nLogVert));
  684.     return TRUE; // call me again
  685. }
  686.  
  687. void CSizeComboBox::InsertSize(int nSize)
  688. {
  689.     ASSERT(nSize > 0);
  690.     DWORD dwSize = (DWORD)nSize;
  691.     TCHAR buf[10];
  692.     TwipsToPointString(buf, nSize);
  693.     if (FindStringExact(-1, buf) == CB_ERR)
  694.     {
  695.         int nIndex = -1;
  696.         int nPos = 0;
  697.         DWORD dw;
  698.         while ((dw = GetItemData(nPos)) != CB_ERR)
  699.         {
  700.             if (dw > dwSize)
  701.             {
  702.                 nIndex = nPos;
  703.                 break;
  704.             }
  705.             nPos++;
  706.         }
  707.         nIndex = InsertString(nIndex, buf);
  708.         ASSERT(nIndex != CB_ERR);
  709.         if (nIndex != CB_ERR)
  710.             SetItemData(nIndex, dwSize);
  711.     }
  712. }
  713.  
  714. /////////////////////////////////////////////////////////////////////////////
  715. // CLocalComboBox
  716.  
  717. BEGIN_MESSAGE_MAP(CLocalComboBox, CComboBox)
  718.     //{{AFX_MSG_MAP(CLocalComboBox)
  719.     ON_WM_CREATE()
  720.     //}}AFX_MSG_MAP
  721.     // Global help commands
  722. END_MESSAGE_MAP()
  723.  
  724. void CLocalComboBox::GetTheText(CString& str)
  725. {
  726.     int nIndex = GetCurSel();
  727.     if (nIndex == CB_ERR)
  728.         GetWindowText(str);
  729.     else
  730.         GetLBText(nIndex, str);
  731. }
  732.  
  733. void CLocalComboBox::SetTheText(LPCTSTR lpszText,BOOL bMatchExact)
  734. {
  735.     int idx = (bMatchExact) ? FindStringExact(-1,lpszText) :
  736.         FindString(-1, lpszText);
  737.     SetCurSel( (idx==CB_ERR) ? -1 : idx);
  738.     if (idx == CB_ERR)
  739.         SetWindowText(lpszText);
  740. }
  741.  
  742. BOOL CLocalComboBox::LimitText(int nMaxChars)
  743. {
  744.     BOOL b = CComboBox::LimitText(nMaxChars);
  745.     if (b)
  746.         m_nLimitText = nMaxChars;
  747.     return b;
  748. }
  749.  
  750. int CLocalComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct)
  751. {
  752.     if (CComboBox::OnCreate(lpCreateStruct) == -1)
  753.         return -1;
  754.     SendMessage(WM_SETFONT, (WPARAM)GetStockObject(theApp.m_nDefFont));
  755.     return 0;
  756. }
  757.  
  758. BOOL CLocalComboBox::PreTranslateMessage(MSG* pMsg)
  759. {
  760.     if (pMsg->message == WM_KEYDOWN)
  761.     {
  762.         CFormatBar* pBar = (CFormatBar*)GetParent();
  763.         switch (pMsg->wParam)
  764.         {
  765.         case VK_ESCAPE:
  766.             pBar->SyncToView();
  767.             pBar->NotifyOwner(NM_RETURN);
  768.             return TRUE;
  769.         case VK_RETURN:
  770.             pBar->NotifyOwner(NM_RETURN);
  771.             return TRUE;
  772.         case VK_TAB:
  773.             pBar->GetNextDlgTabItem(this)->SetFocus();
  774.             return TRUE;
  775.         case VK_UP:
  776.         case VK_DOWN:
  777.             if ((GetKeyState(VK_MENU) >= 0) && (GetKeyState(VK_CONTROL) >=0) &&
  778.                 !GetDroppedState())
  779.             {
  780.                 ShowDropDown();
  781.                 return TRUE;
  782.             }
  783.         }
  784.     }
  785.     return CComboBox::PreTranslateMessage(pMsg);
  786. }
  787.  
  788. void CFormatBar::NotifyOwner(UINT nCode)
  789. {
  790.     NMHDR nm;
  791.     nm.hwndFrom = m_hWnd;
  792.     nm.idFrom = GetDlgCtrlID();
  793.     nm.code = nCode;
  794.     GetOwner()->SendMessage(WM_NOTIFY, nm.idFrom, (LPARAM)&nm);
  795. }
  796.  
  797. void CFormatBar::SetCharFormat(CCharFormat& cf)
  798. {
  799.     CHARHDR fnm;
  800.     fnm.hwndFrom = m_hWnd;
  801.     fnm.idFrom = GetDlgCtrlID();
  802.     fnm.code = FN_SETFORMAT;
  803.     fnm.cf = cf;
  804.     VERIFY(GetOwner()->SendMessage(WM_NOTIFY, fnm.idFrom, (LPARAM)&fnm));
  805. }
  806.