Source code of Windows XP (NT5)
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.

516 lines
15 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: DBLLBOX.H
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 3/25/1999
  12. *
  13. * DESCRIPTION: Owner drawn listbox and combobox that do an icon plus a title and subtitle
  14. *
  15. *******************************************************************************/
  16. #ifndef __DBLLBOX_H_INCLUDED
  17. #define __DBLLBOX_H_INCLUDED
  18. #include "simstr.h"
  19. template <class T>
  20. class CDoubleLineListBoxItem
  21. {
  22. private:
  23. CSimpleString m_strTitle;
  24. CSimpleString m_strSubTitle;
  25. HICON m_hIcon;
  26. T m_Data;
  27. public:
  28. CDoubleLineListBoxItem( const T &data, LPCTSTR pszTitle = NULL, LPCTSTR pszSubTitle = NULL, HICON hIcon = NULL );
  29. CDoubleLineListBoxItem( const CDoubleLineListBoxItem &other );
  30. CDoubleLineListBoxItem &operator=( const CDoubleLineListBoxItem &other );
  31. CDoubleLineListBoxItem &Assign( const CSimpleString &strTitle, const CSimpleString &strSubTitle, HICON hIcon, const T &data );
  32. ~CDoubleLineListBoxItem(void);
  33. CSimpleString Title(void) const;
  34. CSimpleString SubTitle(void) const;
  35. T Data(void) const;
  36. HICON Icon(void) const;
  37. HICON CopyIcon(void) const;
  38. };
  39. template <class T>
  40. CDoubleLineListBoxItem<T>::CDoubleLineListBoxItem( const T &data, LPCTSTR pszTitle, LPCTSTR pszSubTitle, HICON hIcon )
  41. : m_strTitle(),
  42. m_strSubTitle(),
  43. m_hIcon(NULL)
  44. {
  45. Assign( pszTitle, pszSubTitle, hIcon, data );
  46. }
  47. template <class T>
  48. CDoubleLineListBoxItem<T>::CDoubleLineListBoxItem( const CDoubleLineListBoxItem &other )
  49. : m_strTitle(),
  50. m_strSubTitle(),
  51. m_hIcon(NULL)
  52. {
  53. Assign( other.Title(), other.SubTitle(), other.CopyIcon(), other.Data() );
  54. }
  55. template <class T>
  56. CDoubleLineListBoxItem<T> &CDoubleLineListBoxItem<T>::operator=( const CDoubleLineListBoxItem &other )
  57. {
  58. return( Assign( other.Title(), other.SubTitle(), other.CopyIcon(), other.Data() ));
  59. }
  60. template <class T>
  61. CDoubleLineListBoxItem<T> &CDoubleLineListBoxItem<T>::Assign( const CSimpleString &strTitle, const CSimpleString &strSubTitle, HICON hIcon, const T &Data )
  62. {
  63. if (m_hIcon)
  64. {
  65. DestroyIcon( m_hIcon );
  66. }
  67. m_hIcon = hIcon;
  68. m_strTitle = strTitle;
  69. m_strSubTitle = strSubTitle;
  70. m_Data = Data;
  71. return(*this);
  72. }
  73. template <class T>
  74. CDoubleLineListBoxItem<T>::~CDoubleLineListBoxItem(void)
  75. {
  76. if (m_hIcon)
  77. {
  78. DestroyIcon( m_hIcon );
  79. m_hIcon = NULL;
  80. m_strTitle = m_strSubTitle = TEXT("");
  81. }
  82. }
  83. template <class T>
  84. CSimpleString CDoubleLineListBoxItem<T>::Title(void) const
  85. {
  86. return(m_strTitle);
  87. }
  88. template <class T>
  89. CSimpleString CDoubleLineListBoxItem<T>::SubTitle(void) const
  90. {
  91. return(m_strSubTitle);
  92. }
  93. template <class T>
  94. T CDoubleLineListBoxItem<T>::Data(void) const
  95. {
  96. return(m_Data);
  97. }
  98. template <class T>
  99. HICON CDoubleLineListBoxItem<T>::Icon(void) const
  100. {
  101. return(m_hIcon);
  102. }
  103. template <class T>
  104. HICON CDoubleLineListBoxItem<T>::CopyIcon(void) const
  105. {
  106. return(m_hIcon ? ::CopyIcon(m_hIcon) : NULL );
  107. }
  108. template <class T>
  109. class CDoubleLineListBox
  110. {
  111. private:
  112. HWND m_hWnd;
  113. HFONT m_hFontTitle;
  114. HFONT m_hFontSubTitle;
  115. SIZE m_sizeIcon;
  116. BOOL m_bIsComboBox;
  117. int m_nTitleTextHeight;
  118. int m_nSubTitleTextHeight;
  119. enum
  120. {
  121. c_AdditionalIconBorder = 3 // Additional border around icons
  122. };
  123. private:
  124. // No implementation
  125. CDoubleLineListBox( const CDoubleLineListBox & );
  126. CDoubleLineListBox &operator=( const CDoubleLineListBox & );
  127. public:
  128. CDoubleLineListBox(void);
  129. ~CDoubleLineListBox(void);
  130. void Destroy(void);
  131. void AssignFonts( HFONT hFontTitle, HFONT hFontSubTitle );
  132. void CreateDefaultFonts(void);
  133. CDoubleLineListBox &Assign( HWND hWnd );
  134. HWND Handle(void) const;
  135. void Handle( HWND hWnd );
  136. CDoubleLineListBox &operator=( HWND hWnd );
  137. LRESULT AddItem( CDoubleLineListBoxItem<T> *pNewItem );
  138. CDoubleLineListBoxItem<T> *GetItem( int nIndex );
  139. void HandleDeleteItem( LPDELETEITEMSTRUCT pDeleteItem );
  140. void HandleMeasureItem( LPMEASUREITEMSTRUCT pMeasureItem );
  141. void HandleDrawItem( LPDRAWITEMSTRUCT pDrawItem );
  142. int SetHorizontalExtent(void);
  143. SIZE MeasureItem( int nIndex );
  144. };
  145. template <class T>
  146. CDoubleLineListBox<T>::CDoubleLineListBox(void)
  147. : m_hWnd(NULL),
  148. m_hFontTitle(NULL),
  149. m_hFontSubTitle(NULL),
  150. m_bIsComboBox(false),
  151. m_nTitleTextHeight(0),
  152. m_nSubTitleTextHeight(0)
  153. {
  154. }
  155. template <class T>
  156. CDoubleLineListBox<T>::~CDoubleLineListBox(void)
  157. {
  158. Destroy();
  159. }
  160. template <class T>
  161. void CDoubleLineListBox<T>::Destroy(void)
  162. {
  163. m_hWnd = NULL;
  164. if (m_hFontTitle)
  165. {
  166. DeleteObject(m_hFontTitle);
  167. m_hFontTitle = NULL;
  168. }
  169. if (m_hFontSubTitle)
  170. {
  171. DeleteObject(m_hFontSubTitle);
  172. m_hFontSubTitle = NULL;
  173. }
  174. }
  175. template <class T>
  176. void CDoubleLineListBox<T>::AssignFonts( HFONT hFontTitle, HFONT hFontSubTitle )
  177. {
  178. if (m_hFontTitle)
  179. {
  180. DeleteObject(m_hFontTitle);
  181. m_hFontTitle = NULL;
  182. }
  183. if (m_hFontSubTitle)
  184. {
  185. DeleteObject(m_hFontSubTitle);
  186. m_hFontSubTitle = NULL;
  187. }
  188. m_hFontTitle = hFontTitle;
  189. m_hFontSubTitle = hFontSubTitle;
  190. HDC hDC = GetDC(NULL);
  191. if (hDC)
  192. {
  193. HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(hDC,m_hFontTitle));
  194. TEXTMETRIC TextMetric;
  195. GetTextMetrics( hDC, &TextMetric );
  196. m_nTitleTextHeight = TextMetric.tmHeight + TextMetric.tmExternalLeading;
  197. SelectObject(hDC,m_hFontSubTitle);
  198. GetTextMetrics( hDC, &TextMetric );
  199. m_nSubTitleTextHeight = TextMetric.tmHeight + TextMetric.tmExternalLeading;
  200. SelectObject( hDC, hOldFont );
  201. ReleaseDC( NULL, hDC );
  202. }
  203. }
  204. template <class T>
  205. void CDoubleLineListBox<T>::CreateDefaultFonts(void)
  206. {
  207. HFONT hCurrFont = NULL, hFontTitle = NULL, hFontSubTitle = NULL;
  208. if (m_hWnd && IsWindow(m_hWnd))
  209. {
  210. hCurrFont = reinterpret_cast<HFONT>(SendMessage(m_hWnd,WM_GETFONT,0,0));
  211. }
  212. if (!hCurrFont)
  213. {
  214. hCurrFont = reinterpret_cast<HFONT>(GetStockObject(ANSI_VAR_FONT));
  215. }
  216. if (hCurrFont)
  217. {
  218. LOGFONT lf;
  219. if (GetObject( hCurrFont, sizeof(lf), &lf ))
  220. {
  221. lf.lfWeight = FW_BOLD;
  222. hFontTitle = CreateFontIndirect(&lf);
  223. lf.lfWeight = FW_NORMAL;
  224. hFontSubTitle = CreateFontIndirect(&lf);
  225. }
  226. }
  227. AssignFonts( hFontTitle, hFontSubTitle );
  228. }
  229. template <class T>
  230. CDoubleLineListBox<T> &CDoubleLineListBox<T>::Assign( HWND hWnd )
  231. {
  232. Destroy();
  233. m_hWnd = hWnd;
  234. CreateDefaultFonts();
  235. if (m_hWnd && IsWindow(m_hWnd))
  236. {
  237. TCHAR szClassName[MAX_PATH];
  238. if (GetClassName( m_hWnd, szClassName, sizeof(szClassName)/sizeof(szClassName[0])))
  239. {
  240. m_bIsComboBox = (lstrcmpi( szClassName, TEXT("combobox") ) == 0);
  241. }
  242. }
  243. return(*this);
  244. }
  245. template <class T>
  246. HWND CDoubleLineListBox<T>::Handle(void) const
  247. {
  248. return(m_hWnd);
  249. }
  250. template <class T>
  251. void CDoubleLineListBox<T>::Handle( HWND hWnd )
  252. {
  253. Assign(hWnd);
  254. }
  255. template <class T>
  256. CDoubleLineListBox<T> &CDoubleLineListBox<T>::operator=( HWND hWnd )
  257. {
  258. return(Assign(hWnd));
  259. }
  260. template <class T>
  261. LRESULT CDoubleLineListBox<T>::AddItem( CDoubleLineListBoxItem<T> *pNewItem )
  262. {
  263. LRESULT lResult = -1;
  264. if (IsWindow(m_hWnd) && pNewItem)
  265. {
  266. lResult = SendMessage( m_hWnd, m_bIsComboBox ? CB_ADDSTRING : LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(pNewItem->Title().String()) );
  267. if (lResult >= 0)
  268. {
  269. SendMessage( m_hWnd, m_bIsComboBox ? CB_SETITEMDATA : LB_SETITEMDATA, lResult, reinterpret_cast<LPARAM>(pNewItem) );
  270. }
  271. SetHorizontalExtent();
  272. }
  273. return(lResult);
  274. }
  275. template <class T>
  276. CDoubleLineListBoxItem<T> *CDoubleLineListBox<T>::GetItem( int nIndex )
  277. {
  278. LRESULT lResult = 0;
  279. if (IsWindow(m_hWnd))
  280. {
  281. lResult = SendMessage( m_hWnd, m_bIsComboBox ? CB_GETITEMDATA : LB_GETITEMDATA, nIndex, 0 );
  282. if (lResult == CB_ERR || lResult == LB_ERR)
  283. lResult = 0;
  284. }
  285. return(reinterpret_cast<CDoubleLineListBoxItem<T> *>(lResult));
  286. }
  287. // This must be called in response to WM_DELETEITEM
  288. template <class T>
  289. void CDoubleLineListBox<T>::HandleDeleteItem( LPDELETEITEMSTRUCT pDeleteItem )
  290. {
  291. if (pDeleteItem && IsWindow(m_hWnd) && pDeleteItem->hwndItem == m_hWnd)
  292. {
  293. CDoubleLineListBoxItem *pItem = reinterpret_cast<CDoubleLineListBoxItem *>(pDeleteItem->itemData);
  294. if (pItem)
  295. delete pItem;
  296. }
  297. }
  298. // This must be called in response to WM_MEASUREITEM
  299. template <class T>
  300. void CDoubleLineListBox<T>::HandleMeasureItem( LPMEASUREITEMSTRUCT pMeasureItem )
  301. {
  302. if (pMeasureItem)
  303. {
  304. SIZE sizeItem = MeasureItem( pMeasureItem->itemID );
  305. pMeasureItem->itemHeight = sizeItem.cy;
  306. }
  307. }
  308. template <class T>
  309. int CDoubleLineListBox<T>::SetHorizontalExtent(void)
  310. {
  311. if (IsWindow(m_hWnd))
  312. {
  313. int nMaxLength = 0;
  314. LRESULT lCount = SendMessage( m_hWnd, m_bIsComboBox ? CB_GETCOUNT : LB_GETCOUNT, 0, 0 );
  315. for (int i=0;i<(int)lCount;i++)
  316. {
  317. SIZE sizeItem = MeasureItem(i);
  318. nMaxLength = (sizeItem.cx > nMaxLength) ? sizeItem.cx : nMaxLength;
  319. }
  320. SendMessage( m_hWnd, m_bIsComboBox ? CB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, nMaxLength, 0 );
  321. return nMaxLength;
  322. }
  323. return 0;
  324. }
  325. // Return the width and height, in pixels, of an item
  326. template <class T>
  327. SIZE CDoubleLineListBox<T>::MeasureItem( int nIndex )
  328. {
  329. SIZE sizeItem =
  330. {
  331. GetSystemMetrics(SM_CXICON) + c_AdditionalIconBorder * 3 + 2,
  332. GetSystemMetrics(SM_CYICON) + c_AdditionalIconBorder * 2 + 2
  333. };
  334. if (IsWindow(m_hWnd))
  335. {
  336. // Make sure we have valid fonts
  337. if (!m_hFontTitle || !m_hFontSubTitle)
  338. CreateDefaultFonts();
  339. CDoubleLineListBoxItem<T> *pItem = GetItem(nIndex);
  340. if (pItem)
  341. {
  342. HDC hDC = GetDC(m_hWnd);
  343. if (hDC)
  344. {
  345. HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(hDC,m_hFontTitle));
  346. // Calculate the size of the text rectangle for the title
  347. RECT rcText;
  348. ZeroMemory(&rcText,sizeof(rcText));
  349. DrawTextEx( hDC, const_cast<LPTSTR>(pItem->Title().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX|DT_CALCRECT, NULL );
  350. int nTitleWidth = rcText.right - rcText.left;
  351. // Calculate the size of the text rectangle for the sub title
  352. ZeroMemory(&rcText,sizeof(rcText));
  353. SelectObject(hDC,m_hFontSubTitle);
  354. DrawTextEx( hDC, const_cast<LPTSTR>(pItem->SubTitle().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX|DT_CALCRECT, NULL );
  355. int nSubTitleWidth = rcText.right - rcText.left;
  356. sizeItem.cx += (nTitleWidth > nSubTitleWidth) ? nTitleWidth : nSubTitleWidth;
  357. SelectObject( hDC, hOldFont );
  358. ReleaseDC( m_hWnd, hDC );
  359. }
  360. }
  361. }
  362. return(sizeItem);
  363. }
  364. // This must be called in response to WM_DRAWITEM
  365. template <class T>
  366. void CDoubleLineListBox<T>::HandleDrawItem( LPDRAWITEMSTRUCT pDrawItem )
  367. {
  368. if (pDrawItem && IsWindow(m_hWnd) && pDrawItem->hwndItem == m_hWnd)
  369. {
  370. // Make sure we have valid fonts
  371. if (!m_hFontTitle || !m_hFontSubTitle)
  372. CreateDefaultFonts();
  373. RECT rcItem = pDrawItem->rcItem;
  374. // Paint the background
  375. if (ODS_SELECTED & pDrawItem->itemState)
  376. {
  377. if (IsWindowEnabled(pDrawItem->hwndItem))
  378. {
  379. FillRect( pDrawItem->hDC, &rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
  380. }
  381. else
  382. {
  383. FillRect( pDrawItem->hDC, &rcItem, GetSysColorBrush(COLOR_INACTIVECAPTION));
  384. }
  385. }
  386. else
  387. {
  388. FillRect( pDrawItem->hDC, &rcItem, GetSysColorBrush(COLOR_WINDOW));
  389. }
  390. // Paint the focus rectangle
  391. if (ODS_FOCUS & pDrawItem->itemState)
  392. {
  393. DrawFocusRect( pDrawItem->hDC, &rcItem );
  394. }
  395. // Shrink by one pixel, so we don't overwrite the focus rect
  396. InflateRect( &rcItem, -1, -1 );
  397. if (pDrawItem->itemData != -1)
  398. {
  399. CDoubleLineListBoxItem<T> *pItem = reinterpret_cast<CDoubleLineListBoxItem<T> *>(pDrawItem->itemData);
  400. if (pItem)
  401. {
  402. // Draw the icon
  403. DrawIconEx( pDrawItem->hDC, pDrawItem->rcItem.left+c_AdditionalIconBorder, pDrawItem->rcItem.top+c_AdditionalIconBorder, pItem->Icon(), GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0, NULL, DI_NORMAL );
  404. // Move the left margin over to make room for the text
  405. rcItem.left += GetSystemMetrics(SM_CXICON) + c_AdditionalIconBorder * 2;
  406. // Set up the dc
  407. COLORREF crOldTextColor;
  408. if (IsWindowEnabled(pDrawItem->hwndItem))
  409. {
  410. if (ODS_SELECTED & pDrawItem->itemState)
  411. crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT) );
  412. else crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_WINDOWTEXT) );
  413. }
  414. else
  415. {
  416. if (ODS_SELECTED & pDrawItem->itemState)
  417. crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_INACTIVECAPTIONTEXT) );
  418. else crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_GRAYTEXT) );
  419. }
  420. int nOldBkMode = SetBkMode( pDrawItem->hDC, TRANSPARENT );
  421. HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(pDrawItem->hDC,m_hFontTitle));
  422. // Calculate the text rectangle
  423. RECT rcText = rcItem;
  424. rcText.top += (((rcText.bottom - rcText.top)) - (m_nTitleTextHeight + m_nSubTitleTextHeight)) / 2;
  425. rcText.bottom = rcText.top + m_nTitleTextHeight + m_nSubTitleTextHeight;
  426. DrawTextEx( pDrawItem->hDC, const_cast<LPTSTR>(pItem->Title().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX, NULL );
  427. // Get ready for the sub-title
  428. SelectObject(pDrawItem->hDC,m_hFontSubTitle);
  429. // Get the coords for the bottom text rect
  430. rcText.top += m_nTitleTextHeight;
  431. // Draw the text
  432. DrawTextEx( pDrawItem->hDC, const_cast<LPTSTR>(pItem->SubTitle().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX, NULL );
  433. // Restore the dc
  434. SelectObject(pDrawItem->hDC,hOldFont);
  435. SetBkMode( pDrawItem->hDC, nOldBkMode );
  436. SetTextColor( pDrawItem->hDC, crOldTextColor );
  437. }
  438. }
  439. }
  440. }
  441. #endif