// XMonoFontDialog.cpp Version 1.1 // // Author: Hans Dietrich // hdietrich@gmail.com // // Description: // XMonoFontDialog.cpp implements CXMonoFontDialog, a class to display // a customized CFontDialog. // // History // Version 1.1 - 2008 October 29 // - Fixed problem with small point sizes // // Version 1.0 - 2008 October 22 // - Initial public release // // License: // This software is released into the public domain. You are free to use // it in any way you like, except that you may not sell this source code. // // This software is provided "as is" with no expressed or implied warranty. // I accept no liability for any damage or loss of business that this // software may cause. // /////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "XMonoFontDialog.h" #include "XMonoFontDialogRes.h" #include "XFontSize.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #ifndef __noop #if _MSC_VER < 1300 #define __noop ((void)0) #endif #endif #undef TRACE #define TRACE __noop //============================================================================= // if you want to see the TRACE output, uncomment this line: //#include "XTrace.h" //============================================================================= #pragma warning(disable : 4996) // disable bogus deprecation warning #define TIMER_FONTLIST_SELCHANGE 1 #define TIMER_FONTSIZES_SELCHANGE 2 #define TIMER_FONTSIZES_UPDATE 3 static int CALLBACK EnumFontFamExProcSizes(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam); IMPLEMENT_DYNAMIC(CXMonoFontDialog, CDialog) //============================================================================= BEGIN_MESSAGE_MAP(CXMonoFontDialog, CDialog) //============================================================================= //{{AFX_MSG_MAP(CXMonoFontDialog) ON_WM_CTLCOLOR() ON_WM_TIMER() ON_CBN_SELCHANGE(IDC_FONT_LIST, OnSelchangeFontList) ON_CBN_SELCHANGE(IDC_FONT_SIZE, OnSelchangeFontSize) ON_CBN_EDITCHANGE(IDC_FONT_SIZE, OnEditchangeFontSize) //}}AFX_MSG_MAP END_MESSAGE_MAP() //============================================================================= CXMonoFontDialog::CXMonoFontDialog(LPLOGFONT lplfInitial, DWORD /*dwFlags*/, // compatibility with CFontDialog CDC* /*pdcPrinter*/, // compatibility with CFontDialog CWnd* pParentWnd /*= NULL*/) : // use string resource name to avoid resource id conflicts CDialog(_T("IDD_XMONOFONTDIALOG"), pParentWnd) //CDialog(IDD_XMONOFONTDIALOG, pParentWnd) //============================================================================= { m_strFaceName = _T(""); m_strCaption = _T("Font"); m_strSampleText = _T("AaBbYyZz 0123456789"); m_strMonospacedLabel = _T("MONOSPACED"); m_Height = 0; m_dwFontFilter = 0; m_bShowMonospacedLabel = TRUE; m_bShowMonospacedAsBold = TRUE; memset(&m_lfInitial, 0, sizeof(LOGFONT)); memset(&m_lfCurrent, 0, sizeof(LOGFONT)); if (lplfInitial) { memcpy(&m_lfInitial, lplfInitial, sizeof(LOGFONT)); } else { m_lfInitial.lfCharSet = DEFAULT_CHARSET; _tcscpy(m_lfInitial.lfFaceName, _T("Courier")); m_lfInitial.lfHeight = FontSize.GetFontHeight(10); } memcpy(&m_lfCurrent, &m_lfInitial, sizeof(LOGFONT)); m_nPointSize = FontSize.GetFontPointSize(m_lfInitial.lfHeight); m_strFaceName = m_lfInitial.lfFaceName; } //============================================================================= CXMonoFontDialog::~CXMonoFontDialog() //============================================================================= { if (m_SampleFont.GetSafeHandle()) m_SampleFont.DeleteObject(); } //============================================================================= void CXMonoFontDialog::DoDataExchange(CDataExchange* pDX) //============================================================================= { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CXMonoFontDialog) DDX_Control(pDX, IDC_FONT_SIZE, m_FontSizes); DDX_Control(pDX, IDC_FONT_SAMPLE, m_Sample); DDX_Control(pDX, IDC_FONT_MONOSPACED, m_MonospacedLabel); DDX_Control(pDX, IDC_FONT_LIST, m_FontList); //}}AFX_DATA_MAP } //============================================================================= BOOL CXMonoFontDialog::OnInitDialog() //============================================================================= { m_FontList.SetFontFilter(m_dwFontFilter) .SetFont(m_lfInitial) .ShowMonospacedAsBold(m_bShowMonospacedAsBold); CDialog::OnInitDialog(); // at this point the font list combo has been filled with font names m_MonospacedLabel.SetWindowText(m_strMonospacedLabel); int h = m_FontList.GetItemHeight(0); m_FontSizes.SetItemHeight(-1, h); SetWindowText(m_strCaption); m_Sample.SetWindowText(m_strSampleText); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } //============================================================================= HBRUSH CXMonoFontDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) //============================================================================= { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); // set MONOSPACED label to blue CWnd *pMonoSpaced = GetDlgItem(IDC_FONT_MONOSPACED); if (pMonoSpaced && pWnd) { if (pWnd->m_hWnd == pMonoSpaced->m_hWnd) pDC->SetTextColor(RGB(0,0,255)); } return hbr; } //============================================================================= void CXMonoFontDialog::GetCurrentFont(LPLOGFONT lplf) //============================================================================= { ASSERT(lplf); if (lplf) memcpy(lplf, &m_lfCurrent, sizeof(LOGFONT)); } //============================================================================= // called when user selects size in combo list void CXMonoFontDialog::OnSelchangeFontSize() //============================================================================= { TRACE(_T("in CXMonoFontDialog::OnSelchangeFontSize\n")); SetTimer(TIMER_FONTSIZES_SELCHANGE, 50, 0); } //============================================================================= // called when user types in size combo edit box void CXMonoFontDialog::OnEditchangeFontSize() //============================================================================= { TRACE(_T("in CXMonoFontDialog::OnEditchangeFontSize\n")); SetTimer(TIMER_FONTSIZES_UPDATE, 50, 0); } //============================================================================= // called when user selects font in combo list void CXMonoFontDialog::OnSelchangeFontList() //============================================================================= { TRACE(_T("in CXMonoFontDialog::OnSelchangeFontList\n")); CString s = _T(""); CString strFont = _T(""); int index = m_FontList.GetCurSel(); if (index != CB_ERR) { m_FontList.GetLBText(index, strFont); m_FontList.SetWindowText(strFont); m_FontSizes.ResetContent(); DWORD dwFlags = m_FontList.GetItemData(index); if (dwFlags & (XFONT_TRUETYPE | XFONT_OPENTYPE | XFONT_VECTOR)) { // use standard set of sizes TRACE(_T("open or true type or vector\n")); static int nSizes[] = { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72, -1 }; for (int i = 0; nSizes[i] != -1; i++) { s.Format(_T("%d"), nSizes[i]); m_FontSizes.AddString(s); } } else { // some other font type - enumerate sizes m_FontList.GetLBText(index, s); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); lf.lfCharSet = DEFAULT_CHARSET; _tcsncpy(lf.lfFaceName, s, sizeof(lf.lfFaceName)/sizeof(TCHAR)-1); CClientDC dcClient(this); TRACE(_T("===== STARTING SIZE ENUMERATION ===========\n")); EnumFontFamiliesEx(dcClient, &lf, (FONTENUMPROC) EnumFontFamExProcSizes, (LPARAM)&m_FontSizes, 0); TRACE(_T("===== ENDING SIZE ENUMERATION ===========\n")); } } // clear size selection m_FontSizes.SetCurSel(-1); // set size in combo edit box s.Format(_T("%d"), m_nPointSize); m_FontSizes.SetWindowText(s); // try to select size in combo index = m_FontSizes.FindStringExact(-1, s); if (index != CB_ERR) m_FontSizes.SetCurSel(index); SetCurFont(); } //============================================================================= void CXMonoFontDialog::SetCurFont() //============================================================================= { TRACE(_T("in CXMonoFontDialog::SetCurFont\n")); int index = m_FontList.GetCurSel(); if (index != CB_ERR) { m_dwXFontFlags = m_FontList.GetItemData(index); m_FontList.GetLBText(index, m_strFaceName); } CString s = _T(""); m_FontSizes.GetWindowText(s); if (s.IsEmpty()) s = _T("10"); int n = _ttoi(s); if (n > 0) m_nPointSize = n; TRACE(_T("SetCurFont: setting font to %s(%d)\n"), m_strFaceName, m_nPointSize); // set sample font memset(&m_lfCurrent, 0, sizeof(LOGFONT)); m_lfCurrent.lfHeight = FontSize.GetFontHeight(m_nPointSize); m_Height = m_lfCurrent.lfHeight; m_lfCurrent.lfCharSet = DEFAULT_CHARSET; _tcsncpy(m_lfCurrent.lfFaceName, m_strFaceName, sizeof(m_lfCurrent.lfFaceName)/sizeof(TCHAR)-1); DWORD weight = (m_dwXFontFlags & XFONT_WEIGHT_MASK) >> 16; m_lfCurrent.lfWeight = weight; m_lfCurrent.lfItalic = (BYTE) (m_dwXFontFlags & XFONT_ITALIC); if (m_SampleFont.GetSafeHandle()) m_SampleFont.DeleteObject(); m_SampleFont.CreateFontIndirect(&m_lfCurrent); m_Sample.SetFont(&m_SampleFont); // show / hide MONOSPACED label BOOL bIsMonospaced = m_dwXFontFlags & XFONT_MONOSPACED; m_MonospacedLabel.ShowWindow((bIsMonospaced && m_bShowMonospacedLabel) ? SW_SHOW : SW_HIDE); // enable bold typeface in combo list m_FontList.SetBold(bIsMonospaced && m_bShowMonospacedAsBold); } //============================================================================= void CXMonoFontDialog::OnOK() //============================================================================= { CString s = _T(""); m_FontSizes.GetWindowText(s); if (s.IsEmpty()) s = _T("10"); m_nPointSize = _ttoi(s); if (m_nPointSize <= 0) m_nPointSize = 10; memset(&m_lfCurrent, 0, sizeof(LOGFONT)); m_lfCurrent.lfHeight = FontSize.GetFontHeight(m_nPointSize); m_Height = m_lfCurrent.lfHeight; m_lfCurrent.lfCharSet = DEFAULT_CHARSET; _tcsncpy(m_lfCurrent.lfFaceName, m_strFaceName, sizeof(m_lfCurrent.lfFaceName)/sizeof(TCHAR)-1); DWORD weight = (m_dwXFontFlags & XFONT_WEIGHT_MASK) >> 16; m_lfCurrent.lfWeight = weight; m_lfCurrent.lfItalic = (BYTE) (m_dwXFontFlags & XFONT_ITALIC); CDialog::OnOK(); } //============================================================================= void CXMonoFontDialog::OnTimer(UINT nIDEvent) //============================================================================= { KillTimer(nIDEvent); if (nIDEvent == TIMER_FONTSIZES_SELCHANGE) { SetCurFont(); } else if (nIDEvent == TIMER_FONTSIZES_UPDATE) { // user is typing into combo edit box - check if what he has typed // so far is a valid size, and select it if it is CString strSize = _T(""); m_FontSizes.GetWindowText(strSize); int index = m_FontSizes.FindStringExact(-1, strSize); if (index != CB_ERR) { TRACE(_T("found size at %d\n"), index); m_FontSizes.SetCurSel(index); } OnSelchangeFontSize(); } CDialog::OnTimer(nIDEvent); } #pragma warning(push) #pragma warning(disable: 4100) //============================================================================= // This function is the enumeration callback for font sizes. // Its purpose is to fill the size combo with non-duplicate // sizes, making sure that they are entered in numerical order. int CALLBACK EnumFontFamExProcSizes(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam) //============================================================================= { // the lParam is a pointer to the size combobox CComboBox *pCombo = (CComboBox *) lParam; ASSERT(pCombo); ASSERT(IsWindow(pCombo->m_hWnd)); int nFontHeight = lpntme->ntmTm.tmHeight - lpntme->ntmTm.tmInternalLeading; int nPointSize = FontSize.GetFontPointSize(nFontHeight); TRACE(_T("_____ %s nPointSize=%d FontType=0x%X\n"), lpelfe->elfLogFont.lfFaceName, nPointSize, FontType); TCHAR szSize[100]; _stprintf(szSize, _T("%d"), nPointSize); if (pCombo->FindStringExact(-1, szSize) == CB_ERR) { // size is not in list // the sizes are not always enumerated in numerical order, // so we have to check where to insert this size // (example: Terminal font) BOOL bAdded = FALSE; int n = 0; int count = pCombo->GetCount(); TCHAR szEntry[100]; for (int i = 0; i < count; i++) { szEntry[0] = 0; pCombo->GetLBText(i, szEntry); n = _ttoi(szEntry); if (nPointSize < n) { VERIFY(pCombo->InsertString(i, szSize) >= 0); bAdded = TRUE; break; } } if (!bAdded) VERIFY(pCombo->AddString(szSize) >= 0); } return TRUE; // continue enumeration } #pragma warning(pop)