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