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.

434 lines
11 KiB

  1. /*
  2. * LISTS.C
  3. *
  4. * This file implements a generalized multi-collumn listbox with a standard
  5. * frame window.
  6. */
  7. #define UNICODE
  8. #include <windows.h>
  9. #include <windowsx.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include "ddespy.h"
  13. #include "globals.h"
  14. #include "lists.h"
  15. int CompareItems(LPTSTR psz1, LPTSTR psz2, INT SortCol, INT cCols);
  16. int CmpCols(LPTSTR psz1, LPTSTR psz2, INT SortCol);
  17. void DrawLBItem(LPDRAWITEMSTRUCT lpdis);
  18. LRESULT CALLBACK MCLBClientWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPAram);
  19. UINT cyHeading;
  20. #ifdef UNICODE
  21. #define atoi atoiW
  22. //*********************************************************************
  23. //
  24. // atoiW
  25. //
  26. // Unicode version of atoi.
  27. //
  28. INT atoiW (LPTSTR s) {
  29. INT i = 0;
  30. while (isdigit (*s)) {
  31. i = i*10 + (BYTE)*s - TEXT('0');
  32. s++;
  33. }
  34. return i;
  35. }
  36. #endif
  37. HWND CreateMCLBFrame(
  38. HWND hwndParent,
  39. LPTSTR lpszTitle, // frame title string
  40. UINT dwStyle, // frame styles
  41. HICON hIcon,
  42. HBRUSH hbrBkgnd, // background for heading.
  43. LPTSTR lpszHeadings) // tab delimited list of headings. The number of
  44. // headings indicate the number of collumns.
  45. {
  46. static BOOL fRegistered = FALSE;
  47. MCLBCREATESTRUCT mclbcs;
  48. if (!fRegistered) {
  49. WNDCLASS wc;
  50. HDC hdc;
  51. TEXTMETRIC tm;
  52. wc.style = WS_OVERLAPPED | CS_HREDRAW | CS_VREDRAW;
  53. wc.lpfnWndProc = MCLBClientWndProc;
  54. wc.cbClsExtra = 0;
  55. wc.cbWndExtra = 4;
  56. wc.hInstance = hInst;
  57. wc.hIcon = hIcon;
  58. wc.hCursor = NULL;
  59. wc.hbrBackground = hbrBkgnd;
  60. wc.lpszMenuName = NULL;
  61. wc.lpszClassName = (LPCTSTR) RefString(IDS_LISTCLASS);
  62. RegisterClass(&wc);
  63. hdc = GetDC(GetDesktopWindow());
  64. GetTextMetrics(hdc, &tm);
  65. cyHeading = tm.tmHeight;
  66. ReleaseDC(GetDesktopWindow(), hdc);
  67. fRegistered = TRUE;
  68. }
  69. mclbcs.lpszHeadings = lpszHeadings;
  70. return(CreateWindow((LPCTSTR) RefString(IDS_LISTCLASS),
  71. (LPCTSTR) lpszTitle, dwStyle,
  72. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  73. hwndParent, NULL, hInst, (LPVOID)&mclbcs));
  74. }
  75. LRESULT CALLBACK MCLBClientWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  76. {
  77. MCLBSTRUCT *pmclb;
  78. RECT rc;
  79. INT i;
  80. if (msg == WM_CREATE) {
  81. LPTSTR psz;
  82. MCLBCREATESTRUCT FAR *pcs;
  83. pcs = (MCLBCREATESTRUCT FAR *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  84. pmclb = (MCLBSTRUCT *)LocalAlloc(LPTR, sizeof(MCLBSTRUCT));
  85. psz = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)
  86. * (lstrlen(pcs->lpszHeadings) + 1));
  87. lstrcpy((LPTSTR)psz, pcs->lpszHeadings);
  88. pmclb->pszHeadings = psz;
  89. pmclb->cCols = 1;
  90. while (*psz) {
  91. if (*psz == '\t') {
  92. pmclb->cCols++;
  93. }
  94. psz++;
  95. }
  96. pmclb->SortCol = 0;
  97. SetWindowLongPtr(hwnd, 0, (LONG_PTR)pmclb);
  98. GetClientRect(hwnd, &rc);
  99. pmclb->hwndLB = CreateWindow((LPCTSTR) RefString(IDS_LBOX),
  100. (LPCTSTR) szNULL,
  101. MYLBSTYLE | WS_VISIBLE,
  102. 0, 0, 0, 0, hwnd, (HMENU)IntToPtr(pmclb->cCols), hInst, NULL);
  103. return(pmclb->hwndLB ? 0 : -1);
  104. }
  105. pmclb = (MCLBSTRUCT *)GetWindowLongPtr(hwnd, 0);
  106. switch (msg) {
  107. case WM_PAINT:
  108. {
  109. PAINTSTRUCT ps;
  110. DRAWITEMSTRUCT dis;
  111. BeginPaint(hwnd, &ps);
  112. SetBkMode(ps.hdc, TRANSPARENT);
  113. dis.hwndItem = hwnd;
  114. dis.hDC = ps.hdc;
  115. GetClientRect(hwnd, &dis.rcItem);
  116. dis.rcItem.bottom = dis.rcItem.top + cyHeading;
  117. dis.CtlType = ODT_BUTTON; // hack to avoid erasure
  118. dis.CtlID = pmclb->cCols;
  119. dis.itemID = 0;
  120. dis.itemAction = ODA_DRAWENTIRE;
  121. dis.itemData = (UINT_PTR)(LPTSTR)pmclb->pszHeadings;
  122. dis.itemState = 0;
  123. DrawLBItem(&dis);
  124. EndPaint(hwnd, &ps);
  125. }
  126. break;
  127. case WM_SIZE:
  128. MoveWindow(pmclb->hwndLB, 0, cyHeading, LOWORD(lParam),
  129. HIWORD(lParam) - cyHeading, TRUE);
  130. break;
  131. case WM_LBUTTONDOWN:
  132. {
  133. HWND hwndLB;
  134. INT i;
  135. // determine which collumn the mouse landed and sort on that collumn.
  136. SendMessage(hwnd, WM_SETREDRAW, 0, 0);
  137. GetClientRect(hwnd, &rc);
  138. InflateRect(&rc, -1, -1);
  139. pmclb->SortCol = LOWORD(lParam) * pmclb->cCols / (rc.right - rc.left);
  140. hwndLB = CreateWindow((LPCTSTR) RefString(IDS_LBOX),
  141. (LPCTSTR) szNULL, MYLBSTYLE, 1, cyHeading + 1,
  142. rc.right - rc.left, rc.bottom - rc.top - cyHeading,
  143. hwnd, (HMENU)IntToPtr(pmclb->cCols), hInst, NULL);
  144. for (i = (INT)SendMessage(pmclb->hwndLB, LB_GETCOUNT, 0, 0); i;
  145. i--) {
  146. SendMessage(hwndLB, LB_ADDSTRING, 0,
  147. SendMessage(pmclb->hwndLB, LB_GETITEMDATA, i - 1, 0));
  148. SendMessage(pmclb->hwndLB, LB_SETITEMDATA, i - 1, 0);
  149. }
  150. ShowWindow(hwndLB, SW_SHOW);
  151. ShowWindow(pmclb->hwndLB, SW_HIDE);
  152. DestroyWindow(pmclb->hwndLB);
  153. pmclb->hwndLB = hwndLB;
  154. SendMessage(hwnd, WM_SETREDRAW, 1, 0);
  155. InvalidateRect(hwnd, NULL, FALSE);
  156. }
  157. break;
  158. case WM_DELETEITEM:
  159. if ((UINT)((LPDELETEITEMSTRUCT)lParam)->itemData)
  160. LocalFree(LocalHandle((PVOID)((LPDELETEITEMSTRUCT)lParam)->itemData));
  161. break;
  162. case WM_MEASUREITEM:
  163. ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = cyHeading;
  164. break;
  165. case WM_DRAWITEM:
  166. GetClientRect(hwnd, &rc);
  167. // This fudge makes the collumns line up with the heading.
  168. ((LPDRAWITEMSTRUCT)lParam)->rcItem.right = rc.right;
  169. DrawLBItem((LPDRAWITEMSTRUCT)lParam);
  170. return(DefWindowProc(hwnd, msg, wParam, lParam));
  171. break;
  172. case WM_COMPAREITEM:
  173. return(CompareItems((LPTSTR)((LPCOMPAREITEMSTRUCT)lParam)->itemData1,
  174. (LPTSTR)((LPCOMPAREITEMSTRUCT)lParam)->itemData2,
  175. pmclb->SortCol,
  176. pmclb->cCols));
  177. break;
  178. case WM_DESTROY:
  179. LocalFree(LocalHandle((PVOID)pmclb->pszHeadings));
  180. LocalFree(LocalHandle((PVOID)pmclb));
  181. break;
  182. case WM_CLOSE:
  183. for (i = 0; i < IT_COUNT && (hwndTrack[i] != hwnd); i++) {
  184. ;
  185. }
  186. pro.fTrack[i] = FALSE;
  187. hwndTrack[i] = NULL;
  188. SetFilters();
  189. DestroyWindow(hwnd);
  190. break;
  191. default:
  192. return(DefWindowProc(hwnd, msg, wParam, lParam));
  193. }
  194. return 0;
  195. }
  196. /*
  197. * Make this return FALSE if addition not needed.
  198. *
  199. * if pszSearch != NULL, searches for pszSearch - collumns may contain
  200. * wild strings - TEXT("*")
  201. * If found, the string is removed from the LB.
  202. * Adds pszReplace to LB.
  203. */
  204. VOID AddMCLBText(LPTSTR pszSearch, LPTSTR pszReplace, HWND hwndLBFrame)
  205. {
  206. MCLBSTRUCT *pmclb;
  207. INT lit;
  208. LPTSTR psz;
  209. pmclb = (MCLBSTRUCT *)GetWindowLongPtr(hwndLBFrame, 0);
  210. SendMessage(pmclb->hwndLB, WM_SETREDRAW, 0, 0);
  211. if (pszSearch != NULL) {
  212. lit = (INT)SendMessage(pmclb->hwndLB, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pszSearch);
  213. if (lit >= 0) {
  214. SendMessage(pmclb->hwndLB, LB_DELETESTRING, lit, 0);
  215. }
  216. }
  217. psz = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * (lstrlen(pszReplace) + 1));
  218. lstrcpy(psz, pszReplace);
  219. SendMessage(pmclb->hwndLB, WM_SETREDRAW, 1, 0);
  220. SendMessage(pmclb->hwndLB, LB_ADDSTRING, 0, (LPARAM)psz);
  221. }
  222. /*
  223. * This function assumes that the text in cCol is an ASCII number. 0 is
  224. * returned if it is not found.
  225. */
  226. INT GetMCLBColValue(LPTSTR pszSearch, HWND hwndLBFrame, INT cCol)
  227. {
  228. MCLBSTRUCT *pmclb;
  229. LPTSTR psz;
  230. INT lit;
  231. pmclb = (MCLBSTRUCT *)GetWindowLongPtr(hwndLBFrame, 0);
  232. lit = (INT)SendMessage(pmclb->hwndLB, LB_FINDSTRING, (WPARAM)-1,
  233. (LPARAM)(LPTSTR)pszSearch);
  234. if (lit < 0) {
  235. return(0);
  236. }
  237. psz = (LPTSTR)SendMessage(pmclb->hwndLB, LB_GETITEMDATA, lit, 0);
  238. while (--cCol && (psz = wcschr(psz, '\t') + 1)) {
  239. ;
  240. }
  241. if (psz) {
  242. return(atoi(psz));
  243. } else {
  244. return(0);
  245. }
  246. }
  247. /*
  248. * Returns fFoundAndRemoved
  249. */
  250. BOOL DeleteMCLBText(LPTSTR pszSearch, HWND hwndLBFrame)
  251. {
  252. MCLBSTRUCT *pmclb;
  253. INT lit;
  254. pmclb = (MCLBSTRUCT *)GetWindowLongPtr(hwndLBFrame, 0);
  255. lit = (INT)SendMessage(pmclb->hwndLB, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pszSearch);
  256. if (lit >= 0) {
  257. SendMessage(pmclb->hwndLB, LB_DELETESTRING, lit, 0);
  258. return(TRUE);
  259. }
  260. return(FALSE);
  261. }
  262. /*
  263. * Returns >0 if item1 comes first, <0 if item2 comes first, 0 if ==.
  264. */
  265. INT CompareItems(LPTSTR psz1, LPTSTR psz2, INT SortCol, INT cCols)
  266. {
  267. INT i, Col;
  268. i = CmpCols(psz1, psz2, SortCol);
  269. if (i != 0) {
  270. return(i);
  271. }
  272. for (Col = 0; Col < cCols; Col++) {
  273. if (Col == SortCol) {
  274. continue;
  275. }
  276. i = CmpCols(psz1, psz2, Col);
  277. if (i != 0) {
  278. return(i);
  279. }
  280. }
  281. return(0);
  282. }
  283. INT CmpCols(LPTSTR psz1, LPTSTR psz2, INT SortCol)
  284. {
  285. LPTSTR psz, pszT1, pszT2;
  286. INT iRet;
  287. while (SortCol--) {
  288. psz = wcschr(psz1, '\t');
  289. if (psz != NULL) {
  290. psz1 = psz + 1;
  291. } else {
  292. psz1 = psz1 + lstrlen(psz1);
  293. }
  294. psz = wcschr(psz2, '\t');
  295. if (psz != NULL) {
  296. psz2 = psz + 1;
  297. } else {
  298. psz2 = psz2 + lstrlen(psz2);
  299. }
  300. }
  301. pszT1 = wcschr(psz1, '\t');
  302. pszT2 = wcschr(psz2, '\t');
  303. if (pszT1) {
  304. *pszT1 = '\0';
  305. }
  306. if (pszT2) {
  307. *pszT2 = '\0';
  308. }
  309. if (!lstrcmp((LPCTSTR)RefString(IDS_WILD), psz1)
  310. || !lstrcmp((LPCTSTR) RefString(IDS_WILD), psz2)) {
  311. iRet = 0;
  312. } else {
  313. iRet = lstrcmp(psz1, psz2);
  314. }
  315. if (pszT1) {
  316. *pszT1 = '\t';
  317. }
  318. if (pszT2) {
  319. *pszT2 = '\t';
  320. }
  321. return(iRet);
  322. }
  323. VOID DrawLBItem(LPDRAWITEMSTRUCT lpdis)
  324. {
  325. RECT rcDraw;
  326. INT cxSection;
  327. LPTSTR psz, pszEnd;
  328. if (!lpdis->itemData)
  329. return;
  330. if ((lpdis->itemAction & ODA_DRAWENTIRE) ||
  331. ((lpdis->itemAction & ODA_SELECT) &&
  332. (lpdis->itemState & ODS_SELECTED))) {
  333. rcDraw = lpdis->rcItem;
  334. if (lpdis->CtlType != ODT_BUTTON) { // hack to avoid erasure
  335. HBRUSH hbr;
  336. hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  337. FillRect(lpdis->hDC, &lpdis->rcItem, hbr);
  338. DeleteObject(hbr);
  339. }
  340. cxSection = (rcDraw.right - rcDraw.left) / lpdis->CtlID;
  341. psz = (LPTSTR)lpdis->itemData;
  342. rcDraw.right = rcDraw.left + cxSection;
  343. while (pszEnd = wcschr(psz, '\t')) {
  344. *pszEnd = '\0';
  345. DrawText(lpdis->hDC, psz, -1, &rcDraw, DT_LEFT);
  346. OffsetRect(&rcDraw, cxSection, 0);
  347. *pszEnd = '\t';
  348. psz = pszEnd + 1;
  349. }
  350. DrawText(lpdis->hDC, psz, -1, &rcDraw, DT_LEFT);
  351. if (lpdis->itemState & ODS_SELECTED)
  352. InvertRect(lpdis->hDC, &lpdis->rcItem);
  353. if (lpdis->itemState & ODS_FOCUS)
  354. DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
  355. } else if (lpdis->itemAction & ODA_SELECT) {
  356. InvertRect(lpdis->hDC, &lpdis->rcItem);
  357. } else if (lpdis->itemAction & ODA_FOCUS) {
  358. DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
  359. }
  360. }