Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
15 KiB

  1. #include "header.h"
  2. #include "vlist.h"
  3. #include "cpaldc.h"
  4. #include "hhctrl.h"
  5. #include <winuser.h>
  6. #include <commctrl.h>
  7. CVirtualListCtrl::CVirtualListCtrl(LCID lcid)
  8. {
  9. m_cItems = 0;
  10. m_iTopItem = 0;
  11. m_iSelItem = 0;
  12. m_cyItem = 0;
  13. m_cItemsPerPage = 0;
  14. m_fFocus = 0;
  15. m_hFont = 0;
  16. m_hWndParent = m_hWnd = 0;
  17. m_langid = PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID()));
  18. m_lcid = lcid;
  19. m_fBiDi = g_fBiDi;
  20. m_RTL_Style = g_RTL_Style;
  21. //
  22. // Maybe this goo below can go away ?
  23. //
  24. m_cyBackBmp = 0;
  25. m_cxBackBmp = 0;
  26. m_hpalBackGround = 0;
  27. m_hbrBackGround = 0;
  28. m_hbmpBackGround = 0;
  29. m_clrForeground = (COLORREF) -1;
  30. m_clrBackground = (COLORREF) -1;
  31. }
  32. CVirtualListCtrl::~CVirtualListCtrl()
  33. {
  34. if ( IsValidWindow(m_hWnd) )
  35. DestroyWindow(m_hWnd);
  36. WNDCLASSEX wci;
  37. if ( GetClassInfoEx(_Module.GetModuleInstance(), "hh_kwd_vlist", &wci) )
  38. UnregisterClass("hh_kwd_vlist", _Module.GetModuleInstance());
  39. }
  40. void CVirtualListCtrl::RedrawCurrentItem()
  41. {
  42. RECT rc;
  43. GetItemRect(m_iSelItem, &rc);
  44. InvalidateRect(m_hWnd, &rc, TRUE);
  45. }
  46. BOOL CVirtualListCtrl::SetItemCount(int cItems)
  47. {
  48. int scroll;
  49. if (cItems < 0)
  50. return FALSE;
  51. scroll = cItems - 1;
  52. if (scroll < 0)
  53. scroll = 0;
  54. m_cItems = cItems;
  55. m_iSelItem = m_iTopItem = 0;
  56. SetScrollRange(m_hWnd, SB_VERT, 0, scroll, TRUE);
  57. InvalidateRect(m_hWnd, NULL, FALSE); // for now
  58. return TRUE;
  59. }
  60. BOOL CVirtualListCtrl::SetSelection(int iSel, BOOL bNotify /* default = TRUE */)
  61. {
  62. if (iSel < 0 || iSel >= m_cItems)
  63. return FALSE;
  64. if (m_iSelItem != iSel)
  65. {
  66. RedrawCurrentItem();
  67. m_iSelItem = iSel;
  68. RedrawCurrentItem();
  69. EnsureVisible(iSel);
  70. if ( bNotify )
  71. ItemSelected(iSel);
  72. }
  73. return TRUE;
  74. }
  75. int CVirtualListCtrl::GetSelection()
  76. {
  77. return m_iSelItem;
  78. }
  79. int CVirtualListCtrl::GetTopIndex()
  80. {
  81. return m_iTopItem;
  82. }
  83. BOOL CVirtualListCtrl::SetTopIndex(int iItem)
  84. {
  85. if (m_cItemsPerPage >= m_cItems || iItem < 0)
  86. iItem = 0;
  87. else if (iItem > m_cItems - m_cItemsPerPage)
  88. iItem = m_cItems - m_cItemsPerPage;
  89. if (iItem != m_iTopItem)
  90. {
  91. m_iTopItem = iItem;
  92. SetScrollPos(m_hWnd, SB_VERT, iItem, TRUE);
  93. InvalidateRect(m_hWnd, NULL, FALSE); // for now
  94. }
  95. return TRUE;
  96. }
  97. BOOL CVirtualListCtrl::EnsureVisible(int iItem)
  98. {
  99. if (iItem < m_iTopItem)
  100. SetTopIndex(iItem);
  101. else if (iItem >= m_iTopItem + m_cItemsPerPage)
  102. SetTopIndex(iItem - m_cItemsPerPage + 1);
  103. return TRUE;
  104. }
  105. BOOL CVirtualListCtrl::GetItemRect(int iItem, RECT* prc)
  106. {
  107. RECT rcClient;
  108. int y;
  109. GetClientRect(m_hWnd, &rcClient);
  110. y = (iItem - m_iTopItem)*m_cyItem;
  111. prc->left = rcClient.left;
  112. prc->top = y;
  113. prc->right = rcClient.right;
  114. prc->bottom = y+m_cyItem;
  115. return TRUE;
  116. }
  117. const int LEVEL_PAD = 12;
  118. LRESULT CVirtualListCtrl::DrawItem(HDC hDC, int iItem, RECT* prc, BOOL fSel, BOOL fFocus)
  119. {
  120. WCHAR szText[512];
  121. COLORREF clrFore;
  122. COLORREF clrDisabled;
  123. COLORREF clrBack;
  124. int iLevel;
  125. int pad = 0;
  126. if (fSel)
  127. {
  128. clrFore = GetSysColor(COLOR_HIGHLIGHTTEXT);
  129. clrDisabled = GetSysColor(COLOR_GRAYTEXT);
  130. clrBack = GetSysColor(COLOR_HIGHLIGHT);
  131. }
  132. else
  133. {
  134. clrFore = (m_clrForeground == -1)?GetSysColor(COLOR_WINDOWTEXT):m_clrForeground;
  135. clrDisabled = GetSysColor(COLOR_GRAYTEXT);
  136. clrBack = (m_clrBackground == -1)?GetSysColor(COLOR_WINDOW):m_clrBackground;
  137. }
  138. szText[0] = 0x00;
  139. DWORD dwFlags = 0;
  140. if (iItem >= 0 && iItem < m_cItems)
  141. GetItemText(iItem,&iLevel,&dwFlags,szText,(sizeof(szText)/2));
  142. BOOL bDisabled = (dwFlags & 0x1);
  143. if( bDisabled )
  144. SetTextColor(hDC,clrDisabled);
  145. else
  146. SetTextColor(hDC,clrFore);
  147. SetBkColor(hDC,clrBack);
  148. if ( iLevel > 1 )
  149. pad = ((iLevel - 1) * LEVEL_PAD);
  150. else
  151. pad = 2;
  152. #if 0
  153. if (m_fBiDi)
  154. {
  155. /*
  156. * Using ExtTextOut with ETO_RTLREADING fails to clear the entire
  157. * line. So, we clear the background with FillRect first and then
  158. * display the text.
  159. */
  160. SIZE size;
  161. GetTextExtentPointW(hDC, szText, wcslen(szText), &size);
  162. int pos = prc->right - 2 - size.cx - pad;
  163. if (pos < 2)
  164. pos = 2;
  165. HBRUSH hbrush = CreateSolidBrush(fSel ? GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_WINDOW));
  166. FillRect(hDC, prc, hbrush);
  167. DeleteObject(hbrush);
  168. IntlExtTextOutW(hDC, prc->left + pos, prc->top, ETO_OPAQUE | ETO_RTLREADING, prc, szText, wcslen(szText), 0);
  169. }
  170. else
  171. #endif
  172. SIZE size;
  173. GetTextExtentPointW(hDC, szText, wcslen(szText), &size);
  174. int pos = prc->right - 2 - size.cx - pad;
  175. //if (pos < 2)
  176. // pos = 2;
  177. if (m_fBiDi)
  178. IntlExtTextOutW(hDC, pos, prc->top, ETO_OPAQUE|ETO_CLIPPED|ETO_RTLREADING, prc, szText, wcslen(szText), 0);
  179. else
  180. IntlExtTextOutW(hDC, prc->left + pad, prc->top, ETO_OPAQUE | ETO_CLIPPED, prc, szText, wcslen(szText), 0);
  181. if (fFocus && fSel)
  182. DrawFocusRect(hDC, prc);
  183. return 0;
  184. }
  185. LRESULT CVirtualListCtrl::Notify(int not, NMHDR * pNMHdr)
  186. {
  187. NMHDR nmhdr;
  188. if (!pNMHdr)
  189. pNMHdr = &nmhdr;
  190. pNMHdr->hwndFrom = m_hWnd;
  191. pNMHdr->idFrom = GetDlgCtrlID(m_hWnd);
  192. pNMHdr->code = not;
  193. return SendMessage(m_hWndParent, WM_NOTIFY, pNMHdr->idFrom, (LPARAM)pNMHdr);
  194. }
  195. LRESULT CVirtualListCtrl::ItemSelected(int i)
  196. {
  197. return Notify(VLN_SELECT);
  198. }
  199. LRESULT CVirtualListCtrl::ItemDoubleClicked(int i)
  200. {
  201. return Notify(NM_DBLCLK);
  202. }
  203. LRESULT CVirtualListCtrl::GetItemText(int iItem, int* piLevel, DWORD* pdwFlags, WCHAR* lpwsz, int cchMax)
  204. {
  205. VLC_ITEM it;
  206. *lpwsz = 0;
  207. it.iItem = iItem;
  208. it.lpwsz = lpwsz;
  209. it.cchMax = cchMax;
  210. Notify(VLN_GETITEM,(NMHDR*)&it);
  211. *piLevel = it.iLevel;
  212. *pdwFlags = it.dwFlags;
  213. return S_OK;
  214. }
  215. LRESULT CVirtualListCtrl::StaticWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  216. {
  217. CVirtualListCtrl* pThis;
  218. PAINTSTRUCT ps;
  219. HDC hDC;
  220. RECT rc;
  221. SIZE cs;
  222. int i;
  223. pThis = (CVirtualListCtrl*)GetWindowLongPtr(hWnd,0);
  224. switch (msg)
  225. {
  226. case WM_CREATE:
  227. pThis = (CVirtualListCtrl*)((LPCREATESTRUCT)lParam)->lpCreateParams;
  228. SetWindowLongPtr(hWnd,0,(LONG_PTR)pThis);
  229. pThis->m_hWnd = hWnd;
  230. break;
  231. case WM_SETFONT:
  232. pThis->m_hFont = (HFONT)wParam;
  233. // FALL THRU to WM_SIZE
  234. case WM_SIZE:
  235. GetClientRect(hWnd, &rc);
  236. hDC = GetDC(hWnd);
  237. SaveDC(hDC);
  238. if (pThis->m_hFont)
  239. SelectObject(hDC, pThis->m_hFont);
  240. GetTextExtentPoint(hDC, "CC", 2, &cs);
  241. pThis->m_cyItem = cs.cy;
  242. if (pThis->m_cyItem)
  243. pThis->m_cItemsPerPage = ((rc.bottom - rc.top) / pThis->m_cyItem);
  244. else
  245. pThis->m_cItemsPerPage = 0;
  246. {
  247. SCROLLINFO si;
  248. si.cbSize = sizeof(SCROLLINFO);
  249. si.fMask = SIF_PAGE;
  250. si.nPage = pThis->m_cItemsPerPage;
  251. SetScrollInfo(hWnd, SB_VERT, &si, TRUE );
  252. }
  253. RestoreDC(hDC, -1);
  254. ReleaseDC(hWnd, hDC);
  255. break;
  256. case WM_PAINT:
  257. hDC = BeginPaint(hWnd, &ps);
  258. SaveDC(hDC);
  259. if (pThis->m_hFont)
  260. SelectObject(hDC, pThis->m_hFont);
  261. for (i = 0; i <= pThis->m_cItemsPerPage; i++)
  262. {
  263. pThis->GetItemRect(pThis->m_iTopItem + i, &rc);
  264. pThis->DrawItem(hDC, pThis->m_iTopItem + i, &rc, pThis->m_iTopItem + i == pThis->m_iSelItem, pThis->m_fFocus);
  265. }
  266. RestoreDC(hDC, -1);
  267. EndPaint(hWnd, &ps);
  268. break;
  269. case WM_SETFOCUS:
  270. pThis->m_fFocus = 1;
  271. pThis->RedrawCurrentItem();
  272. pThis->Notify(NM_SETFOCUS);
  273. break;
  274. case WM_KILLFOCUS:
  275. pThis->m_fFocus = 0;
  276. pThis->RedrawCurrentItem();
  277. pThis->Notify(NM_KILLFOCUS);
  278. break;
  279. case WM_KEYDOWN:
  280. switch (wParam)
  281. {
  282. case VK_UP:
  283. i = pThis->m_iSelItem - 1;
  284. goto go_there;
  285. case VK_DOWN:
  286. i = pThis->m_iSelItem + 1;
  287. goto go_there;
  288. case VK_PRIOR:
  289. i = pThis->m_iSelItem - pThis->m_cItemsPerPage;
  290. goto go_there;
  291. case VK_NEXT:
  292. i = pThis->m_iSelItem + pThis->m_cItemsPerPage;
  293. go_there:
  294. if (i < 0)
  295. i = 0;
  296. else if (i >= pThis->m_cItems)
  297. i = pThis->m_cItems - 1;
  298. pThis->SetSelection(i);
  299. break;
  300. case VK_HOME:
  301. pThis->SetSelection(0);
  302. break;
  303. case VK_END:
  304. pThis->SetSelection(pThis->m_cItems - 1);
  305. break;
  306. case VK_RETURN:
  307. pThis->Notify(NM_RETURN);
  308. break;
  309. case VK_TAB:
  310. pThis->Notify(VLN_TAB);
  311. break;
  312. }
  313. break;
  314. case WM_MOUSEWHEEL:
  315. if (! SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &i, 0) )
  316. i = 3;
  317. if( (short) HIWORD(wParam) > 0 )
  318. pThis->SetTopIndex(pThis->m_iTopItem - i);
  319. else
  320. pThis->SetTopIndex(pThis->m_iTopItem + i);
  321. break;
  322. case WM_VSCROLL:
  323. switch (LOWORD(wParam))
  324. {
  325. case SB_LINEUP:
  326. pThis->SetTopIndex(pThis->m_iTopItem - 1);
  327. break;
  328. case SB_LINEDOWN:
  329. pThis->SetTopIndex(pThis->m_iTopItem + 1);
  330. break;
  331. case SB_PAGEUP:
  332. pThis->SetTopIndex(pThis->m_iTopItem - pThis->m_cItemsPerPage);
  333. break;
  334. case SB_PAGEDOWN:
  335. pThis->SetTopIndex(pThis->m_iTopItem + pThis->m_cItemsPerPage);
  336. break;
  337. case SB_BOTTOM:
  338. pThis->SetTopIndex(pThis->m_cItems);
  339. break;
  340. case SB_TOP:
  341. pThis->SetTopIndex(0);
  342. break;
  343. case SB_THUMBPOSITION:
  344. case SB_THUMBTRACK:
  345. if( pThis->m_cItems > 65535 )
  346. {
  347. SCROLLINFO si;
  348. si.cbSize = sizeof(SCROLLINFO);
  349. si.fMask = SIF_TRACKPOS;
  350. GetScrollInfo(hWnd, SB_VERT, &si);
  351. pThis->SetTopIndex( si.nTrackPos );
  352. }
  353. else
  354. pThis->SetTopIndex( HIWORD( wParam ) );
  355. break;
  356. }
  357. break;
  358. case WM_LBUTTONDOWN:
  359. SetFocus(hWnd);
  360. if (pThis->m_cyItem)
  361. pThis->SetSelection(pThis->m_iTopItem + (HIWORD(lParam) / pThis->m_cyItem));
  362. pThis->Notify(NM_CLICK);
  363. break;
  364. case WM_LBUTTONDBLCLK:
  365. SetFocus(hWnd);
  366. if (pThis->m_cyItem)
  367. if (pThis->m_iSelItem == (pThis->m_iTopItem + (HIWORD(lParam) / pThis->m_cyItem)))
  368. pThis->ItemDoubleClicked(pThis->m_iSelItem);
  369. break;
  370. case WM_RBUTTONDOWN:
  371. SetFocus(hWnd);
  372. pThis->Notify(NM_RCLICK);
  373. break;
  374. case WM_RBUTTONDBLCLK:
  375. SetFocus(hWnd);
  376. pThis->Notify(NM_RDBLCLK);
  377. break;
  378. case WM_GETDLGCODE:
  379. return DLGC_WANTARROWS;
  380. break;
  381. case WM_ERASEBKGND:
  382. if ( pThis->m_hbmpBackGround )
  383. {
  384. RECT rc;
  385. HDC hdc = (HDC) wParam;
  386. GetClientRect(hWnd, &rc);
  387. CPalDC dc(pThis->m_hbmpBackGround);
  388. HPALETTE hpalTmp = NULL;
  389. if (pThis->m_hpalBackGround) {
  390. hpalTmp = SelectPalette(hdc, pThis->m_hpalBackGround, FALSE);
  391. RealizePalette(hdc);
  392. }
  393. for (int left = 0; left <= rc.right; left += pThis->m_cxBackBmp) {
  394. for (int top = 0; top <= rc.bottom; top += pThis->m_cyBackBmp) {
  395. BitBlt(hdc, left, top, min(pThis->m_cxBackBmp, rc.right - left),
  396. min(pThis->m_cyBackBmp, rc.bottom - top), dc, 0, 0, SRCCOPY);
  397. }
  398. }
  399. if (hpalTmp)
  400. SelectPalette(hdc, hpalTmp, FALSE);
  401. return TRUE;
  402. }
  403. else if ( pThis->m_hbrBackGround )
  404. {
  405. RECT rc;
  406. GetClipBox((HDC) wParam, &rc);
  407. FillRect((HDC) wParam, &rc, pThis->m_hbrBackGround);
  408. return TRUE;
  409. }
  410. else
  411. return DefWindowProc(hWnd, msg, wParam, lParam);
  412. default:
  413. return DefWindowProc(hWnd, msg, wParam, lParam);
  414. }
  415. return 0;
  416. }
  417. //
  418. // Something Ralphs code must use. Maybe this can go away ?
  419. // 09-Nov-1997 [ralphw] Nope, it can't go away.
  420. //
  421. void CVirtualListCtrl::PaintParamsSetup(COLORREF clrBackground, COLORREF clrForeground, LPCSTR pszBackBitmap)
  422. {
  423. if (clrBackground != -1 && clrForeground != -1) {
  424. HDC hdc = GetWindowDC(m_hWnd);
  425. // If the colors are the same, then ignore them both
  426. if (GetHighContrastFlag() || GetNearestColor(hdc, clrBackground) == GetNearestColor(hdc, clrForeground))
  427. m_clrBackground = m_clrForeground = (COLORREF) -1;
  428. ReleaseDC(m_hWnd, hdc);
  429. }
  430. if (m_clrBackground != -1)
  431. m_hbrBackGround = CreateSolidBrush(m_clrBackground);
  432. if ( pszBackBitmap ) {
  433. char szBitmap[MAX_PATH];
  434. if (ConvertToCacheFile(pszBackBitmap, szBitmap) &&
  435. LoadGif(szBitmap, &m_hbmpBackGround, &m_hpalBackGround, NULL)) {
  436. BITMAP bmp;
  437. GetObject(m_hbmpBackGround, sizeof(BITMAP), &bmp);
  438. m_cxBackBmp = bmp.bmWidth;
  439. m_cyBackBmp = bmp.bmHeight;
  440. }
  441. }
  442. }
  443. HWND CVirtualListCtrl::CreateVlistbox(HWND hWndParent, RECT* prc)
  444. {
  445. WNDCLASS wc;
  446. WNDCLASSEX wci;
  447. if (! GetClassInfoEx(_Module.GetModuleInstance(), "hh_kwd_vlist", &wci) )
  448. {
  449. wc.style = CS_DBLCLKS; // | CS_HREDRAW | CS_VREDRAW;
  450. wc.lpfnWndProc = StaticWindowProc;
  451. wc.hIcon = NULL;
  452. wc.cbClsExtra = 0;
  453. wc.cbWndExtra = sizeof(CVirtualListCtrl*);
  454. wc.hInstance = _Module.GetModuleInstance();
  455. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  456. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  457. wc.lpszMenuName = NULL;
  458. wc.lpszClassName = "hh_kwd_vlist";
  459. if (! RegisterClass(&wc) )
  460. return FALSE;
  461. }
  462. CreateWindowEx(WS_EX_CLIENTEDGE | g_RTL_Style | (m_fBiDi ? WS_EX_LEFTSCROLLBAR : 0),
  463. "hh_kwd_vlist", NULL,
  464. WS_CHILD|WS_BORDER|WS_VISIBLE|WS_GROUP|WS_TABSTOP|WS_VSCROLL,
  465. prc->left, prc->top, (prc->right - prc->left), (prc->bottom - prc->top), hWndParent,
  466. (HMENU) IDC_KWD_VLIST, _Module.GetModuleInstance(), this);
  467. m_hWndParent = hWndParent;
  468. return m_hWnd;
  469. }