home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / ddespy / lists.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  13KB  |  443 lines

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