Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

942 lines
26 KiB

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