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