/thirdparty/wtl/atlctrlx.h

http://crashrpt.googlecode.com/ · C Header · 4978 lines · 4061 code · 711 blank · 206 comment · 941 complexity · 6edefb128a55dda12e6890062fe322aa MD5 · raw file

Large files are truncated click here to view the full file

  1. // Windows Template Library - WTL version 8.1
  2. // Copyright (C) Microsoft Corporation. All rights reserved.
  3. //
  4. // This file is a part of the Windows Template Library.
  5. // The use and distribution terms for this software are covered by the
  6. // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
  7. // which can be found in the file CPL.TXT at the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by
  9. // the terms of this license. You must not remove this notice, or
  10. // any other, from this software.
  11. #ifndef __ATLCTRLX_H__
  12. #define __ATLCTRLX_H__
  13. #pragma once
  14. #ifndef __ATLAPP_H__
  15. #error atlctrlx.h requires atlapp.h to be included first
  16. #endif
  17. #ifndef __ATLCTRLS_H__
  18. #error atlctrlx.h requires atlctrls.h to be included first
  19. #endif
  20. #ifndef WM_UPDATEUISTATE
  21. #define WM_UPDATEUISTATE 0x0128
  22. #endif // !WM_UPDATEUISTATE
  23. ///////////////////////////////////////////////////////////////////////////////
  24. // Classes in this file:
  25. //
  26. // CBitmapButtonImpl<T, TBase, TWinTraits>
  27. // CBitmapButton
  28. // CCheckListViewCtrlImpl<T, TBase, TWinTraits>
  29. // CCheckListViewCtrl
  30. // CHyperLinkImpl<T, TBase, TWinTraits>
  31. // CHyperLink
  32. // CWaitCursor
  33. // CCustomWaitCursor
  34. // CMultiPaneStatusBarCtrlImpl<T, TBase>
  35. // CMultiPaneStatusBarCtrl
  36. // CPaneContainerImpl<T, TBase, TWinTraits>
  37. // CPaneContainer
  38. // CSortListViewImpl<T>
  39. // CSortListViewCtrlImpl<T, TBase, TWinTraits>
  40. // CSortListViewCtrl
  41. // CTabViewImpl<T, TBase, TWinTraits>
  42. // CTabView
  43. namespace WTL
  44. {
  45. ///////////////////////////////////////////////////////////////////////////////
  46. // CBitmapButton - bitmap button implementation
  47. #ifndef _WIN32_WCE
  48. // bitmap button extended styles
  49. #define BMPBTN_HOVER 0x00000001
  50. #define BMPBTN_AUTO3D_SINGLE 0x00000002
  51. #define BMPBTN_AUTO3D_DOUBLE 0x00000004
  52. #define BMPBTN_AUTOSIZE 0x00000008
  53. #define BMPBTN_SHAREIMAGELISTS 0x00000010
  54. #define BMPBTN_AUTOFIRE 0x00000020
  55. template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
  56. class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits>
  57. {
  58. public:
  59. DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
  60. enum
  61. {
  62. _nImageNormal = 0,
  63. _nImagePushed,
  64. _nImageFocusOrHover,
  65. _nImageDisabled,
  66. _nImageCount = 4,
  67. };
  68. enum
  69. {
  70. ID_TIMER_FIRST = 1000,
  71. ID_TIMER_REPEAT = 1001
  72. };
  73. // Bitmap button specific extended styles
  74. DWORD m_dwExtendedStyle;
  75. CImageList m_ImageList;
  76. int m_nImage[_nImageCount];
  77. CToolTipCtrl m_tip;
  78. LPTSTR m_lpstrToolTipText;
  79. // Internal states
  80. unsigned m_fMouseOver:1;
  81. unsigned m_fFocus:1;
  82. unsigned m_fPressed:1;
  83. // Constructor/Destructor
  84. CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
  85. m_ImageList(hImageList), m_dwExtendedStyle(dwExtendedStyle),
  86. m_lpstrToolTipText(NULL),
  87. m_fMouseOver(0), m_fFocus(0), m_fPressed(0)
  88. {
  89. m_nImage[_nImageNormal] = -1;
  90. m_nImage[_nImagePushed] = -1;
  91. m_nImage[_nImageFocusOrHover] = -1;
  92. m_nImage[_nImageDisabled] = -1;
  93. }
  94. ~CBitmapButtonImpl()
  95. {
  96. if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0)
  97. m_ImageList.Destroy();
  98. delete [] m_lpstrToolTipText;
  99. }
  100. // overridden to provide proper initialization
  101. BOOL SubclassWindow(HWND hWnd)
  102. {
  103. #if (_MSC_VER >= 1300)
  104. BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd);
  105. #else // !(_MSC_VER >= 1300)
  106. typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass;
  107. BOOL bRet = _baseClass::SubclassWindow(hWnd);
  108. #endif // !(_MSC_VER >= 1300)
  109. if(bRet)
  110. Init();
  111. return bRet;
  112. }
  113. // Attributes
  114. DWORD GetBitmapButtonExtendedStyle() const
  115. {
  116. return m_dwExtendedStyle;
  117. }
  118. DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
  119. {
  120. DWORD dwPrevStyle = m_dwExtendedStyle;
  121. if(dwMask == 0)
  122. m_dwExtendedStyle = dwExtendedStyle;
  123. else
  124. m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
  125. return dwPrevStyle;
  126. }
  127. HIMAGELIST GetImageList() const
  128. {
  129. return m_ImageList;
  130. }
  131. HIMAGELIST SetImageList(HIMAGELIST hImageList)
  132. {
  133. HIMAGELIST hImageListPrev = m_ImageList;
  134. m_ImageList = hImageList;
  135. if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd))
  136. SizeToImage();
  137. return hImageListPrev;
  138. }
  139. int GetToolTipTextLength() const
  140. {
  141. return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText);
  142. }
  143. bool GetToolTipText(LPTSTR lpstrText, int nLength) const
  144. {
  145. ATLASSERT(lpstrText != NULL);
  146. if(m_lpstrToolTipText == NULL)
  147. return false;
  148. errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE);
  149. return (nRet == 0 || nRet == STRUNCATE);
  150. }
  151. bool SetToolTipText(LPCTSTR lpstrText)
  152. {
  153. if(m_lpstrToolTipText != NULL)
  154. {
  155. delete [] m_lpstrToolTipText;
  156. m_lpstrToolTipText = NULL;
  157. }
  158. if(lpstrText == NULL)
  159. {
  160. if(m_tip.IsWindow())
  161. m_tip.Activate(FALSE);
  162. return true;
  163. }
  164. int cchLen = lstrlen(lpstrText) + 1;
  165. ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]);
  166. if(m_lpstrToolTipText == NULL)
  167. return false;
  168. SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText);
  169. if(m_tip.IsWindow())
  170. {
  171. m_tip.Activate(TRUE);
  172. m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
  173. }
  174. return true;
  175. }
  176. // Operations
  177. void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1)
  178. {
  179. if(nNormal != -1)
  180. m_nImage[_nImageNormal] = nNormal;
  181. if(nPushed != -1)
  182. m_nImage[_nImagePushed] = nPushed;
  183. if(nFocusOrHover != -1)
  184. m_nImage[_nImageFocusOrHover] = nFocusOrHover;
  185. if(nDisabled != -1)
  186. m_nImage[_nImageDisabled] = nDisabled;
  187. }
  188. BOOL SizeToImage()
  189. {
  190. ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL);
  191. int cx = 0;
  192. int cy = 0;
  193. if(!m_ImageList.GetIconSize(cx, cy))
  194. return FALSE;
  195. return ResizeClient(cx, cy);
  196. }
  197. // Overrideables
  198. void DoPaint(CDCHandle dc)
  199. {
  200. ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set
  201. ATLASSERT(m_nImage[0] != -1); // main bitmap must be set
  202. // set bitmap according to the current button state
  203. int nImage = -1;
  204. bool bHover = IsHoverMode();
  205. if(!IsWindowEnabled())
  206. nImage = m_nImage[_nImageDisabled];
  207. else if(m_fPressed == 1)
  208. nImage = m_nImage[_nImagePushed];
  209. else if((!bHover && m_fFocus == 1) || (bHover && m_fMouseOver == 1))
  210. nImage = m_nImage[_nImageFocusOrHover];
  211. if(nImage == -1) // not there, use default one
  212. nImage = m_nImage[_nImageNormal];
  213. // draw the button image
  214. int xyPos = 0;
  215. if((m_fPressed == 1) && ((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) && (m_nImage[_nImagePushed] == -1))
  216. xyPos = 1;
  217. m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL);
  218. // draw 3D border if required
  219. if((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0)
  220. {
  221. RECT rect;
  222. GetClientRect(&rect);
  223. if(m_fPressed == 1)
  224. dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT);
  225. else if(!bHover || m_fMouseOver == 1)
  226. dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT);
  227. if(!bHover && m_fFocus == 1)
  228. {
  229. ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));
  230. dc.DrawFocusRect(&rect);
  231. }
  232. }
  233. }
  234. // Message map and handlers
  235. BEGIN_MSG_MAP(CBitmapButtonImpl)
  236. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  237. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  238. MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
  239. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  240. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  241. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  242. MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
  243. MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
  244. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  245. MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
  246. MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
  247. MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
  248. MESSAGE_HANDLER(WM_ENABLE, OnEnable)
  249. MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  250. MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
  251. MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
  252. MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
  253. MESSAGE_HANDLER(WM_TIMER, OnTimer)
  254. MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
  255. END_MSG_MAP()
  256. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  257. {
  258. Init();
  259. bHandled = FALSE;
  260. return 1;
  261. }
  262. LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  263. {
  264. if(m_tip.IsWindow())
  265. {
  266. m_tip.DestroyWindow();
  267. m_tip.m_hWnd = NULL;
  268. }
  269. bHandled = FALSE;
  270. return 1;
  271. }
  272. LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  273. {
  274. MSG msg = { m_hWnd, uMsg, wParam, lParam };
  275. if(m_tip.IsWindow())
  276. m_tip.RelayEvent(&msg);
  277. bHandled = FALSE;
  278. return 1;
  279. }
  280. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  281. {
  282. return 1; // no background needed
  283. }
  284. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  285. {
  286. T* pT = static_cast<T*>(this);
  287. if(wParam != NULL)
  288. {
  289. pT->DoPaint((HDC)wParam);
  290. }
  291. else
  292. {
  293. CPaintDC dc(m_hWnd);
  294. pT->DoPaint(dc.m_hDC);
  295. }
  296. return 0;
  297. }
  298. LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  299. {
  300. m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0;
  301. Invalidate();
  302. UpdateWindow();
  303. bHandled = FALSE;
  304. return 1;
  305. }
  306. LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  307. {
  308. LRESULT lRet = 0;
  309. if(IsHoverMode())
  310. SetCapture();
  311. else
  312. lRet = DefWindowProc(uMsg, wParam, lParam);
  313. if(::GetCapture() == m_hWnd)
  314. {
  315. m_fPressed = 1;
  316. Invalidate();
  317. UpdateWindow();
  318. }
  319. if((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0)
  320. {
  321. int nElapse = 250;
  322. int nDelay = 0;
  323. if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0))
  324. nElapse += nDelay * 250; // all milli-seconds
  325. SetTimer(ID_TIMER_FIRST, nElapse);
  326. }
  327. return lRet;
  328. }
  329. LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  330. {
  331. LRESULT lRet = 0;
  332. if(!IsHoverMode())
  333. lRet = DefWindowProc(uMsg, wParam, lParam);
  334. if(::GetCapture() != m_hWnd)
  335. SetCapture();
  336. if(m_fPressed == 0)
  337. {
  338. m_fPressed = 1;
  339. Invalidate();
  340. UpdateWindow();
  341. }
  342. return lRet;
  343. }
  344. LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  345. {
  346. LRESULT lRet = 0;
  347. bool bHover = IsHoverMode();
  348. if(!bHover)
  349. lRet = DefWindowProc(uMsg, wParam, lParam);
  350. if(::GetCapture() == m_hWnd)
  351. {
  352. if(bHover && m_fPressed == 1)
  353. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  354. ::ReleaseCapture();
  355. }
  356. return lRet;
  357. }
  358. LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  359. {
  360. if(m_fPressed == 1)
  361. {
  362. m_fPressed = 0;
  363. Invalidate();
  364. UpdateWindow();
  365. }
  366. bHandled = FALSE;
  367. return 1;
  368. }
  369. LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  370. {
  371. Invalidate();
  372. UpdateWindow();
  373. bHandled = FALSE;
  374. return 1;
  375. }
  376. LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  377. {
  378. if(::GetCapture() == m_hWnd)
  379. {
  380. POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  381. ClientToScreen(&ptCursor);
  382. RECT rect = { 0 };
  383. GetWindowRect(&rect);
  384. unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0;
  385. if(m_fPressed != uPressed)
  386. {
  387. m_fPressed = uPressed;
  388. Invalidate();
  389. UpdateWindow();
  390. }
  391. }
  392. else if(IsHoverMode() && m_fMouseOver == 0)
  393. {
  394. m_fMouseOver = 1;
  395. Invalidate();
  396. UpdateWindow();
  397. StartTrackMouseLeave();
  398. }
  399. bHandled = FALSE;
  400. return 1;
  401. }
  402. LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  403. {
  404. if(m_fMouseOver == 1)
  405. {
  406. m_fMouseOver = 0;
  407. Invalidate();
  408. UpdateWindow();
  409. }
  410. return 0;
  411. }
  412. LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  413. {
  414. if(wParam == VK_SPACE && IsHoverMode())
  415. return 0; // ignore if in hover mode
  416. if(wParam == VK_SPACE && m_fPressed == 0)
  417. {
  418. m_fPressed = 1;
  419. Invalidate();
  420. UpdateWindow();
  421. }
  422. bHandled = FALSE;
  423. return 1;
  424. }
  425. LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  426. {
  427. if(wParam == VK_SPACE && IsHoverMode())
  428. return 0; // ignore if in hover mode
  429. if(wParam == VK_SPACE && m_fPressed == 1)
  430. {
  431. m_fPressed = 0;
  432. Invalidate();
  433. UpdateWindow();
  434. }
  435. bHandled = FALSE;
  436. return 1;
  437. }
  438. LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  439. {
  440. ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0);
  441. switch(wParam) // timer ID
  442. {
  443. case ID_TIMER_FIRST:
  444. KillTimer(ID_TIMER_FIRST);
  445. if(m_fPressed == 1)
  446. {
  447. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  448. int nElapse = 250;
  449. int nRepeat = 40;
  450. if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))
  451. nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated
  452. SetTimer(ID_TIMER_REPEAT, nElapse);
  453. }
  454. break;
  455. case ID_TIMER_REPEAT:
  456. if(m_fPressed == 1)
  457. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  458. else if(::GetCapture() != m_hWnd)
  459. KillTimer(ID_TIMER_REPEAT);
  460. break;
  461. default: // not our timer
  462. break;
  463. }
  464. return 0;
  465. }
  466. LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  467. {
  468. // If the control is subclassed or superclassed, this message can cause
  469. // repainting without WM_PAINT. We don't use this state, so just do nothing.
  470. return 0;
  471. }
  472. // Implementation
  473. void Init()
  474. {
  475. // We need this style to prevent Windows from painting the button
  476. ModifyStyle(0, BS_OWNERDRAW);
  477. // create a tool tip
  478. m_tip.Create(m_hWnd);
  479. ATLASSERT(m_tip.IsWindow());
  480. if(m_tip.IsWindow() && m_lpstrToolTipText != NULL)
  481. {
  482. m_tip.Activate(TRUE);
  483. m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
  484. }
  485. if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0)
  486. SizeToImage();
  487. }
  488. BOOL StartTrackMouseLeave()
  489. {
  490. TRACKMOUSEEVENT tme = { 0 };
  491. tme.cbSize = sizeof(tme);
  492. tme.dwFlags = TME_LEAVE;
  493. tme.hwndTrack = m_hWnd;
  494. return _TrackMouseEvent(&tme);
  495. }
  496. bool IsHoverMode() const
  497. {
  498. return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0);
  499. }
  500. };
  501. class CBitmapButton : public CBitmapButtonImpl<CBitmapButton>
  502. {
  503. public:
  504. DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
  505. CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
  506. CBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList)
  507. { }
  508. };
  509. #endif // !_WIN32_WCE
  510. ///////////////////////////////////////////////////////////////////////////////
  511. // CCheckListCtrlView - list view control with check boxes
  512. template <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle>
  513. class CCheckListViewCtrlImplTraits
  514. {
  515. public:
  516. static DWORD GetWndStyle(DWORD dwStyle)
  517. {
  518. return (dwStyle == 0) ? t_dwStyle : dwStyle;
  519. }
  520. static DWORD GetWndExStyle(DWORD dwExStyle)
  521. {
  522. return (dwExStyle == 0) ? t_dwExStyle : dwExStyle;
  523. }
  524. static DWORD GetExtendedLVStyle()
  525. {
  526. return t_dwExListViewStyle;
  527. }
  528. };
  529. typedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT> CCheckListViewCtrlTraits;
  530. template <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListViewCtrlTraits>
  531. class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>
  532. {
  533. public:
  534. DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
  535. // Attributes
  536. static DWORD GetExtendedLVStyle()
  537. {
  538. return TWinTraits::GetExtendedLVStyle();
  539. }
  540. // Operations
  541. BOOL SubclassWindow(HWND hWnd)
  542. {
  543. #if (_MSC_VER >= 1300)
  544. BOOL bRet = ATL::CWindowImplBaseT< TBase, TWinTraits>::SubclassWindow(hWnd);
  545. #else // !(_MSC_VER >= 1300)
  546. typedef ATL::CWindowImplBaseT< TBase, TWinTraits> _baseClass;
  547. BOOL bRet = _baseClass::SubclassWindow(hWnd);
  548. #endif // !(_MSC_VER >= 1300)
  549. if(bRet)
  550. {
  551. T* pT = static_cast<T*>(this);
  552. pT;
  553. ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
  554. SetExtendedListViewStyle(pT->GetExtendedLVStyle());
  555. }
  556. return bRet;
  557. }
  558. void CheckSelectedItems(int nCurrItem)
  559. {
  560. // first check if this item is selected
  561. LVITEM lvi = { 0 };
  562. lvi.iItem = nCurrItem;
  563. lvi.iSubItem = 0;
  564. lvi.mask = LVIF_STATE;
  565. lvi.stateMask = LVIS_SELECTED;
  566. GetItem(&lvi);
  567. // if item is not selected, don't do anything
  568. if(!(lvi.state & LVIS_SELECTED))
  569. return;
  570. // new check state will be reverse of the current state,
  571. BOOL bCheck = !GetCheckState(nCurrItem);
  572. int nItem = -1;
  573. int nOldItem = -1;
  574. while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1)
  575. {
  576. if(nItem != nCurrItem)
  577. SetCheckState(nItem, bCheck);
  578. nOldItem = nItem;
  579. }
  580. }
  581. // Implementation
  582. BEGIN_MSG_MAP(CCheckListViewCtrlImpl)
  583. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  584. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  585. MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
  586. MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
  587. END_MSG_MAP()
  588. LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  589. {
  590. // first let list view control initialize everything
  591. LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
  592. T* pT = static_cast<T*>(this);
  593. pT;
  594. ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
  595. SetExtendedListViewStyle(pT->GetExtendedLVStyle());
  596. return lRet;
  597. }
  598. LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  599. {
  600. POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  601. LVHITTESTINFO lvh = { 0 };
  602. lvh.pt = ptMsg;
  603. if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0)
  604. {
  605. T* pT = static_cast<T*>(this);
  606. pT->CheckSelectedItems(lvh.iItem);
  607. }
  608. bHandled = FALSE;
  609. return 1;
  610. }
  611. LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  612. {
  613. if(wParam == VK_SPACE)
  614. {
  615. int nCurrItem = GetNextItem(-1, LVNI_FOCUSED);
  616. if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0)
  617. {
  618. T* pT = static_cast<T*>(this);
  619. pT->CheckSelectedItems(nCurrItem);
  620. }
  621. }
  622. bHandled = FALSE;
  623. return 1;
  624. }
  625. };
  626. class CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl>
  627. {
  628. public:
  629. DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
  630. };
  631. ///////////////////////////////////////////////////////////////////////////////
  632. // CHyperLink - hyper link control implementation
  633. #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
  634. __declspec(selectany) struct
  635. {
  636. enum { cxWidth = 32, cyHeight = 32 };
  637. int xHotSpot;
  638. int yHotSpot;
  639. unsigned char arrANDPlane[cxWidth * cyHeight / 8];
  640. unsigned char arrXORPlane[cxWidth * cyHeight / 8];
  641. } _AtlHyperLink_CursorData =
  642. {
  643. 5, 0,
  644. {
  645. 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
  646. 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF,
  647. 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF,
  648. 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF,
  649. 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF,
  650. 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  651. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  652. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
  653. },
  654. {
  655. 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
  656. 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00,
  657. 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00,
  658. 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00,
  659. 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00,
  660. 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  661. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  662. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  663. }
  664. };
  665. #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
  666. #define HLINK_UNDERLINED 0x00000000
  667. #define HLINK_NOTUNDERLINED 0x00000001
  668. #define HLINK_UNDERLINEHOVER 0x00000002
  669. #define HLINK_COMMANDBUTTON 0x00000004
  670. #define HLINK_NOTIFYBUTTON 0x0000000C
  671. #define HLINK_USETAGS 0x00000010
  672. #define HLINK_USETAGSBOLD 0x00000030
  673. #define HLINK_NOTOOLTIP 0x00000040
  674. #define HLINK_AUTOCREATELINKFONT 0x00000080
  675. #define HLINK_SINGLELINE 0x00000100
  676. // Notes:
  677. // - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned
  678. // - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored
  679. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  680. class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
  681. {
  682. public:
  683. LPTSTR m_lpstrLabel;
  684. LPTSTR m_lpstrHyperLink;
  685. HCURSOR m_hCursor;
  686. HFONT m_hFontLink;
  687. HFONT m_hFontNormal;
  688. RECT m_rcLink;
  689. #ifndef _WIN32_WCE
  690. CToolTipCtrl m_tip;
  691. #endif // !_WIN32_WCE
  692. COLORREF m_clrLink;
  693. COLORREF m_clrVisited;
  694. DWORD m_dwExtendedStyle; // Hyper Link specific extended styles
  695. bool m_bPaintLabel:1;
  696. bool m_bVisited:1;
  697. bool m_bHover:1;
  698. bool m_bInternalLinkFont:1;
  699. bool m_bInternalNormalFont:1;
  700. // Constructor/Destructor
  701. CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) :
  702. m_lpstrLabel(NULL), m_lpstrHyperLink(NULL),
  703. m_hCursor(NULL), m_hFontLink(NULL), m_hFontNormal(NULL),
  704. m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)),
  705. m_dwExtendedStyle(dwExtendedStyle),
  706. m_bPaintLabel(true), m_bVisited(false),
  707. m_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false)
  708. {
  709. ::SetRectEmpty(&m_rcLink);
  710. }
  711. ~CHyperLinkImpl()
  712. {
  713. delete [] m_lpstrLabel;
  714. delete [] m_lpstrHyperLink;
  715. #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
  716. // It was created, not loaded, so we have to destroy it
  717. if(m_hCursor != NULL)
  718. ::DestroyCursor(m_hCursor);
  719. #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
  720. }
  721. // Attributes
  722. DWORD GetHyperLinkExtendedStyle() const
  723. {
  724. return m_dwExtendedStyle;
  725. }
  726. DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
  727. {
  728. DWORD dwPrevStyle = m_dwExtendedStyle;
  729. if(dwMask == 0)
  730. m_dwExtendedStyle = dwExtendedStyle;
  731. else
  732. m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
  733. return dwPrevStyle;
  734. }
  735. bool GetLabel(LPTSTR lpstrBuffer, int nLength) const
  736. {
  737. if(m_lpstrLabel == NULL)
  738. return false;
  739. ATLASSERT(lpstrBuffer != NULL);
  740. if(nLength <= lstrlen(m_lpstrLabel))
  741. return false;
  742. SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel);
  743. return true;
  744. }
  745. bool SetLabel(LPCTSTR lpstrLabel)
  746. {
  747. delete [] m_lpstrLabel;
  748. m_lpstrLabel = NULL;
  749. int cchLen = lstrlen(lpstrLabel) + 1;
  750. ATLTRY(m_lpstrLabel = new TCHAR[cchLen]);
  751. if(m_lpstrLabel == NULL)
  752. return false;
  753. SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel);
  754. T* pT = static_cast<T*>(this);
  755. pT->CalcLabelRect();
  756. if(m_hWnd != NULL)
  757. SetWindowText(lpstrLabel); // Set this for accessibility
  758. return true;
  759. }
  760. bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const
  761. {
  762. if(m_lpstrHyperLink == NULL)
  763. return false;
  764. ATLASSERT(lpstrBuffer != NULL);
  765. if(nLength <= lstrlen(m_lpstrHyperLink))
  766. return false;
  767. SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink);
  768. return true;
  769. }
  770. bool SetHyperLink(LPCTSTR lpstrLink)
  771. {
  772. delete [] m_lpstrHyperLink;
  773. m_lpstrHyperLink = NULL;
  774. int cchLen = lstrlen(lpstrLink) + 1;
  775. ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]);
  776. if(m_lpstrHyperLink == NULL)
  777. return false;
  778. SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink);
  779. if(m_lpstrLabel == NULL)
  780. {
  781. T* pT = static_cast<T*>(this);
  782. pT->CalcLabelRect();
  783. }
  784. #ifndef _WIN32_WCE
  785. if(m_tip.IsWindow())
  786. {
  787. m_tip.Activate(TRUE);
  788. m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
  789. }
  790. #endif // !_WIN32_WCE
  791. return true;
  792. }
  793. HFONT GetLinkFont() const
  794. {
  795. return m_hFontLink;
  796. }
  797. void SetLinkFont(HFONT hFont)
  798. {
  799. if(m_bInternalLinkFont)
  800. {
  801. ::DeleteObject(m_hFontLink);
  802. m_bInternalLinkFont = false;
  803. }
  804. m_hFontLink = hFont;
  805. T* pT = static_cast<T*>(this);
  806. pT->CalcLabelRect();
  807. }
  808. int GetIdealHeight() const
  809. {
  810. ATLASSERT(::IsWindow(m_hWnd));
  811. if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
  812. return -1;
  813. if(!m_bPaintLabel)
  814. return -1;
  815. UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  816. CClientDC dc(m_hWnd);
  817. RECT rect = { 0 };
  818. GetClientRect(&rect);
  819. HFONT hFontOld = dc.SelectFont(m_hFontNormal);
  820. RECT rcText = rect;
  821. dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | uFormat | DT_CALCRECT);
  822. dc.SelectFont(m_hFontLink);
  823. RECT rcLink = rect;
  824. dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
  825. dc.SelectFont(hFontOld);
  826. return max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top);
  827. }
  828. bool GetIdealSize(SIZE& size) const
  829. {
  830. int cx = 0, cy = 0;
  831. bool bRet = GetIdealSize(cx, cy);
  832. if(bRet)
  833. {
  834. size.cx = cx;
  835. size.cy = cy;
  836. }
  837. return bRet;
  838. }
  839. bool GetIdealSize(int& cx, int& cy) const
  840. {
  841. ATLASSERT(::IsWindow(m_hWnd));
  842. if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
  843. return false;
  844. if(!m_bPaintLabel)
  845. return false;
  846. CClientDC dc(m_hWnd);
  847. RECT rcClient = { 0 };
  848. GetClientRect(&rcClient);
  849. RECT rcAll = rcClient;
  850. if(IsUsingTags())
  851. {
  852. // find tags and label parts
  853. LPTSTR lpstrLeft = NULL;
  854. int cchLeft = 0;
  855. LPTSTR lpstrLink = NULL;
  856. int cchLink = 0;
  857. LPTSTR lpstrRight = NULL;
  858. int cchRight = 0;
  859. const T* pT = static_cast<const T*>(this);
  860. pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
  861. // get label part rects
  862. UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  863. HFONT hFontOld = dc.SelectFont(m_hFontNormal);
  864. RECT rcLeft = rcClient;
  865. dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);
  866. dc.SelectFont(m_hFontLink);
  867. RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom };
  868. dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
  869. dc.SelectFont(m_hFontNormal);
  870. RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom };
  871. dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | DT_CALCRECT);
  872. dc.SelectFont(hFontOld);
  873. int cyMax = max(rcLeft.bottom, max(rcLink.bottom, rcRight.bottom));
  874. ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax);
  875. }
  876. else
  877. {
  878. HFONT hOldFont = NULL;
  879. if(m_hFontLink != NULL)
  880. hOldFont = dc.SelectFont(m_hFontLink);
  881. LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
  882. DWORD dwStyle = GetStyle();
  883. UINT uFormat = DT_LEFT;
  884. if (dwStyle & SS_CENTER)
  885. uFormat = DT_CENTER;
  886. else if (dwStyle & SS_RIGHT)
  887. uFormat = DT_RIGHT;
  888. uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  889. dc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT);
  890. if(m_hFontLink != NULL)
  891. dc.SelectFont(hOldFont);
  892. if (dwStyle & SS_CENTER)
  893. {
  894. int dx = (rcClient.right - rcAll.right) / 2;
  895. ::OffsetRect(&rcAll, dx, 0);
  896. }
  897. else if (dwStyle & SS_RIGHT)
  898. {
  899. int dx = rcClient.right - rcAll.right;
  900. ::OffsetRect(&rcAll, dx, 0);
  901. }
  902. }
  903. cx = rcAll.right - rcAll.left;
  904. cy = rcAll.bottom - rcAll.top;
  905. return true;
  906. }
  907. // for command buttons only
  908. bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const
  909. {
  910. ATLASSERT(IsCommandButton());
  911. return GetHyperLink(lpstrBuffer, nLength);
  912. }
  913. bool SetToolTipText(LPCTSTR lpstrToolTipText)
  914. {
  915. ATLASSERT(IsCommandButton());
  916. return SetHyperLink(lpstrToolTipText);
  917. }
  918. // Operations
  919. BOOL SubclassWindow(HWND hWnd)
  920. {
  921. ATLASSERT(m_hWnd == NULL);
  922. ATLASSERT(::IsWindow(hWnd));
  923. if(m_hFontNormal == NULL)
  924. m_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
  925. #if (_MSC_VER >= 1300)
  926. BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd);
  927. #else // !(_MSC_VER >= 1300)
  928. typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass;
  929. BOOL bRet = _baseClass::SubclassWindow(hWnd);
  930. #endif // !(_MSC_VER >= 1300)
  931. if(bRet)
  932. {
  933. T* pT = static_cast<T*>(this);
  934. pT->Init();
  935. }
  936. return bRet;
  937. }
  938. bool Navigate()
  939. {
  940. ATLASSERT(::IsWindow(m_hWnd));
  941. bool bRet = true;
  942. if(IsNotifyButton())
  943. {
  944. NMHDR nmhdr = { m_hWnd, GetDlgCtrlID(), NM_CLICK };
  945. ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr);
  946. }
  947. else if(IsCommandButton())
  948. {
  949. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  950. }
  951. else
  952. {
  953. ATLASSERT(m_lpstrHyperLink != NULL);
  954. #ifndef _WIN32_WCE
  955. DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);
  956. bRet = (dwRet > 32);
  957. #else // CE specific
  958. SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 };
  959. ::ShellExecuteEx(&shExeInfo);
  960. DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp;
  961. bRet = (dwRet == 0) || (dwRet > 32);
  962. #endif // _WIN32_WCE
  963. ATLASSERT(bRet);
  964. if(bRet)
  965. {
  966. m_bVisited = true;
  967. Invalidate();
  968. }
  969. }
  970. return bRet;
  971. }
  972. void CreateLinkFontFromNormal()
  973. {
  974. if(m_bInternalLinkFont)
  975. {
  976. ::DeleteObject(m_hFontLink);
  977. m_bInternalLinkFont = false;
  978. }
  979. CFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT);
  980. LOGFONT lf = { 0 };
  981. font.GetLogFont(&lf);
  982. if(IsUsingTagsBold())
  983. lf.lfWeight = FW_BOLD;
  984. else if(!IsNotUnderlined())
  985. lf.lfUnderline = TRUE;
  986. m_hFontLink = ::CreateFontIndirect(&lf);
  987. m_bInternalLinkFont = true;
  988. ATLASSERT(m_hFontLink != NULL);
  989. }
  990. // Message map and handlers
  991. BEGIN_MSG_MAP(CHyperLinkImpl)
  992. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  993. #ifndef _WIN32_WCE
  994. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  995. MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
  996. #endif // !_WIN32_WCE
  997. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  998. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  999. #ifndef _WIN32_WCE
  1000. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  1001. #endif // !_WIN32_WCE
  1002. MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
  1003. MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
  1004. MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  1005. #ifndef _WIN32_WCE
  1006. MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
  1007. #endif // !_WIN32_WCE
  1008. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  1009. MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
  1010. MESSAGE_HANDLER(WM_CHAR, OnChar)
  1011. MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
  1012. MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
  1013. MESSAGE_HANDLER(WM_ENABLE, OnEnable)
  1014. MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
  1015. MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
  1016. MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
  1017. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1018. END_MSG_MAP()
  1019. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1020. {
  1021. T* pT = static_cast<T*>(this);
  1022. pT->Init();
  1023. return 0;
  1024. }
  1025. #ifndef _WIN32_WCE
  1026. LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1027. {
  1028. if(m_tip.IsWindow())
  1029. {
  1030. m_tip.DestroyWindow();
  1031. m_tip.m_hWnd = NULL;
  1032. }
  1033. if(m_bInternalLinkFont)
  1034. {
  1035. ::DeleteObject(m_hFontLink);
  1036. m_hFontLink = NULL;
  1037. m_bInternalLinkFont = false;
  1038. }
  1039. if(m_bInternalNormalFont)
  1040. {
  1041. ::DeleteObject(m_hFontNormal);
  1042. m_hFontNormal = NULL;
  1043. m_bInternalNormalFont = false;
  1044. }
  1045. bHandled = FALSE;
  1046. return 1;
  1047. }
  1048. LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1049. {
  1050. MSG msg = { m_hWnd, uMsg, wParam, lParam };
  1051. if(m_tip.IsWindow() && IsUsingToolTip())
  1052. m_tip.RelayEvent(&msg);
  1053. bHandled = FALSE;
  1054. return 1;
  1055. }
  1056. #endif // !_WIN32_WCE
  1057. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1058. {
  1059. return 1; // no background painting needed (we do it all during WM_PAINT)
  1060. }
  1061. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1062. {
  1063. if(!m_bPaintLabel)
  1064. {
  1065. bHandled = FALSE;
  1066. return 1;
  1067. }
  1068. T* pT = static_cast<T*>(this);
  1069. if(wParam != NULL)
  1070. {
  1071. pT->DoEraseBackground((HDC)wParam);
  1072. pT->DoPaint((HDC)wParam);
  1073. }
  1074. else
  1075. {
  1076. CPaintDC dc(m_hWnd);
  1077. pT->DoEraseBackground(dc.m_hDC);
  1078. pT->DoPaint(dc.m_hDC);
  1079. }
  1080. return 0;
  1081. }
  1082. LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1083. {
  1084. if(m_bPaintLabel)
  1085. Invalidate();
  1086. else
  1087. bHandled = FALSE;
  1088. return 0;
  1089. }
  1090. LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1091. {
  1092. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  1093. if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))
  1094. {
  1095. ::SetCursor(m_hCursor);
  1096. if(IsUnderlineHover())
  1097. {
  1098. if(!m_bHover)
  1099. {
  1100. m_bHover = true;
  1101. InvalidateRect(&m_rcLink);
  1102. UpdateWindow();
  1103. #ifndef _WIN32_WCE
  1104. StartTrackMouseLeave();
  1105. #endif // !_WIN32_WCE
  1106. }
  1107. }
  1108. }
  1109. else
  1110. {
  1111. if(IsUnderlineHover())
  1112. {
  1113. if(m_bHover)
  1114. {
  1115. m_bHover = false;
  1116. InvalidateRect(&m_rcLink);
  1117. UpdateWindow();
  1118. }
  1119. }
  1120. bHandled = FALSE;
  1121. }
  1122. return 0;
  1123. }
  1124. #ifndef _WIN32_WCE
  1125. LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1126. {
  1127. if(IsUnderlineHover() && m_bHover)
  1128. {
  1129. m_bHover = false;
  1130. InvalidateRect(&m_rcLink);
  1131. UpdateWindow();
  1132. }
  1133. return 0;
  1134. }
  1135. #endif // !_WIN32_WCE
  1136. LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  1137. {
  1138. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  1139. if(::PtInRect(&m_rcLink, pt))
  1140. {
  1141. SetFocus();
  1142. SetCapture();
  1143. }
  1144. return 0;
  1145. }
  1146. LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  1147. {
  1148. if(GetCapture() == m_hWnd)
  1149. {
  1150. ReleaseCapture();
  1151. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  1152. if(::PtInRect(&m_rcLink, pt))
  1153. {
  1154. T* pT = static_cast<T*>(this);
  1155. pT->Navigate();
  1156. }
  1157. }
  1158. return 0;
  1159. }
  1160. LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1161. {
  1162. if(wParam == VK_RETURN || wParam == VK_SPACE)
  1163. {
  1164. T* pT = static_cast<T*>(this);
  1165. pT->Navigate();
  1166. }
  1167. return 0;
  1168. }
  1169. LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1170. {
  1171. return DLGC_WANTCHARS;
  1172. }
  1173. LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1174. {
  1175. POINT pt = { 0, 0 };
  1176. GetCursorPos(&pt);
  1177. ScreenToClient(&pt);
  1178. if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))
  1179. {
  1180. return TRUE;
  1181. }
  1182. bHandled = FALSE;
  1183. return FALSE;
  1184. }
  1185. LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1186. {
  1187. Invalidate();
  1188. UpdateWindow();
  1189. return 0;
  1190. }
  1191. LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1192. {
  1193. return (LRESULT)m_hFontNormal;
  1194. }
  1195. LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1196. {
  1197. if(m_bInternalNormalFont)
  1198. {
  1199. ::DeleteObject(m_hFontNormal);
  1200. m_bInternalNormalFont = false;
  1201. }
  1202. bool bCreateLinkFont = m_bInternalLinkFont;
  1203. m_hFontNormal = (HFONT)wParam;
  1204. if(bCreateLinkFont || IsAutoCreateLinkFont())
  1205. CreateLinkFontFromNormal();
  1206. T* pT = static_cast<T*>(this);
  1207. pT->CalcLabelRect();
  1208. if((BOOL)lParam)
  1209. {
  1210. Invalidate();
  1211. UpdateWindow();
  1212. }
  1213. return 0;
  1214. }
  1215. LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1216. {
  1217. // If the control is subclassed or superclassed, this message can cause
  1218. // repainting without WM_PAINT. We don't use this state, so just do nothing.
  1219. return 0;
  1220. }
  1221. LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1222. {
  1223. T* pT = static_cast<T*>(this);
  1224. pT->CalcLabelRect();
  1225. pT->Invalidate();
  1226. return 0;
  1227. }
  1228. // Implementation
  1229. void Init()
  1230. {
  1231. ATLASSERT(::IsWindow(m_hWnd));
  1232. // Check if we should paint a label
  1233. const int cchBuff = 8;
  1234. TCHAR szBuffer[cchBuff] = { 0 };
  1235. if(::GetClassName(m_hWnd, szBuffer, cchBuff))
  1236. {
  1237. if(lstrcmpi(szBuffer, _T("static")) == 0)
  1238. {
  1239. ModifyStyle(0, SS_NOTIFY); // we need this
  1240. DWORD dwStyle = GetStyle() & 0x000000FF;
  1241. #ifndef _WIN32_WCE
  1242. if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT ||
  1243. dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME ||
  1244. dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW ||
  1245. dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE)
  1246. #else // CE specific
  1247. if(dwStyle == SS_ICON || dwStyle == SS_BITMAP)
  1248. #endif // _WIN32_WCE
  1249. m_bPaintLabel = false;
  1250. }
  1251. }
  1252. // create or load a cursor
  1253. #if (WINVER >= 0x0500) || defined(_WIN32_WCE)
  1254. m_hCursor = ::LoadCursor(NULL, IDC_HAND);
  1255. #else
  1256. m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane);
  1257. #endif
  1258. ATLASSERT(m_hCursor != NULL);
  1259. // set fonts
  1260. if(m_bPaintLabel)
  1261. {
  1262. if(m_hFontNormal == NULL)
  1263. {
  1264. m_hFontNormal = AtlCreateControlFont();
  1265. m_bInternalNormalFont = true;
  1266. }
  1267. if(m_hFontLink == NULL)
  1268. CreateLinkFontFromNormal();
  1269. }
  1270. #ifndef _WIN32_WCE
  1271. // create a tool tip
  1272. m_tip.Create(m_hWnd);
  1273. ATLASSERT(m_tip.IsWindow());
  1274. #endif // !_WIN32_WCE
  1275. // set label (defaults to window text)
  1276. if(m_lpstrLabel == NULL)
  1277. {
  1278. int nLen = GetWindowTextLength();
  1279. if(nLen > 0)
  1280. {
  1281. ATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]);
  1282. if(m_lpstrLabel != NULL)
  1283. ATLVERIFY(GetWindowText(m_lpstrLabel, nLen + 1) > 0);
  1284. }
  1285. }
  1286. T* pT = static_cast<T*>(this);
  1287. pT->CalcLabelRect();
  1288. // set hyperlink (defaults to label), or just activate tool tip if already set
  1289. if(m_lpstrHyperLink == NULL && !IsCommandButton())
  1290. {
  1291. if(m_lpstrLabel != NULL)
  1292. SetHyperLink(m_lpstrLabel);
  1293. }
  1294. #ifndef _WIN32_WCE
  1295. else
  1296. {
  1297. m_tip.Activate(TRUE);
  1298. m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
  1299. }
  1300. #endif // !_WIN32_WCE
  1301. // set link colors
  1302. if(m_bPaintLabel)
  1303. {
  1304. CRegKeyEx rk;
  1305. LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings"));
  1306. if(lRet == ERROR_SUCCESS)
  1307. {
  1308. const int cchValue = 12;
  1309. TCHAR szValue[cchValue] = { 0 };
  1310. ULONG ulCount = cchValue;
  1311. lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount);
  1312. if(lRet == ERROR_SUCCESS)
  1313. {
  1314. COLORREF clr = pT->_ParseColorString(szValue);
  1315. ATLASSERT(clr != CLR_INVALID);
  1316. if(clr != CLR_INVALID)
  1317. m_clrLink = clr;
  1318. }
  1319. ulCount = cchValue;
  1320. lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount);
  1321. if(lRet == ERROR_SUCCESS)
  1322. {
  1323. COLORREF clr = pT->_ParseColorString(szValue);
  1324. ATLASSERT(clr != CLR_INVALID);
  1325. if(clr != CLR_INVALID)
  1326. m_clrVisited = clr;
  1327. }
  1328. }
  1329. }
  1330. }
  1331. static COLORREF _ParseColorString(LPTSTR lpstr)
  1332. {
  1333. int c[3] = { -1, -1, -1 };
  1334. LPTSTR p = NULL;
  1335. for(int i = 0; i < 2; i++)
  1336. {
  1337. for(p = lpstr; *p != _T('\0'); p = ::CharNext(p))
  1338. {
  1339. if(*p == _T(','))
  1340. {
  1341. *p = _T('\0');
  1342. c[i] = MinCrtHelper::_atoi(lpstr);
  1343. lpstr = &p[1];
  1344. break;
  1345. }
  1346. }
  1347. if(c[i] == -1)
  1348. return CLR_INVALID;
  1349. }
  1350. if(*lpstr == _T('\0'))
  1351. return CLR_INVALID;
  1352. c[2] = MinCrtHelper::_atoi(lpstr);
  1353. return RGB(c[0], c[1], c[2]);
  1354. }
  1355. bool CalcLabelRect()
  1356. {
  1357. if(!::IsWindow(m_hWnd))
  1358. return false;
  1359. if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
  1360. return false;
  1361. CClientDC dc(m_hWnd);
  1362. RECT rcClient = { 0 };
  1363. GetClientRect(&rcClient);
  1364. m_rcLink = rcClient;
  1365. if(!m_bPaintLabel)
  1366. return true;
  1367. if(IsUsingTags())
  1368. {
  1369. // find tags and label parts
  1370. LPTSTR lpstrLeft = NULL;
  1371. int cchLeft = 0;
  1372. LPTSTR lpstrLink = NULL;
  1373. int cchLink = 0;
  1374. LPTSTR lpstrRight = NULL;
  1375. int cchRight = 0;
  1376. T* pT = static_cast<T*>(this);
  1377. pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
  1378. ATLASSERT(lpstrLink != NULL);
  1379. ATLASSERT(cchLink > 0);
  1380. // get label part rects
  1381. HFONT hFontOld = dc.SelectFont(m_hFontNormal);
  1382. UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  1383. RECT rcLeft = rcClient;
  1384. if(lpstrLeft != NULL)
  1385. dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);
  1386. dc.SelectFont(m_hFontLink);
  1387. RECT rcLink = rcClient;
  1388. if(lpstrLeft != NULL)
  1389. rcLink.left = rcLeft.right;
  1390. dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
  1391. dc.SelectFont(hFontOld);
  1392. m_rcLink = rcLink;
  1393. }
  1394. else
  1395. {
  1396. HFONT hOldFont = NULL;
  1397. if(m_hFontLink != NULL)
  1398. hOldFont = dc.SelectFont(m_hFontLink);
  1399. LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
  1400. DWORD dwStyle = GetStyle();
  1401. UINT uFormat = DT_LEFT;
  1402. if (dwStyle & SS_CENTER)
  1403. uFormat = DT_CENTER;
  1404. else if (dwStyle & SS_RIGHT)
  1405. uFormat = DT_RIGHT;
  1406. uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  1407. dc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT);
  1408. if(m_hFontLink != NULL)
  1409. dc.SelectFont(hOldFont);
  1410. if (dwStyle & SS_CENTER)
  1411. {
  1412. int dx = (rcClient.right - m_rcLink.right) / 2;
  1413. ::OffsetRect(&m_rcLink, dx, 0);
  1414. }
  1415. else if (dwStyle & SS_RIGHT)
  1416. {
  1417. int dx = rcClient.right - m_rcLink.right;
  1418. ::OffsetRect(&m_rcLink, dx, 0);
  1419. }
  1420. }
  1421. return true;
  1422. }
  1423. void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const
  1424. {
  1425. lpstrLeft = NULL;
  1426. cchLeft = 0;
  1427. lpstrLink = NULL;
  1428. cchLink = 0;
  1429. lpstrRight = NULL;
  1430. cchRight = 0;
  1431. LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
  1432. int cchText = lstrlen(lpstrText);
  1433. bool bOutsideLink = true;
  1434. for(int i = 0; i < cchText; i++)
  1435. {
  1436. if(lpstrText[i] != _T('<'))
  1437. continue;
  1438. if(bOutsideLink)
  1439. {
  1440. if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T("<A>"), 3) == CSTR_EQUAL)
  1441. {
  1442. if(i > 0)
  1443. {
  1444. lpstrLeft = lpstrText;
  1445. cchLeft = i;
  1446. }
  1447. lpstrLink = &lpstrText[i + 3];
  1448. bOutsideLink = false;
  1449. }
  1450. }
  1451. else
  1452. {
  1453. if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T("</A>"), 4) == CSTR_EQUAL)
  1454. {
  1455. cchLink = i - 3 - cchLeft;
  1456. if(lpstrText[i + 4] != 0)
  1457. {
  1458. lpstrRight = &lpstrText[i + 4];
  1459. cchRight = cchText - (i + 4);
  1460. break;
  1461. }
  1462. }
  1463. }
  1464. }
  1465. }
  1466. void DoEraseBackground(CDCHandle dc)
  1467. {
  1468. HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd);
  1469. if(hBrush != NULL)
  1470. {
  1471. RECT rect = { 0 };
  1472. GetClientRect(&rect);
  1473. dc.FillRect(&rect, hBrush);
  1474. }
  1475. }
  1476. void DoPaint(CDCHandle dc)
  1477. {
  1478. if(IsUsingTags())
  1479. {
  1480. // find tags and label parts
  1481. LPTSTR lpstrLeft = NULL;
  1482. int cchLeft = 0;
  1483. LPTSTR lpstrLink = NULL;
  1484. int cchLink = 0;
  1485. LPTSTR lpstrRight = NULL;
  1486. int cchRight = 0;
  1487. T* pT = static_cast<T*>(this);
  1488. pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
  1489. // get label part rects
  1490. RECT rcClient = { 0 };
  1491. GetClientRect(&rcClient);
  1492. dc.SetBkMode(TRANSPARENT);
  1493. HFONT hFontOld = dc.SelectFont(m_hFontNormal);
  1494. UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  1495. if(lpstrLeft != NULL)
  1496. dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat);
  1497. COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
  1498. if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))
  1499. dc.SelectFont(m_hFontLink);
  1500. else
  1501. dc.SelectFont(m_hFontNormal);
  1502. dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat);
  1503. dc.SetTextColor(clrOld);
  1504. dc.SelectFont(m_hFontNormal);
  1505. if(lpstrRight != NULL)
  1506. {
  1507. RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom };
  1508. dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat);
  1509. }
  1510. if(GetFocus() == m_hWnd)
  1511. dc.DrawFocusRect(&m_rcLink);
  1512. dc.SelectFont(hFontOld);
  1513. }
  1514. else
  1515. {
  1516. dc.SetBkMode(TRANSPARENT);
  1517. COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
  1518. HFONT hFontOld = NULL;
  1519. if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))
  1520. hFontOld = dc.SelectFont(m_hFontLink);
  1521. else
  1522. hFontOld = dc.SelectFont(m_hFontNormal);
  1523. LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
  1524. DWORD dwStyle = GetStyle();
  1525. UINT uFormat = DT_LEFT;
  1526. if (dwStyle & SS_CENTER)
  1527. uFormat = DT_CENTER;
  1528. else if (dwStyle & SS_RIGHT)
  1529. uFormat = DT_RIGHT;
  1530. uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
  1531. dc.DrawText(lpstrText, -1, &m_rcLink, uFormat);
  1532. if(GetFocus() == m_hWnd)
  1533. dc.DrawFocusRect(&m_rcLink);
  1534. dc.SetTextColor(clrOld);
  1535. dc.SelectFont(hFontOld);
  1536. }
  1537. }
  1538. #ifndef _WIN32_WCE
  1539. BOOL StartTrackMouseLeave()
  1540. {
  1541. TRACKMOUSEEVENT tme = { 0 };
  1542. tme.cbSize = sizeof(tme);
  1543. tme.dwFlags = TME_LEAVE;
  1544. tme.hwndTrack = m_hWnd;
  1545. return _TrackMouseEvent(&tme);
  1546. }
  1547. #endif // !_WIN32_WCE
  1548. // Implementation helpers
  1549. bool IsUnderlined() const
  1550. {
  1551. return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0);
  1552. }
  1553. bool IsNotUnderlined() const
  1554. {
  1555. return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0);
  1556. }
  1557. bool IsUnderlineHover() const
  1558. {
  1559. return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0);
  1560. }
  1561. bool IsCommandButton() const
  1562. {
  1563. return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0);
  1564. }
  1565. bool IsNotifyButton() const
  1566. {
  1567. return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON);
  1568. }
  1569. bool IsUsingTags() const
  1570. {
  1571. return ((m_dwExtendedStyle & HLINK_USETAGS) != 0);
  1572. }
  1573. bool IsUsingTagsBold() const
  1574. {
  1575. return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD);
  1576. }
  1577. bool IsUsingToolTip() const
  1578. {
  1579. return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0);
  1580. }
  1581. bool IsAutoCreateLinkFont() const
  1582. {
  1583. return ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT);
  1584. }
  1585. bool IsSingleLine() const
  1586. {
  1587. return ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE);
  1588. }
  1589. };
  1590. class CHyperLink : public CHyperLinkImpl<CHyperLink>
  1591. {
  1592. public:
  1593. DECLARE_WND_CLASS(_T("WTL_HyperLink"))
  1594. };
  1595. ///////////////////////////////////////////////////////////////////////////////
  1596. // CWaitCursor - displays a wait cursor
  1597. class CWaitCursor
  1598. {
  1599. public:
  1600. // Data
  1601. HCURSOR m_hWaitCursor;
  1602. HCURSOR m_hOldCursor;
  1603. bool m_bInUse;
  1604. // Constructor/destructor
  1605. CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false)
  1606. {
  1607. HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance();
  1608. m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor);
  1609. ATLASSERT(m_hWaitCursor != NULL);
  1610. if(bSet)
  1611. Set();
  1612. }
  1613. ~CWaitCursor()
  1614. {
  1615. Restore();
  1616. }
  1617. // Methods
  1618. bool Set()
  1619. {
  1620. if(m_bInUse)
  1621. return false;
  1622. m_hOldCursor = ::SetCursor(m_hWaitCursor);
  1623. m_bInUse = true;
  1624. return true;
  1625. }
  1626. bool Restore()
  1627. {
  1628. if(!m_bInUse)
  1629. return false;
  1630. ::SetCursor(m_hOldCursor);
  1631. m_bInUse = false;
  1632. return true;
  1633. }
  1634. };
  1635. ///////////////////////////////////////////////////////////////////////////////
  1636. // CCustomWaitCursor - for custom and animated cursors
  1637. class CCustomWaitCursor : public CWaitCursor
  1638. {
  1639. public:
  1640. // Constructor/destructor
  1641. CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL)