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.

1355 lines
42 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corp., 1991-2001 **/
  4. /**********************************************************************/
  5. /*
  6. CHKLIST.CPP
  7. This file contains the implementation of the CheckList control.
  8. */
  9. #include "pch.h"
  10. #include "chklist.h"
  11. #include <assert.h>
  12. #include <windowsx.h>
  13. #define TraceLeaveVoid() { return; }
  14. #define TraceEnter(dwMask, fn) { ; }
  15. #define TraceAssert(x) assert(x)
  16. #define TraceLeaveValue(value) { return(value); }
  17. //
  18. // Text and Background colors
  19. //
  20. #define TEXT_COLOR COLOR_WINDOWTEXT
  21. #define BK_COLOR COLOR_WINDOW
  22. //
  23. // Default dimensions for child controls. All are in dialog units.
  24. // Currently only the column width is user-adjustable (via the
  25. // CLM_SETCOLUMNWIDTH message).
  26. //
  27. #define DEFAULT_COLUMN_WIDTH 32
  28. #define DEFAULT_CHECK_WIDTH 9
  29. #define DEFAULT_HORZ_SPACE 7
  30. #define DEFAULT_VERTICAL_SPACE 3
  31. #define DEFAULT_ITEM_HEIGHT 8
  32. //
  33. // 16 bits are used for the control ID's, divided into n bits for
  34. // the subitem (least significant) and 16-n bits for the item index.
  35. //
  36. // ID_SUBITEM_BITS can be adjusted to control the maximum number of
  37. // items and subitems. For example, to allow up to 7 subitems and 8k
  38. // items, set ID_SUBITEM_BITS to 3.
  39. //
  40. // Use the low 2 bits for the subitem index, the rest for the item index.
  41. // (4 subitems max, 16k items max)
  42. #define ID_SUBITEM_BITS 2
  43. #define ID_SUBITEM_MASK ((1 << ID_SUBITEM_BITS) - 1)
  44. #define GET_ITEM(id) ((id) >> ID_SUBITEM_BITS)
  45. #define GET_SUBITEM(id) ((id) & ID_SUBITEM_MASK)
  46. #define MAKE_CTRL_ID(i, s) (0xffff & (((i) << ID_SUBITEM_BITS) | ((s) & ID_SUBITEM_MASK)))
  47. #define MAKE_LABEL_ID(i) MAKE_CTRL_ID(i, 0)
  48. // Note that the subitem (column) index is one-based for the checkboxes
  49. // (the zero column is the label). The item (row) index is zero-based.
  50. #define MAX_CHECK_COLUMNS ID_SUBITEM_MASK
  51. typedef struct _USERDATA_STRUCT_LABEL
  52. {
  53. LPARAM lParam;
  54. int nLabelHeight;
  55. int itemIndex;
  56. } USERDATA_STRUCT_LABEL, *LPUSERDATA_STRUCT_LABEL;
  57. class CheckList
  58. {
  59. private:
  60. LONG m_cItems;
  61. LONG m_cSubItems;
  62. RECT m_rcItemLabel;
  63. LONG m_nCheckPos[MAX_CHECK_COLUMNS];
  64. LONG m_cxCheckBox;
  65. LONG m_cxCheckColumn;
  66. int m_nDefaultVerticalSpace;
  67. int m_nDefaultItemHeight;
  68. int m_nNewItemYPos;
  69. HWND m_hwndCheckFocus;
  70. BOOL m_fInMessageEnable;
  71. int m_cWheelDelta;
  72. static UINT g_ucScrollLines;
  73. private:
  74. CheckList(HWND hWnd, LPCREATESTRUCT lpcs);
  75. LRESULT MsgCommand(HWND hWnd, WORD idCmd, WORD wNotify, HWND hwndCtrl);
  76. void MsgPaint(HWND hWnd, HDC hdc);
  77. void MsgVScroll(HWND hWnd, int nCode, int nPos);
  78. void MsgMouseWheel(HWND hWnd, WORD fwFlags, int zDelta);
  79. void MsgButtonDown(HWND hWnd, WPARAM fwFlags, int xPos, int yPos);
  80. void MsgEnable(HWND hWnd, BOOL fEnabled);
  81. void MsgSize(HWND hWnd, DWORD dwSizeType, LONG nWidth, LONG nHeight);
  82. LONG AddItem(HWND hWnd, LPCTSTR pszLabel, LPARAM lParam);
  83. void SetState(HWND hWnd, WORD iItem, WORD iSubItem, LONG lState);
  84. LONG GetState(HWND hWnd, WORD iItem, WORD iSubItem);
  85. void SetColumnWidth(HWND hWnd, LONG cxDialog, LONG cxColumn);
  86. void ResetContent(HWND hWnd);
  87. LONG GetVisibleCount(HWND hWnd);
  88. LONG GetTopIndex(HWND hWnd, LONG *pnAmountObscured = NULL);
  89. void SetTopIndex(HWND hWnd, LONG nIndex);
  90. void EnsureVisible(HWND hWnd, LONG nIndex);
  91. void DrawCheckFocusRect(HWND hWnd, HWND hwndCheck, BOOL fDraw);
  92. public:
  93. HWND m_hWnd;
  94. static LRESULT CALLBACK WindowProc(HWND hWnd,
  95. UINT uMsg,
  96. WPARAM wParam,
  97. LPARAM lParam);
  98. };
  99. BOOL RegisterCheckListWndClass(HINSTANCE hInstance)
  100. {
  101. WNDCLASS wc;
  102. wc.style = 0;
  103. wc.lpfnWndProc = CheckList::WindowProc;
  104. wc.cbClsExtra = 0;
  105. wc.cbWndExtra = 0;
  106. //AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetInstanceHandle()
  107. wc.hInstance = hInstance; //AfxGetInstanceHandle(); //hModule;
  108. wc.hIcon = NULL;
  109. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  110. wc.hbrBackground = (HBRUSH)(BK_COLOR+1);
  111. wc.lpszMenuName = NULL;
  112. wc.lpszClassName = TEXT(WC_CHECKLIST);
  113. return (BOOL)RegisterClass(&wc);
  114. }
  115. UINT CheckList::g_ucScrollLines = (UINT)-1;
  116. CheckList::CheckList(HWND hWnd, LPCREATESTRUCT lpcs)
  117. : m_cItems(0), m_hwndCheckFocus(NULL), m_fInMessageEnable(FALSE), m_cWheelDelta(0)
  118. {
  119. assert(hWnd != NULL);
  120. assert(lpcs != NULL);
  121. m_hWnd = hWnd;
  122. //
  123. // Get number of check columns
  124. //
  125. m_cSubItems = lpcs->style & CLS_CHECKMASK;
  126. // for wsecedit only
  127. if ( m_cSubItems > 3 ) {
  128. m_cSubItems = 3;
  129. }
  130. if( lpcs->style & CLS_LEFTALIGN ) //if checkbox is at the left of text only 1 checkbox is allowed.
  131. {
  132. m_cSubItems = 1;
  133. }
  134. //
  135. // Convert default coordinates from dialog units to pixels
  136. //
  137. RECT rc;
  138. rc.left = DEFAULT_CHECK_WIDTH;
  139. rc.right = DEFAULT_COLUMN_WIDTH;
  140. rc.top = rc.bottom = 0;
  141. MapDialogRect(lpcs->hwndParent, &rc);
  142. // Save the converted values
  143. m_cxCheckBox = rc.left;
  144. m_cxCheckColumn = rc.right;
  145. rc.left = DEFAULT_HORZ_SPACE;
  146. rc.top = DEFAULT_VERTICAL_SPACE;
  147. rc.right = 10; // bogus (unused)
  148. rc.bottom = DEFAULT_VERTICAL_SPACE + DEFAULT_ITEM_HEIGHT;
  149. MapDialogRect(lpcs->hwndParent, &rc);
  150. // Save the converted values
  151. m_rcItemLabel = rc;
  152. m_nDefaultVerticalSpace = rc.top;
  153. m_nDefaultItemHeight = rc.bottom - rc.top;
  154. m_nNewItemYPos = rc.top;
  155. //
  156. // Get info for mouse wheel scrolling
  157. //
  158. if ((UINT)-1 == g_ucScrollLines)
  159. {
  160. g_ucScrollLines = 3; // default
  161. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &g_ucScrollLines, 0);
  162. }
  163. TraceLeaveVoid();
  164. }
  165. LRESULT
  166. CheckList::MsgCommand(HWND hWnd, WORD idCmd, WORD wNotify, HWND hwndCtrl)
  167. {
  168. TraceEnter(TRACE_CHECKLIST, "CheckList::MsgCommand");
  169. // Should only get notifications from visible, enabled, check boxes
  170. TraceAssert(GET_ITEM(idCmd) < m_cItems);
  171. TraceAssert(0 < GET_SUBITEM(idCmd) && GET_SUBITEM(idCmd) <= m_cSubItems);
  172. TraceAssert(hwndCtrl && IsWindowEnabled(hwndCtrl));
  173. switch (wNotify)
  174. {
  175. case EN_SETFOCUS:
  176. {
  177. // Make the focus go to one of the checkboxes
  178. POINT pt;
  179. DWORD dwPos = GetMessagePos();
  180. pt.x = GET_X_LPARAM(dwPos);
  181. pt.y = GET_Y_LPARAM(dwPos);
  182. MapWindowPoints(NULL, hWnd, &pt, 1);
  183. MsgButtonDown(hWnd, 0, pt.x, pt.y);
  184. }
  185. break;
  186. case BN_CLICKED:
  187. {
  188. LPUSERDATA_STRUCT_LABEL lpUserData = NULL;
  189. NM_CHECKLIST nmc;
  190. nmc.hdr.hwndFrom = hWnd;
  191. nmc.hdr.idFrom = GetDlgCtrlID(hWnd);
  192. nmc.hdr.code = CLN_CLICK;
  193. nmc.iItem = GET_ITEM(idCmd);
  194. nmc.iSubItem = GET_SUBITEM(idCmd);
  195. nmc.dwState = (DWORD)SendMessage(hwndCtrl, BM_GETCHECK, 0, 0);
  196. if (!IsWindowEnabled(hwndCtrl))
  197. nmc.dwState |= CLST_DISABLED;
  198. HRESULT hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID(nmc.iItem)),
  199. GWLP_USERDATA, (LONG_PTR&)lpUserData);
  200. //lpUserData = (LPUSERDATA_STRUCT_LABEL)
  201. // Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID(nmc.iItem)),
  202. // GWLP_USERDATA);
  203. if (SUCCEEDED(hr) && lpUserData)
  204. {
  205. nmc.dwItemData = lpUserData->lParam;
  206. }
  207. SendMessage(GetParent(hWnd),
  208. WM_NOTIFY,
  209. nmc.hdr.idFrom,
  210. (LPARAM)&nmc);
  211. }
  212. break;
  213. case BN_SETFOCUS:
  214. if (GetFocus() != hwndCtrl)
  215. {
  216. // This causes another BN_SETFOCUS
  217. SetFocus(hwndCtrl);
  218. }
  219. else
  220. {
  221. if (m_hwndCheckFocus != hwndCtrl) // Has the focus moved?
  222. {
  223. // Remember where the focus is
  224. m_hwndCheckFocus = hwndCtrl;
  225. // Make sure the row is scrolled into view
  226. EnsureVisible(hWnd, GET_ITEM(idCmd));
  227. }
  228. // Always draw the focus rect
  229. DrawCheckFocusRect(hWnd, hwndCtrl, TRUE);
  230. }
  231. break;
  232. case BN_KILLFOCUS:
  233. // Remove the focus rect
  234. m_hwndCheckFocus = NULL;
  235. DrawCheckFocusRect(hWnd, hwndCtrl, FALSE);
  236. break;
  237. }
  238. TraceLeaveValue(0);
  239. }
  240. void
  241. CheckList::MsgPaint(HWND hWnd, HDC hdc)
  242. {
  243. if (hdc == NULL && m_hwndCheckFocus != NULL)
  244. {
  245. // This will cause a focus rect to be drawn after the window and
  246. // all checkboxes have been painted.
  247. PostMessage(hWnd,
  248. WM_COMMAND,
  249. GET_WM_COMMAND_MPS(GetDlgCtrlID(m_hwndCheckFocus), m_hwndCheckFocus, BN_SETFOCUS));
  250. }
  251. // Default paint
  252. DefWindowProc(hWnd, WM_PAINT, (WPARAM)hdc, 0);
  253. }
  254. void
  255. CheckList::MsgVScroll(HWND hWnd, int nCode, int nPos)
  256. {
  257. UINT cScrollUnitsPerLine;
  258. SCROLLINFO si;
  259. si.cbSize = sizeof(si);
  260. si.fMask = SIF_ALL;
  261. if (!GetScrollInfo(hWnd, SB_VERT, &si))
  262. return;
  263. cScrollUnitsPerLine = m_rcItemLabel.bottom;
  264. // One page is always visible, so adjust the range to a more useful value
  265. si.nMax -= si.nPage - 1;
  266. switch (nCode)
  267. {
  268. case SB_LINEUP:
  269. // "line" is the height of one item (includes the space in between)
  270. nPos = si.nPos - cScrollUnitsPerLine;
  271. break;
  272. case SB_LINEDOWN:
  273. nPos = si.nPos + cScrollUnitsPerLine;
  274. break;
  275. case SB_PAGEUP:
  276. nPos = si.nPos - si.nPage;
  277. break;
  278. case SB_PAGEDOWN:
  279. nPos = si.nPos + si.nPage;
  280. break;
  281. case SB_TOP:
  282. nPos = si.nMin;
  283. break;
  284. case SB_BOTTOM:
  285. nPos = si.nMax;
  286. break;
  287. case SB_ENDSCROLL:
  288. nPos = si.nPos; // don't go anywhere
  289. break;
  290. case SB_THUMBTRACK:
  291. // Do nothing here to allow tracking
  292. // nPos = si.nPos; // Do this to prevent tracking
  293. case SB_THUMBPOSITION:
  294. // nothing to do here... nPos is passed in
  295. break;
  296. }
  297. // Make sure the new position is within the range
  298. if (nPos < si.nMin)
  299. nPos = si.nMin;
  300. else if (nPos > si.nMax)
  301. nPos = si.nMax;
  302. if (nPos != si.nPos) // are we moving?
  303. {
  304. SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
  305. ScrollWindow(hWnd, 0, si.nPos - nPos, NULL, NULL);
  306. }
  307. }
  308. void
  309. CheckList::MsgMouseWheel(HWND hWnd, WORD fwFlags, int iWheelDelta)
  310. {
  311. int cDetants;
  312. if ((fwFlags & (MK_SHIFT | MK_CONTROL)) || 0 == g_ucScrollLines)
  313. return;
  314. TraceEnter(TRACE_CHECKLIST, "CheckList::MsgMouseWheel");
  315. // Update count of scroll amount
  316. m_cWheelDelta -= iWheelDelta;
  317. cDetants = m_cWheelDelta / WHEEL_DELTA;
  318. if (0 == cDetants)
  319. TraceLeaveVoid();
  320. m_cWheelDelta %= WHEEL_DELTA;
  321. //if (WS_VSCROLL & GetWindowLong(hWnd, GWL_STYLE))
  322. long winlong = 0;
  323. Win::GetWindowLong(hWnd, GWL_STYLE, winlong);
  324. if (WS_VSCROLL & winlong)
  325. {
  326. SCROLLINFO si;
  327. UINT cScrollUnitsPerLine;
  328. UINT cLinesPerPage;
  329. UINT cLinesPerDetant;
  330. // Get the scroll amount of one line
  331. cScrollUnitsPerLine = m_rcItemLabel.bottom;
  332. TraceAssert(cScrollUnitsPerLine > 0);
  333. si.cbSize = sizeof(SCROLLINFO);
  334. si.fMask = SIF_PAGE | SIF_POS;
  335. if (!GetScrollInfo(hWnd, SB_VERT, &si))
  336. TraceLeaveVoid();
  337. // The size of a page is at least one line, and
  338. // leaves one line of overlap
  339. cLinesPerPage = (si.nPage - cScrollUnitsPerLine) / cScrollUnitsPerLine;
  340. cLinesPerPage = max(1, cLinesPerPage);
  341. // Don't scroll more than one page per detant
  342. cLinesPerDetant = min(cLinesPerPage, g_ucScrollLines);
  343. si.nPos += cDetants * cLinesPerDetant * cScrollUnitsPerLine;
  344. MsgVScroll(hWnd, SB_THUMBTRACK, si.nPos);
  345. }
  346. TraceLeaveVoid();
  347. }
  348. void
  349. CheckList::MsgButtonDown(HWND hWnd, WPARAM /*fwFlags*/, int xPos, int yPos)
  350. {
  351. LONG nItemIndex;
  352. HWND hwndCheck;
  353. RECT rc;
  354. // Get position of the top visible item in client coords
  355. nItemIndex = GetTopIndex(hWnd);
  356. if (nItemIndex == -1)
  357. {
  358. return;
  359. }
  360. hwndCheck = GetDlgItem(hWnd, MAKE_CTRL_ID(nItemIndex, 0));
  361. GetWindowRect(hwndCheck, &rc);
  362. MapWindowPoints(NULL, hWnd, (LPPOINT)&rc, 2);
  363. // Find nearest item
  364. if( hWnd == m_hWnd ) //Raid #387542, 5/9/2001
  365. {
  366. POINT pos = {xPos,yPos};
  367. HWND ChildhWnd = ::ChildWindowFromPointEx(hWnd, pos, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED);
  368. if( ChildhWnd )
  369. {
  370. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  371. HRESULT hr = Win::GetWindowLongPtr(ChildhWnd, GWLP_USERDATA, (LONG_PTR&)pUserData);
  372. //LPUSERDATA_STRUCT_LABEL pUserData = (LPUSERDATA_STRUCT_LABEL)GetWindowLongPtr(ChildhWnd, GWLP_USERDATA);
  373. if (SUCCEEDED(hr) && pUserData)
  374. {
  375. nItemIndex = pUserData->itemIndex;
  376. }
  377. else
  378. {
  379. return;
  380. }
  381. }
  382. }
  383. // Set focus to first subitem that is enabled
  384. for (LONG j = 1; j <= m_cSubItems; j++)
  385. {
  386. int id = MAKE_CTRL_ID(nItemIndex, j);
  387. HWND hwndCheck = GetDlgItem(hWnd, id);
  388. if (IsWindowEnabled(hwndCheck))
  389. {
  390. // Don't just SetFocus here. We sometimes call this during
  391. // EN_SETFOCUS, and USER doesn't like it when you mess with
  392. // focus during a focus change.
  393. //
  394. //SetFocus(hwndCheck);
  395. PostMessage(hWnd,
  396. WM_COMMAND,
  397. GET_WM_COMMAND_MPS(id, hwndCheck, BN_SETFOCUS));
  398. break;
  399. }
  400. }
  401. }
  402. void
  403. CheckList::MsgEnable(HWND hWnd, BOOL fEnabled)
  404. {
  405. HWND hwndCurrentCheck;
  406. BOOL fCheckEnabled = FALSE;
  407. if (!m_fInMessageEnable)
  408. {
  409. m_fInMessageEnable = TRUE;
  410. for (LONG i = 0; i < m_cItems; i++)
  411. {
  412. for (LONG j = 1; j <= m_cSubItems; j++)
  413. {
  414. hwndCurrentCheck = GetDlgItem(hWnd, MAKE_CTRL_ID(i, j));
  415. //fCheckEnabled = (BOOL) GetWindowLongPtr(hwndCurrentCheck, GWLP_USERDATA);
  416. Win::GetWindowLongPtr(hwndCurrentCheck, GWLP_USERDATA, (LONG_PTR&)fCheckEnabled);
  417. //
  418. // If the user of the checklist control is disabling the control
  419. // altogether, or the current checkbox has been disabled singularly
  420. // then disable the checkbox
  421. //
  422. if (!fEnabled || !fCheckEnabled)
  423. {
  424. EnableWindow(hwndCurrentCheck, FALSE);
  425. }
  426. else
  427. {
  428. EnableWindow(hwndCurrentCheck, TRUE);
  429. }
  430. }
  431. }
  432. // Note that the main chklist window must remain enabled
  433. // for scrolling to work while "disabled".
  434. if (!fEnabled)
  435. EnableWindow(hWnd, TRUE);
  436. m_fInMessageEnable = FALSE;
  437. }
  438. }
  439. void
  440. CheckList::MsgSize(HWND hWnd, DWORD dwSizeType, LONG nWidth, LONG nHeight)
  441. {
  442. TraceEnter(TRACE_CHECKLIST, "CheckList::MsgSize");
  443. TraceAssert(hWnd != NULL);
  444. if (dwSizeType == SIZE_RESTORED)
  445. {
  446. RECT rc;
  447. SCROLLINFO si;
  448. si.cbSize = sizeof(si);
  449. si.fMask = SIF_RANGE | SIF_PAGE;
  450. si.nMin = 0;
  451. si.nMax = m_nNewItemYPos - 1;
  452. si.nPage = nHeight;
  453. SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
  454. // Don't trust the width value passed in, since SetScrollInfo may
  455. // affect it if the scroll bar is turning on or off.
  456. GetClientRect(hWnd, &rc);
  457. nWidth = rc.right;
  458. // If the scrollbar is turned on, artificially bump up the width
  459. // by the width of the scrollbar, so the boxes don't jump to the left
  460. // when we have a scrollbar.
  461. if ((UINT)si.nMax >= si.nPage)
  462. nWidth += GetSystemMetrics(SM_CYHSCROLL);
  463. SetColumnWidth(hWnd, nWidth, m_cxCheckColumn);
  464. }
  465. TraceLeaveVoid();
  466. }
  467. LONG CheckList::AddItem(HWND hWnd, LPCTSTR pszLabel, LPARAM lParam)
  468. {
  469. HWND hwndPrev = 0;
  470. LPUSERDATA_STRUCT_LABEL lpUserData = 0;
  471. TraceEnter(TRACE_CHECKLIST, "CheckList::AddItem");
  472. TraceAssert(hWnd != NULL);
  473. TraceAssert(pszLabel != NULL && !IsBadStringPtr(pszLabel, MAX_PATH));
  474. if ( !hWnd || !pszLabel || IsBadStringPtr(pszLabel, MAX_PATH) )
  475. return -1;
  476. lpUserData = new (USERDATA_STRUCT_LABEL);
  477. if ( lpUserData )
  478. {
  479. SCROLLINFO si;
  480. si.cbSize = sizeof(si);
  481. si.fMask = SIF_POS;
  482. si.nPos = 0;
  483. GetScrollInfo(hWnd, SB_VERT, &si);
  484. // Set the initial label height extra big so the control can wrap the text,
  485. // then reset it after creating the control.
  486. RECT rc;
  487. GetClientRect(hWnd, &rc);
  488. LONG nLabelHeight = rc.bottom;
  489. //AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetInstanceHandle()
  490. HMODULE hModule = GetResourceModuleHandle(); //AfxGetInstanceHandle();
  491. // Create a new label control
  492. HWND hwndNew = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  493. TEXT("edit"),
  494. pszLabel,
  495. WS_CHILD | WS_VISIBLE | WS_GROUP | ES_MULTILINE | ES_READONLY | ES_LEFT,// | WS_GROUP,
  496. m_rcItemLabel.left,
  497. m_nNewItemYPos - si.nPos,
  498. m_rcItemLabel.right - m_rcItemLabel.left,
  499. nLabelHeight,
  500. hWnd,
  501. (HMENU)IntToPtr(MAKE_LABEL_ID(m_cItems)),
  502. hModule,
  503. NULL);
  504. if ( hwndNew )
  505. {
  506. HWND hwndEdit = hwndNew;
  507. //
  508. // Reset window height after word wrap has been done.
  509. //
  510. LONG nLineCount = (LONG) SendMessage(hwndNew, EM_GETLINECOUNT, 0, (LPARAM) 0);
  511. nLabelHeight = nLineCount * m_nDefaultItemHeight;
  512. SetWindowPos(hwndNew,
  513. NULL,
  514. 0,
  515. 0,
  516. m_rcItemLabel.right - m_rcItemLabel.left,
  517. nLabelHeight,
  518. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  519. //
  520. // Save item data
  521. //
  522. lpUserData->lParam = lParam;
  523. lpUserData->nLabelHeight = nLabelHeight;
  524. lpUserData->itemIndex = m_cItems; //Raid #387542
  525. SetLastError(0);
  526. //SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LPARAM) lpUserData); //Raid #286697, 4/4/2001
  527. HRESULT hr = Win::SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LONG_PTR)lpUserData);
  528. if (SUCCEEDED(hr)) // 0 == GetLastError() )
  529. {
  530. // Set the font
  531. SendMessage(hwndNew,
  532. WM_SETFONT,
  533. SendMessage(GetParent(hWnd), WM_GETFONT, 0, 0),
  534. 0);
  535. // Set Z-order position just after the last checkbox. This keeps
  536. // tab order correct.
  537. if (m_cItems > 0)
  538. {
  539. hwndPrev = GetDlgItem(hWnd, MAKE_CTRL_ID(m_cItems - 1, m_cSubItems));
  540. SetWindowPos(hwndNew,
  541. hwndPrev,
  542. 0, 0, 0, 0,
  543. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  544. }
  545. // Create new checkboxes
  546. DWORD dwCheckStyle = WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_NOTIFY | BS_FLAT | BS_AUTOCHECKBOX;
  547. for (LONG j = 0; j < m_cSubItems; j++)
  548. {
  549. hwndPrev = hwndNew;
  550. hwndNew = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  551. TEXT("BUTTON"),
  552. NULL,
  553. dwCheckStyle,
  554. m_nCheckPos[j],
  555. m_nNewItemYPos - si.nPos,
  556. m_cxCheckBox,
  557. m_rcItemLabel.bottom - m_rcItemLabel.top,
  558. hWnd,
  559. (HMENU)IntToPtr(MAKE_CTRL_ID(m_cItems, j + 1)),
  560. hModule,
  561. NULL);
  562. if (!hwndNew)
  563. {
  564. while (j >= 0)
  565. {
  566. DestroyWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(m_cItems, j)));
  567. j--;
  568. }
  569. DestroyWindow (hwndEdit);
  570. delete lpUserData;
  571. TraceLeaveValue(-1);
  572. }
  573. // Set Z-order position just after the last checkbox. This keeps
  574. // tab order correct.
  575. SetWindowPos(hwndNew,
  576. hwndPrev,
  577. 0, 0, 0, 0,
  578. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  579. //
  580. // Default "enabled" to TRUE
  581. //
  582. //SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LPARAM) TRUE);
  583. hr = Win::SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LONG_PTR)TRUE);
  584. // Only want this style on the first checkbox
  585. dwCheckStyle &= ~WS_GROUP;
  586. }
  587. // We now officially have a new item
  588. m_cItems++;
  589. // calculate Y pos for next item to be inserted
  590. m_nNewItemYPos += nLabelHeight + m_nDefaultVerticalSpace;
  591. //
  592. // The last thing is to set the scroll range
  593. //
  594. GetClientRect(hWnd, &rc);
  595. si.cbSize = sizeof(si);
  596. si.fMask = SIF_PAGE | SIF_RANGE;
  597. si.nMin = 0;
  598. si.nMax = m_nNewItemYPos - 1;
  599. si.nPage = rc.bottom;
  600. SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
  601. }
  602. else
  603. {
  604. delete lpUserData;
  605. DestroyWindow(hwndNew);
  606. }
  607. }
  608. else
  609. delete lpUserData;
  610. }
  611. TraceLeaveValue(m_cItems - 1); // return the index of the new item
  612. }
  613. void
  614. CheckList::SetState(HWND hWnd, WORD iItem, WORD iSubItem, LONG lState)
  615. {
  616. HWND hwndCtrl;
  617. TraceEnter(TRACE_CHECKLIST, "CheckList::SetState");
  618. TraceAssert(hWnd != NULL);
  619. TraceAssert(iItem < m_cItems);
  620. TraceAssert(0 < iSubItem && iSubItem <= m_cSubItems);
  621. if (iSubItem > 0)
  622. {
  623. hwndCtrl = GetDlgItem(hWnd, MAKE_CTRL_ID(iItem, iSubItem));
  624. if (hwndCtrl != NULL)
  625. {
  626. //SetWindowLongPtr(hwndCtrl, GWLP_USERDATA, (LPARAM) !(lState & CLST_DISABLED));
  627. Win::SetWindowLongPtr(hwndCtrl, GWLP_USERDATA, (LONG_PTR)!(lState & CLST_DISABLED));
  628. SendMessage(hwndCtrl, BM_SETCHECK, lState & CLST_CHECKED, 0);
  629. EnableWindow(hwndCtrl, !(lState & CLST_DISABLED));
  630. }
  631. }
  632. TraceLeaveVoid();
  633. }
  634. LONG
  635. CheckList::GetState(HWND hWnd, WORD iItem, WORD iSubItem)
  636. {
  637. LONG lState = 0;
  638. TraceEnter(TRACE_CHECKLIST, "CheckList::GetState");
  639. TraceAssert(hWnd != NULL);
  640. TraceAssert(iItem < m_cItems);
  641. TraceAssert(0 < iSubItem && iSubItem <= m_cSubItems);
  642. HWND hwndCtrl = GetDlgItem(hWnd, MAKE_CTRL_ID(iItem, iSubItem));
  643. if (hwndCtrl != NULL)
  644. {
  645. lState = (LONG)SendMessage(hwndCtrl, BM_GETCHECK, 0, 0);
  646. TraceAssert(!(lState & BST_INDETERMINATE));
  647. if (!IsWindowEnabled(hwndCtrl))
  648. lState |= CLST_DISABLED;
  649. }
  650. TraceLeaveValue(lState);
  651. }
  652. void
  653. CheckList::SetColumnWidth(HWND hWnd, LONG cxDialog, LONG cxColumn)
  654. {
  655. LONG j;
  656. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  657. LONG nLabelHeight;
  658. TraceEnter(TRACE_CHECKLIST, "CheckList::SetColumnWidth");
  659. TraceAssert(hWnd != NULL);
  660. TraceAssert(cxColumn > 10);
  661. m_cxCheckColumn = cxColumn;
  662. long dwChkListStyle = 0;
  663. Win::GetWindowLong(hWnd, GWL_STYLE, dwChkListStyle);
  664. if (m_cSubItems > 0)
  665. {
  666. if ( dwChkListStyle & CLS_LEFTALIGN )
  667. {
  668. // Put the checkboxes at the left of the text
  669. int xSubItem = m_rcItemLabel.left;
  670. for (j = 0; j < m_cSubItems; j++, xSubItem += cxColumn)
  671. m_nCheckPos[j] = xSubItem;
  672. m_rcItemLabel.left = xSubItem - (cxColumn + m_cxCheckBox)/2;
  673. m_rcItemLabel.right = cxDialog - m_rcItemLabel.left;
  674. }
  675. else
  676. {
  677. m_nCheckPos[m_cSubItems-1] = cxDialog // dlg width
  678. - m_rcItemLabel.left // right margin
  679. - (cxColumn + m_cxCheckBox)/2; // 1/2 col & 1/2 checkbox
  680. for (j = m_cSubItems - 1; j > 0; j--)
  681. m_nCheckPos[j-1] = m_nCheckPos[j] - cxColumn;
  682. // (leftmost check pos) - (horz margin)
  683. m_rcItemLabel.right = m_nCheckPos[0] - m_rcItemLabel.left;
  684. }
  685. }
  686. else
  687. m_rcItemLabel.right = cxDialog - m_rcItemLabel.left;
  688. LONG nTop = m_rcItemLabel.top;
  689. LONG nBottom = m_rcItemLabel.bottom;
  690. for (LONG i = 0; i < m_cItems; i++)
  691. {
  692. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  693. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
  694. // GWLP_USERDATA);
  695. HRESULT hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
  696. GWLP_USERDATA, (LONG_PTR&)pUserData);
  697. if (SUCCEEDED(hr) && pUserData != NULL)
  698. {
  699. nLabelHeight = pUserData->nLabelHeight;
  700. }
  701. else
  702. {
  703. nLabelHeight = nBottom - nTop;
  704. }
  705. MoveWindow(GetDlgItem(hWnd, MAKE_LABEL_ID(i)),
  706. m_rcItemLabel.left,
  707. nTop,
  708. m_rcItemLabel.right - m_rcItemLabel.left,
  709. nLabelHeight,
  710. FALSE);
  711. for (j = 0; j < m_cSubItems; j++)
  712. {
  713. MoveWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(i, j + 1)),
  714. m_nCheckPos[j],
  715. nTop,
  716. m_cxCheckBox,
  717. nBottom - nTop,
  718. FALSE);
  719. }
  720. nTop += nLabelHeight + m_nDefaultVerticalSpace;
  721. nBottom += nLabelHeight + m_nDefaultVerticalSpace;
  722. }
  723. TraceLeaveVoid();
  724. }
  725. void
  726. CheckList::ResetContent(HWND hWnd)
  727. {
  728. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  729. HWND hwndCurrentLabel;
  730. for (LONG i = 0; i < m_cItems; i++)
  731. {
  732. hwndCurrentLabel = GetDlgItem(hWnd, MAKE_LABEL_ID((int)i));
  733. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  734. // GetWindowLongPtr( hwndCurrentLabel,
  735. // GWLP_USERDATA);
  736. HRESULT hr = Win::GetWindowLongPtr( hwndCurrentLabel,
  737. GWLP_USERDATA, (LONG_PTR&)pUserData);
  738. if (SUCCEEDED(hr) && pUserData != NULL)
  739. {
  740. delete(pUserData);
  741. }
  742. DestroyWindow(hwndCurrentLabel);
  743. for (LONG j = 1; j <= m_cSubItems; j++)
  744. {
  745. DestroyWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(i, j)));
  746. }
  747. }
  748. // Hide the scroll bar
  749. SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
  750. m_cItems = 0;
  751. }
  752. LONG
  753. CheckList::GetVisibleCount(HWND hWnd)
  754. {
  755. LONG nCount = 0;
  756. RECT rc;
  757. LONG nTopIndex;
  758. LONG nAmountShown = 0;
  759. LONG nAmountObscured = 0;
  760. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  761. if (!GetClientRect(hWnd, &rc))
  762. {
  763. return 1;
  764. }
  765. nTopIndex = GetTopIndex(hWnd, &nAmountObscured);
  766. if (nTopIndex == -1)
  767. {
  768. return 1;
  769. }
  770. while ((nTopIndex < m_cItems) && (nAmountShown < rc.bottom))
  771. {
  772. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  773. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
  774. // GWLP_USERDATA);
  775. HRESULT hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
  776. GWLP_USERDATA, (LONG_PTR&)pUserData);
  777. if (SUCCEEDED(hr) && pUserData)
  778. {
  779. nAmountShown += (m_nDefaultVerticalSpace + pUserData->nLabelHeight - nAmountObscured);
  780. }
  781. nAmountObscured = 0; // nAmountObscured only matters for the first iteration where
  782. // the real top index's amount shown is being calculated
  783. nCount++;
  784. nTopIndex++;
  785. }
  786. //
  787. // since that last one may be obscured see if we need to adjust nCount
  788. //
  789. if (nAmountShown > rc.bottom)
  790. {
  791. nCount--;
  792. }
  793. return max(1, nCount);
  794. }
  795. LONG
  796. CheckList::GetTopIndex(HWND hWnd, LONG *pnAmountObscured)
  797. {
  798. LONG nIndex = 0;
  799. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  800. SCROLLINFO si;
  801. si.cbSize = sizeof(si);
  802. si.fMask = SIF_POS;
  803. //
  804. // initialize
  805. //
  806. if (pnAmountObscured != NULL)
  807. {
  808. *pnAmountObscured = 0;
  809. }
  810. if (GetScrollInfo(hWnd, SB_VERT, &si) && m_rcItemLabel.bottom > 0)
  811. {
  812. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  813. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
  814. // GWLP_USERDATA);
  815. HRESULT hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
  816. GWLP_USERDATA, (LONG_PTR&)pUserData);
  817. //
  818. // if there are no items get out
  819. //
  820. if (FAILED(hr) || pUserData == NULL)
  821. {
  822. return -1;
  823. }
  824. while (si.nPos >= (m_nDefaultVerticalSpace + pUserData->nLabelHeight))
  825. {
  826. si.nPos -= (m_nDefaultVerticalSpace + pUserData->nLabelHeight);
  827. nIndex++;
  828. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  829. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
  830. // GWLP_USERDATA);
  831. hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
  832. GWLP_USERDATA, (LONG_PTR&)pUserData);
  833. }
  834. if (pnAmountObscured != NULL)
  835. {
  836. *pnAmountObscured = si.nPos;
  837. }
  838. }
  839. return nIndex;
  840. }
  841. void
  842. CheckList::SetTopIndex(HWND hWnd, LONG nIndex)
  843. {
  844. int i;
  845. int nPos = 0;
  846. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  847. for (i=0; i<nIndex; i++)
  848. {
  849. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  850. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
  851. // GWLP_USERDATA);
  852. HRESULT hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
  853. GWLP_USERDATA, (LONG_PTR&)pUserData);
  854. if (SUCCEEDED(hr) && pUserData)
  855. {
  856. nPos += (m_nDefaultVerticalSpace + pUserData->nLabelHeight);
  857. }
  858. }
  859. m_cWheelDelta = 0;
  860. MsgVScroll(hWnd, SB_THUMBPOSITION, nPos);
  861. }
  862. void
  863. CheckList::EnsureVisible(HWND hWnd, LONG nItemIndex)
  864. {
  865. LONG nAmountObscured = 0;
  866. LONG nTopIndex;
  867. RECT rc;
  868. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  869. nTopIndex = GetTopIndex(hWnd, &nAmountObscured);
  870. if (nTopIndex == -1)
  871. {
  872. return;
  873. }
  874. // Note that the top item may only be partially visible,
  875. // so we need to test for equality here. Raid #208449
  876. if (nItemIndex < nTopIndex)
  877. {
  878. SetTopIndex(hWnd, nItemIndex);
  879. }
  880. else if (nItemIndex == nTopIndex)
  881. {
  882. if (nAmountObscured != 0)
  883. {
  884. SetTopIndex(hWnd, nItemIndex);
  885. }
  886. }
  887. else
  888. {
  889. LONG nVisible = GetVisibleCount(hWnd);
  890. if (nItemIndex >= nTopIndex + nVisible)
  891. {
  892. if (!GetClientRect(hWnd, &rc))
  893. {
  894. //
  895. // This is just best effort
  896. //
  897. SetTopIndex(hWnd, nItemIndex - nVisible + 1);
  898. }
  899. else
  900. {
  901. //
  902. // Calculate what the top index should be to allow
  903. // nItemIndex to be fully visible
  904. //
  905. nTopIndex = nItemIndex + 1;
  906. HRESULT hr = S_OK;
  907. do
  908. {
  909. nTopIndex--;
  910. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  911. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
  912. // GWLP_USERDATA);
  913. hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
  914. GWLP_USERDATA, (LONG_PTR&)pUserData);
  915. if (SUCCEEDED(hr) && pUserData != NULL)
  916. {
  917. rc.bottom -= (pUserData->nLabelHeight + m_nDefaultVerticalSpace);
  918. if (rc.bottom < 0)
  919. {
  920. nTopIndex++;
  921. }
  922. }
  923. else
  924. {
  925. //
  926. // Should not hit this, just added to make things safe
  927. //
  928. rc.bottom = 0;
  929. nTopIndex = 0;
  930. }
  931. } while (rc.bottom > 0);
  932. SetTopIndex(hWnd, nTopIndex);
  933. }
  934. }
  935. }
  936. }
  937. void
  938. CheckList::DrawCheckFocusRect(HWND hWnd, HWND hwndCheck, BOOL fDraw)
  939. {
  940. RECT rcCheck;
  941. TraceEnter(TRACE_CHECKLIST, "CheckList::DrawCheckFocusRect");
  942. TraceAssert(hWnd != NULL);
  943. TraceAssert(hwndCheck != NULL);
  944. GetWindowRect(hwndCheck, &rcCheck);
  945. MapWindowPoints(NULL, hWnd, (LPPOINT)&rcCheck, 2);
  946. InflateRect(&rcCheck, 2, 2); // draw *outside* the checkbox
  947. HDC hdc = GetDC(hWnd);
  948. if (hdc)
  949. {
  950. // Always erase before drawing, since we may already be
  951. // partially visible and drawing is an XOR operation.
  952. // (Don't want to leave any turds on the screen.)
  953. FrameRect(hdc, &rcCheck, GetSysColorBrush(BK_COLOR));
  954. if (fDraw)
  955. {
  956. SetTextColor(hdc, GetSysColor(TEXT_COLOR));
  957. SetBkColor(hdc, GetSysColor(BK_COLOR));
  958. DrawFocusRect(hdc, &rcCheck);
  959. }
  960. ReleaseDC(hWnd, hdc);
  961. }
  962. TraceLeaveVoid();
  963. }
  964. LRESULT
  965. CALLBACK
  966. CheckList::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  967. {
  968. LRESULT lResult = 0;
  969. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  970. CheckList *pThis = NULL; //(CheckList*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  971. HRESULT hr = Win::GetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR&)pThis);
  972. if (FAILED(hr))
  973. {
  974. TraceAssert(false);
  975. return 0;
  976. }
  977. TraceEnter(TRACE_CHECKLIST, "CheckList::WindowProc");
  978. TraceAssert(hWnd != NULL);
  979. switch (uMsg)
  980. {
  981. case WM_NCCREATE:
  982. pThis = new CheckList(hWnd, (LPCREATESTRUCT)lParam);
  983. if (pThis != NULL)
  984. {
  985. //SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
  986. hr = Win::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
  987. lResult = TRUE;
  988. }
  989. break;
  990. case WM_DESTROY:
  991. pThis->ResetContent(hWnd);
  992. break;
  993. case WM_NCDESTROY:
  994. delete pThis;
  995. break;
  996. case WM_COMMAND:
  997. TraceAssert(pThis != NULL);
  998. lResult = pThis->MsgCommand(hWnd,
  999. GET_WM_COMMAND_ID(wParam, lParam),
  1000. GET_WM_COMMAND_CMD(wParam, lParam),
  1001. GET_WM_COMMAND_HWND(wParam, lParam));
  1002. break;
  1003. case WM_CTLCOLORSTATIC:
  1004. TraceAssert(pThis != NULL);
  1005. SetBkMode((HDC)wParam, TRANSPARENT);
  1006. SetTextColor((HDC)wParam, GetSysColor(TEXT_COLOR));
  1007. SetBkColor((HDC)wParam, GetSysColor(BK_COLOR));
  1008. lResult = (LRESULT)GetSysColorBrush(BK_COLOR);
  1009. break;
  1010. case WM_PAINT:
  1011. TraceAssert(pThis != NULL);
  1012. pThis->MsgPaint(hWnd, (HDC)wParam);
  1013. break;
  1014. case WM_VSCROLL:
  1015. TraceAssert(pThis != NULL);
  1016. pThis->MsgVScroll(hWnd,
  1017. (int)(short)GET_WM_VSCROLL_CODE(wParam, lParam),
  1018. (int)(short)GET_WM_VSCROLL_POS(wParam, lParam));
  1019. break;
  1020. case WM_MOUSEWHEEL:
  1021. TraceAssert(pThis != NULL);
  1022. pThis->MsgMouseWheel(hWnd,
  1023. LOWORD(wParam),
  1024. (int)(short)HIWORD(wParam));
  1025. break;
  1026. case WM_LBUTTONDOWN:
  1027. TraceAssert(pThis != NULL);
  1028. pThis->MsgButtonDown(hWnd,
  1029. wParam,
  1030. (int)(short)LOWORD(lParam),
  1031. (int)(short)HIWORD(lParam));
  1032. break;
  1033. case WM_ENABLE:
  1034. TraceAssert(pThis != NULL);
  1035. pThis->MsgEnable(hWnd, (BOOL)wParam);
  1036. break;
  1037. case WM_SETFONT:
  1038. TraceAssert(pThis != NULL);
  1039. {
  1040. for (LONG i = 0; i < pThis->m_cItems; i++)
  1041. SendDlgItemMessage(hWnd,
  1042. MAKE_LABEL_ID(i),
  1043. WM_SETFONT,
  1044. wParam,
  1045. lParam);
  1046. }
  1047. break;
  1048. case WM_SIZE:
  1049. TraceAssert(pThis != NULL);
  1050. pThis->MsgSize(hWnd, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
  1051. break;
  1052. case CLM_ADDITEM:
  1053. TraceAssert(pThis != NULL);
  1054. lResult = pThis->AddItem(hWnd, (LPCTSTR)wParam, lParam);
  1055. break;
  1056. case CLM_GETITEMCOUNT:
  1057. TraceAssert(pThis != NULL);
  1058. lResult = pThis->m_cItems;
  1059. break;
  1060. case CLM_SETSTATE:
  1061. TraceAssert(pThis != NULL);
  1062. pThis->SetState(hWnd, LOWORD(wParam), HIWORD(wParam), (LONG)lParam);
  1063. break;
  1064. case CLM_GETSTATE:
  1065. TraceAssert(pThis != NULL);
  1066. lResult = pThis->GetState(hWnd, LOWORD(wParam), HIWORD(wParam));
  1067. break;
  1068. case CLM_SETCOLUMNWIDTH:
  1069. TraceAssert(pThis != NULL);
  1070. {
  1071. RECT rc;
  1072. LONG cxDialog;
  1073. GetClientRect(hWnd, &rc);
  1074. cxDialog = rc.right;
  1075. rc.right = (LONG)lParam;
  1076. MapDialogRect(GetParent(hWnd), &rc);
  1077. pThis->SetColumnWidth(hWnd, cxDialog, rc.right);
  1078. }
  1079. break;
  1080. case CLM_SETITEMDATA:
  1081. TraceAssert(GET_ITEM(wParam) < (ULONG)pThis->m_cItems);
  1082. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  1083. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
  1084. // GWLP_USERDATA);
  1085. hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
  1086. GWLP_USERDATA, (LONG_PTR&)pUserData);
  1087. if (pUserData != NULL)
  1088. pUserData->lParam = lParam;
  1089. break;
  1090. case CLM_GETITEMDATA:
  1091. TraceAssert(GET_ITEM(wParam) < (ULONG)pThis->m_cItems);
  1092. //pUserData = (LPUSERDATA_STRUCT_LABEL)
  1093. // GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
  1094. // GWLP_USERDATA);
  1095. hr = Win::GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
  1096. GWLP_USERDATA, (LONG_PTR&)pUserData);
  1097. if (pUserData != NULL)
  1098. lResult = pUserData->lParam;
  1099. break;
  1100. case CLM_RESETCONTENT:
  1101. TraceAssert(pThis != NULL);
  1102. pThis->ResetContent(hWnd);
  1103. break;
  1104. case CLM_GETVISIBLECOUNT:
  1105. TraceAssert(pThis != NULL);
  1106. lResult = pThis->GetVisibleCount(hWnd);
  1107. break;
  1108. case CLM_GETTOPINDEX:
  1109. TraceAssert(pThis != NULL);
  1110. lResult = pThis->GetTopIndex(hWnd);
  1111. break;
  1112. case CLM_SETTOPINDEX:
  1113. TraceAssert(pThis != NULL);
  1114. pThis->SetTopIndex(hWnd, (LONG)wParam);
  1115. break;
  1116. case CLM_ENSUREVISIBLE:
  1117. TraceAssert(pThis != NULL);
  1118. pThis->EnsureVisible(hWnd, (LONG)wParam);
  1119. break;
  1120. //
  1121. // Always refer to the chklist window for help. Don't pass
  1122. // one of the child window handles here.
  1123. //
  1124. case WM_HELP:
  1125. ((LPHELPINFO)lParam)->hItemHandle = hWnd;
  1126. lResult = SendMessage(GetParent(hWnd), uMsg, wParam, lParam);
  1127. break;
  1128. case WM_CONTEXTMENU:
  1129. lResult = SendMessage(GetParent(hWnd), uMsg, (WPARAM)hWnd, lParam);
  1130. break;
  1131. case WM_SETCURSOR:
  1132. if (LOWORD(lParam) == HTCLIENT)
  1133. {
  1134. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1135. lResult = TRUE;
  1136. break;
  1137. }
  1138. // Fall Through
  1139. default:
  1140. lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
  1141. }
  1142. TraceLeaveValue(lResult);
  1143. }