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.

1973 lines
52 KiB

  1. // WTL Version 3.1
  2. // Copyright (C) 1997-2000 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This file is a part of Windows Template Library.
  6. // The code and information is provided "as-is" without
  7. // warranty of any kind, either expressed or implied.
  8. #ifndef __ATLCTRLX_H__
  9. #define __ATLCTRLX_H__
  10. #pragma once
  11. #ifndef __cplusplus
  12. #error ATL requires C++ compilation (use a .cpp suffix)
  13. #endif
  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. namespace WTL
  21. {
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Forward declarations
  24. template <class T, class TBase = CButton, class TWinTraits = CControlWinTraits> class CBitmapButtonImpl;
  25. class CBitmapButton;
  26. template <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListViewCtrlTraits> class CCheckListViewCtrlImpl;
  27. class CCheckListViewCtrl;
  28. template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class CHyperLinkImpl;
  29. class CHyperLink;
  30. class CWaitCursor;
  31. template <class T, class TBase = CStatusBarCtrl> class CMultiPaneStatusBarCtrlImpl;
  32. class CMultiPaneStatusBarCtrl;
  33. template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class CPaneContainerImpl;
  34. class CPaneContainer;
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CBitmapButton - bitmap button implementation
  37. // bitmap button extended styles
  38. #define BMPBTN_HOVER 0x00000001
  39. #define BMPBTN_AUTO3D_SINGLE 0x00000002
  40. #define BMPBTN_AUTO3D_DOUBLE 0x00000004
  41. #define BMPBTN_AUTOSIZE 0x00000008
  42. #define BMPBTN_SHAREIMAGELISTS 0x00000010
  43. #define BMPBTN_AUTOFIRE 0x00000020
  44. template <class T, class TBase /*= CButton */, class TWinTraits /*= CControlWinTraits */ >
  45. class ATL_NO_VTABLE CBitmapButtonImpl : public CWindowImpl< T, TBase, TWinTraits>
  46. {
  47. public:
  48. DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
  49. enum
  50. {
  51. _nImageNormal = 0,
  52. _nImagePushed,
  53. _nImageFocusOrHover,
  54. _nImageDisabled,
  55. _nImageCount = 4,
  56. };
  57. enum
  58. {
  59. ID_TIMER_FIRST = 1000,
  60. ID_TIMER_REPEAT = 1001
  61. };
  62. // Bitmap button specific extended styles
  63. DWORD m_dwExtendedStyle;
  64. CImageList m_ImageList;
  65. int m_nImage[_nImageCount];
  66. CToolTipCtrl m_tip;
  67. LPTSTR m_lpstrToolTipText;
  68. // Internal states
  69. unsigned m_fMouseOver:1;
  70. unsigned m_fFocus:1;
  71. unsigned m_fPressed:1;
  72. // Constructor/Destructor
  73. CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
  74. m_ImageList(hImageList), m_dwExtendedStyle(dwExtendedStyle), m_lpstrToolTipText(NULL),
  75. m_fMouseOver(0), m_fFocus(0), m_fPressed(0)
  76. {
  77. m_nImage[_nImageNormal] = -1;
  78. m_nImage[_nImagePushed] = -1;
  79. m_nImage[_nImageFocusOrHover] = -1;
  80. m_nImage[_nImageDisabled] = -1;
  81. }
  82. ~CBitmapButtonImpl()
  83. {
  84. if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0)
  85. m_ImageList.Destroy();
  86. delete [] m_lpstrToolTipText;
  87. }
  88. // overridden to provide proper initialization
  89. BOOL SubclassWindow(HWND hWnd)
  90. {
  91. BOOL bRet = CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd);
  92. if(bRet)
  93. Init();
  94. return bRet;
  95. }
  96. // Attributes
  97. DWORD GetBitmapButtonExtendedStyle() const
  98. {
  99. return m_dwExtendedStyle;
  100. }
  101. DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
  102. {
  103. DWORD dwPrevStyle = m_dwExtendedStyle;
  104. if(dwMask == 0)
  105. m_dwExtendedStyle = dwExtendedStyle;
  106. else
  107. m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
  108. return dwPrevStyle;
  109. }
  110. HIMAGELIST GetImageList() const
  111. {
  112. return m_ImageList;
  113. }
  114. HIMAGELIST SetImageList(HIMAGELIST hImageList)
  115. {
  116. HIMAGELIST hImageListPrev = m_ImageList;
  117. m_ImageList = hImageList;
  118. if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd))
  119. SizeToImage();
  120. return hImageListPrev;
  121. }
  122. int GetToolTipTextLength() const
  123. {
  124. return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText);
  125. }
  126. bool GetToolTipText(LPTSTR lpstrText, int nLength) const
  127. {
  128. ATLASSERT(lpstrText != NULL);
  129. if(m_lpstrToolTipText == NULL)
  130. return false;
  131. return (lstrcpyn(lpstrText, m_lpstrToolTipText, min(nLength, lstrlen(m_lpstrToolTipText) + 1)) != NULL);
  132. }
  133. bool SetToolTipText(LPCTSTR lpstrText)
  134. {
  135. if(m_lpstrToolTipText != NULL)
  136. {
  137. delete [] m_lpstrToolTipText;
  138. m_lpstrToolTipText = NULL;
  139. }
  140. if(lpstrText == NULL)
  141. {
  142. if(m_tip.IsWindow())
  143. m_tip.Activate(FALSE);
  144. return true;
  145. }
  146. ATLTRY(m_lpstrToolTipText = new TCHAR[lstrlen(lpstrText) + 1]);
  147. if(m_lpstrToolTipText == NULL)
  148. return false;
  149. bool bRet = (lstrcpy(m_lpstrToolTipText, lpstrText) != NULL);
  150. if(bRet && m_tip.IsWindow())
  151. {
  152. m_tip.Activate(TRUE);
  153. m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
  154. }
  155. return bRet;
  156. }
  157. // Operations
  158. void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1)
  159. {
  160. if(nNormal != -1)
  161. m_nImage[_nImageNormal] = nNormal;
  162. if(nPushed != -1)
  163. m_nImage[_nImagePushed] = nPushed;
  164. if(nFocusOrHover != -1)
  165. m_nImage[_nImageFocusOrHover] = nFocusOrHover;
  166. if(nDisabled != -1)
  167. m_nImage[_nImageDisabled] = nDisabled;
  168. }
  169. BOOL SizeToImage()
  170. {
  171. ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL);
  172. int cx = 0;
  173. int cy = 0;
  174. if(!m_ImageList.GetIconSize(cx, cy))
  175. return FALSE;
  176. return ResizeClient(cx, cy);
  177. }
  178. // Overrideables
  179. void DoPaint(CDCHandle dc)
  180. {
  181. ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set
  182. ATLASSERT(m_nImage[0] != -1); // main bitmap must be set
  183. // set bitmap according to the current button state
  184. int nImage = -1;
  185. bool bHover = IsHoverMode();
  186. if(m_fPressed == 1)
  187. nImage = m_nImage[_nImagePushed];
  188. else if((!bHover && m_fFocus == 1) || (bHover && m_fMouseOver == 1))
  189. nImage = m_nImage[_nImageFocusOrHover];
  190. else if(!IsWindowEnabled())
  191. nImage = m_nImage[_nImageDisabled];
  192. if(nImage == -1) // not there, use default one
  193. nImage = m_nImage[_nImageNormal];
  194. // draw the button image
  195. int xyPos = 0;
  196. if((m_fPressed == 1) && ((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) && (m_nImage[_nImagePushed] == -1))
  197. xyPos = 1;
  198. m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL);
  199. // draw 3D border if required
  200. if((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0)
  201. {
  202. RECT rect;
  203. GetClientRect(&rect);
  204. if(m_fPressed == 1)
  205. dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT);
  206. else if(!bHover || m_fMouseOver == 1)
  207. dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT);
  208. if(!bHover && m_fFocus == 1)
  209. {
  210. ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));
  211. dc.DrawFocusRect(&rect);
  212. }
  213. }
  214. }
  215. // Message map and handlers
  216. typedef CBitmapButtonImpl< T, TBase, TWinTraits > thisClass;
  217. BEGIN_MSG_MAP(thisClass)
  218. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  219. MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
  220. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  221. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  222. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  223. MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
  224. MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
  225. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  226. MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
  227. MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
  228. MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
  229. MESSAGE_HANDLER(WM_ENABLE, OnEnable)
  230. MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  231. MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
  232. MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
  233. MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
  234. MESSAGE_HANDLER(WM_TIMER, OnTimer)
  235. END_MSG_MAP()
  236. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  237. {
  238. Init();
  239. bHandled = FALSE;
  240. return 1;
  241. }
  242. LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  243. {
  244. MSG msg = { m_hWnd, uMsg, wParam, lParam };
  245. if(m_tip.IsWindow())
  246. m_tip.RelayEvent(&msg);
  247. bHandled = FALSE;
  248. return 1;
  249. }
  250. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  251. {
  252. return 1; // no background needed
  253. }
  254. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  255. {
  256. T* pT = static_cast<T*>(this);
  257. if(wParam != NULL)
  258. {
  259. pT->DoPaint((HDC)wParam);
  260. }
  261. else
  262. {
  263. CPaintDC dc(m_hWnd);
  264. pT->DoPaint(dc.m_hDC);
  265. }
  266. return 0;
  267. }
  268. LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  269. {
  270. m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0;
  271. Invalidate();
  272. UpdateWindow();
  273. bHandled = FALSE;
  274. return 1;
  275. }
  276. LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  277. {
  278. LRESULT lRet = 0;
  279. if(IsHoverMode())
  280. SetCapture();
  281. else
  282. lRet = DefWindowProc(uMsg, wParam, lParam);
  283. if(::GetCapture() == m_hWnd)
  284. {
  285. m_fPressed = 1;
  286. Invalidate();
  287. UpdateWindow();
  288. }
  289. if((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0)
  290. {
  291. int nElapse = 250;
  292. int nDelay = 0;
  293. if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0))
  294. nElapse += nDelay * 250; // all milli-seconds
  295. SetTimer(ID_TIMER_FIRST, nElapse);
  296. }
  297. return lRet;
  298. }
  299. LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  300. {
  301. LRESULT lRet = 0;
  302. if(!IsHoverMode())
  303. lRet = DefWindowProc(uMsg, wParam, lParam);
  304. if(::GetCapture() != m_hWnd)
  305. SetCapture();
  306. if(m_fPressed == 0)
  307. {
  308. m_fPressed = 1;
  309. Invalidate();
  310. UpdateWindow();
  311. }
  312. return lRet;
  313. }
  314. LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  315. {
  316. LRESULT lRet = 0;
  317. bool bHover = IsHoverMode();
  318. if(!bHover)
  319. lRet = DefWindowProc(uMsg, wParam, lParam);
  320. if(::GetCapture() == m_hWnd)
  321. {
  322. if(bHover && m_fPressed == 1)
  323. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  324. ::ReleaseCapture();
  325. }
  326. return lRet;
  327. }
  328. LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  329. {
  330. if(m_fPressed == 1)
  331. {
  332. m_fPressed = 0;
  333. Invalidate();
  334. UpdateWindow();
  335. }
  336. bHandled = FALSE;
  337. return 1;
  338. }
  339. LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  340. {
  341. Invalidate();
  342. UpdateWindow();
  343. bHandled = FALSE;
  344. return 1;
  345. }
  346. LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  347. {
  348. if(::GetCapture() == m_hWnd)
  349. {
  350. POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  351. ClientToScreen(&ptCursor);
  352. RECT rect;
  353. GetWindowRect(&rect);
  354. unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0;
  355. if(m_fPressed != uPressed)
  356. {
  357. m_fPressed = uPressed;
  358. Invalidate();
  359. UpdateWindow();
  360. }
  361. }
  362. else if(IsHoverMode() && m_fMouseOver == 0)
  363. {
  364. m_fMouseOver = 1;
  365. Invalidate();
  366. UpdateWindow();
  367. StartTrackMouseLeave();
  368. }
  369. bHandled = FALSE;
  370. return 1;
  371. }
  372. LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  373. {
  374. if(m_fMouseOver == 1)
  375. {
  376. m_fMouseOver = 0;
  377. Invalidate();
  378. UpdateWindow();
  379. }
  380. return 0;
  381. }
  382. LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  383. {
  384. if(wParam == VK_SPACE && IsHoverMode())
  385. return 0; // ignore if in hover mode
  386. if(wParam == VK_SPACE && m_fPressed == 0)
  387. {
  388. m_fPressed = 1;
  389. Invalidate();
  390. UpdateWindow();
  391. }
  392. bHandled = FALSE;
  393. return 1;
  394. }
  395. LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  396. {
  397. if(wParam == VK_SPACE && IsHoverMode())
  398. return 0; // ignore if in hover mode
  399. if(wParam == VK_SPACE && m_fPressed == 1)
  400. {
  401. m_fPressed = 0;
  402. Invalidate();
  403. UpdateWindow();
  404. }
  405. bHandled = FALSE;
  406. return 1;
  407. }
  408. LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  409. {
  410. ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0);
  411. switch(wParam) // timer ID
  412. {
  413. case ID_TIMER_FIRST:
  414. KillTimer(ID_TIMER_FIRST);
  415. if(m_fPressed == 1)
  416. {
  417. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  418. int nElapse = 250;
  419. int nRepeat = 40;
  420. if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))
  421. nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated
  422. SetTimer(ID_TIMER_REPEAT, nElapse);
  423. }
  424. break;
  425. case ID_TIMER_REPEAT:
  426. if(m_fPressed == 1)
  427. ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
  428. else if(::GetCapture() != m_hWnd)
  429. KillTimer(ID_TIMER_REPEAT);
  430. break;
  431. default: // not our timer
  432. break;
  433. }
  434. return 0;
  435. }
  436. // Implementation
  437. void Init()
  438. {
  439. // We need this style to prevent Windows from painting the button
  440. ModifyStyle(0, BS_OWNERDRAW);
  441. // create a tool tip
  442. m_tip.Create(m_hWnd);
  443. ATLASSERT(m_tip.IsWindow());
  444. if(m_tip.IsWindow() && m_lpstrToolTipText != NULL)
  445. {
  446. m_tip.Activate(TRUE);
  447. m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
  448. }
  449. if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0)
  450. SizeToImage();
  451. }
  452. BOOL StartTrackMouseLeave()
  453. {
  454. TRACKMOUSEEVENT tme;
  455. tme.cbSize = sizeof(tme);
  456. tme.dwFlags = TME_LEAVE;
  457. tme.hwndTrack = m_hWnd;
  458. return _TrackMouseEvent(&tme);
  459. }
  460. bool IsHoverMode() const
  461. {
  462. return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0);
  463. }
  464. };
  465. class CBitmapButton : public CBitmapButtonImpl<CBitmapButton>
  466. {
  467. public:
  468. DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
  469. CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
  470. CBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList)
  471. { }
  472. };
  473. /////////////////////////////////////////////////////////////////////////////
  474. // CCheckListCtrlView - list view control with check boxes
  475. template <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle>
  476. class CCheckListViewCtrlImplTraits
  477. {
  478. public:
  479. static DWORD GetWndStyle(DWORD dwStyle)
  480. {
  481. return dwStyle == 0 ? t_dwStyle : dwStyle;
  482. }
  483. static DWORD GetWndExStyle(DWORD dwExStyle)
  484. {
  485. return dwExStyle == 0 ? t_dwExStyle : dwExStyle;
  486. }
  487. static DWORD GetExtendedLVStyle()
  488. {
  489. return t_dwExListViewStyle;
  490. }
  491. };
  492. typedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT> CCheckListViewCtrlTraits;
  493. template <class T, class TBase /*= CListViewCtrl */, class TWinTraits /*= CCheckListViewCtrlTraits */>
  494. class ATL_NO_VTABLE CCheckListViewCtrlImpl : public CWindowImpl<T, TBase, TWinTraits>
  495. {
  496. public:
  497. DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
  498. // Attributes
  499. static DWORD GetExtendedLVStyle()
  500. {
  501. return TWinTraits::GetExtendedLVStyle();
  502. }
  503. // Operations
  504. BOOL SubclassWindow(HWND hWnd)
  505. {
  506. BOOL bRet = CWindowImplBaseT< TBase, TWinTraits>::SubclassWindow(hWnd);
  507. if(bRet)
  508. {
  509. T* pT = static_cast<T*>(this);
  510. pT;
  511. ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
  512. SetExtendedListViewStyle(pT->GetExtendedLVStyle());
  513. }
  514. return bRet;
  515. }
  516. void CheckSelectedItems(int nCurrItem)
  517. {
  518. // first check if this item is selected
  519. LVITEM lvi;
  520. lvi.iItem = nCurrItem;
  521. lvi.iSubItem = 0;
  522. lvi.mask = LVIF_STATE;
  523. lvi.stateMask = LVIS_SELECTED;
  524. GetItem(&lvi);
  525. // if item is not selected, don't do anything
  526. if(!(lvi.state & LVIS_SELECTED))
  527. return;
  528. // new check state will be reverse of the current state,
  529. BOOL bCheck = !GetCheckState(nCurrItem);
  530. int nItem = -1;
  531. int nOldItem = -1;
  532. while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1)
  533. {
  534. if(nItem != nCurrItem)
  535. SetCheckState(nItem, bCheck);
  536. nOldItem = nItem;
  537. }
  538. }
  539. // Implementation
  540. typedef CCheckListViewCtrlImpl< T, TBase, TWinTraits > thisClass;
  541. BEGIN_MSG_MAP(thisClass)
  542. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  543. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  544. MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
  545. MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
  546. END_MSG_MAP()
  547. LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  548. {
  549. // first let list view control initialize everything
  550. LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
  551. T* pT = static_cast<T*>(this);
  552. pT;
  553. ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
  554. SetExtendedListViewStyle(pT->GetExtendedLVStyle());
  555. return lRet;
  556. }
  557. LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  558. {
  559. POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  560. LVHITTESTINFO lvh;
  561. lvh.pt = ptMsg;
  562. if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0)
  563. CheckSelectedItems(lvh.iItem);
  564. bHandled = FALSE;
  565. return 1;
  566. }
  567. LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  568. {
  569. if(wParam == VK_SPACE)
  570. {
  571. int nCurrItem = GetNextItem(-1, LVNI_FOCUSED);
  572. if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0)
  573. CheckSelectedItems(nCurrItem);
  574. }
  575. bHandled = FALSE;
  576. return 1;
  577. }
  578. };
  579. class CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl>
  580. {
  581. public:
  582. DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
  583. };
  584. /////////////////////////////////////////////////////////////////////////////
  585. // CHyperLink - hyper link control implementation
  586. #if (WINVER < 0x0500)
  587. __declspec(selectany) struct
  588. {
  589. enum { cxWidth = 32, cyHeight = 32 };
  590. int xHotSpot;
  591. int yHotSpot;
  592. unsigned char arrANDPlane[cxWidth * cyHeight / 8];
  593. unsigned char arrXORPlane[cxWidth * cyHeight / 8];
  594. } _AtlHyperLink_CursorData =
  595. {
  596. 5, 0,
  597. {
  598. 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
  599. 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF,
  600. 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF,
  601. 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF,
  602. 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF,
  603. 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  604. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  605. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
  606. },
  607. {
  608. 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
  609. 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00,
  610. 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00,
  611. 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00,
  612. 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00,
  613. 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  614. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  615. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  616. }
  617. };
  618. #endif //(WINVER < 0x0500)
  619. template <class T, class TBase /*= CWindow */, class TWinTraits /*= CControlWinTraits */ >
  620. class ATL_NO_VTABLE CHyperLinkImpl : public CWindowImpl< T, TBase, TWinTraits >
  621. {
  622. public:
  623. LPTSTR m_lpstrLabel;
  624. LPTSTR m_lpstrHyperLink;
  625. HCURSOR m_hCursor;
  626. HFONT m_hFont;
  627. RECT m_rcLink;
  628. bool m_bPaintLabel;
  629. CToolTipCtrl m_tip;
  630. bool m_bVisited;
  631. COLORREF m_clrLink;
  632. COLORREF m_clrVisited;
  633. // Constructor/Destructor
  634. CHyperLinkImpl() : m_lpstrLabel(NULL), m_lpstrHyperLink(NULL),
  635. m_hCursor(NULL), m_hFont(NULL), m_bPaintLabel(true), m_bVisited(false),
  636. m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128))
  637. {
  638. ::SetRectEmpty(&m_rcLink);
  639. }
  640. ~CHyperLinkImpl()
  641. {
  642. free(m_lpstrLabel);
  643. free(m_lpstrHyperLink);
  644. if(m_hFont != NULL)
  645. ::DeleteObject(m_hFont);
  646. #if (WINVER < 0x0500)
  647. // It was created, not loaded, so we have to destroy it
  648. if(m_hCursor != NULL)
  649. ::DestroyCursor(m_hCursor);
  650. #endif //(WINVER < 0x0500)
  651. }
  652. // Attributes
  653. bool GetLabel(LPTSTR lpstrBuffer, int nLength) const
  654. {
  655. if(m_lpstrLabel == NULL)
  656. return false;
  657. ATLASSERT(lpstrBuffer != NULL);
  658. if(nLength > lstrlen(m_lpstrLabel) + 1)
  659. {
  660. lstrcpy(lpstrBuffer, m_lpstrLabel);
  661. return true;
  662. }
  663. return false;
  664. }
  665. bool SetLabel(LPCTSTR lpstrLabel)
  666. {
  667. free(m_lpstrLabel);
  668. m_lpstrLabel = NULL;
  669. ATLTRY(m_lpstrLabel = (LPTSTR)malloc((lstrlen(lpstrLabel) + 1) * sizeof(TCHAR)));
  670. if(m_lpstrLabel == NULL)
  671. return false;
  672. lstrcpy(m_lpstrLabel, lpstrLabel);
  673. CalcLabelRect();
  674. return true;
  675. }
  676. bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const
  677. {
  678. if(m_lpstrHyperLink == NULL)
  679. return false;
  680. ATLASSERT(lpstrBuffer != NULL);
  681. if(nLength > lstrlen(m_lpstrHyperLink) + 1)
  682. {
  683. lstrcpy(lpstrBuffer, m_lpstrHyperLink);
  684. return true;
  685. }
  686. return false;
  687. }
  688. bool SetHyperLink(LPCTSTR lpstrLink)
  689. {
  690. free(m_lpstrHyperLink);
  691. m_lpstrHyperLink = NULL;
  692. ATLTRY(m_lpstrHyperLink = (LPTSTR)malloc((lstrlen(lpstrLink) + 1) * sizeof(TCHAR)));
  693. if(m_lpstrHyperLink == NULL)
  694. return false;
  695. lstrcpy(m_lpstrHyperLink, lpstrLink);
  696. if(m_lpstrLabel == NULL)
  697. CalcLabelRect();
  698. return true;
  699. }
  700. // Operations
  701. BOOL SubclassWindow(HWND hWnd)
  702. {
  703. ATLASSERT(m_hWnd == NULL);
  704. ATLASSERT(::IsWindow(hWnd));
  705. BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
  706. if(bRet)
  707. Init();
  708. return bRet;
  709. }
  710. bool Navigate()
  711. {
  712. ATLASSERT(::IsWindow(m_hWnd));
  713. ATLASSERT(m_lpstrHyperLink != NULL);
  714. DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);
  715. if(dwRet > 32)
  716. {
  717. m_bVisited = true;
  718. Invalidate();
  719. }
  720. return (dwRet > 32);
  721. }
  722. // Message map and handlers
  723. BEGIN_MSG_MAP(CHyperLinkImpl)
  724. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  725. MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
  726. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  727. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  728. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  729. MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
  730. MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
  731. MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  732. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  733. MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
  734. MESSAGE_HANDLER(WM_CHAR, OnChar)
  735. MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
  736. MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
  737. END_MSG_MAP()
  738. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  739. {
  740. Init();
  741. return 0;
  742. }
  743. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  744. {
  745. if(m_bPaintLabel)
  746. {
  747. HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, wParam, (LPARAM)m_hWnd);
  748. if(hBrush != NULL)
  749. {
  750. CDCHandle dc = (HDC)wParam;
  751. RECT rect;
  752. GetClientRect(&rect);
  753. dc.FillRect(&rect, hBrush);
  754. }
  755. }
  756. else
  757. {
  758. bHandled = FALSE;
  759. }
  760. return 1;
  761. }
  762. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  763. {
  764. if(!m_bPaintLabel)
  765. {
  766. bHandled = FALSE;
  767. return 1;
  768. }
  769. T* pT = static_cast<T*>(this);
  770. if(wParam != NULL)
  771. {
  772. pT->DoPaint((HDC)wParam);
  773. }
  774. else
  775. {
  776. CPaintDC dc(m_hWnd);
  777. pT->DoPaint(dc.m_hDC);
  778. }
  779. return 0;
  780. }
  781. LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  782. {
  783. if(m_bPaintLabel)
  784. Invalidate();
  785. else
  786. bHandled = FALSE;
  787. return 0;
  788. }
  789. LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  790. {
  791. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  792. if(m_lpstrHyperLink != NULL && ::PtInRect(&m_rcLink, pt))
  793. ::SetCursor(m_hCursor);
  794. else
  795. bHandled = FALSE;
  796. return 0;
  797. }
  798. LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  799. {
  800. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  801. if(::PtInRect(&m_rcLink, pt))
  802. {
  803. SetFocus();
  804. SetCapture();
  805. }
  806. return 0;
  807. }
  808. LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  809. {
  810. if(GetCapture() == m_hWnd)
  811. {
  812. ReleaseCapture();
  813. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  814. if(::PtInRect(&m_rcLink, pt))
  815. Navigate();
  816. }
  817. return 0;
  818. }
  819. LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  820. {
  821. POINT pt;
  822. GetCursorPos(&pt);
  823. ScreenToClient(&pt);
  824. if(m_lpstrHyperLink != NULL && ::PtInRect(&m_rcLink, pt))
  825. {
  826. return TRUE;
  827. }
  828. bHandled = FALSE;
  829. return FALSE;
  830. }
  831. LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  832. {
  833. if(wParam == VK_RETURN || wParam == VK_SPACE)
  834. Navigate();
  835. return 0;
  836. }
  837. LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  838. {
  839. return DLGC_WANTCHARS;
  840. }
  841. LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  842. {
  843. MSG msg = { m_hWnd, uMsg, wParam, lParam };
  844. if(m_tip.IsWindow())
  845. m_tip.RelayEvent(&msg);
  846. bHandled = FALSE;
  847. return 1;
  848. }
  849. // Implementation
  850. void Init()
  851. {
  852. ATLASSERT(::IsWindow(m_hWnd));
  853. // Check if we should paint a label
  854. TCHAR lpszBuffer[8];
  855. if(::GetClassName(m_hWnd, lpszBuffer, 8))
  856. {
  857. if(lstrcmpi(lpszBuffer, _T("static")) == 0)
  858. {
  859. ModifyStyle(0, SS_NOTIFY); // we need this
  860. DWORD dwStyle = GetStyle() & 0x000000FF;
  861. if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT ||
  862. dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME ||
  863. dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW ||
  864. dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE)
  865. m_bPaintLabel = false;
  866. }
  867. }
  868. // create or load a cursor
  869. #if (WINVER >= 0x0500)
  870. m_hCursor = ::LoadCursor(NULL, IDC_HAND);
  871. #else
  872. m_hCursor = ::CreateCursor(_Module.GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane);
  873. #endif //!(WINVER >= 0x0500)
  874. ATLASSERT(m_hCursor != NULL);
  875. // set font
  876. if(m_bPaintLabel)
  877. {
  878. CWindow wnd = GetParent();
  879. CFontHandle font = wnd.GetFont();
  880. if(font.m_hFont != NULL)
  881. {
  882. LOGFONT lf;
  883. font.GetLogFont(&lf);
  884. lf.lfUnderline = TRUE;
  885. m_hFont = ::CreateFontIndirect(&lf);
  886. }
  887. }
  888. // set label (defaults to window text)
  889. if(m_lpstrLabel == NULL)
  890. {
  891. int nLen = GetWindowTextLength();
  892. if(nLen > 0)
  893. {
  894. LPTSTR lpszText = (LPTSTR)_alloca((nLen+1)*sizeof(TCHAR));
  895. if(GetWindowText(lpszText, nLen+1))
  896. SetLabel(lpszText);
  897. }
  898. }
  899. // set hyperlink (defaults to label)
  900. if(m_lpstrHyperLink == NULL && m_lpstrLabel != NULL)
  901. SetHyperLink(m_lpstrLabel);
  902. CalcLabelRect();
  903. // create a tool tip
  904. m_tip.Create(m_hWnd);
  905. ATLASSERT(m_tip.IsWindow());
  906. m_tip.Activate(TRUE);
  907. m_tip.AddTool(m_hWnd, m_lpstrHyperLink);
  908. // set link colors
  909. if(m_bPaintLabel)
  910. {
  911. CRegKey rk;
  912. LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings"));
  913. if(lRet == 0)
  914. {
  915. TCHAR szBuff[12];
  916. DWORD dwCount = 12 * sizeof(TCHAR);
  917. lRet = rk.QueryValue(szBuff, _T("Anchor Color"), &dwCount);
  918. if(lRet == 0)
  919. {
  920. COLORREF clr = _ParseColorString(szBuff);
  921. ATLASSERT(clr != CLR_INVALID);
  922. if(clr != CLR_INVALID)
  923. m_clrLink = clr;
  924. }
  925. dwCount = 12 * sizeof(TCHAR);
  926. lRet = rk.QueryValue(szBuff, _T("Anchor Color Visited"), &dwCount);
  927. if(lRet == 0)
  928. {
  929. COLORREF clr = _ParseColorString(szBuff);
  930. ATLASSERT(clr != CLR_INVALID);
  931. if(clr != CLR_INVALID)
  932. m_clrVisited = clr;
  933. }
  934. }
  935. }
  936. }
  937. static COLORREF _ParseColorString(LPTSTR lpstr)
  938. {
  939. int c[3] = { -1, -1, -1 };
  940. LPTSTR p;
  941. for(int i = 0; i < 2; i++)
  942. {
  943. for(p = lpstr; *p != _T('\0'); p = ::CharNext(p))
  944. {
  945. if(*p == _T(','))
  946. {
  947. *p = _T('\0');
  948. c[i] = _ttoi(lpstr);
  949. lpstr = &p[1];
  950. break;
  951. }
  952. }
  953. if(c[i] == -1)
  954. return CLR_INVALID;
  955. }
  956. if(*lpstr == _T('\0'))
  957. return CLR_INVALID;
  958. c[2] = _ttoi(lpstr);
  959. return RGB(c[0], c[1], c[2]);
  960. }
  961. bool CalcLabelRect()
  962. {
  963. if(!::IsWindow(m_hWnd))
  964. return false;
  965. if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
  966. return false;
  967. CClientDC dc(m_hWnd);
  968. RECT rect;
  969. GetClientRect(&rect);
  970. m_rcLink = rect;
  971. if(m_bPaintLabel)
  972. {
  973. HFONT hOldFont = NULL;
  974. if(m_hFont != NULL)
  975. hOldFont = dc.SelectFont(m_hFont);
  976. LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
  977. DWORD dwStyle = GetStyle();
  978. int nDrawStyle = DT_LEFT;
  979. if (dwStyle & SS_CENTER)
  980. nDrawStyle = DT_CENTER;
  981. else if (dwStyle & SS_RIGHT)
  982. nDrawStyle = DT_RIGHT;
  983. dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK | DT_CALCRECT);
  984. if(m_hFont != NULL)
  985. dc.SelectFont(hOldFont);
  986. }
  987. return true;
  988. }
  989. void DoPaint(CDCHandle dc)
  990. {
  991. dc.SetBkMode(TRANSPARENT);
  992. dc.SetTextColor(m_bVisited ? m_clrVisited : m_clrLink);
  993. if(m_hFont != NULL)
  994. dc.SelectFont(m_hFont);
  995. LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
  996. DWORD dwStyle = GetStyle();
  997. int nDrawStyle = DT_LEFT;
  998. if (dwStyle & SS_CENTER)
  999. nDrawStyle = DT_CENTER;
  1000. else if (dwStyle & SS_RIGHT)
  1001. nDrawStyle = DT_RIGHT;
  1002. dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK);
  1003. if(GetFocus() == m_hWnd)
  1004. dc.DrawFocusRect(&m_rcLink);
  1005. }
  1006. };
  1007. class CHyperLink : public CHyperLinkImpl<CHyperLink>
  1008. {
  1009. public:
  1010. DECLARE_WND_CLASS(_T("WTL_HyperLink"))
  1011. };
  1012. /////////////////////////////////////////////////////////////////////////////
  1013. // CWaitCursor - displays a wait cursor
  1014. class CWaitCursor
  1015. {
  1016. public:
  1017. // Data
  1018. HCURSOR m_hWaitCursor;
  1019. HCURSOR m_hOldCursor;
  1020. bool m_bInUse;
  1021. // Constructor/destructor
  1022. CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false)
  1023. {
  1024. HINSTANCE hInstance = bSys ? NULL : _Module.GetResourceInstance();
  1025. m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor);
  1026. ATLASSERT(m_hWaitCursor != NULL);
  1027. if(bSet)
  1028. Set();
  1029. }
  1030. ~CWaitCursor()
  1031. {
  1032. Restore();
  1033. }
  1034. // Methods
  1035. bool Set()
  1036. {
  1037. if(m_bInUse)
  1038. return false;
  1039. m_hOldCursor = ::SetCursor(m_hWaitCursor);
  1040. m_bInUse = true;
  1041. return true;
  1042. }
  1043. bool Restore()
  1044. {
  1045. if(!m_bInUse)
  1046. return false;
  1047. ::SetCursor(m_hOldCursor);
  1048. m_bInUse = false;
  1049. return true;
  1050. }
  1051. };
  1052. /////////////////////////////////////////////////////////////////////////////
  1053. // CMultiPaneStatusBarCtrl - Status Bar with multiple panes
  1054. template <class T, class TBase /*= CStatusBarCtrl */ >
  1055. class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public CWindowImpl< T, TBase >
  1056. {
  1057. public:
  1058. DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
  1059. // Data
  1060. enum { m_cxPaneMargin = 3 };
  1061. int m_nPanes;
  1062. int* m_pPane;
  1063. // Constructor/destructor
  1064. CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL)
  1065. { }
  1066. ~CMultiPaneStatusBarCtrlImpl()
  1067. {
  1068. delete [] m_pPane;
  1069. }
  1070. // Methods
  1071. HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
  1072. {
  1073. return CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID);
  1074. }
  1075. HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
  1076. {
  1077. TCHAR szText[128]; // max text lentgth is 127 for status bars
  1078. szText[0] = 0;
  1079. ::LoadString(_Module.GetResourceInstance(), nTextID, szText, 127);
  1080. return Create(hWndParent, szText, dwStyle, nID);
  1081. }
  1082. BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true)
  1083. {
  1084. ATLASSERT(::IsWindow(m_hWnd));
  1085. ATLASSERT(nPanes > 0);
  1086. m_nPanes = nPanes;
  1087. delete [] m_pPane;
  1088. m_pPane = NULL;
  1089. ATLTRY(m_pPane = new int[nPanes]);
  1090. ATLASSERT(m_pPane != NULL);
  1091. if(m_pPane == NULL)
  1092. return FALSE;
  1093. memcpy(m_pPane, pPanes, nPanes * sizeof(int));
  1094. int* pPanesPos = NULL;
  1095. ATLTRY(pPanesPos = (int*)_alloca(nPanes * sizeof(int)));
  1096. ATLASSERT(pPanesPos != NULL);
  1097. // get status bar DC and set font
  1098. CClientDC dc(m_hWnd);
  1099. HFONT hOldFont = dc.SelectFont(GetFont());
  1100. // get status bar borders
  1101. int arrBorders[3];
  1102. GetBorders(arrBorders);
  1103. TCHAR szBuff[256];
  1104. SIZE size;
  1105. int cxLeft = arrBorders[0];
  1106. // calculate right edge of each part
  1107. for(int i = 0; i < nPanes; i++)
  1108. {
  1109. if(pPanes[i] == ID_DEFAULT_PANE)
  1110. {
  1111. // will be resized later
  1112. pPanesPos[i] = 100 + cxLeft + arrBorders[2];
  1113. }
  1114. else
  1115. {
  1116. ::LoadString(_Module.GetResourceInstance(), pPanes[i], szBuff, sizeof(szBuff) / sizeof(TCHAR));
  1117. dc.GetTextExtent(szBuff, lstrlen(szBuff), &size);
  1118. T* pT = static_cast<T*>(this);
  1119. pT;
  1120. pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin;
  1121. }
  1122. cxLeft = pPanesPos[i];
  1123. }
  1124. BOOL bRet = SetParts(nPanes, pPanesPos);
  1125. if(bRet && bSetText)
  1126. {
  1127. for(int i = 0; i < nPanes; i++)
  1128. {
  1129. if(pPanes[i] != ID_DEFAULT_PANE)
  1130. {
  1131. ::LoadString(_Module.GetResourceInstance(), pPanes[i], szBuff, sizeof(szBuff) / sizeof(TCHAR));
  1132. SetPaneText(m_pPane[i], szBuff);
  1133. }
  1134. }
  1135. }
  1136. dc.SelectFont(hOldFont);
  1137. return bRet;
  1138. }
  1139. bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const
  1140. {
  1141. ATLASSERT(::IsWindow(m_hWnd));
  1142. int nIndex = GetPaneIndexFromID(nPaneID);
  1143. if(nIndex == -1)
  1144. return false;
  1145. int nLength = GetTextLength(nIndex, pnType);
  1146. if(pcchLength != NULL)
  1147. *pcchLength = nLength;
  1148. return true;
  1149. }
  1150. BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const
  1151. {
  1152. ATLASSERT(::IsWindow(m_hWnd));
  1153. int nIndex = GetPaneIndexFromID(nPaneID);
  1154. if(nIndex == -1)
  1155. return FALSE;
  1156. int nLength = GetText(nIndex, lpstrText, pnType);
  1157. if(pcchLength != NULL)
  1158. *pcchLength = nLength;
  1159. return TRUE;
  1160. }
  1161. BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0)
  1162. {
  1163. ATLASSERT(::IsWindow(m_hWnd));
  1164. int nIndex = GetPaneIndexFromID(nPaneID);
  1165. if(nIndex == -1)
  1166. return FALSE;
  1167. return SetText(nIndex, lpstrText, nType);
  1168. }
  1169. BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const
  1170. {
  1171. ATLASSERT(::IsWindow(m_hWnd));
  1172. int nIndex = GetPaneIndexFromID(nPaneID);
  1173. if(nIndex == -1)
  1174. return FALSE;
  1175. return GetRect(nIndex, lpRect);
  1176. }
  1177. BOOL SetPaneWidth(int nPaneID, int cxWidth)
  1178. {
  1179. ATLASSERT(::IsWindow(m_hWnd));
  1180. ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one
  1181. int nIndex = GetPaneIndexFromID(nPaneID);
  1182. if(nIndex == -1)
  1183. return FALSE;
  1184. // get pane positions
  1185. int* pPanesPos = NULL;
  1186. ATLTRY(pPanesPos = (int*)_alloca(m_nPanes * sizeof(int)));
  1187. GetParts(m_nPanes, pPanesPos);
  1188. // calculate offset
  1189. int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]);
  1190. int cxOff = cxWidth - cxPaneWidth;
  1191. // find variable width pane
  1192. int nDef = m_nPanes;
  1193. for(int i = 0; i < m_nPanes; i++)
  1194. {
  1195. if(m_pPane[i] == ID_DEFAULT_PANE)
  1196. {
  1197. nDef = i;
  1198. break;
  1199. }
  1200. }
  1201. // resize
  1202. if(nIndex < nDef) // before default pane
  1203. {
  1204. for(int i = nIndex; i < nDef; i++)
  1205. pPanesPos[i] += cxOff;
  1206. }
  1207. else // after default one
  1208. {
  1209. for(int i = nDef; i < nIndex; i++)
  1210. pPanesPos[i] -= cxOff;
  1211. }
  1212. // set pane postions
  1213. return SetParts(m_nPanes, pPanesPos);
  1214. }
  1215. #if (_WIN32_IE >= 0x0400)
  1216. BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const
  1217. {
  1218. ATLASSERT(::IsWindow(m_hWnd));
  1219. int nIndex = GetPaneIndexFromID(nPaneID);
  1220. if(nIndex == -1)
  1221. return FALSE;
  1222. GetTipText(nIndex, lpstrText, nSize);
  1223. return TRUE;
  1224. }
  1225. BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText)
  1226. {
  1227. ATLASSERT(::IsWindow(m_hWnd));
  1228. int nIndex = GetPaneIndexFromID(nPaneID);
  1229. if(nIndex == -1)
  1230. return FALSE;
  1231. SetTipText(nIndex, lpstrText);
  1232. return TRUE;
  1233. }
  1234. BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const
  1235. {
  1236. ATLASSERT(::IsWindow(m_hWnd));
  1237. int nIndex = GetPaneIndexFromID(nPaneID);
  1238. if(nIndex == -1)
  1239. return FALSE;
  1240. hIcon = GetIcon(nIndex);
  1241. return TRUE;
  1242. }
  1243. BOOL SetPaneIcon(int nPaneID, HICON hIcon)
  1244. {
  1245. ATLASSERT(::IsWindow(m_hWnd));
  1246. int nIndex = GetPaneIndexFromID(nPaneID);
  1247. if(nIndex == -1)
  1248. return FALSE;
  1249. return SetIcon(nIndex, hIcon);
  1250. }
  1251. #endif //(_WIN32_IE >= 0x0400)
  1252. // Message map and handlers
  1253. BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >)
  1254. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1255. END_MSG_MAP()
  1256. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1257. {
  1258. LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
  1259. if(wParam != SIZE_MINIMIZED && m_nPanes > 0)
  1260. {
  1261. T* pT = static_cast<T*>(this);
  1262. pT->UpdatePanesLayout();
  1263. }
  1264. return lRet;
  1265. }
  1266. // Implementation
  1267. BOOL UpdatePanesLayout()
  1268. {
  1269. // get pane positions
  1270. int* pPanesPos = NULL;
  1271. ATLTRY(pPanesPos = (int*)_alloca(m_nPanes * sizeof(int)));
  1272. ATLASSERT(pPanesPos != NULL);
  1273. if(pPanesPos == NULL)
  1274. return FALSE;
  1275. int nRet = GetParts(m_nPanes, pPanesPos);
  1276. ATLASSERT(nRet == m_nPanes);
  1277. if(nRet != m_nPanes)
  1278. return FALSE;
  1279. // calculate offset
  1280. RECT rcClient;
  1281. GetClientRect(&rcClient);
  1282. int cxOff = rcClient.right - (pPanesPos[m_nPanes - 1] + ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE));
  1283. // find variable width pane
  1284. int i;
  1285. for(i = 0; i < m_nPanes; i++)
  1286. {
  1287. if(m_pPane[i] == ID_DEFAULT_PANE)
  1288. break;
  1289. }
  1290. // resize all panes from the variable one to the right
  1291. if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1]))
  1292. {
  1293. for(; i < m_nPanes; i++)
  1294. pPanesPos[i] += cxOff;
  1295. }
  1296. // set pane postions
  1297. return SetParts(m_nPanes, pPanesPos);
  1298. }
  1299. int GetPaneIndexFromID(int nPaneID) const
  1300. {
  1301. for(int i = 0; i < m_nPanes; i++)
  1302. {
  1303. if(m_pPane[i] == nPaneID)
  1304. return i;
  1305. }
  1306. return -1; // not found
  1307. }
  1308. };
  1309. class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl<CMultiPaneStatusBarCtrl>
  1310. {
  1311. public:
  1312. DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
  1313. };
  1314. /////////////////////////////////////////////////////////////////////////////
  1315. // CPaneContainer - provides header with title and close button for panes
  1316. // pane container extended styles
  1317. #define PANECNT_NOCLOSEBUTTON 0x00000001
  1318. #define PANECNT_VERTICAL 0x00000002
  1319. template <class T, class TBase /*= CWindow */, class TWinTraits /*= CControlWinTraits */ >
  1320. class ATL_NO_VTABLE CPaneContainerImpl : public CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T >
  1321. {
  1322. public:
  1323. DECLARE_WND_CLASS_EX(NULL, 0, -1)
  1324. // Constants
  1325. enum
  1326. {
  1327. m_cxyBorder = 2,
  1328. m_cxyTextOffset = 4,
  1329. m_cxyBtnOffset = 1,
  1330. m_cchTitle = 80,
  1331. m_cxImageTB = 13,
  1332. m_cyImageTB = 11,
  1333. m_cxyBtnAddTB = 7,
  1334. m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset,
  1335. m_xBtnImageLeft = 6,
  1336. m_yBtnImageTop = 5,
  1337. m_xBtnImageRight = 12,
  1338. m_yBtnImageBottom = 11,
  1339. m_nCloseBtnID = ID_PANE_CLOSE
  1340. };
  1341. // Data members
  1342. CToolBarCtrl m_tb;
  1343. CWindow m_wndClient;
  1344. int m_cxyHeader;
  1345. TCHAR m_szTitle[m_cchTitle];
  1346. DWORD m_dwExtendedStyle; // Pane container specific extended styles
  1347. // Constructor
  1348. CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0)
  1349. {
  1350. m_szTitle[0] = 0;
  1351. }
  1352. // Attributes
  1353. DWORD GetPaneContainerExtendedStyle() const
  1354. {
  1355. return m_dwExtendedStyle;
  1356. }
  1357. DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
  1358. {
  1359. DWORD dwPrevStyle = m_dwExtendedStyle;
  1360. if(dwMask == 0)
  1361. m_dwExtendedStyle = dwExtendedStyle;
  1362. else
  1363. m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
  1364. if(m_hWnd != NULL)
  1365. {
  1366. T* pT = static_cast<T*>(this);
  1367. bool bUpdate = false;
  1368. if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button
  1369. {
  1370. pT->CreateCloseButton();
  1371. bUpdate = true;
  1372. }
  1373. else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button
  1374. {
  1375. pT->DestroyCloseButton();
  1376. bUpdate = true;
  1377. }
  1378. if((dwPrevStyle & PANECNT_VERTICAL) != (dwExtendedStyle & PANECNT_VERTICAL)) // change orientation
  1379. {
  1380. CalcSize();
  1381. bUpdate = true;
  1382. }
  1383. if(bUpdate)
  1384. pT->UpdateLayout();
  1385. }
  1386. return dwPrevStyle;
  1387. }
  1388. HWND GetClient() const
  1389. {
  1390. return m_wndClient;
  1391. }
  1392. HWND SetClient(HWND hWndClient)
  1393. {
  1394. HWND hWndOldClient = m_wndClient;
  1395. m_wndClient = hWndClient;
  1396. if(m_hWnd != NULL)
  1397. {
  1398. T* pT = static_cast<T*>(this);
  1399. pT->UpdateLayout();
  1400. }
  1401. return hWndOldClient;
  1402. }
  1403. BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const
  1404. {
  1405. ATLASSERT(lpstrTitle != NULL);
  1406. return (lstrcpyn(lpstrTitle, m_szTitle, cchLength) != NULL);
  1407. }
  1408. BOOL SetTitle(LPCTSTR lpstrTitle)
  1409. {
  1410. ATLASSERT(lpstrTitle != NULL);
  1411. BOOL bRet = (lstrcpyn(m_szTitle, lpstrTitle, m_cchTitle) != NULL);
  1412. if(bRet && m_hWnd != NULL)
  1413. {
  1414. T* pT = static_cast<T*>(this);
  1415. pT->UpdateLayout();
  1416. }
  1417. return bRet;
  1418. }
  1419. int GetTitleLength() const
  1420. {
  1421. return lstrlen(m_szTitle);
  1422. }
  1423. // Methods
  1424. HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  1425. DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
  1426. {
  1427. if(lpstrTitle != NULL)
  1428. lstrcpyn(m_szTitle, lpstrTitle, m_cchTitle);
  1429. return CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
  1430. }
  1431. HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  1432. DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
  1433. {
  1434. if(uTitleID != 0U)
  1435. ::LoadString(_Module.GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle);
  1436. return CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
  1437. }
  1438. BOOL EnableCloseButton(BOOL bEnable)
  1439. {
  1440. ATLASSERT(::IsWindow(m_hWnd));
  1441. T* pT = static_cast<T*>(this);
  1442. pT; // avoid level 4 warning
  1443. return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE;
  1444. }
  1445. void UpdateLayout()
  1446. {
  1447. RECT rcClient;
  1448. GetClientRect(&rcClient);
  1449. T* pT = static_cast<T*>(this);
  1450. pT->UpdateLayout(rcClient.right, rcClient.bottom);
  1451. }
  1452. // Message map and handlers
  1453. BEGIN_MSG_MAP(CPaneContainerImpl)
  1454. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  1455. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1456. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  1457. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  1458. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  1459. MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
  1460. MESSAGE_HANDLER(WM_COMMAND, OnCommand)
  1461. FORWARD_NOTIFICATIONS()
  1462. END_MSG_MAP()
  1463. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1464. {
  1465. T* pT = static_cast<T*>(this);
  1466. pT->CalcSize();
  1467. if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)
  1468. pT->CreateCloseButton();
  1469. return 0;
  1470. }
  1471. LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  1472. {
  1473. T* pT = static_cast<T*>(this);
  1474. pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  1475. return 0;
  1476. }
  1477. LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1478. {
  1479. if(m_wndClient.m_hWnd != NULL)
  1480. m_wndClient.SetFocus();
  1481. return 0;
  1482. }
  1483. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1484. {
  1485. return 1; // no background needed
  1486. }
  1487. LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1488. {
  1489. CPaintDC dc(m_hWnd);
  1490. T* pT = static_cast<T*>(this);
  1491. pT->DrawPaneTitle(dc.m_hDC);
  1492. if(m_wndClient.m_hWnd == NULL) // no client window
  1493. pT->DrawPane(dc.m_hDC);
  1494. return 0;
  1495. }
  1496. LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1497. {
  1498. if(m_tb.m_hWnd == NULL)
  1499. {
  1500. bHandled = FALSE;
  1501. return 1;
  1502. }
  1503. T* pT = static_cast<T*>(this);
  1504. LPNMHDR lpnmh = (LPNMHDR)lParam;
  1505. LRESULT lRet = 0;
  1506. // pass toolbar custom draw notifications to the base class
  1507. if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd)
  1508. lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled);
  1509. // tooltip notifications come with the tooltip window handle and button ID,
  1510. // pass them to the parent if we don't handle them
  1511. else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID)
  1512. bHandled = pT->GetToolTipText(lpnmh);
  1513. // only let notifications not from the toolbar go to the parent
  1514. else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID)
  1515. bHandled = FALSE;
  1516. return lRet;
  1517. }
  1518. LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1519. {
  1520. // if command comes from the close button, substitute HWND of the pane container instead
  1521. if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd)
  1522. return ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd);
  1523. bHandled = FALSE;
  1524. return 1;
  1525. }
  1526. // Custom draw overrides
  1527. DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
  1528. {
  1529. return CDRF_NOTIFYITEMDRAW; // we need per-item notifications
  1530. }
  1531. DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
  1532. {
  1533. CDCHandle dc = lpNMCustomDraw->hdc;
  1534. #if (_WIN32_IE >= 0x0400)
  1535. RECT& rc = lpNMCustomDraw->rc;
  1536. #else //!(_WIN32_IE >= 0x0400)
  1537. RECT rc;
  1538. m_tb.GetItemRect(0, &rc);
  1539. #endif //!(_WIN32_IE >= 0x0400)
  1540. dc.FillRect(&rc, (HBRUSH)LongToPtr(COLOR_3DFACE + 1));
  1541. return CDRF_NOTIFYPOSTPAINT;
  1542. }
  1543. DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
  1544. {
  1545. CDCHandle dc = lpNMCustomDraw->hdc;
  1546. #if (_WIN32_IE >= 0x0400)
  1547. RECT& rc = lpNMCustomDraw->rc;
  1548. #else //!(_WIN32_IE >= 0x0400)
  1549. RECT rc;
  1550. m_tb.GetItemRect(0, &rc);
  1551. #endif //!(_WIN32_IE >= 0x0400)
  1552. RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 };
  1553. ::OffsetRect(&rcImage, rc.left, rc.top);
  1554. T* pT = static_cast<T*>(this);
  1555. if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0)
  1556. {
  1557. RECT rcShadow = rcImage;
  1558. ::OffsetRect(&rcShadow, 1, 1);
  1559. CPen pen1;
  1560. pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT));
  1561. pT->DrawButtonImage(dc, rcShadow, pen1);
  1562. CPen pen2;
  1563. pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW));
  1564. pT->DrawButtonImage(dc, rcImage, pen2);
  1565. }
  1566. else
  1567. {
  1568. if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0)
  1569. ::OffsetRect(&rcImage, 1, 1);
  1570. CPen pen;
  1571. pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT));
  1572. pT->DrawButtonImage(dc, rcImage, pen);
  1573. }
  1574. return CDRF_DODEFAULT; // continue with the default item painting
  1575. }
  1576. // Implementation - overrideable methods
  1577. void UpdateLayout(int cxWidth, int cyHeight)
  1578. {
  1579. ATLASSERT(::IsWindow(m_hWnd));
  1580. RECT rect;
  1581. if(IsVertical())
  1582. {
  1583. ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight);
  1584. if(m_tb.m_hWnd != NULL)
  1585. m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1586. if(m_wndClient.m_hWnd != NULL)
  1587. m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER);
  1588. else
  1589. rect.right = cxWidth;
  1590. }
  1591. else
  1592. {
  1593. ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader);
  1594. if(m_tb.m_hWnd != NULL)
  1595. m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1596. if(m_wndClient.m_hWnd != NULL)
  1597. m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER);
  1598. else
  1599. rect.bottom = cyHeight;
  1600. }
  1601. InvalidateRect(&rect);
  1602. }
  1603. void CreateCloseButton()
  1604. {
  1605. ATLASSERT(m_tb.m_hWnd == NULL);
  1606. // create toolbar for the "x" button
  1607. m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0);
  1608. ATLASSERT(m_tb.IsWindow());
  1609. if(m_tb.m_hWnd != NULL)
  1610. {
  1611. T* pT = static_cast<T*>(this);
  1612. pT; // avoid level 4 warning
  1613. m_tb.SetButtonStructSize();
  1614. TBBUTTON tbbtn;
  1615. memset(&tbbtn, 0, sizeof(tbbtn));
  1616. tbbtn.idCommand = pT->m_nCloseBtnID;
  1617. tbbtn.fsState = TBSTATE_ENABLED;
  1618. tbbtn.fsStyle = TBSTYLE_BUTTON;
  1619. m_tb.AddButtons(1, &tbbtn);
  1620. m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB);
  1621. m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB);
  1622. if(IsVertical())
  1623. m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOACTIVATE);
  1624. else
  1625. m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  1626. }
  1627. }
  1628. void DestroyCloseButton()
  1629. {
  1630. if(m_tb.m_hWnd != NULL)
  1631. m_tb.DestroyWindow();
  1632. }
  1633. void CalcSize()
  1634. {
  1635. T* pT = static_cast<T*>(this);
  1636. CFontHandle font = pT->GetTitleFont();
  1637. LOGFONT lf;
  1638. font.GetLogFont(lf);
  1639. if(IsVertical())
  1640. {
  1641. m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder;
  1642. }
  1643. else
  1644. {
  1645. int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset;
  1646. int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset;
  1647. m_cxyHeader = max(cyFont, cyBtn);
  1648. }
  1649. }
  1650. HFONT GetTitleFont() const
  1651. {
  1652. return AtlGetDefaultGuiFont();
  1653. }
  1654. BOOL GetToolTipText(LPNMHDR /*lpnmh*/)
  1655. {
  1656. return FALSE;
  1657. }
  1658. void DrawPaneTitle(CDCHandle dc)
  1659. {
  1660. RECT rect;
  1661. GetClientRect(&rect);
  1662. if(IsVertical())
  1663. {
  1664. rect.right = rect.left + m_cxyHeader;
  1665. dc.DrawEdge(&rect, EDGE_ETCHED, BF_LEFT | BF_TOP | BF_BOTTOM | BF_ADJUST);
  1666. dc.FillRect(&rect, (HBRUSH)LongToPtr(COLOR_3DFACE + 1));
  1667. }
  1668. else
  1669. {
  1670. rect.bottom = rect.top + m_cxyHeader;
  1671. dc.DrawEdge(&rect, EDGE_ETCHED, BF_LEFT | BF_TOP | BF_RIGHT | BF_ADJUST);
  1672. dc.FillRect(&rect, (HBRUSH)LongToPtr(COLOR_3DFACE + 1));
  1673. // draw title only for horizontal pane container
  1674. dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
  1675. dc.SetBkMode(TRANSPARENT);
  1676. T* pT = static_cast<T*>(this);
  1677. HFONT hFontOld = dc.SelectFont(pT->GetTitleFont());
  1678. rect.left += m_cxyTextOffset;
  1679. rect.right -= m_cxyTextOffset;
  1680. if(m_tb.m_hWnd != NULL)
  1681. rect.right -= m_cxToolBar;;
  1682. dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
  1683. dc.SelectFont(hFontOld);
  1684. }
  1685. }
  1686. // called only if pane is empty
  1687. void DrawPane(CDCHandle dc)
  1688. {
  1689. RECT rect;
  1690. GetClientRect(&rect);
  1691. if(IsVertical())
  1692. rect.left += m_cxyHeader;
  1693. else
  1694. rect.top += m_cxyHeader;
  1695. if((GetExStyle() & WS_EX_CLIENTEDGE) == 0)
  1696. dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  1697. dc.FillRect(&rect, (HBRUSH)LongToPtr(COLOR_APPWORKSPACE + 1));
  1698. }
  1699. // drawing helper - draws "x" button image
  1700. void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen)
  1701. {
  1702. HPEN hPenOld = dc.SelectPen(hPen);
  1703. dc.MoveTo(rcImage.left, rcImage.top);
  1704. dc.LineTo(rcImage.right, rcImage.bottom);
  1705. dc.MoveTo(rcImage.left + 1, rcImage.top);
  1706. dc.LineTo(rcImage.right + 1, rcImage.bottom);
  1707. dc.MoveTo(rcImage.left, rcImage.bottom - 1);
  1708. dc.LineTo(rcImage.right, rcImage.top - 1);
  1709. dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1);
  1710. dc.LineTo(rcImage.right + 1, rcImage.top - 1);
  1711. dc.SelectPen(hPenOld);
  1712. }
  1713. bool IsVertical() const
  1714. {
  1715. return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0);
  1716. }
  1717. };
  1718. class CPaneContainer : public CPaneContainerImpl<CPaneContainer>
  1719. {
  1720. public:
  1721. DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1)
  1722. };
  1723. }; //namespace WTL
  1724. #endif // __ATLCTRLX_H__