home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / LISTCTRL.PAK / LISTVIEW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  15.3 KB  |  547 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   listview.c
  9. //
  10. //  PURPOSE:   Implement the functions specific to the listview control.
  11. //
  12. //  FUNCTIONS:
  13. //    MsgNotify              - Processes the WM_NOTIFY message
  14. //    ListViewCompareProc    - Callback routine for sorting listview items
  15. //    InitListViewImageLists - Initialize the listview image lists
  16. //    InitListViewColumns    - Specify the text for the column headings.
  17. //    InitListViewItems      - Add the items to the listview control
  18. //    CreateListView         - Create the listview control
  19. //    SwitchView             - Change the visual view of the listview control
  20. //
  21. //  COMMENTS:
  22. //
  23.  
  24. #include <windows.h>            // required for all Windows applications
  25. #include <windowsx.h>
  26. #include <commctrl.h>
  27. #include "globals.h"            // prototypes specific to this application
  28. #include "listview.h"           // prototypes and defines specific to the
  29.                                 // listview control
  30. #include "resource.h"
  31.  
  32. // Module specific globals
  33.  
  34. STOCKINFO rgStockInfo[]=
  35. {
  36.     {"Banc One",     "ONE",      "NYSE",      33, 32, 33, "Yes"},
  37.     {"Borland",      "BORL",     "NASDAQ",    14, 13, 13, "Yes"},
  38.     {"Intel",        "INTC",     "NASDAQ",    65, 64, 64, "No"},
  39.     {"Kodak",        "EK",       "NYSE",      45, 43, 44, "Yes"},
  40.     {"Microsoft",    "MSFT",     "NASDAQ",    80, 78, 79, "Yes"},
  41. };
  42.  
  43.  
  44. //
  45. //  FUNCTION: MsgNotify(HWND, UINT, WPARAM, LPARAM)
  46. //
  47. //  PURPOSE: Processes the WM_NOTIFY message sent by the listview control
  48. //
  49. //  PARAMETERS:
  50. //
  51. //    hwnd      - Window handle  (Unused)
  52. //    uMessage  - Message number (Unused)
  53. //    wparam    - Extra data     (Unused)
  54. //    lparam    - Extra data     (Unused)
  55. //
  56. //  RETURN VALUE:
  57. //
  58. //    Always returns 0 - Message handled
  59. //
  60. //  COMMENTS:
  61. //
  62. //
  63.  
  64. #pragma argsused
  65. LRESULT MsgNotify(HWND   hwnd,
  66.                   UINT   uMessage, 
  67.                   WPARAM wparam, 
  68.                   LPARAM lparam)
  69. {
  70.     LPNM_LISTVIEW  pnm    = (LPNM_LISTVIEW)lparam;
  71.     HWND           hwndLV = pnm->hdr.hwndFrom;
  72.     UINT           state;
  73.     DWORD          dwpos;
  74.     LV_HITTESTINFO lvhti;
  75.     int            iItemClicked;
  76.  
  77.     if (wparam != IDD_LISTVIEW)
  78.        return 0L;
  79.  
  80.     switch (pnm->hdr.code)
  81.     {
  82.         case LVN_GETDISPINFO:
  83.         {
  84.             LV_DISPINFO *plvdi = (LV_DISPINFO *)lparam;
  85.             STOCKINFO   *pi    = (STOCKINFO *)(plvdi->item.lParam);
  86.  
  87.             if (plvdi->item.mask & LVIF_TEXT)
  88.             {
  89.                 switch (plvdi->item.iSubItem)
  90.                 {
  91.                     case 0:
  92.                         
  93.                         plvdi->item.pszText = pi->szCompany;
  94.                         break;
  95.  
  96.                     case 1:
  97.  
  98.                         plvdi->item.pszText = pi->szSymbol;
  99.                         break;
  100.  
  101.                     case 2:
  102.  
  103.                         plvdi->item.pszText = pi->szExchange;
  104.                         break;
  105.  
  106.                     case 3:
  107.  
  108.                         //Before sending the WM_NOTIFY/LVN_GETDISPINFO message,
  109.                         //the control has allocated plvdi->item.cchTextMax 
  110.                         //characters for the plvdi->item.pszText member.
  111.                         //Since we will only be copying 3 characters (including
  112.                         //the NULL terminator), we don't bother checking
  113.                         //plvdi->item.cchTextMax since it's set to MAX_PATH in this
  114.                         //version of Windows 95.
  115.                         
  116.                         wsprintf(plvdi->item.pszText, "%u", pi->iHigh);
  117.                         break;
  118.  
  119.                     case 4:
  120.  
  121.                         wsprintf(plvdi->item.pszText, "%u", pi->iLow);
  122.                         break;
  123.  
  124.                     case 5:
  125.  
  126.                         wsprintf(plvdi->item.pszText, "%u", pi->iClose);
  127.                         break;
  128.  
  129.                     case 6:
  130.  
  131.                         plvdi->item.pszText = pi->szNews;
  132.                         break;
  133.                   
  134.                     default:
  135.                         break;
  136.                 }
  137.  
  138.                 break;
  139.             }
  140.  
  141.             break;
  142.         }
  143.         
  144.         case LVN_ENDLABELEDIT:
  145.  
  146.             return TRUE;
  147.  
  148.         case LVN_SETDISPINFO:
  149.  
  150.         {
  151.             LV_DISPINFO *plvdi = (LV_DISPINFO *)lparam;
  152.             STOCKINFO   *pi    = (STOCKINFO *)(plvdi->item.lParam);
  153.  
  154. //We really should check the mask here, but Win95 does not set this bit before
  155. //sending the LVN_SETDISPINFO notification.  The *only* time LVN_SETDISPINFO is
  156. //sent is when the text has been modified, so you can assume the pszText member
  157. //is valid.
  158. //            if (plvdi->item.mask & LVIF_TEXT)
  159.  
  160.             lstrcpy(pi->szCompany, plvdi->item.pszText);
  161.             PostMessage(hwnd, WM_COMMAND, IDM_EDITSTOCKINFO, 0L);
  162.             break;
  163.         }
  164.  
  165.         case LVN_COLUMNCLICK:
  166.  
  167.             ListView_SortItems(pnm->hdr.hwndFrom,
  168.                                ListViewCompareProc,
  169.                                (LPARAM)(pnm->iSubItem));
  170.             break;
  171.  
  172.         case NM_CLICK:
  173.         case NM_RCLICK:
  174.  
  175.             // This code does the check box stuff...
  176.  
  177.             // Find out where the cursor was
  178.             dwpos = GetMessagePos();
  179.             lvhti.pt.x = LOWORD(dwpos);
  180.             lvhti.pt.y = HIWORD(dwpos);
  181.  
  182.             MapWindowPoints(HWND_DESKTOP, hwndLV, &lvhti.pt, 1);
  183.  
  184.             // Now do a hittest with this point.
  185.             iItemClicked = ListView_HitTest(hwndLV, &lvhti);
  186.  
  187.             if (lvhti.flags & LVHT_ONITEMSTATEICON)
  188.             {
  189.                 // Now lets get the state from the item and toggle it.
  190.                 state = ListView_GetItemState(hwndLV, 
  191.                                               iItemClicked, 
  192.                                               LVIS_STATEIMAGEMASK);
  193.  
  194.                 state = (state == LVIS_GCNOCHECK) ? LVIS_GCCHECK : LVIS_GCNOCHECK;
  195.  
  196.                 ListView_SetItemState(hwndLV,
  197.                                       iItemClicked,
  198.                                       state, 
  199.                                       LVIS_STATEIMAGEMASK);
  200.             }
  201.             break;
  202.  
  203.         default:
  204.             break;
  205.     }
  206.  
  207.     return 0;
  208. }
  209.  
  210.  
  211. //
  212. //  FUNCTION: ListViewCompareProc(LPARAM, LPARAM, LPARAM)
  213. //
  214. //  PURPOSE: Callback routine for sorting list
  215. //
  216. //  PARAMETERS:
  217. //
  218. //    lparam1    - Pointer to STOCKINFO structure
  219. //    lparam2    - Pointer to STOCKINFO structure
  220. //    lparamSort - Column being sorted.  Same value that was
  221. //                 passed in the lparam of the ListView_SortItems()
  222. //                 call.
  223. //
  224. //  RETURN VALUE:
  225. //
  226. //    Always returns 0 - Message handled
  227. //
  228. //  COMMENTS:
  229. //    lparam1 and lparam2 are pointers to STOCKINFO structures.
  230. //    These two parameters will always point to the same type of
  231. //    structure that was specified in the lparam of the LV_ITEM
  232. //    structure when the item was added.  See InitListViewItems()
  233. //    below, where the lvi.lparam value is set.
  234. //
  235.  
  236. int CALLBACK ListViewCompareProc(LPARAM lparam1, 
  237.                                  LPARAM lparam2,
  238.                                  LPARAM lparamSort)
  239. {
  240.     STOCKINFO *pRec1 = (STOCKINFO *)lparam1;
  241.     STOCKINFO *pRec2 = (STOCKINFO *)lparam2;
  242.     LPSTR     lpString1 = NULL, lpString2 = NULL;
  243.     char      szTemp1[5];
  244.     char      szTemp2[5];
  245.     int       iResult = 1;
  246.  
  247.     if (pRec1 && pRec2)
  248.     {
  249.         switch (lparamSort)
  250.         {
  251.             case 0:
  252.                 lpString1 = pRec1->szCompany;
  253.                 lpString2 = pRec2->szCompany;
  254.                 break;             
  255.  
  256.             case 1:
  257.                 lpString1 = pRec1->szSymbol;
  258.                 lpString2 = pRec2->szSymbol;
  259.                 break;
  260.  
  261.             case 2:
  262.                 lpString1 = pRec1->szExchange;
  263.                 lpString2 = pRec2->szExchange;
  264.                 break;
  265.  
  266.             case 3:
  267.                 wsprintf(szTemp1, "%d", pRec1->iHigh);
  268.                 wsprintf(szTemp2, "%d", pRec2->iHigh);
  269.                 lpString1 = szTemp1;
  270.                 lpString2 = szTemp2;
  271.                 break;
  272.  
  273.             case 4:
  274.                 wsprintf(szTemp1, "%d", pRec1->iLow);
  275.                 wsprintf(szTemp2, "%d", pRec2->iLow);
  276.                 lpString1 = szTemp1;
  277.                 lpString2 = szTemp2;
  278.                 break;
  279.  
  280.             case 5:
  281.                 wsprintf(szTemp1, "%d", pRec1->iClose);
  282.                 wsprintf(szTemp2, "%d", pRec2->iClose);
  283.                 lpString1 = szTemp1;
  284.                 lpString2 = szTemp2;
  285.                 break;
  286.  
  287.             case 6:
  288.                 lpString1 = pRec1->szNews;
  289.                 lpString2 = pRec2->szNews;
  290.                 break;
  291.  
  292.             default:
  293.                 break;
  294.         }
  295.  
  296.         iResult = lstrcmpi(lpString1, lpString2);
  297.  
  298.         //Now, if the strings are equal, compare the szCompany fields
  299.         if (!iResult)
  300.            iResult = lstrcmpi(pRec1->szCompany, pRec2->szCompany);
  301.     }
  302.  
  303.     return iResult;
  304. }
  305.  
  306.  
  307. //
  308. //  FUNCTION: InitListViewImageLists(HWND)
  309. //
  310. //  PURPOSE: Fill the image lists with the icons images that will
  311. //           be used when displaying the items.
  312. //
  313. //  PARAMETERS:
  314. //
  315. //    HWND - Handle to the listview control
  316. //
  317. //  RETURN VALUE:
  318. //
  319. //    TRUE  - if image lists were successfully initialized
  320. //    FALSE - if image lists were not successfully initialized
  321. //
  322. //  COMMENTS:
  323. //
  324.  
  325. BOOL WINAPI InitListViewImageLists(HWND hwndLV)
  326. {
  327.     HICON hicon;
  328.     UINT  i;
  329.     HIMAGELIST himlSmall;
  330.     HIMAGELIST himlLarge;
  331.     HIMAGELIST himlState;
  332.  
  333.     himlSmall = ImageList_Create(16, 16, TRUE, IDC_NUMITEMS, 0); 
  334.     himlLarge = ImageList_Create(32, 32, TRUE, IDC_NUMITEMS, 0); 
  335.     himlState = ImageList_Create(16, 16, TRUE, 2, 0);
  336.  
  337.     ImageList_AddMasked (himlState, 
  338.                          LoadBitmap (hInst,MAKEINTRESOURCE(IDB_CHECKSTATES)),
  339.                          RGB (255,0,0));
  340.     
  341.     for (i = IDC_ONE; i <= IDC_MSFT; i++)
  342.     {
  343.         hicon = LoadIcon(hInst, MAKEINTRESOURCE(i));
  344.         if (ImageList_AddIcon(himlSmall, hicon) == -1 ||
  345.             ImageList_AddIcon(himlLarge, hicon) == -1)
  346.             return FALSE;
  347.     }
  348.  
  349.     (void) ListView_SetImageList(hwndLV, himlLarge, LVSIL_NORMAL);
  350.     (void) ListView_SetImageList(hwndLV, himlSmall, LVSIL_SMALL);
  351.     (void) ListView_SetImageList(hwndLV, himlState, LVSIL_STATE);
  352.  
  353.     return TRUE;
  354. }
  355.  
  356.  
  357. //
  358. //  FUNCTION: InitListViewColumns(HWND)
  359. //
  360. //  PURPOSE: Specify the text for the column headings.
  361. //
  362. //  PARAMETERS:
  363. //
  364. //    HWND - Handle to the listview control
  365. //
  366. //  RETURN VALUE:
  367. //
  368. //    TRUE  - if column headings were successfully initialized
  369. //    FALSE - if column headings were not successfully initialized
  370. //
  371. //  COMMENTS:
  372. //
  373.  
  374. BOOL WINAPI InitListViewColumns(HWND hwndLV)
  375. {
  376.     LV_COLUMN lvc;
  377.     int       iCol;
  378.     char      szText[IDC_MAXCOLUMNHDG];
  379.  
  380.     // Initialize the LV_COLUMN structure.
  381.  
  382.     lvc.mask    = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  383.     lvc.fmt     = LVCFMT_LEFT;
  384.     lvc.cx      = 95;
  385.     lvc.pszText = szText; 
  386.  
  387.     // Add the columns.  NOTE: This code assumes that IDS_COMPANYCOLUMN
  388.     // is the first string in the group, and that the other strings are
  389.     // in numerical order following.  See LISTVIEW.H for the defines.
  390.  
  391.     for (iCol = 0; iCol < IDC_NUMCOLUMNS; iCol++)
  392.     {
  393.         lvc.iSubItem = iCol;
  394.         LoadString(hInst, 
  395.                    IDS_COMPANYCOLUMN + iCol,
  396.                    szText,
  397.                    sizeof(szText));
  398.         if (ListView_InsertColumn(hwndLV, iCol, &lvc) == -1)
  399.             return FALSE;
  400.     }
  401.  
  402. //  Now, set the column widths based on the header.  I really want to put
  403. //  this in the loop above, but for some reason it doesn't like it there.
  404.  
  405.     for (iCol = 1; iCol < IDC_NUMCOLUMNS; iCol++)
  406.         ListView_SetColumnWidth(hwndLV, iCol, LVSCW_AUTOSIZE_USEHEADER);
  407.     return TRUE;
  408. }
  409.  
  410.  
  411. //
  412. //  FUNCTION: InitListViewItems(HWND)
  413. //
  414. //  PURPOSE: Add the items to the listview control
  415. //
  416. //  PARAMETERS:
  417. //
  418. //    HWND - Handle to the listview control
  419. //
  420. //  RETURN VALUE:
  421. //
  422. //    TRUE  - if items were successfully added
  423. //    FALSE - if items were not successfully added
  424. //
  425. //  COMMENTS:
  426. //
  427.  
  428. BOOL WINAPI InitListViewItems(HWND hwndLV)
  429. {
  430.     LV_ITEM lvi;
  431.     int iItem;
  432.     int iSubItem;
  433.                                                  
  434.  
  435.     lvi.mask        = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  436.     lvi.state       = LVIS_GCNOCHECK;
  437.     lvi.stateMask   = LVIS_STATEIMAGEMASK;
  438.  
  439.     for (iItem = 0; iItem < IDC_NUMITEMS; iItem++)
  440.     {
  441.         lvi.iItem       = iItem;
  442.         lvi.iSubItem    = 0;
  443.         lvi.pszText     = LPSTR_TEXTCALLBACK;
  444.         lvi.cchTextMax  = IDC_MAXCOMPANYLEN;
  445.         lvi.iImage      = iItem;
  446.         lvi.lParam      = (LPARAM)&rgStockInfo[iItem];
  447.  
  448.         if (ListView_InsertItem(hwndLV, &lvi) == -1)
  449.            return FALSE;
  450.  
  451.         for (iSubItem = 1; iSubItem < IDC_NUMCOLUMNS; iSubItem++)
  452.         {
  453.             ListView_SetItemText(hwndLV,
  454.                                  iItem, 
  455.                                  iSubItem, 
  456.                                  LPSTR_TEXTCALLBACK);
  457.         }
  458.     }
  459.  
  460.     return TRUE;
  461. }
  462.  
  463.  
  464. //
  465. //  FUNCTION: CreateListView(HWND)
  466. //
  467. //  PURPOSE: Create the listview control
  468. //
  469. //  PARAMETERS:
  470. //
  471. //    HWND - Handle to the parent window
  472. //
  473. //  RETURN VALUE:
  474. //
  475. //    hwndLV - Handle to listview control if successful
  476. //    NULL   - if creation of listview control fails
  477. //
  478. //  COMMENTS:
  479. //
  480.  
  481. HWND WINAPI CreateListView(HWND hwndParent)
  482. {
  483.     HWND hwndLV;
  484.     RECT rc;
  485.  
  486.     // Force the common controls DLL to be loaded.
  487.  
  488.     InitCommonControls();
  489.  
  490.     // Create the control.
  491.  
  492.     GetClientRect(hwndParent, &rc);
  493.  
  494.     hwndLV = CreateWindow(WC_LISTVIEW, "",
  495.                           WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_EDITLABELS |
  496.                           LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS,
  497.                           0, 0, 
  498.                           rc.right-rc.left, rc.bottom-rc.top,
  499.                           hwndParent,
  500.                           (HMENU)IDD_LISTVIEW, 
  501.                           hInst, 
  502.                           NULL);
  503.  
  504.     if (hwndLV == NULL)
  505.         return NULL;
  506.  
  507.     // Initialize the image lists, add columns, and add some
  508.     // items and subitems.
  509.  
  510.     if (!InitListViewImageLists(hwndLV) ||
  511.         !InitListViewColumns(hwndLV)    ||
  512.         !InitListViewItems(hwndLV))
  513.     {
  514.         DestroyWindow(hwndLV);
  515.         return FALSE;
  516.     }
  517.     return hwndLV;
  518. }
  519.  
  520.  
  521. //
  522. //  FUNCTION: SwitchView(HWND, DWORD)
  523. //
  524. //  PURPOSE: Change the visual view of the listview control
  525. //
  526. //  PARAMETERS:
  527. //
  528. //    HWND  - Handle to the listview control
  529. //    DWORD - View style indicating new view
  530. //
  531. //  RETURN VALUE:
  532. //
  533. //    void
  534. //
  535. //  COMMENTS:
  536. //
  537.  
  538. void SwitchView(HWND hwndLV, DWORD dwView)
  539. {
  540.     DWORD dwStyle = GetWindowLong(hwndLV, GWL_STYLE);
  541.  
  542.     if ((dwStyle & LVS_TYPEMASK) != dwView)
  543.         SetWindowLong(hwndLV, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK) | dwView);
  544. }
  545.  
  546.  
  547.