home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lbfix.zip / listbox.c next >
C/C++ Source or Header  |  1994-07-05  |  106KB  |  2,988 lines

  1. #pragma    title("List Box Replacement  --  Version 1.1 -- (ListBox.C)")
  2. #pragma    subtitle("   List Box Control - Interface Definitions")
  3.  
  4. /* Program name: Listbox.C    Title: A List Box    Replacement        */
  5. /*                                    */
  6. /* OS/2    Developer Magazine, Issue:  May    '94, page 12                    */
  7. /* Author:  Mark Benge       IBM Corp.                    */
  8. /*        Matt Smith       Prominare Inc.                */
  9. /* Description:     Replacement for OS/2 List Box,    first of a series.    */
  10. /*                                    */
  11. /* Program Requirements:  OS/2 2.x                    */
  12. /*              IBM C    Set++                    */
  13. /*              WATCOM C 386/9.0                */
  14. /*              Borland C++ for OS/2                */
  15. /*              OS/2 Toolkit                    */
  16.  
  17. /* Copyright ╕ International Business Machines Corp. 1991-1994        */
  18. /* Copyright ╕ 1989-1994  Prominare Inc.  All Rights Reserved.        */
  19.  
  20.  
  21. /************************************************************************/
  22. /************************************************************************/
  23. /*                 SPECIAL NOTE                */
  24. /************************************************************************/
  25. /************************************************************************/
  26. /*     The behaviour of    this control is    similar    to that    provided    */
  27. /*     by OS/2 PM.  Although it    may be based on    documentation        */
  28. /*     describing programming interfaces and techniques, it should    */
  29. /*     not be misconstrued that    this sample code is an official        */
  30. /*     release of the OS/2 PM control and is supported as such.        */
  31. /************************************************************************/
  32. /************************************************************************/
  33.  
  34. /************************************************************************/
  35. /************************************************************************/
  36. /*               DISCLAIMER OF WARRANTIES.            */
  37. /************************************************************************/
  38. /************************************************************************/
  39. /*     The following [enclosed]    code is    source code created by the    */
  40. /*     authors.     This source code is  provided to you solely        */
  41. /*     for the purpose of assisting you    in the development of your    */
  42. /*     applications.  The code is provided "AS IS", without        */
  43. /*     warranty    of any kind.  The authors shall    not be liable        */
  44. /*     for any damages arising out of your use of the source code,    */
  45. /*     even if they have been advised of the possibility of such    */
  46. /*     damages.     It is provided    purely for instructional and        */
  47. /*     illustrative purposes.                        */
  48. /************************************************************************/
  49. /************************************************************************/
  50.  
  51. #pragma    info(noext)
  52. #pragma    strings(readonly)
  53.  
  54. #define    INCL_GPI           /* Include OS/2 PM GPI Interface    */
  55. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  56.  
  57. #include <os2.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <stdio.h>
  61.  
  62. #include "listbox.h"
  63.  
  64. /* This    module contains    the common routines used by the    list box along    */
  65. /* with    the window procedure for the list box.                */
  66. /*                                    */
  67. /* Equivalent command line invocation of each module using the        */
  68. /* IBM C Set++ Compiler    Version    2.0 is:                    */
  69. /*                                    */
  70. /*     Icc -G3e- -O+ -Rn -C -W3    -FoListBox ListBox.C            */
  71.  
  72. /* Filename:   ListBox.C                        */
  73.  
  74. /*  Version:   1.1                            */
  75. /*  Created:   1993-10-14                        */
  76. /*  Revised:   1994-02-27                        */
  77.  
  78. /* Routines:   BOOL fRegisterListBox(HAB hAB);                */
  79. /*           VOID UpdateScrollBars(PLISTBOXWIN plbw);            */
  80. /*           VOID DrawSelection(HWND hWnd, PRECTL prcl,        */
  81. /*                  PLISTBOXWIN plbw, LONG iItem);    */
  82. /*           VOID DrawItem(PLISTBOXWIN plbw, LONG iItem, HPS hPS,    */
  83. /*                 PRECTL prcl, PPOINTL pptl);        */
  84. /*           BOOL fItemVisible(PLISTBOXWIN plbw, LONG    iItem);        */
  85. /*           LONG lItemFromPoint(PLISTBOXWIN plbw, LONG y);        */
  86. /*           MRESULT EXPENTRY    ScrollBarWndProc(HWND hWnd, ULONG msg,    */
  87. /*                         MPARAM    mp1,        */
  88. /*                         MPARAM    mp2);        */
  89. /*           MRESULT EXPENTRY    ListBoxWndProc(HWND hWnd, ULONG    msg,    */
  90. /*                           MPARAM mp1, MPARAM mp2);    */
  91.  
  92.  
  93. /* --------------------------------------------------------------------    */
  94.  
  95. /************************************************************************/
  96. /*                                    */
  97. /* Standard List Box Styles                        */
  98. /*                                    */
  99. /*     LS_MULTIPLESEL       0x00000001L                    */
  100. /*     LS_OWNERDRAW       0x00000002L                    */
  101. /*     LS_NOADJUSTPOS       0x00000004L                    */
  102. /*     LS_HORZSCROLL       0x00000008L                    */
  103. /*     LS_EXTENDEDSEL       0x00000010L                    */
  104. /*                                    */
  105. /* Standard List Box notification messages                */
  106. /*                                    */
  107. /*     LN_SELECT          1                    */
  108. /*     LN_SETFOCUS          2                    */
  109. /*     LN_KILLFOCUS          3                    */
  110. /*     LN_SCROLL          4                    */
  111. /*     LN_ENTER              5                    */
  112. /*                                    */
  113. /* Standard List Box messages                        */
  114. /*                                    */
  115. /*     LM_QUERYITEMCOUNT      0x0160                */
  116. /*     LM_INSERTITEM          0x0161                */
  117. /*     LM_SETTOPINDEX          0x0162                */
  118. /*     LM_DELETEITEM          0x0163                */
  119. /*     LM_SELECTITEM          0x0164                */
  120. /*     LM_QUERYSELECTION      0x0165                */
  121. /*     LM_SETITEMTEXT          0x0166                */
  122. /*     LM_QUERYITEMTEXTLENGTH      0x0167                */
  123. /*     LM_QUERYITEMTEXT          0x0168                */
  124. /*     LM_SETITEMHANDLE          0x0169                */
  125. /*     LM_QUERYITEMHANDLE      0x016a                */
  126. /*     LM_SEARCHSTRING          0x016b                */
  127. /*     LM_SETITEMHEIGHT          0x016c                */
  128. /*     LM_QUERYTOPINDEX          0x016d                */
  129. /*     LM_DELETEALL          0x016e                */
  130.  
  131. /************************************************************************/
  132. /*                                    */
  133. /* Module Variable Definitions                        */
  134. /*                                    */
  135. /************************************************************************/
  136.  
  137. static HMODULE hmodDLL;           /* DLL Module Handle            */
  138.  
  139. /************************************************************************/
  140. /*                                    */
  141. /* Module Prototype Definitions                        */
  142. /*                                    */
  143. /************************************************************************/
  144.  
  145. static VOID DrawItem(PLISTBOXWIN plbw, LONG iItem, HPS hPS, PRECTL prcl, PPOINTL pptl);
  146.  
  147. /************************************************************************/
  148. /************************************************************************/
  149. /*                                    */
  150. /* DLL Initialization Functions                        */
  151. /*                                    */
  152. /************************************************************************/
  153. /************************************************************************/
  154.  
  155. #if defined(__IBMC__) || defined(__IBMCPP__)
  156.  
  157. #pragma    subtitle("   List Box Control - DLL Initialization/Termination Procedure")
  158. #pragma    page( )
  159.  
  160. /* --- _Dll_InitTerm ----------------------------------- [ Public ] ---    */
  161. /*                                    */
  162. /*     This function is    used to    provide    the DLL    initialization and    */
  163. /*     termination.  The function is called by the C startup code    */
  164. /*     and allows the control to register itself and provide any    */
  165. /*     necessary startup.                        */
  166. /*                                    */
  167. /*     This function is    designed for IBM C Set/2 Version 1.0 and    */
  168. /*     IBM C Set++ Version 2.x.                        */
  169. /*                                    */
  170. /*     Upon Entry:                            */
  171. /*                                    */
  172. /*     ULONG hModule; =    DLL Module Handle                */
  173. /*     ULONG fl;      =    Startup    / Termination Flag            */
  174. /*                                    */
  175. /*     Upon Exit:                            */
  176. /*                                    */
  177. /*     _Dll_InitTerm =    0 : Error Return                */
  178. /*             =    1 : Successful Startup / Termination        */
  179. /*                                    */
  180. /* --------------------------------------------------------------------    */
  181.  
  182. ULONG _System _Dll_InitTerm(ULONG hModule, ULONG fl)
  183.  
  184. {
  185.                /* Determine if in startup or termination mode    */
  186. if ( fl    == 0 )
  187.    {
  188.                /* DLL being initialized, save the DLL module    */
  189.                /* handle to allow the bitmap loading routines    */
  190.                /* routines a means of loading the default    */
  191.                /* bitmaps when required                */
  192.    hmodDLL = hModule;
  193.    }
  194.  
  195. return(1UL);
  196. }
  197.  
  198. #else
  199. #if defined(__WATCOMC__)
  200.  
  201. extern INT __hmodule;
  202.  
  203. #pragma    subtitle("   List Box Control - DLL Initialization Procedure")
  204. #pragma    page( )
  205.  
  206. /* --- __dll_initialize    -------------------------------- [ Public ] ---    */
  207. /*                                    */
  208. /*     This function is    used to    provide    the DLL    initialization and    */
  209. /*     termination.  The function is called by the C startup code    */
  210. /*     and allows the control to register itself and provide any    */
  211. /*     necessary startup.                        */
  212. /*                                    */
  213. /*     This function is    designed for WATCOM C 386 Version 9.0 and for    */
  214. /*     WATCOM C/C++ⁿ² Version 9.5.                    */
  215. /*                                    */
  216. /*     Upon Entry:                            */
  217. /*                                    */
  218. /*     Nothing                                */
  219. /*                                    */
  220. /*     Upon Exit:                            */
  221. /*                                    */
  222. /*     __dll_initialize    =  0 : Error Return                */
  223. /*            =  1 : Successful Startup            */
  224. /*                                    */
  225. /* --------------------------------------------------------------------    */
  226.  
  227. INT __dll_initialize(VOID)
  228.  
  229. {
  230.                /* DLL being initialized, save the DLL module    */
  231.                /* handle to allow the bitmap loading routines    */
  232.                /* routines a means of loading the default    */
  233.                /* bitmaps when required                */
  234. hmodDLL    = __hmodule;
  235.  
  236. return(1);
  237. }
  238. #pragma    subtitle("   Image Button Control - DLL Initialization Procedure")
  239. #pragma    page( )
  240.  
  241. /* --- __dll_terminate --------------------------------- [ Public ] ---    */
  242. /*                                    */
  243. /*     This function is    used to    provide    the DLL    initialization and    */
  244. /*     termination.  The function is called by the C startup code    */
  245. /*     and allows the control to register itself and provide any    */
  246. /*     necessary startup.                        */
  247. /*                                    */
  248. /*     This function is    designed for WATCOM C 386 Version 9.0 and for    */
  249. /*     WATCOM C/C++ⁿ² Version 9.5.                    */
  250. /*                                    */
  251. /*     Upon Entry:                            */
  252. /*                                    */
  253. /*     Nothing                                */
  254. /*                                    */
  255. /*     Upon Exit:                            */
  256. /*                                    */
  257. /*     __dll_terminate =  0 : Error Return                */
  258. /*               =  1 : Successful Startup            */
  259. /*                                    */
  260. /* --------------------------------------------------------------------    */
  261.  
  262. INT __dll_terminate(VOID)
  263.  
  264. {
  265.  
  266. return(1);
  267.  
  268. }
  269.  
  270. #else
  271. #if defined(__BCPLUSPLUS__) || defined(__BORLANDC__)
  272.  
  273. #pragma    subtitle("   List Box Control - DLL Initialization/Termination Procedure")
  274. #pragma    page( )
  275.  
  276. /* --- _dllmain    ---------------------------------------- [ Public ] ---    */
  277. /*                                    */
  278. /*     This function is    used to    provide    the DLL    initialization and    */
  279. /*     termination.  The function is called by the C startup code    */
  280. /*     and allows the control to register itself and provide any    */
  281. /*     necessary startup.                        */
  282. /*                                    */
  283. /*     This function is    designed for Borland C++ for OS/2 Version 1.x.    */
  284. /*                                    */
  285. /*     Upon Entry:                            */
  286. /*                                    */
  287. /*     ULONG fl;      =    Startup    / Termination Flag            */
  288. /*     ULONG hModule; =    DLL Module Handle                */
  289. /*                                    */
  290. /*     Upon Exit:                            */
  291. /*                                    */
  292. /*     _dllmain    =  0 : Error Return                    */
  293. /*        =  1 : Successful Startup / Termination            */
  294. /*                                    */
  295. /* --------------------------------------------------------------------    */
  296.  
  297. ULONG _dllmain(ULONG fl, ULONG hModule)
  298.  
  299. {
  300.                /* Determine if in startup or termination mode    */
  301. if ( fl    == 0 )
  302.    {
  303.                /* DLL being initialized, save the DLL module    */
  304.                /* handle to allow the bitmap loading routines    */
  305.                /* routines a means of loading the default    */
  306.                /* bitmaps when required                */
  307.    hmodDLL = hModule;
  308.    }
  309.  
  310. return(1UL);
  311. }
  312.  
  313. #endif
  314. #endif
  315. #endif
  316.  
  317. /************************************************************************/
  318. /************************************************************************/
  319. /*                                    */
  320. /* Module Private Functions                        */
  321. /*                                    */
  322. /************************************************************************/
  323. /************************************************************************/
  324.  
  325. #pragma    subtitle("   List Box Control - Item Draw Routine")
  326. #pragma    page( )
  327.  
  328. /* --- DrawItem    ---------------------------------------    [ Private ] ---    */
  329. /*                                    */
  330. /*     This function is    used to    draw a specified item within the list    */
  331. /*     box.  All drawing of items contained within the list box    MUST    */
  332. /*     use this    routine    since it insures that list boxes that are    */
  333. /*     owner drawn are properly    handled.                */
  334. /*                                    */
  335. /*     Upon Entry:                            */
  336. /*                                    */
  337. /*     PLISTBOXWIN plbw;  = List Box Data Pointer            */
  338. /*     LONG       iItem; = Item to Draw                */
  339. /*     HPS       hPS;      = Presentation Space Handle            */
  340. /*     PRECTL       prcl;  = Clipping Rectangle                */
  341. /*     PPOINTL       pptl;  = Starting Point                */
  342. /*                                    */
  343. /*     Upon Exit:                            */
  344. /*                                    */
  345. /*     Nothing                                */
  346. /*                                    */
  347. /* --------------------------------------------------------------------    */
  348.  
  349. static VOID DrawItem(PLISTBOXWIN plbw, LONG iItem, HPS hPS, PRECTL prcl, PPOINTL pptl)
  350.  
  351. {
  352. BOOL      fDraw    = TRUE;           /* Draw Item    Flag            */
  353. OWNERITEM oi;               /* List Box Item Pointer        */
  354. POINTL      ptl;               /* Display Point Holder        */
  355. RECTL      rcl;               /* Display Rectangle            */
  356. LONG      lPSid;           /* PS ID                */
  357.  
  358. if ( (plbw->plc[0].apli[iItem]->fl & LI_FOCUS) && plbw->fFocusShown )
  359.    WinShowCursor(plbw->hWnd, FALSE);
  360.  
  361.                /* Check    to see if the list box is owner    drawn    */
  362.                /* in which case, the OWNERITEM package needs to    */
  363.                /* be completed and sent    off to the list    box    */
  364.                /* owner    to allow it to draw the    specified item    */
  365.  
  366. if ( plbw->flStyle & LS_OWNERDRAW )
  367.    {
  368.                /* Fill in the owner draw structure to before    */
  369.                /* sending off the message to the owner of the    */
  370.                /* list box                    */
  371.  
  372.    memset(&oi, 0, sizeof(OWNERITEM));
  373.    oi.hwnd         = plbw->hWnd;
  374.    oi.hps         = hPS;
  375.  
  376.    if (    plbw->plc[0].apli[iItem]->fl & LI_SELECTED )
  377.        oi.fsState    = TRUE;
  378.  
  379.    if (    plbw->plc[0].apli[iItem]->fl & LI_SELECTEDPREV )
  380.        {
  381.        oi.fsStateOld = TRUE;
  382.        plbw->plc[0].apli[iItem]->fl &= ~LI_SELECTEDPREV;
  383.        }
  384.  
  385.    oi.rclItem         = *prcl;
  386.    --oi.rclItem.xRight;
  387.  
  388.    if (    plbw->iHorzScroll )
  389.        oi.rclItem.xLeft    += 1L -    (plbw->iHorzScroll * plbw->xChar);
  390.    else
  391.        oi.rclItem.xLeft    += 1L;
  392.    oi.idItem         = iItem;
  393.    oi.hItem         = plbw->plc[0].apli[iItem]->ulHandle;
  394.  
  395.                /* Clear    the display rectangle before giving the    */
  396.                /* owner    item to    the list box owner        */
  397.    rcl = *prcl;
  398.    rcl.xRight =    rcl.xLeft + 1L;
  399.    WinFillRect(hPS, &rcl, plbw->lClrList);
  400.    rcl.xLeft = prcl->xRight - 1L;
  401.    rcl.xRight =    prcl->xRight;
  402.    WinFillRect(hPS, &rcl, plbw->lClrList);
  403.  
  404.    lPSid = GpiSavePS(hPS);
  405.  
  406.                /* Place    the colour table back into index mode    */
  407.                /* for the owner    draw portion            */
  408.  
  409.    GpiCreateLogColorTable(hPS, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, (PLONG)NULL);
  410.    GpiSetColor(hPS, plbw->lClrTextIndex);
  411.    GpiSetBackColor(hPS,    plbw->lClrListIndex);
  412.  
  413.                /* Send of the draw item    message    to the list box    */
  414.                /* owner.  If the owner returns a value of FALSE    */
  415.                /* the owner has    indicated that it wants    the    */
  416.                /* drawing of the item to be performed by the    */
  417.                /* list box.  A return value of TRUE indicates    */
  418.                /* that the owner fully handled the drawing of    */
  419.                /* the item.                    */
  420.  
  421.    if (    WinSendMsg(plbw->hwndOwner, WM_DRAWITEM,
  422.            MPFROMLONG(plbw->id), MPFROMP(&oi)) )
  423.        {
  424.        if ( oi.fsState )
  425.        {
  426.        rcl = *prcl;
  427.        ++rcl.xLeft;
  428.        --rcl.xRight;
  429.        WinInvertRect(hPS, &rcl);
  430.        }
  431.        fDraw = FALSE;
  432.        }
  433.    GpiRestorePS(hPS, lPSid);
  434.  
  435.                /* Reset    the colour back    into RGB mode        */
  436.  
  437.    GpiCreateLogColorTable(hPS, 0L, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  438.    }
  439.  
  440. if ( fDraw )
  441.    {
  442.                /* Depending on the selection status of the item    */
  443.                /* being    drawn, set the colours for the item    */
  444.  
  445.    if (    plbw->plc[0].apli[iItem]->fl & LI_SELECTED )
  446.        {
  447.                /* Selected item    being drawn, use the        */
  448.                /* appropriate colours for the selected item    */
  449.  
  450.        GpiSetColor(hPS,    plbw->lClrHilite);
  451.        GpiSetBackColor(hPS, plbw->lClrHiliteBackground);
  452.        WinFillRect(hPS,    prcl, plbw->lClrHiliteBackground);
  453.        }
  454.    else
  455.        {
  456.                /* Normal item being drawn, use the appropriate    */
  457.                /* colours for the selected item            */
  458.  
  459.        GpiSetColor(hPS,    plbw->lClrText);
  460.        GpiSetBackColor(hPS, plbw->lClrList);
  461.        WinFillRect(hPS,    prcl, plbw->lClrList);
  462.        }
  463.  
  464.    if (    plbw->flStyleExt & LSXS_CHECKBOX )
  465.        {
  466.                /* When a predefined point specified, the    */
  467.                /* starting point for the text has been defined,    */
  468.                /* therefore only need to draw the text in the    */
  469.                /* position specified                */
  470.        if ( pptl )
  471.        ptl.x = pptl->x;
  472.        else
  473.                /* No predefined    point specified, need to    */
  474.                /* calculate the    starting point for the text    */
  475.  
  476.        ptl.x = prcl->xLeft + 2L;
  477.  
  478.        ptl.y = (((prcl->yTop - prcl->yBottom) /    2L) + prcl->yBottom) - plbw->cyHalfBitmap;
  479.        WinDrawBitmap(hPS, plbw->hbm,
  480.              (plbw->plc[0].apli[iItem]->fl & LI_CHECKED) ? &plbw->rclChecked : &plbw->rclUnChecked,
  481.              &ptl, 0L, 0L, DBM_IMAGEATTRS | DBM_NORMAL);
  482.        ptl.x +=    plbw->xTextOffset;
  483.        ptl.y = prcl->yTop - plbw->yAscender;
  484.        }
  485.    else
  486.                /* When a predefined point specified, the    */
  487.                /* starting point for the text has been defined,    */
  488.                /* therefore only need to draw the text in the    */
  489.                /* position specified                */
  490.        if ( pptl )
  491.        ptl = *pptl;
  492.        else
  493.                /* No predefined    point specified, need to    */
  494.                /* calculate the    starting point for the text    */
  495.        {
  496.        ptl.x = prcl->xLeft + 2L;
  497.        ptl.y = prcl->yTop -    plbw->yAscender;
  498.        }
  499.                /* For the extreme right    edge of    the rectangle,    */
  500.                /* clear    a 1 pel    verticle strip such that it    */
  501.                /* provides visual separation between the item    */
  502.                /* and the vertical scroll bar            */
  503.    rcl = *prcl;
  504.    rcl.xLeft = prcl->xRight - 1L;
  505.    WinFillRect(hPS, &rcl, plbw->lClrList);
  506.    GpiCharStringPosAt(hPS, &ptl, prcl, CHS_CLIP,
  507.               (LONG)plbw->plc[0].apli[iItem]->cText,
  508.               plbw->plc[0].apli[iItem]->pszText, (PLONG)NULL);
  509.    }
  510.                /* When the list    box item has focus, draw the    */
  511.                /* focus    rectangle around the item        */
  512.  
  513. if ( (plbw->plc[0].apli[iItem]->fl & LI_FOCUS) && plbw->fFocusShown )
  514.    WinShowCursor(plbw->hWnd, TRUE);
  515.  
  516. plbw->plc[0].apli[iItem]->fl &=    ~LI_SELECTEDPREV;
  517.  
  518. }
  519. #pragma    subtitle("   List Box Control - Scroll Bar Procedure")
  520. #pragma    page( )
  521.  
  522. /* --- ScrollBarWndProc    -------------------------------    [ Private ] ---    */
  523. /*                                    */
  524. /*     This function is    used to    handle the button down message of the    */
  525. /*     subclassed scroll bar window to make sure that the focus    is    */
  526. /*     placed back to the list box in the proper manner.  The vertical    */
  527. /*     and horizontal scrolls of the list box are subclassed to    allow    */
  528. /*     the detection of    the mouse clicks which will be used to allow    */
  529. /*     the proper display of the focus indicator.            */
  530. /*                                    */
  531. /*     Upon Entry:                            */
  532. /*                                    */
  533. /*     HWND   hWnd; = Window Handle                    */
  534. /*     ULONG  msg;  = PM Message                    */
  535. /*     MPARAM mp1;  = Message Parameter    1                */
  536. /*     MPARAM mp2;  = Message Parameter    2                */
  537. /*                                    */
  538. /*     Upon Exit:                            */
  539. /*                                    */
  540. /*     ScrollBarWndProc    = Message Handling Result            */
  541. /*                                    */
  542. /* --------------------------------------------------------------------    */
  543.  
  544. MRESULT    EXPENTRY ScrollBarWndProc(HWND hWnd, ULONG msg,    MPARAM mp1, MPARAM mp2)
  545.  
  546. {
  547. PFNWP pfnScrollBarProc;           /* Original Scroll Bar Function    */
  548.  
  549. switch ( msg )
  550.    {
  551.  
  552.    /*********************************************************************/
  553.    /*  Button click                            */
  554.    /*********************************************************************/
  555.  
  556.    case    WM_BUTTON1DOWN :
  557.    case    WM_BUTTON2DOWN :
  558.    case    WM_BUTTON3DOWN :
  559.        WinFocusChange(HWND_DESKTOP, WinQueryWindow(hWnd, QW_OWNER), 0UL);
  560.        break;
  561.    }
  562. pfnScrollBarProc = (PFNWP)WinQueryWindowULong(hWnd, QWL_USER);
  563. return((*pfnScrollBarProc)(hWnd, msg, mp1, mp2));
  564. }
  565.  
  566. /************************************************************************/
  567. /************************************************************************/
  568. /*                                    */
  569. /* Module Public Functions                        */
  570. /*                                    */
  571. /************************************************************************/
  572. /************************************************************************/
  573.  
  574. #pragma    subtitle("   List Box Control - List Box Registration Procedure")
  575. #pragma    page( )
  576.  
  577. /* --- fRegisterListBox    -------------------------------- [ Public ] ---    */
  578. /*                                    */
  579. /*     This function is    used to    register the list box for the        */
  580. /*     application with    PM.                        */
  581. /*                                    */
  582. /*     Upon Entry:                            */
  583. /*                                    */
  584. /*     HAB hAB;    = Anchor Block Handle                    */
  585. /*                                    */
  586. /*     Upon Exit:                            */
  587. /*                                    */
  588. /*     fRegisterListBox    =  TRUE    : List Box Registration    Successfull    */
  589. /*            = FALSE    : List Box Registration    Failed        */
  590. /*                                    */
  591. /* --------------------------------------------------------------------    */
  592.  
  593. BOOL EXPENTRY fRegisterListBox(HAB hAB)
  594.  
  595. {
  596.                /* Register the main program window class    */
  597.  
  598. if ( WinRegisterClass(hAB, "ListBoxWindow", (PFNWP)ListBoxWndProc,
  599.               CS_SYNCPAINT | CS_SIZEREDRAW | CS_PARENTCLIP | CS_CLIPCHILDREN,
  600.               USER_RESERVED) )
  601.    return(TRUE);
  602. else
  603.    return(FALSE);
  604. }
  605. #pragma    subtitle("   List Box Control - Scroll Bar Update Procedure")
  606. #pragma    page( )
  607.  
  608. /* --- UpdateScrollBars    -------------------------------- [ Public ] ---    */
  609. /*                                    */
  610. /*     This function is    used to    update the scroll bars for the        */
  611. /*     list box    control.                        */
  612. /*                                    */
  613. /*     Upon Entry:                            */
  614. /*                                    */
  615. /*     PLISTBOXWIN plbw; = List    Box Internal Data Pointer        */
  616. /*                                    */
  617. /*     Upon Exit:                            */
  618. /*                                    */
  619. /*     Nothing                                */
  620. /*                                    */
  621. /* --------------------------------------------------------------------    */
  622.  
  623. VOID UpdateScrollBars(PLISTBOXWIN plbw)
  624.  
  625. {
  626. register INT n;               /* Loop Counters            */
  627.  
  628.                /* Get the list box information pointer from    */
  629.                /* the reserved memory of the window        */
  630.  
  631. if ( plbw->cItems > plbw->cLinesPage )
  632.    {
  633.    WinEnableWindow(plbw->hwndScrollRight, TRUE);
  634.  
  635.                /* Reset    the scroll bars    to take    into        */
  636.                /* consideration    the visible number of lines    */
  637.                /* now contained    within the window        */
  638.  
  639.    WinSendMsg(plbw->hwndScrollRight, SBM_SETSCROLLBAR,
  640.           MPFROMSHORT(plbw->iVertScroll),
  641.           MPFROM2SHORT(0, (((n = plbw->cItems - plbw->cLinesPage) <    0) ?
  642.                    (plbw->iVertScroll = plbw->cVertScroll =    0) :
  643.                    (plbw->cVertScroll = n))));
  644.    WinSendMsg(plbw->hwndScrollRight, SBM_SETTHUMBSIZE,
  645.           MPFROM2SHORT(plbw->cLinesPage, plbw->cItems), 0L);
  646.    }
  647. else
  648.    {
  649.    if (    plbw->iVertScroll )
  650.        plbw->iVertScroll = 0;
  651.    WinEnableWindow(plbw->hwndScrollRight, FALSE);
  652.    }
  653.                /* Get the list box information pointer from    */
  654.                /* the reserved memory of the window        */
  655.  
  656. if ( plbw->flStyle & LS_HORZSCROLL )
  657.    if (    plbw->cxItem > (plbw->rcl.xRight - plbw->rcl.xLeft) )
  658.        {
  659.        WinEnableWindow(plbw->hwndScrollBottom, TRUE);
  660.  
  661.                /* Reset    the scroll bars    to take    into        */
  662.                /* consideration    the visible number of lines    */
  663.                /* now contained    within the window        */
  664.  
  665.        WinSendMsg(plbw->hwndScrollBottom, SBM_SETSCROLLBAR,
  666.           MPFROMSHORT(plbw->iHorzScroll),
  667.           MPFROM2SHORT(0, (((n = ((plbw->cxItem    - (plbw->rcl.xRight - plbw->rcl.xLeft))    / plbw->xChar +    1)) < 0) ?
  668.                    (plbw->iHorzScroll =    plbw->iHorzScroll = 0) :
  669.                    (plbw->cHorzScroll =    n))));
  670.        WinSendMsg(plbw->hwndScrollBottom, SBM_SETTHUMBSIZE,
  671.           MPFROM2SHORT(plbw->cCharsPage, (plbw->cxItem / plbw->xChar) +    1), 0L);
  672.        }
  673.    else
  674.        {
  675.        if ( plbw->iHorzScroll )
  676.        plbw->iHorzScroll = 0;
  677.        WinEnableWindow(plbw->hwndScrollBottom, FALSE);
  678.        }
  679.  
  680. plbw->fDirty = FALSE;
  681. }
  682. #pragma    subtitle("   List Box Control - Selected Item Draw Routine")
  683. #pragma    page( )
  684.  
  685. /* --- DrawSelection ----------------------------------    [ Private ] ---    */
  686. /*                                    */
  687. /*     This function is    used to    draw the specified item    as a        */
  688. /*     selected    item within the    list box.                */
  689. /*                                    */
  690. /*     Upon Entry:                            */
  691. /*                                    */
  692. /*     HWND       hWnd;  = List Box Window Handle            */
  693. /*     PRECTL       prcl;  = Display and    Clipping Rectangle        */
  694. /*     PLISTBOXWIN plbw;  = List Box Data Pointer            */
  695. /*     LONG       iItem; = Item to Check                */
  696. /*                                    */
  697. /*     Upon Exit:                            */
  698. /*                                    */
  699. /*     Nothing                                */
  700. /*                                    */
  701. /* --------------------------------------------------------------------    */
  702.  
  703. VOID DrawSelection(PLISTBOXWIN plbw, LONG iItem)
  704.  
  705. {
  706. HPS    hPS;               /* Presentation Space Handle        */
  707. POINTL ptl;               /* Text Display Point        */
  708. RECTL  rcl;               /* Display Rectangle            */
  709.  
  710.                /* Check    to see if the item requested is    visible    */
  711.  
  712. if ( fItemVisible(plbw,    iItem) )
  713.  
  714.                /* Get the presentation space that is to    be used    */
  715.                /* to draw the text                */
  716.  
  717.    if (    (hPS = WinGetPS(plbw->hWnd)) !=    (HPS)NULL )
  718.        {
  719.                /* Current entry    viewable, calculate the    actual    */
  720.                /* rectangle which the entry resides in        */
  721.        rcl = plbw->rcl;
  722.        rcl.yTop    = plbw->rcl.yTop - (iItem - plbw->iVertScroll) *
  723.           plbw->cyItem;
  724.        rcl.yBottom = rcl.yTop -    plbw->cyItem;
  725.  
  726.                /* Form the starting point for the text        */
  727.  
  728.        ptl.x = rcl.xLeft + 2L -    (plbw->iHorzScroll * plbw->xChar);
  729.        ptl.y = rcl.yTop    - plbw->yAscender;
  730.  
  731.                /* Set the colour table to RGB mode        */
  732.  
  733.        GpiCreateLogColorTable(hPS, 0L, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  734.  
  735.                /* Draw the text    of the list box    item        */
  736.  
  737.        DrawItem(plbw, iItem, hPS, &rcl,    &ptl);
  738.  
  739.                /* Release the presentation space        */
  740.        WinReleasePS(hPS);
  741.        }
  742. }
  743. #pragma    subtitle("   Traffic Manager - Focus Draw Routine")
  744. #pragma    page( )
  745.  
  746. /* --- DrawItemSelection ------------------------------    [ Private ] ---    */
  747. /*                                    */
  748. /*     This function is    used to    draw the focus indicator around    a    */
  749. /*     list box    item.                            */
  750. /*                                    */
  751. /*     Upon Entry:                            */
  752. /*                                    */
  753. /*     PLISTBOXWIN plbw;  = List Box Data Pointer            */
  754. /*     LONG       iItem; = Item to Check                */
  755. /*                                    */
  756. /*     Upon Exit:                            */
  757. /*                                    */
  758. /*     Nothing                                */
  759. /*                                    */
  760. /* --------------------------------------------------------------------    */
  761.  
  762. VOID DrawItemSelection(PLISTBOXWIN plbw, LONG iItem)
  763.  
  764. {
  765. HPS    hPS;               /* Presentation Space Handle        */
  766. POINTL ptl;               /* Text Display Point        */
  767. RECTL  rcl;               /* Drawing Rectangle            */
  768.  
  769.                /* Get the presentation space for the list box    */
  770.  
  771. if ( (hPS = WinGetPS(plbw->hWnd)) != (HPS)NULL )
  772.    {
  773.                /* Form the display rectangle for the item    */
  774.    rcl = plbw->rcl;
  775.  
  776.    rcl.yBottom = (rcl.yTop = plbw->rcl.yTop - (iItem - plbw->iVertScroll) *
  777.                  plbw->cyItem) - plbw->cyItem;
  778.  
  779.                /* Form the display point for the text to be    */
  780.                /* drawn                        */
  781.  
  782.    ptl.x = rcl.xLeft + 2L;
  783.    ptl.y = rcl.yTop - plbw->yAscender;
  784.  
  785.                /* Place    the colour table into RGB mode and draw    */
  786.                /* the text item                    */
  787.  
  788.    GpiCreateLogColorTable(hPS, 0L, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  789.    DrawItem(plbw, iItem, hPS, &rcl, &ptl);
  790.  
  791.                /* Release the presentation space handle        */
  792.    WinReleasePS(hPS);
  793.    }
  794. }
  795. #pragma    subtitle("   List Box Control - Item Visibility Routine")
  796. #pragma    page( )
  797.  
  798. /* --- fItemVisible -----------------------------------    [ Private ] ---    */
  799. /*                                    */
  800. /*     This function is    used to    determine if the item is within    the    */
  801. /*     visible portion of the list box.                    */
  802. /*                                    */
  803. /*     Upon Entry:                            */
  804. /*                                    */
  805. /*     PLISTBOXWIN plbw;  = List Box Data Pointer            */
  806. /*     LONG       iItem; = Item to Check                */
  807. /*                                    */
  808. /*     Upon Exit:                            */
  809. /*                                    */
  810. /*     fItemVisible =  TRUE : Item is Visible                */
  811. /*            = FALSE : Item is not Visible            */
  812. /*                                    */
  813. /* --------------------------------------------------------------------    */
  814.  
  815. BOOL fItemVisible(PLISTBOXWIN plbw, LONG iItem)
  816.  
  817. {
  818.                /* Check    to see that the    item specified is    */
  819.                /* currently visible within the list box.  An    */
  820.                /* item is visible when it is within the    range    */
  821.                /* of the top and bottom    lines that are        */
  822.                /* displayed.                    */
  823.  
  824. if ( (iItem >= plbw->iVertScroll) &&
  825.      (iItem < (plbw->iVertScroll + plbw->cLinesPage)) )
  826.  
  827.                /* Item within the visible range, return    with    */
  828.                /* visible flag                    */
  829.    return(TRUE);
  830. else
  831.                /* Item not within the visible range, return    */
  832.                /* with hidden flag                */
  833.    return(FALSE);
  834. }
  835. #pragma    subtitle("   List Box Control - Descending Insert Item Locate Routine")
  836. #pragma    page( )
  837.  
  838. /* --- lItemFromPoint ---------------------------------- [ Public ] ---    */
  839. /*                                    */
  840. /*     This function is    used to    determine the index of the item    within    */
  841. /*     the list    box using a vertical point within the list box.     The    */
  842. /*     calculation is based on the point falling within    a horizontal    */
  843. /*     band which is the height    of the item.  This initial index is    */
  844. /*     combined    with the scroll    bar position to    determine the actual    */
  845. /*     item index.  All    calculations are base on premise of the    first    */
  846. /*     item in the list    box is the topmost item.            */
  847. /*                                    */
  848. /*     Upon Entry:                            */
  849. /*                                    */
  850. /*     PLISTBOXWIN plbw; = List    Box Internal Data Pointer        */
  851. /*     LONG       y;     = Vertical Point                */
  852. /*                                    */
  853. /*     Upon Exit:                            */
  854. /*                                    */
  855. /*     lItemFromPoint =    Index of Item                    */
  856. /*                                    */
  857. /* --------------------------------------------------------------------    */
  858.  
  859. LONG lItemFromPoint(PLISTBOXWIN    plbw, LONG y)
  860.  
  861. {
  862. LONG iSelected;               /* Selected Item Index        */
  863.  
  864.                /* Calculate the    item from the vertical point in    */
  865.                /* the list box.     The formula used is by    taking    */
  866.                /* the current top index    position (which        */
  867.                /* corresponds to the vertical scroll bar    */
  868.                /* position) and    adding this to a value formed    */
  869.                /* by subtracting the point from    the top    edge    */
  870.                /* point, which results in the distance from the    */
  871.                /* top edge and then taking this    value and    */
  872.                /* dividing it by the height of each item which    */
  873.                /* results in a zero based index    from the top    */
  874.                /* item shown.                    */
  875.  
  876.                /*                        */
  877.                /*          plbw->rcl.yTop            */
  878.                /*  ┌────────────────────────────────┬─┐        */
  879.                /*  │           plbw->iVertScroll│^│        */
  880.                /*  ├────────────────────────────────┼─┤        */
  881.                /*  │                    │ │        */
  882.                /*  ├────────────────────────────────┤ │        */
  883.                /*  │          ₧ y            │ │        */
  884.                /*  ├────────────────────────────────┼─┤        */
  885.                /*  │               plbw->cyItem │v│        */
  886.                /*  ├─┬────────────────────────────┬─┼─┘        */
  887.                /*  │<│                  │>│        */
  888.                /*  └─┴────────────────────────────┴─┘        */
  889.  
  890. iSelected = (plbw->rcl.yTop - y) / plbw->cyItem    + plbw->iVertScroll;
  891.  
  892.                /* When the point is on a boundary between two    */
  893.                /* items    (the height of the item    divides    evenly    */
  894.                /* in point), need to adjust the    index value to    */
  895.                /* apply    to the item before it            */
  896.  
  897. return((LONG)((plbw->rcl.yTop -    y) % plbw->cyItem ? iSelected :    iSelected - 1L));
  898. }
  899. #pragma    subtitle("   List Box Control - List Box Window Procedure")
  900. #pragma    page( )
  901.  
  902. /* --- ListBoxWndProc ---------------------------------- [ Public ] ---    */
  903. /*                                    */
  904. /*     This function is    used to    process    the messages for the list box    */
  905. /*     control window.                            */
  906. /*                                    */
  907. /*     Upon Entry:                            */
  908. /*                                    */
  909. /*     HWND   hWnd; = Window Handle                    */
  910. /*     ULONG  msg;  = PM Message                    */
  911. /*     MPARAM mp1;  = Message Parameter    1                */
  912. /*     MPARAM mp2;  = Message Parameter    2                */
  913. /*                                    */
  914. /*     Upon Exit:                            */
  915. /*                                    */
  916. /*     ListBoxWndProc =    Message    Handling Result                */
  917. /*                                    */
  918. /* --------------------------------------------------------------------    */
  919.  
  920. MRESULT    EXPENTRY ListBoxWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  921.  
  922. {
  923. BITMAPINFOHEADER bmp;           /* Bitmap Information Holder        */
  924. BOOL          fItemSelect;       /* Select Item Flag            */
  925. BOOL          fItemValid;       /* Valid Item Flag            */
  926. BOOL          fScroll;           /* Scroll List Flag            */
  927. FONTMETRICS   fm;           /* Font Metrics            */
  928. HHEAPMEM      hHeap;           /* Heap Handle            */
  929. HPS          hPS;           /* Presentation Space Handle        */
  930. HWND          hwndHelp;           /* Help Window Handle        */
  931. PCREATESTRUCT pcrst;           /* Create Structure Pointer        */
  932. PLISTBOXCDATA plbwcd;           /* List Box Window Data Pointer    */
  933. PLISTBOXWIN   plbw;           /* List Box Internal    Data Pointer    */
  934. POINTL          ptl;           /* Display Point            */
  935. POINTL          rgptl[TXTBOX_COUNT]; /* Text Box Point Array        */
  936. PSWP          pswp;           /* Size Window Position Pointer    */
  937. RECTL          rcl;           /* Display Rectangle            */
  938. RECTL          rclPaint;           /* Display Rectangle            */
  939. ULONG          fl;           /* Flags                */
  940. ULONG          flStyle;           /* Style Holder            */
  941. ULONG          ulID;           /* Presentation Parameter ID        */
  942. register INT i,    n;           /* Loop Counter            */
  943.  
  944. switch ( msg )
  945.    {
  946.  
  947. /************************************************************************/
  948. /************************************************************************/
  949. /*                                    */
  950. /* Part    1: Control creation coding                    */
  951. /*                                    */
  952. /************************************************************************/
  953. /************************************************************************/
  954.  
  955.    /*********************************************************************/
  956.    /*  Control creation                            */
  957.    /*********************************************************************/
  958.  
  959.    case    WM_CREATE :
  960.                /* Allocate space for the internal control data    */
  961.                /* as well as a small heap            */
  962.  
  963.        plbw = (PLISTBOXWIN)HeapMalloc(hHeap = HeapAlloc(4096UL,    4096UL), sizeof(LISTBOXWIN));
  964.        plbw->hHeap = hHeap;
  965.  
  966.                /* Save the address of the internal control data    */
  967.                /* in the control's reserved memory to allow it  */
  968.                /* to be    referenced as required by the control    */
  969.  
  970.        WinSetWindowPtr(hWnd, QUCWP_WNDP, (PVOID)plbw);
  971.  
  972.                /* Get the control's creation structure address  */
  973.                /* to copy the relevant information such    as the    */
  974.                /* size,    position and text of the control into    */
  975.                /* the internal control data            */
  976.  
  977.        pcrst = (PCREATESTRUCT)PVOIDFROMMP(mp2);
  978.  
  979.                /* Save the owner and parent of the control so    */
  980.                /* notification messages    can be sent back to    */
  981.                /* the proper locations within the owning    */
  982.                /* application                    */
  983.  
  984.        plbw->hAB    = WinQueryAnchorBlock(hWnd);
  985.        plbw->hWnd    = hWnd;
  986.        plbw->hwndOwner    = pcrst->hwndOwner;
  987.        plbw->hwndParent    = pcrst->hwndParent;
  988.        plbw->id        = pcrst->id;
  989.  
  990.                /* Save the size    of the list box    along with the    */
  991.                /* current style                    */
  992.  
  993.        plbw->cxWindow    = pcrst->cx;
  994.        plbw->cyWindow    = pcrst->cy;
  995.        plbw->flStyle    = pcrst->flStyle;
  996.  
  997.                /* Set the current selected index        */
  998.  
  999.        plbw->iFocus = plbw->iSelected =    LIT_NONE;
  1000.  
  1001.                /* Set column count                */
  1002.  
  1003.        plbw->cColumns =    1L;
  1004.  
  1005.                /* Get the default colours for the list box    */
  1006.  
  1007.        plbw->lClrText          = lGetPresParam(hWnd,    PP_FOREGROUNDCOLOR,
  1008.                           PP_FOREGROUNDCOLORINDEX,
  1009.                           SYSCLR_OUTPUTTEXT);
  1010.        plbw->lClrList          = lGetPresParam(hWnd,    PP_BACKGROUNDCOLOR,
  1011.                           PP_BACKGROUNDCOLORINDEX,
  1012.                           SYSCLR_ENTRYFIELD);
  1013.        plbw->lClrBorder          = lGetPresParam(hWnd,    PP_BORDERCOLOR,
  1014.                           PP_BORDERCOLORINDEX,
  1015.                           SYSCLR_BUTTONDARK);
  1016.        plbw->lClrBackground      = lGetPresParam(hWnd,    PP_BACKGROUNDCOLOR,
  1017.                           PP_BACKGROUNDCOLORINDEX,
  1018.                           SYSCLR_FIELDBACKGROUND);
  1019.        plbw->lClrHilite          = lGetPresParam(hWnd,    PP_HILITEFOREGROUNDCOLOR,
  1020.                           PP_HILITEFOREGROUNDCOLORINDEX,
  1021.                           SYSCLR_HILITEFOREGROUND);
  1022.        plbw->lClrHiliteBackground = lGetPresParam(hWnd,    PP_HILITEBACKGROUNDCOLOR,
  1023.                           PP_HILITEBACKGROUNDCOLORINDEX,
  1024.                           SYSCLR_HILITEBACKGROUND);
  1025.        if ( !WinQueryPresParam(hWnd, PP_FOREGROUNDCOLORINDEX, 0UL, &ulID, sizeof(LONG),    (PVOID)&plbw->lClrTextIndex,
  1026.                    QPF_NOINHERIT | QPF_ID1COLORINDEX) )
  1027.        plbw->lClrTextIndex = SYSCLR_OUTPUTTEXT;
  1028.        if ( !WinQueryPresParam(hWnd, PP_BACKGROUNDCOLORINDEX, 0UL, &ulID, sizeof(LONG),    (PVOID)&plbw->lClrListIndex,
  1029.                    QPF_NOINHERIT | QPF_ID1COLORINDEX) )
  1030.        plbw->lClrListIndex = SYSCLR_ENTRYFIELD;
  1031.  
  1032.                /* Determine the    size of    the scroll bars        */
  1033.  
  1034.        plbw->cxScroll =    WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  1035.        plbw->cyScroll =    WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
  1036.        plbw->hptr     =    WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE);
  1037.  
  1038.                /* Get the font metrics to determine the    height    */
  1039.                /* and width of a character            */
  1040.  
  1041.        GpiQueryFontMetrics(hPS = WinGetPS(hWnd), sizeof(FONTMETRICS), &fm);
  1042.        plbw->hbm = GpiLoadBitmap(hPS, hmodDLL, IDB_CHECKMARKS, 0L, 0L);
  1043.  
  1044.        WinReleasePS(hPS);
  1045.  
  1046.        GpiQueryBitmapParameters(plbw->hbm, &bmp);
  1047.  
  1048.        plbw->rclChecked.xRight = bmp.cx    - (bmp.cx / 4L);
  1049.        plbw->rclChecked.xLeft  = bmp.cx    / 2L;
  1050.  
  1051.        plbw->rclUnChecked.xRight = bmp.cx / 4L;
  1052.        plbw->rclChecked.yTop = plbw->rclUnChecked.yTop = bmp.cy    / 2L;
  1053.        plbw->cyHalfBitmap = bmp.cy / 4L;
  1054.  
  1055.        plbw->xTextOffset = (bmp.cx / 4L) + fm.lAveCharWidth / 2L;
  1056.  
  1057.        plbw->yAscender = fm.lMaxAscender;
  1058.        plbw->xChar     = fm.lAveCharWidth;
  1059.  
  1060.                /* Create the vertical scroll bar that is placed    */
  1061.                /* on the right side of the list    box        */
  1062.  
  1063.        if ( (plbw->hwndScrollRight = WinCreateWindow(hWnd, WC_SCROLLBAR, (PSZ)NULL,
  1064.                              SBS_VERT |    WS_VISIBLE,
  1065.                              pcrst->cx - plbw->cxScroll, 0L,
  1066.                              plbw->cxScroll, pcrst->cy,
  1067.                              hWnd, HWND_TOP,
  1068.                              0x0000c001UL, (PVOID)NULL,
  1069.                              (PVOID)NULL)) != (HWND)NULL )
  1070.        {
  1071.                /* Sub-class the    scroll bar to allow the        */
  1072.                /* monitoring of    the button up events which will    */
  1073.                /* allow    the proper refocusing to the list box    */
  1074.  
  1075.        WinSetWindowULong(plbw->hwndScrollRight, QWL_USER,
  1076.                  (ULONG)WinSubclassWindow(plbw->hwndScrollRight, (PFNWP)ScrollBarWndProc));    
  1077.        WinQueryWindowPos(plbw->hwndScrollRight, &plbw->aswp[SWP_VERT]);
  1078.        WinEnableWindow(plbw->hwndScrollRight, FALSE);
  1079.        }
  1080.        else
  1081.        return(MRFROMLONG(TRUE));
  1082.  
  1083.                /* When a horizontal scroll bar is requested,    */
  1084.                /* create the horizontal    scroll bar at the    */
  1085.                /* bottom of the    list box            */
  1086.  
  1087.        if ( (pcrst->flStyle & LS_HORZSCROLL) &&    !fAddHorzScroll(hWnd, plbw) )
  1088.        return(MRFROMLONG(TRUE));
  1089.  
  1090.                /* Check    to see if the list box is owner    drawn    */
  1091.                /* in which case    need to    get the    item height to    */
  1092.                /* allow    for the    proper calculation of the    */
  1093.                /* drawing rectangle that will be passed    to the    */
  1094.                /* owner    when an    item needs to be drawn        */
  1095.  
  1096.        MeasureItem(plbw, fm.lMaxBaselineExt);
  1097.  
  1098.                /* Calculate the    placement of the various    */
  1099.                /* elements of the list box            */
  1100.  
  1101.        if ( (pcrst->cx > 0L) &&    (pcrst->cy > 0L) )
  1102.        SizeListBox(plbw);
  1103.  
  1104.                /* Try to load the sound    support    DLL which is    */
  1105.                /* used to interface with the MMPM/2 sound    */
  1106.                /* system                    */
  1107.  
  1108.        LoadSoundSupport(plbw);
  1109.  
  1110.                /* Get the address of the CTLDATA structure that    */
  1111.                /* may contain the listbox items    that the    */
  1112.                /* control can use during its creation instead    */
  1113.                /* of using messages to set the listbox items    */
  1114.  
  1115.        if ( (plbwcd = (PLISTBOXCDATA)PVOIDFROMMP(mp1)) != NULL )
  1116.        if (    plbwcd->ulVersion == LBV_100 )
  1117.            SetControlDataList(plbw,    plbwcd->vdata.lbcd1_0.cItems, plbwcd->vdata.lbcd1_0.abList);
  1118.        else
  1119.            if ( plbwcd->ulVersion == LBV_110 )
  1120.            {
  1121.            SetControlDataSounds(plbw, plbwcd->vdata.lbcd1_1.cItems,
  1122.                     plbwcd->vdata.lbcd1_1.cSounds,
  1123.                     plbwcd->vdata.lbcd1_1.abList);
  1124.  
  1125.            if (    plbwcd->vdata.lbcd1_1.flExtStyles )
  1126.                if ( (plbw->flStyleExt =    plbwcd->vdata.lbcd1_1.flExtStyles) & LSXS_CHECKBOX )
  1127.                plbw->fEnableCheckboxes = TRUE;
  1128.            }
  1129.        break;
  1130.  
  1131. /************************************************************************/
  1132. /************************************************************************/
  1133. /*                                    */
  1134. /* Part    2: Control activation                        */
  1135. /*                                    */
  1136. /************************************************************************/
  1137. /************************************************************************/
  1138.  
  1139.    /*********************************************************************/
  1140.    /*  Control being activated/deactivated                */
  1141.    /*********************************************************************/
  1142.  
  1143.    case    WM_ACTIVATE :
  1144.        if ( (hwndHelp =    WinQueryHelpInstance(hWnd)) != (HWND)NULL )
  1145.  
  1146.                /* When the window is being activated or        */
  1147.                /* deactivated, make sure that the control    */
  1148.                /* responds properly to help requests when it    */
  1149.                /* has the focus                    */
  1150.  
  1151.        if (    SHORT1FROMMP(mp1) )
  1152.            WinSendMsg(hwndHelp, HM_SET_ACTIVE_WINDOW,
  1153.               MPFROMHWND(WinQueryWindow(hWnd, QW_PARENT)),
  1154.               MPFROMHWND(WinQueryWindow(hWnd, QW_PARENT)));
  1155.        else
  1156.            WinSendMsg(hwndHelp, HM_SET_ACTIVE_WINDOW, 0L, 0L);
  1157.        break;
  1158.  
  1159.    /*********************************************************************/
  1160.    /*  Control receiving/losing    focus                    */
  1161.    /*********************************************************************/
  1162.  
  1163.    case    WM_SETFOCUS :
  1164.                /* Get the list box information pointer from    */
  1165.                /* the reserved memory of the window        */
  1166.  
  1167.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1168.  
  1169.                /* When the window is being activated or        */
  1170.                /* deactivated, make sure that the control    */
  1171.                /* responds properly to help requests when it    */
  1172.                /* has the focus                    */
  1173.  
  1174.        if ( SHORT1FROMMP(mp2) )
  1175.        {
  1176.                /* Notify the owner of the list box that    that    */
  1177.                /* list box is gaining focus            */
  1178.  
  1179.        mrNotifyOwner(plbw, LN_SETFOCUS);
  1180.  
  1181.        if (    plbw->cItems )
  1182.            {
  1183.                /* When the focus is being received and none of    */
  1184.                /* the list box items has previously received    */
  1185.                /* the focus, set the first item    in the list box    */
  1186.                /* as receiving the focus            */
  1187.  
  1188.            if ( !plbw->fFocus )
  1189.            {
  1190.            if (    plbw->iFocus ==    LIT_NONE )
  1191.                plbw->iFocus = 0L;
  1192.  
  1193.            WinCreateCursor(plbw->hWnd, plbw->rcl.xLeft,
  1194.                    (plbw->rcl.yTop - (plbw->iFocus - plbw->iVertScroll)    *
  1195.                               plbw->cyItem) - plbw->cyItem,
  1196.                    plbw->rcl.xRight - 1L - plbw->rcl.xLeft, plbw->cyItem,
  1197.                    CURSOR_FRAME    | CURSOR_HALFTONE, NULL);
  1198.            }
  1199.                /* Show the focus indicator on the item that is    */
  1200.                /* deemed to have the focus            */
  1201.  
  1202.            if ( !plbw->fFocusShown )
  1203.            FocusChange(plbw, plbw->iFocus, TRUE);
  1204.            }
  1205.        else
  1206.            if ( !plbw->fFocus )
  1207.            WinCreateCursor(plbw->hWnd, 0L, 0L,
  1208.                    plbw->rcl.xRight - 1L - plbw->rcl.xLeft, plbw->cyItem,
  1209.                    CURSOR_FRAME    | CURSOR_HALFTONE, NULL);
  1210.  
  1211.                /* Set the focus    flag                */
  1212.  
  1213.        plbw->fFocus    = TRUE;
  1214.        }
  1215.        else
  1216.                /* Focus    being lost, only update    internal flags    */
  1217.                /* if the control has received focus previously    */
  1218.  
  1219.        if (    plbw->fFocus )
  1220.            {
  1221.                /* Notify the owner of the list box that    that    */
  1222.                /* list box is losing focus            */
  1223.  
  1224.            mrNotifyOwner(plbw, LN_KILLFOCUS);
  1225.  
  1226.                /* Remove the focus indicator if    one was    being    */
  1227.                /* used                        */
  1228.  
  1229.            if ( plbw->cItems )
  1230.            RemoveFocus(plbw);
  1231.            WinDestroyCursor(hWnd);
  1232.  
  1233.                /* Clear    the focus flag.     NOTE:    the flag MUST    */
  1234.                /* NOT be cleared before    the focus indicator is    */
  1235.                /* removed since    the RemoveFocus    routine    checks    */
  1236.                /* to see if the    control    has focus and will only    */
  1237.                /* remove the indicator if the control does    */
  1238.                /* indeed have focus.                */
  1239.  
  1240.            plbw->fFocus = plbw->fFocusShown    = FALSE;
  1241.            }
  1242.        break;
  1243.  
  1244. /************************************************************************/
  1245. /************************************************************************/
  1246. /*                                    */
  1247. /* Part    3: Control sizing                        */
  1248. /*                                    */
  1249. /************************************************************************/
  1250. /************************************************************************/
  1251.  
  1252.    /*********************************************************************/
  1253.    /*  Control changing    size or    position                */
  1254.    /*********************************************************************/
  1255.  
  1256.    case    WM_ADJUSTWINDOWPOS :
  1257.        pswp = (PSWP)PVOIDFROMMP(mp1);
  1258.        if ( (pswp->fl &    SWP_SIZE) && (pswp->cx > 0) && (pswp->cx > 0) )
  1259.  
  1260.                /* Get the address of the control info from the    */
  1261.                /* control's reserved memory and save the new    */
  1262.                /* size of the control                */
  1263.        {
  1264.        plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1265.        plbw->cxWindow = pswp->cx;
  1266.        plbw->cyWindow = pswp->cy;
  1267.        SizeListBox(plbw);
  1268.        if (    plbw->fFocus )
  1269.            {
  1270.            WinCreateCursor(plbw->hWnd, 0L, 0L,
  1271.                    plbw->rcl.xRight    - 1L - plbw->rcl.xLeft,    plbw->cyItem,
  1272.                    CURSOR_FRAME | CURSOR_HALFTONE, NULL);
  1273.            WinCreateCursor(plbw->hWnd, plbw->rcl.xLeft,
  1274.                    (plbw->rcl.yTop - (plbw->iFocus - plbw->iVertScroll) *
  1275.                           plbw->cyItem)    - plbw->cyItem,
  1276.                    plbw->rcl.xRight    - 1L - plbw->rcl.xLeft,    plbw->cyItem,
  1277.                    CURSOR_FRAME | CURSOR_HALFTONE, NULL);
  1278.            }
  1279.                /* Reset    the scroll bars    to take    into        */
  1280.                /* consideration    the visible number of lines    */
  1281.                /* now contained    within the window        */
  1282.  
  1283.        UpdateScrollBars(plbw);
  1284.        }
  1285.        break;
  1286.  
  1287.    /*********************************************************************/
  1288.    /*  Convert position    query                        */
  1289.    /*********************************************************************/
  1290.  
  1291.    case    WM_QUERYCONVERTPOS :
  1292.        return(MRFROMLONG(QCP_NOCONVERT));
  1293.  
  1294.    /*********************************************************************/
  1295.    /*  Control changing    size                        */
  1296.    /*********************************************************************/
  1297.  
  1298.    case    WM_SIZE    :
  1299.                /* Get the address of the control info from the    */
  1300.                /* control's reserved memory and save the new    */
  1301.                /* size of the control                */
  1302.  
  1303.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1304.        plbw->cxWindow =    (LONG)(SHORT)SHORT1FROMMP(mp2);
  1305.        plbw->cyWindow =    (LONG)(SHORT)SHORT2FROMMP(mp2);
  1306.        SizeListBox(plbw);
  1307.        if ( plbw->fFocus )
  1308.        {
  1309.        WinDestroyCursor(plbw->hWnd);
  1310.        WinCreateCursor(plbw->hWnd, plbw->rcl.xLeft,
  1311.                (plbw->rcl.yTop - (plbw->iFocus - plbw->iVertScroll)    *
  1312.                           plbw->cyItem) - plbw->cyItem,
  1313.                plbw->rcl.xRight - 1L - plbw->rcl.xLeft, plbw->cyItem,
  1314.                CURSOR_FRAME    | CURSOR_HALFTONE, NULL);
  1315.        }
  1316.                /* Reset    the scroll bars    to take    into        */
  1317.                /* consideration    the visible number of lines    */
  1318.                /* now contained    within the window        */
  1319.  
  1320.        UpdateScrollBars(plbw);
  1321.        break;
  1322.  
  1323. /************************************************************************/
  1324. /************************************************************************/
  1325. /*                                    */
  1326. /* Part    3: Mouse interface                        */
  1327. /*                                    */
  1328. /************************************************************************/
  1329. /************************************************************************/
  1330.  
  1331.    /*********************************************************************/
  1332.    /*  Button 1    click                            */
  1333.    /*********************************************************************/
  1334.  
  1335.    case    WM_BUTTON1DOWN :
  1336.                /* Get the list box information pointer from    */
  1337.                /* the reserved memory of the window        */
  1338.  
  1339.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1340.  
  1341.                /* Make sure that the list box has focus        */
  1342.  
  1343.        if ( !plbw->fFocus )
  1344.        WinSetFocus(HWND_DESKTOP, hWnd);
  1345.  
  1346.                /* Check    to see that there are items contained    */
  1347.                /* within the list box                */
  1348.  
  1349.        if ( plbw->cItems )
  1350.        {
  1351.                /* Save the extended information    for undo    */
  1352.  
  1353.        SaveExtendedState(plbw);
  1354.  
  1355.        if (    plbw->flStyleExt & LSXS_CHECKBOX )
  1356.            if ( SHORT1FROMMP(mp1) <    plbw->xTextOffset )
  1357.            if (    fDecodeChkSelect(plbw, mp1) )
  1358.                {
  1359.                /* Capture the mouse to allow proper tracking of    */
  1360.                /* group    selections where the mouse is dragged    */
  1361.                /* over more than one item            */
  1362.  
  1363.                WinSetCapture(HWND_DESKTOP, hWnd);
  1364.                plbw->fCapture =    TRUE;
  1365.  
  1366.                /* Play any associated sounds for the double    */
  1367.                /* click    event                    */
  1368.  
  1369.             /* PlaySound(plbw, LSND_SINGLECLICK); */
  1370.                return(MRFROMLONG(TRUE));
  1371.                }
  1372.  
  1373.                /* Check    to see if the list box is using    the    */
  1374.                /* extended selection interface in which    case    */
  1375.                /* need to check    for extended selection mouse    */
  1376.                /* clicks                    */
  1377.  
  1378.        if (    plbw->flStyle &    LS_EXTENDEDSEL )
  1379.            {
  1380.                /* Check    for Shift+Button 1 selection which is    */
  1381.                /* used to select all items from    the anchor    */
  1382.                /* point    to the item selected            */
  1383.  
  1384.            if ( (ULONG)WinGetKeyState(HWND_DESKTOP,    VK_SHIFT) & 0x00008000UL )
  1385.            fItemValid =    fDecodeExtendedMouse(plbw, mp1,    TRUE);
  1386.            else
  1387.                /* Check    for Ctrl+Button    1 selection which is    */
  1388.                /* used to select or deselect an    item selected    */
  1389.  
  1390.            if (    (ULONG)WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x00008000UL )
  1391.                {
  1392.                if ( (fItemValid    = fDecodeExtendedMouse(plbw, mp1, FALSE)) == TRUE )
  1393.  
  1394.                /* Check    to see if the item was previously    */
  1395.                /* selected and if not, set this    item as    the    */
  1396.                /* new anchor point                */
  1397.  
  1398.                if (    !(plbw->plc[0].apli[plbw->iFocus]->fl &    LI_SELECTEDOLD)    )
  1399.                    plbw->iAnchor = plbw->iFocus;
  1400.                }
  1401.            else
  1402.                /* No extended keyboard selection being used,    */
  1403.                /* process the click such that when the mouse is    */
  1404.                /* over a selected item,    only the focus changes    */
  1405.                /* whereas when it is over an unselected    item,    */
  1406.                /* all items that were selected are unselected    */
  1407.                /* the the new item is the only item selected    */
  1408.  
  1409.                if ( (fItemValid    = fDecodeMouse(plbw, mp1)) == TRUE )
  1410.                if (    !(plbw->plc[0].apli[plbw->iFocus]->fl &    LI_SELECTEDOLD)    )
  1411.  
  1412.                /* Check    to see if the item was previously    */
  1413.                /* selected and if not, set this    item as    the    */
  1414.                /* new anchor point                */
  1415.  
  1416.                    plbw->iAnchor = plbw->iFocus;
  1417.            }
  1418.        else
  1419.                /* No extended keyboard selection being used,    */
  1420.                /* process the click such that when the mouse is    */
  1421.                /* over a selected item,    only the focus changes    */
  1422.                /* whereas when it is over an unselected    item,    */
  1423.                /* all items that were selected are unselected    */
  1424.                /* the the new item is the only item selected    */
  1425.  
  1426.            fItemValid = fDecodeMouse(plbw, mp1);
  1427.  
  1428.                /* Check    to see if the item was valid in    which    */
  1429.                /* case need to set the mouse capture for the    */
  1430.                /* list box to insure that all mouse movements    */
  1431.                /* are properly processed until the user        */
  1432.                /* releases button 1 on the mouse        */
  1433.  
  1434.        if (    fItemValid )
  1435.            {
  1436.                /* Capture the mouse to allow proper tracking of    */
  1437.                /* group    selections where the mouse is dragged    */
  1438.                /* over more than one item            */
  1439.  
  1440.            WinSetCapture(HWND_DESKTOP, hWnd);
  1441.            plbw->fCapture =    TRUE;
  1442.  
  1443.                /* Play any associated sounds for the double    */
  1444.                /* click    event                    */
  1445.  
  1446.            PlaySound(plbw, LSND_SINGLECLICK);
  1447.            }
  1448.        }
  1449.        return(MRFROMLONG(TRUE));
  1450.  
  1451.    /*********************************************************************/
  1452.    /*  Button 1    double click                        */
  1453.    /*********************************************************************/
  1454.  
  1455.    case    WM_BUTTON1DBLCLK :
  1456.                /* Get the list box information pointer from    */
  1457.                /* the reserved memory of the window        */
  1458.  
  1459.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1460.  
  1461.                /* Check    to see that there are items contained    */
  1462.                /* within the list box                */
  1463.  
  1464.        if ( plbw->cItems )
  1465.        {
  1466.                /* Check    to see if the mouse point within the    */
  1467.                /* list box item    area                */
  1468.  
  1469.        ptl.x = (LONG)SHORT1FROMMP(mp1);
  1470.        ptl.y = (LONG)SHORT2FROMMP(mp1);
  1471.        if (    WinPtInRect(plbw->hAB, &plbw->rcl, &ptl) )
  1472.  
  1473.                /* Point    clicked    is within the list box item    */
  1474.                /* area,    now check to see that the point    is over    */
  1475.                /* a valid item                    */
  1476.  
  1477.            if ( lItemFromPoint(plbw, (LONG)SHORT2FROMMP(mp1)) >= plbw->cItems )
  1478.  
  1479.                /* Point    clicked    on does    not contain a valid    */
  1480.                /* entry, make sure that    the item is deselected    */
  1481.  
  1482.            return(MRFROMLONG(TRUE));
  1483.            else
  1484.            {
  1485.                /* Point    clicked    over a valid item, set the    */
  1486.                /* double click flag which will be checked when    */
  1487.                /* the final mouse processing (button 1 up)    */
  1488.                /* determines type of notification that should    */
  1489.                /* be sent to the owning    window            */
  1490.  
  1491.            plbw->fDblClk = TRUE;
  1492.  
  1493.                /* Play any associated sounds for the double    */
  1494.                /* click    event                    */
  1495.  
  1496.            PlaySound(plbw, LSND_DOUBLECLICK);
  1497.            }
  1498.            }
  1499.        return(MRFROMLONG(TRUE));
  1500.  
  1501.    /*********************************************************************/
  1502.    /*  Button 1    released                        */
  1503.    /*********************************************************************/
  1504.  
  1505.    case    WM_BUTTON1UP :
  1506.                /* Get the list box information pointer from    */
  1507.                /* the reserved memory of the window        */
  1508.  
  1509.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1510.  
  1511.                /* Check    to see that there are items contained    */
  1512.                /* within the list box                */
  1513.  
  1514.        if ( plbw->cItems )
  1515.        {
  1516.  
  1517.                /* Check    to see if the capture is currently    */
  1518.                /* active                    */
  1519.  
  1520.        if (    WinQueryCapture(HWND_DESKTOP) == hWnd )
  1521.            {
  1522.                /* Capture still    active,    release    the mouse    */
  1523.                /* capture and clear the    internal capture flag    */
  1524.  
  1525.            WinSetCapture(HWND_DESKTOP, (HWND)NULL);
  1526.            plbw->fCapture =    FALSE;
  1527.            }
  1528.                /* Check    to see if the timer active in which    */
  1529.                /* case need to turn it off            */
  1530.  
  1531.        if (    plbw->fTimer )
  1532.            {
  1533.            plbw->fTimer = FALSE;
  1534.            WinStopTimer(plbw->hAB, hWnd, TID_SCROLL);
  1535.            }
  1536.                /* Check    to see if the mouse was    double clicked    */
  1537.                /* which    means that the owner should be notified    */
  1538.                /* using    the appropriate    notification message    */
  1539.  
  1540.        if (    plbw->fDblClk )
  1541.            {
  1542.            mrNotifyOwner(plbw, LN_ENTER);
  1543.            plbw->fDblClk = FALSE;
  1544.            }
  1545.        }
  1546.        return(MRFROMLONG(TRUE));
  1547.  
  1548.    /*********************************************************************/
  1549.    /*  Button 2    clicked                            */
  1550.    /*  Button 3    clicked                            */
  1551.    /*********************************************************************/
  1552.  
  1553.    case    WM_BUTTON2DOWN :
  1554.    case    WM_BUTTON3DOWN :
  1555.        WinSetActiveWindow(HWND_DESKTOP,    hWnd);
  1556.        break;
  1557.  
  1558. #define    DEBUG_LISTBOX
  1559.  
  1560. #if defined(DEBUG_LISTBOX)
  1561.  
  1562.    case    WM_BUTTON2DBLCLK :
  1563.        {
  1564.        PSZ pszBuffer;           /* Buffer Pointer            */
  1565.  
  1566.                /* Get the list box information pointer from    */
  1567.                /* the reserved memory of the window        */
  1568.  
  1569.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1570.        DosAllocMem((PPVOID)(PVOID)&pszBuffer, 4096UL, PAG_READ | PAG_WRITE | PAG_COMMIT);
  1571.        sprintf(pszBuffer, "iFocus = %d\niSelected = %d\nfFocus = %d\nfFocusShown = %d\nCursor Level = %d",
  1572.               plbw->iFocus,    plbw->iSelected, plbw->fFocus, plbw->fFocusShown,
  1573.               WinQuerySysValue(HWND_DESKTOP, SV_CURSORLEVEL));
  1574.        WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, pszBuffer, "List Box Data", 0UL,
  1575.              MB_OK);
  1576.        DosFreeMem((PVOID)pszBuffer);
  1577.        HeapDisplayStatus(plbw->plc[0].hHeap);
  1578.        }
  1579.        break;
  1580. #endif
  1581.  
  1582.    /*********************************************************************/
  1583.    /* Process mouse movement over the list box                */
  1584.    /*********************************************************************/
  1585.  
  1586.    case    WM_MOUSEMOVE :
  1587.                /* Get the list box information pointer from    */
  1588.                /* the reserved memory of the window        */
  1589.  
  1590.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1591.  
  1592.                /* Check    to see if the mouse is in capture mode    */
  1593.                /* which    means that the user has    not released    */
  1594.                /* Button 1 yet and is probably in a drag    */
  1595.                /* operation                    */
  1596.  
  1597.        if ( (WinQueryCapture(HWND_DESKTOP) == hWnd) && plbw->fCapture )
  1598.  
  1599.                /* User dragging    the mouse while    pressing Button    */
  1600.                /* 1, check to see if the mouse pointer inside    */
  1601.                /* or outside the list box area and where    */
  1602.                /* appropriate, change the item selected    based    */
  1603.                /* on that position                */
  1604.  
  1605.        if (    (LONG)(SHORT)SHORT2FROMMP(mp1) > plbw->rcl.yTop    )
  1606.            {
  1607.                /* User has dragged the mouse pointer above the    */
  1608.                /* top item of the list box, move up a line and    */
  1609.                /* start    the scroll timer if it isn't already    */
  1610.                /* running                    */
  1611.  
  1612.            DragUp(plbw);
  1613.            if ( !plbw->fTimer )
  1614.            {
  1615.            plbw->fTimer    = TRUE;
  1616.            WinStartTimer(plbw->hAB, hWnd, TID_SCROLL, 50UL);
  1617.            }
  1618.            }
  1619.        else
  1620.            if ( (LONG)(SHORT)SHORT2FROMMP(mp1) < plbw->rcl.yBottom )
  1621.            {
  1622.                /* User has dragged the mouse pointer below the    */
  1623.                /* bottom item of the list box, move up a line    */
  1624.                /* and start the    scroll timer if    it isn't        */
  1625.                /* already running                */
  1626.  
  1627.            DragDown(plbw);
  1628.            if (    !plbw->fTimer )
  1629.                {
  1630.                plbw->fTimer = TRUE;
  1631.                WinStartTimer(plbw->hAB,    hWnd, TID_SCROLL, 50UL);
  1632.                }
  1633.            }
  1634.            else
  1635.                /* The mouse pointer position is    vertically    */
  1636.                /* within the list box limits although it may be    */
  1637.                /* horizontally outside of the list box.     Take    */
  1638.                /* the vertical position    and using a "canned"    */
  1639.                /* horizontal position, process the point to see    */
  1640.                /* if this changes the selected items within the    */
  1641.                /* list box.                    */
  1642.  
  1643.            if (    fDecodeMouse(plbw,
  1644.                      MPFROMLONG(MAKEULONG((USHORT)(plbw->rcl.xLeft + 1L),
  1645.                         SHORT2FROMMP(mp1)))) )
  1646.                {
  1647.                /* Valid    position, stop the timer if it was set    */
  1648.                /* since    any vertical movement can be easily    */
  1649.                /* monitored and    the list box does not need to    */
  1650.                /* be scrolled                    */
  1651.  
  1652.                if ( plbw->fTimer )
  1653.  
  1654.                {
  1655.                plbw->fTimer    = FALSE;
  1656.                WinStopTimer(plbw->hAB, hWnd, TID_SCROLL);
  1657.                }
  1658.                }
  1659.            else
  1660.                /* Invalid position, start the timer since any    */
  1661.                /* vertical movement cannot be easily monitored    */
  1662.                /* monitored and    the list box needs to be    */
  1663.                /* scrolled                    */
  1664.  
  1665.                if ( !plbw->fTimer )
  1666.                {
  1667.                plbw->fTimer    = TRUE;
  1668.                WinStartTimer(plbw->hAB, hWnd, TID_SCROLL, 50UL);
  1669.                }
  1670.  
  1671.                /* Send the WM_CONTROLPOINTER message to    the    */
  1672.                /* owner    of the control to allow    the owner of    */
  1673.                /* control to change the    pointer    shape from the    */
  1674.                /* current defined arrow    shape            */
  1675.  
  1676.        WinSetPointer(HWND_DESKTOP,
  1677.              (HPOINTER)WinSendMsg(plbw->hwndOwner,
  1678.                       WM_CONTROLPOINTER,
  1679.                       MPFROMLONG(plbw->id),
  1680.                       MPFROMLONG(plbw->hptr)));
  1681.        return(MRFROMLONG(TRUE));
  1682.  
  1683.    /*********************************************************************/
  1684.    /* Process timer notification                    */
  1685.    /*********************************************************************/
  1686.  
  1687.    case    WM_TIMER :
  1688.                /* Check    to make    sure that the timer is the    */
  1689.                /* scroll timer for the list box    when mouse    */
  1690.                /* capture has been started during the drag    */
  1691.                /* operation of the mouse and the mouse pointer    */
  1692.                /* is outside the list box display area        */
  1693.  
  1694.        if ( SHORT1FROMMP(mp1) == TID_SCROLL )
  1695.        {
  1696.                /* Get the address of the control info from the    */
  1697.                /* control's reserved memory                     */
  1698.  
  1699.        plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1700.  
  1701.                /* Get the current mouse    pointer    position    */
  1702.  
  1703.        WinQueryPointerPos(HWND_DESKTOP, &ptl);
  1704.  
  1705.                /* Convert the mouse pointer position, which is    */
  1706.                /* in desktop co-ordinates to the list box    */
  1707.                /* co-ordinates                    */
  1708.  
  1709.        WinMapWindowPoints(HWND_DESKTOP, hWnd, &ptl,    1L);
  1710.  
  1711.                /* Check    to see if the mouse pointer is inside    */
  1712.                /* the display rectangle    in which case the timer    */
  1713.                /* should be stopped to allow the normal        */
  1714.                /* mouse    handling to be performed        */
  1715.  
  1716.        if (    WinPtInRect(plbw->hAB, &plbw->rcl, &ptl) )
  1717.            {
  1718.            plbw->fTimer = FALSE;
  1719.            WinStopTimer(plbw->hAB, hWnd, TID_SCROLL);
  1720.            }
  1721.        else
  1722.                /* When the mouse pointer is above the list box,    */
  1723.                /* scroll upwards                */
  1724.  
  1725.            if ( ptl.y > plbw->rcl.yTop )
  1726.            DragUp(plbw);
  1727.            else
  1728.                /* When the mouse pointer is below the list box,    */
  1729.                /* scroll downwards                */
  1730.  
  1731.            if (    ptl.y <    plbw->rcl.yBottom )
  1732.                DragDown(plbw);
  1733.        }
  1734.        break;
  1735.  
  1736. /************************************************************************/
  1737. /************************************************************************/
  1738. /*                                    */
  1739. /* Part    4: Keyboard interface                        */
  1740. /*                                    */
  1741. /************************************************************************/
  1742. /************************************************************************/
  1743.  
  1744.    /*********************************************************************/
  1745.    /*  Key being pressed                        */
  1746.    /*********************************************************************/
  1747.  
  1748.                /* Keyboard character received            */
  1749.    case    WM_CHAR    :
  1750.                /* Only act on key down requests    therefore if a    */
  1751.                /* key up event,    ignore it            */
  1752.  
  1753.        if ( SHORT1FROMMP(mp1) &    KC_KEYUP )
  1754.        break;
  1755.  
  1756.        if ( SHORT1FROMMP(mp1) &    KC_CHAR    )
  1757.        {
  1758.                /* Get the list box data    pointer    from the window    */
  1759.  
  1760.        plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1761.        fItemSelect = FALSE;
  1762.        if (    plbw->iSelected    != LIT_NONE )
  1763.            {
  1764.            if ( (n = (CHAR1FROMMP(mp2) & 223)) <
  1765.             (i = (plbw->plc[0].apli[plbw->iSelected]->pszText[0] & 223)) )
  1766.            {
  1767.            if (    plbw->iSelected    )
  1768.                for ( i = plbw->iSelected - 1L; i >= 0; i-- )
  1769.                if (    (plbw->plc[0].apli[i]->pszText[0] & 223) == (CHAR1FROMMP(mp2) &    223) )
  1770.                    {
  1771.                    fItemSelect = TRUE;
  1772.                    break;
  1773.                    }
  1774.            }
  1775.            else
  1776.            for ( i = plbw->iSelected + 1L; i < plbw->cItems; i++ )
  1777.                if ( (plbw->plc[0].apli[i]->pszText[0] &    223) ==    (CHAR1FROMMP(mp2) & 223) )
  1778.                {
  1779.                fItemSelect = TRUE;
  1780.                break;
  1781.                }
  1782.            }
  1783.        else
  1784.            for ( i = 0; i <    plbw->cItems; i++ )
  1785.            if (    (plbw->plc[0].apli[i]->pszText[0] & 223) == (CHAR1FROMMP(mp2) &    223) )
  1786.                {
  1787.                fItemSelect = TRUE;
  1788.                break;
  1789.                }
  1790.  
  1791.        if (    fItemSelect )
  1792.            {
  1793.            if ( i <    plbw->iVertScroll )
  1794.            {
  1795.            if (    (plbw->iVertScroll = plbw->iSelected = i) >
  1796.             plbw->cVertScroll )
  1797.                plbw->iVertScroll = plbw->cVertScroll;
  1798.  
  1799.                /* Update the scroll bar    positioning and    force    */
  1800.                /* the repainting of the    list            */
  1801.  
  1802.            WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  1803.                   MPFROMSHORT(plbw->iVertScroll), 0L);
  1804.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1805.            }
  1806.            else
  1807.            if (    i <= (plbw->iVertScroll    + plbw->cLinesPage) )
  1808.                {
  1809.                /* Determine if the currently selected item    */
  1810.                /* within the list is displayed in the viewable    */
  1811.                /* area of the window in    which case the entry    */
  1812.                /* needs    to be changed back to normal        */
  1813.  
  1814.                if ( (plbw->iSelected >=    plbw->iVertScroll) &&
  1815.                 (plbw->iSelected <=    (plbw->iVertScroll + plbw->cLinesPage))    )
  1816.                fSelectItem(plbw, 0L, plbw->iSelected, FALSE);
  1817.  
  1818.                fSelectItem(plbw, 0L, plbw->iSelected = i, TRUE);
  1819.                }
  1820.            else
  1821.                {
  1822.                if ( (plbw->iVertScroll = plbw->iSelected = i) >
  1823.                 plbw->cVertScroll )
  1824.                plbw->iVertScroll = plbw->cVertScroll;
  1825.  
  1826.                /* Update the scroll bar    positioning and    force    */
  1827.                /* the repainting of the    list            */
  1828.  
  1829.                WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  1830.                   MPFROMSHORT(plbw->iVertScroll), 0L);
  1831.                WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1832.                }
  1833.            return(MRFROMLONG(TRUE));
  1834.            }
  1835.        }
  1836.                /* Check    to make    sure the key is    decodeable key    */
  1837.  
  1838.        if ( (CHARMSG(&msg)->fs & KC_CTRL) && (CHARMSG(&msg)->chr == '\\') )
  1839.        {
  1840.                /* Ctrl+\ : Deselect all                */
  1841.                /* Get the list box data    pointer    from the window    */
  1842.  
  1843.        plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1844.        if (    plbw->flStyle &    (LS_MULTIPLESEL    | LS_EXTENDEDSEL) )
  1845.            {
  1846.            if ( plbw->iFocus != LIT_NONE )
  1847.            if (    plbw->plc[0].apli[plbw->iFocus]->fl & LI_SELECTEDOLD )
  1848.                fItemSelect = TRUE;
  1849.            else
  1850.                fItemSelect = FALSE;
  1851.            else
  1852.            fItemSelect = FALSE;
  1853.  
  1854.            SaveExtendedState(plbw);
  1855.            for ( i = 0; i <    plbw->cItems; i++ )
  1856.            if (    i == plbw->iFocus )
  1857.                {
  1858.                if ( !fItemSelect &&
  1859.                  (plbw->plc[0].apli[i]->fl & LI_SELECTED) )
  1860.                {
  1861.                SaveSelectState(0L, i);
  1862.                plbw->plc[0].apli[i]->fl &= ~LI_SELECTED;
  1863.                }
  1864.                }
  1865.            else
  1866.                if ( (plbw->plc[0].apli[i]->fl &    LI_SELECTED) )
  1867.                {
  1868.                SaveSelectState(0L, i);
  1869.                plbw->plc[0].apli[i]->fl &= ~LI_SELECTED;
  1870.                }
  1871.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1872.            mrNotifyOwner(plbw, LN_SELECT);
  1873.            return(MRFROMLONG(TRUE));
  1874.            }
  1875.        }
  1876.        else
  1877.        if (    (CHARMSG(&msg)->fs & KC_CTRL) && (CHARMSG(&msg)->chr ==    '/') )
  1878.            {
  1879.                /* Ctrl+/ : Select all                */
  1880.  
  1881.                /* Get the list box data    pointer    from the window    */
  1882.  
  1883.            plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1884.            if ( plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL) )
  1885.            {
  1886.            SaveExtendedState(plbw);
  1887.            for ( i = 0;    i < plbw->cItems; i++ )
  1888.                if ( !(plbw->plc[0].apli[i]->fl & LI_SELECTED) )
  1889.                {
  1890.                SaveSelectState(0L, i);
  1891.                plbw->plc[0].apli[i]->fl |= LI_SELECTED;
  1892.                }
  1893.  
  1894.            plbw->iSelected = plbw->iFocus;
  1895.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1896.            mrNotifyOwner(plbw, LN_SELECT);
  1897.            return(MRFROMLONG(TRUE));
  1898.            }
  1899.            }
  1900.        else
  1901.                /* Check    to make    sure the key is    decodeable key    */
  1902.  
  1903.            if ( CHARMSG(&msg)->fs &    KC_VIRTUALKEY )
  1904.            switch ( CHARMSG(&msg)->vkey    )
  1905.                {
  1906.                /* Alt+Backspace    : Undo                */
  1907.  
  1908.                case VK_BACKSPACE :
  1909.  
  1910.                /* Get the list box data    pointer    from the window    */
  1911.  
  1912.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1913.                if (    (CHARMSG(&msg)->fs & KC_ALT) &&    (plbw->flStyle & LS_EXTENDEDSEL) )
  1914.                    {
  1915.                    RestoreExtendedState(plbw);
  1916.                    WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1917.                    }
  1918.                return(MRFROMLONG(TRUE));
  1919.  
  1920.                /* Enter    key pressed                */
  1921.  
  1922.                case VK_ENTER :
  1923.                case VK_NEWLINE :
  1924.  
  1925.                /* Get the list box data    pointer    from the window    */
  1926.  
  1927.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1928.  
  1929.                /* Check    to see if there    is a valid selection    */
  1930.                /* and if not, ignore the keystroke.  When valid    */
  1931.                /* send a message back to the window that will    */
  1932.                /* cause    the item to be selected.        */
  1933.  
  1934.                if (    plbw->iSelected    == LIT_NONE )
  1935.                    return(0L);
  1936.                else
  1937.                    if ( plbw->fFocus )
  1938.                    mrNotifyOwner(plbw, LN_ENTER);
  1939.  
  1940.                return(MRFROMLONG(TRUE));
  1941.  
  1942.                /* Space    bar pressed                */
  1943.  
  1944.                case VK_SPACE :
  1945.  
  1946.                /* Get the list box data    pointer    from the window    */
  1947.  
  1948.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1949.  
  1950.                /* Check    to see if the focus has    been placed on    */
  1951.                /* the list box and if it is visible remove the    */
  1952.                /* focus    indicator                */
  1953.  
  1954.                if (    plbw->iFocus > 0L )
  1955.  
  1956.                /* Check    to see if the list box is in single    */
  1957.                /* select mode which means that the item    which    */
  1958.                /* contains the focus also is the current item    */
  1959.                /* selected                    */
  1960.  
  1961.                    if ( plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL) )
  1962.                    {
  1963.                    if (    plbw->flStyle &    LS_MULTIPLESEL )
  1964.                        fSelectMultipleItem(plbw, 0L, plbw->iFocus,
  1965.                                (BOOL)(plbw->plc[0].apli[plbw->iFocus]->fl &    LI_SELECTED ? FALSE : TRUE));
  1966.                    else
  1967.                        if ( !(plbw->plc[0].apli[plbw->iFocus]->fl & LI_SELECTED) )
  1968.                        fSelectMultipleItem(plbw, 0L, plbw->iFocus,
  1969.                                    TRUE);
  1970.                    if (    !fItemVisible(plbw, plbw->iFocus) )
  1971.                        {
  1972.                        if ( (plbw->iVertScroll = plbw->iFocus -    plbw->cLinesPage / 2L) < 0L )
  1973.                        plbw->iVertScroll = 0L;
  1974.  
  1975.                        mrNotifyOwner(plbw, LN_SCROLL);
  1976.                        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  1977.                           MPFROMSHORT(plbw->iVertScroll), 0L);
  1978.                        WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1979.                        }
  1980.                    mrNotifyOwner(plbw, LN_SELECT);
  1981.                    }
  1982.                return(MRFROMLONG(TRUE));
  1983.  
  1984.                /* Up cursor key    selected            */
  1985.  
  1986.                case VK_UP :
  1987.  
  1988.                /* Get the list box data    pointer    from the window    */
  1989.  
  1990.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1991.  
  1992.                if (    (plbw->flStyle & LS_EXTENDEDSEL) &&
  1993.                 (CHARMSG(&msg)->fs & KC_SHIFT) )
  1994.                    if ( plbw->iFocus > plbw->iAnchor )
  1995.                    fSelectMultipleItem(plbw, 0L, plbw->iFocus, FALSE);
  1996.                    else
  1997.                    if (    plbw->iFocus )
  1998.                        fSelectMultipleItem(plbw, 0L, plbw->iFocus - 1L,    TRUE);
  1999.  
  2000.                /* Get the list box data    pointer    from the window    */
  2001.  
  2002.                LineUp(plbw);
  2003.                return(MRFROMLONG(TRUE));
  2004.  
  2005.                case VK_DOWN :
  2006.  
  2007.                /* Get the list box data    pointer    from the window    */
  2008.  
  2009.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2010.  
  2011.                if (    (plbw->flStyle & LS_EXTENDEDSEL) &&
  2012.                 (CHARMSG(&msg)->fs & KC_SHIFT) )
  2013.                    if ( plbw->iFocus < plbw->iAnchor )
  2014.                    fSelectMultipleItem(plbw, 0L, plbw->iFocus, FALSE);
  2015.                    else
  2016.                    if (    plbw->iFocus < (plbw->cItems - 1L) )
  2017.                        fSelectMultipleItem(plbw, 0L, plbw->iFocus + 1L,    TRUE);
  2018.  
  2019.                /* Get the list box data    pointer    from the window    */
  2020.  
  2021.                LineDown(plbw);
  2022.                return(MRFROMLONG(TRUE));
  2023.  
  2024.                case VK_RIGHT :
  2025.  
  2026.                /* Get the list box data    pointer    from the window    */
  2027.  
  2028.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2029.  
  2030.                /* Calculate the    proper position    of the scroll    */
  2031.                /* bar such that    it falls within    a valid    range    */
  2032.                /* and set the new scroll bar position and force    */
  2033.                /* the repainting of the    output window        */
  2034.  
  2035.                if (    plbw->iHorzScroll < plbw->cHorzScroll )
  2036.                    {
  2037.  
  2038.                /* Send the scroll notification to the list box    */
  2039.                /* owner                        */
  2040.  
  2041.                    mrNotifyOwner(plbw, LN_SCROLL);
  2042.  
  2043.                /* Remove the focus indicator since it will    */
  2044.                /* show the right edge repeatedly along the line    */
  2045.                /* while    scrolling                */
  2046.  
  2047.                    RemoveFocus(plbw);
  2048.  
  2049.                /* Update the scroll bar    position and then cause    */
  2050.                /* the list area    to scroll horizontally before    */
  2051.                /* forcing the list box to repaint the area    */
  2052.                /* invalidated                    */
  2053.  
  2054.                    WinSendMsg(plbw->hwndScrollBottom, SBM_SETPOS, MPFROMSHORT(++plbw->iHorzScroll),    0L);
  2055.                    WinScrollWindow(hWnd, -plbw->xChar, 0L,
  2056.                            (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  2057.                            (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  2058.                    WinUpdateWindow(hWnd);
  2059.  
  2060.                /* Redisplay the    focus since the    text has been    */
  2061.                /* scrolled properly                */
  2062.  
  2063.                    SetFocus(plbw, plbw->iFocus);
  2064.                    }
  2065.                return(MRFROMLONG(TRUE));
  2066.  
  2067.                case VK_LEFT :
  2068.  
  2069.                /* Get the list box data    pointer    from the window    */
  2070.  
  2071.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2072.  
  2073.                /* Calculate the    proper position    of the scroll    */
  2074.                /* bar such that    it falls within    a valid    range    */
  2075.                /* and set the new scroll bar position and force    */
  2076.                /* the repainting of the    output window        */
  2077.  
  2078.                if (    plbw->iHorzScroll > 0L )
  2079.                    {
  2080.                /* Send the scroll notification to the list box    */
  2081.                /* owner                        */
  2082.  
  2083.                    mrNotifyOwner(plbw, LN_SCROLL);
  2084.  
  2085.                /* Remove the focus indicator since it will    */
  2086.                /* show the right edge repeatedly along the line    */
  2087.                /* while    scrolling                */
  2088.  
  2089.                    RemoveFocus(plbw);
  2090.  
  2091.                /* Update the scroll bar    position and then cause    */
  2092.                /* the list area    to scroll horizontally before    */
  2093.                /* forcing the list box to repaint the area    */
  2094.                /* invalidated                    */
  2095.  
  2096.                    WinSendMsg(plbw->hwndScrollBottom, SBM_SETPOS, MPFROMSHORT(--plbw->iHorzScroll),    0L);
  2097.                    WinScrollWindow(hWnd, plbw->xChar, 0L,
  2098.                            (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  2099.                            (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  2100.                    WinUpdateWindow(hWnd);
  2101.  
  2102.                /* Redisplay the    focus since the    text has been    */
  2103.                /* scrolled properly                */
  2104.  
  2105.                    SetFocus(plbw, plbw->iFocus);
  2106.                    }
  2107.                return(MRFROMLONG(TRUE));
  2108.  
  2109.                case VK_PAGEUP :
  2110.                case VK_F7 :
  2111.  
  2112.                /* Get the list box data    pointer    from the window    */
  2113.  
  2114.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2115.  
  2116.                /* Check    to see if the focus has    been placed on    */
  2117.                /* the list box and if it is visible remove the    */
  2118.                /* focus    indicator                */
  2119.  
  2120.                if (    (plbw->iFocus != LIT_NONE) && (plbw->iVertScroll != 0L)    )
  2121.                    if ( (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL))    == 0UL )
  2122.                    {
  2123.                    SaveSelectState(0L, plbw->iFocus);
  2124.                    plbw->plc[0].apli[plbw->iFocus]->fl &= ~(LI_FOCUS | LI_SELECTED);
  2125.                    if (    fItemVisible(plbw, plbw->iFocus) )
  2126.                        DrawItemSelection(plbw, plbw->iFocus);
  2127.  
  2128.                /* Check    to see if the new position calculated    */
  2129.                /* will be after    the list bottom    display    item,    */
  2130.                /* in which case, the list will need to be    */
  2131.                /* shifted downwards and    the list redisplayed    */
  2132.  
  2133.                    if (    (plbw->iFocus -= (plbw->cLinesPage - 1L)) < plbw->iVertScroll )
  2134.                        {
  2135.  
  2136.                /* Check    to see that the    movement doesn't cause  */
  2137.                /* the bottom of    the list to be greater than the    */
  2138.                /* scroll limits    in which case, the scroll index    */
  2139.                /* should be set    to this    limit            */
  2140.  
  2141.                        if ( (plbw->iVertScroll -= (plbw->cLinesPage - 1L)) < 0L    )
  2142.                        plbw->iVertScroll = 0L;
  2143.  
  2144.                /* Check    to make    sure that the selected item    */
  2145.                /* due to the page up is    not invalid by being    */
  2146.                /* outside the limits of    the array        */        
  2147.  
  2148.                        if ( plbw->iFocus < 0L )
  2149.                        plbw->iFocus    = 0L;
  2150.  
  2151.                /* Update the scroll bar    positioning and    force    */
  2152.                /* the repainting of the    list            */
  2153.  
  2154.                        mrNotifyOwner(plbw, LN_SCROLL);
  2155.                        SaveSelectState(0L, plbw->iFocus);
  2156.                        plbw->plc[0].apli[plbw->iSelected = plbw->iFocus]->fl |=    (LI_FOCUS | LI_SELECTED);
  2157.                        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  2158.                           MPFROMSHORT(plbw->iVertScroll), 0L);
  2159.                        WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  2160.                        }
  2161.                    else
  2162.                        {
  2163.                        SaveSelectState(0L, plbw->iFocus);
  2164.                        plbw->plc[0].apli[plbw->iSelected = plbw->iFocus]->fl |=    (LI_FOCUS | LI_SELECTED);
  2165.                        DrawItemSelection(plbw, plbw->iFocus);
  2166.                        }
  2167.                    }
  2168.                    else
  2169.                    {
  2170.                    RemoveFocus(plbw);
  2171.  
  2172.                /* Check    to see if the new position calculated    */
  2173.                /* will be after    the list bottom    display    item,    */
  2174.                /* in which case, the list will need to be    */
  2175.                /* shifted downwards and    the list redisplayed    */
  2176.  
  2177.                    if (    (plbw->iFocus -= (plbw->cLinesPage - 1L)) < plbw->iVertScroll )
  2178.                        {
  2179.  
  2180.                /* Check    to see that the    movement doesn't cause  */
  2181.                /* the bottom of    the list to be greater than the    */
  2182.                /* scroll limits    in which case, the scroll index    */
  2183.                /* should be set    to this    limit            */
  2184.  
  2185.                        if ( (plbw->iVertScroll -= (plbw->cLinesPage - 1L)) < 0L    )
  2186.                        plbw->iVertScroll = 0L;
  2187.  
  2188.                /* Check    to make    sure that the selected item    */
  2189.                /* due to the page up is    not invalid by being    */
  2190.                /* outside the limits of    the array        */        
  2191.  
  2192.                        if ( plbw->iFocus < 0L )
  2193.                        plbw->iFocus    = 0L;
  2194.  
  2195.                /* Update the scroll bar    positioning and    force    */
  2196.                /* the repainting of the    list            */
  2197.  
  2198.                        mrNotifyOwner(plbw, LN_SCROLL);
  2199.                        plbw->plc[0].apli[plbw->iFocus]->fl |= LI_FOCUS;
  2200.                        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  2201.                           MPFROMSHORT(plbw->iVertScroll), 0L);
  2202.                        WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  2203.                        }
  2204.                    else
  2205.                        SetFocus(plbw, plbw->iFocus);
  2206.                    }
  2207.                return(MRFROMLONG(TRUE));
  2208.  
  2209.                case VK_F8 :
  2210.                case VK_PAGEDOWN    :
  2211.  
  2212.                /* Get the list box data    pointer    from the window    */
  2213.  
  2214.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2215.  
  2216.                /* Check    to see if the focus has    been placed on    */
  2217.                /* the list box and if it is visible remove the    */
  2218.                /* focus    indicator                */
  2219.  
  2220.                if (    (plbw->iFocus != LIT_NONE) && (plbw->iVertScroll != plbw->cVertScroll) )
  2221.                    if ( (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL))    == 0UL )
  2222.                    {
  2223.                    SaveSelectState(0L, plbw->iFocus);
  2224.                    plbw->plc[0].apli[plbw->iFocus]->fl &= ~(LI_FOCUS | LI_SELECTED);
  2225.                    if (    fItemVisible(plbw, plbw->iFocus) )
  2226.                        DrawItemSelection(plbw, plbw->iFocus);
  2227.  
  2228.                /* Check    to see if the new position calculated    */
  2229.                /* will be a after the current list bottom    */
  2230.                /* display item,    in which case, the list    will    */
  2231.                /* need to be shifted downwards and the list    */
  2232.                /* redisplayed                    */
  2233.  
  2234.                    if (    (plbw->iFocus += (plbw->cLinesPage - 1L)) >=
  2235.                     (plbw->iVertScroll + plbw->cLinesPage) )
  2236.                        {
  2237.  
  2238.                /* Check    to see that the    movement doesn't cause  */
  2239.                /* the bottom of    the list to be greater than the    */
  2240.                /* scroll limits    in which case, the scroll index    */
  2241.                /* should be set    to this    limit            */
  2242.  
  2243.                        if ( (plbw->iVertScroll += (plbw->cLinesPage - 1L)) > plbw->cVertScroll )
  2244.                        plbw->iVertScroll = plbw->cVertScroll;
  2245.  
  2246.                /* Check    to make    sure that the selected item    */
  2247.                /* due to the page up is    not invalid by being    */
  2248.                /* outside the limits of    the array        */        
  2249.  
  2250.                        if ( plbw->iFocus >= plbw->cItems )
  2251.                        plbw->iFocus    = plbw->cItems - 1L;
  2252.  
  2253.                /* Update the scroll bar    positioning and    force    */
  2254.                /* the repainting of the    list            */
  2255.  
  2256.                        SaveSelectState(0L, plbw->iFocus);
  2257.                        plbw->plc[0].apli[plbw->iSelected = plbw->iFocus]->fl |=    (LI_FOCUS | LI_SELECTED);
  2258.                        mrNotifyOwner(plbw, LN_SCROLL);
  2259.                        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  2260.                           MPFROMSHORT(plbw->iVertScroll), 0L);
  2261.                        WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  2262.                        }
  2263.                    else
  2264.                        {
  2265.                        SaveSelectState(0L, plbw->iFocus);
  2266.                        plbw->plc[0].apli[plbw->iSelected = plbw->iFocus]->fl |=    (LI_FOCUS | LI_SELECTED);
  2267.                        DrawItemSelection(plbw, plbw->iFocus);
  2268.                        }
  2269.                    }
  2270.                    else
  2271.                    {
  2272.                    RemoveFocus(plbw);
  2273.  
  2274.                /* Check    to see if the new position calculated    */
  2275.                /* will be a after the current list bottom    */
  2276.                /* display item,    in which case, the list    will    */
  2277.                /* need to be shifted downwards and the list    */
  2278.                /* redisplayed                    */
  2279.  
  2280.                    if (    (plbw->iFocus += (plbw->cLinesPage - 1L)) >=
  2281.                     (plbw->iVertScroll + plbw->cLinesPage) )
  2282.                        {
  2283.  
  2284.                /* Check    to see that the    movement doesn't cause  */
  2285.                /* the bottom of    the list to be greater than the    */
  2286.                /* scroll limits    in which case, the scroll index    */
  2287.                /* should be set    to this    limit            */
  2288.  
  2289.                        if ( (plbw->iVertScroll += (plbw->cLinesPage - 1L)) > plbw->cVertScroll )
  2290.                        plbw->iVertScroll = plbw->cVertScroll;
  2291.  
  2292.                /* Check    to make    sure that the selected item    */
  2293.                /* due to the page up is    not invalid by being    */
  2294.                /* outside the limits of    the array        */        
  2295.  
  2296.                        if ( plbw->iFocus >= plbw->cItems )
  2297.                        plbw->iFocus    = plbw->cItems - 1L;
  2298.  
  2299.                /* Update the scroll bar    positioning and    force    */
  2300.                /* the repainting of the    list            */
  2301.  
  2302.                        plbw->plc[0].apli[plbw->iFocus]->fl |= LI_FOCUS;
  2303.                        mrNotifyOwner(plbw, LN_SCROLL);
  2304.                        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  2305.                           MPFROMSHORT(plbw->iVertScroll), 0L);
  2306.                        WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  2307.                        }
  2308.                   else
  2309.                        SetFocus(plbw, plbw->iFocus);
  2310.                    }
  2311.                return(MRFROMLONG(TRUE));
  2312.  
  2313.                case VK_HOME :
  2314.  
  2315.                /* Get the list box data    pointer    from the window    */
  2316.  
  2317.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2318.  
  2319.                /* Set the current item selected    to the top of    */
  2320.                /* the list and update the scroll bar to        */
  2321.                /* reflect this change before forcing the window    */
  2322.                /* to be    repainted                */
  2323.  
  2324.                if (    plbw->iVertScroll )
  2325.                    {
  2326.                    if ( plbw->iFocus > plbw->cLinesPage )
  2327.                    fScroll = TRUE;
  2328.                    else
  2329.                    fScroll = FALSE;
  2330.  
  2331.                    if ( (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL))    == 0UL )
  2332.                    {
  2333.                    SaveSelectState(0L, plbw->iFocus);
  2334.                    plbw->plc[0].apli[plbw->iFocus]->fl &= ~(LI_FOCUS | LI_SELECTED);
  2335.                    plbw->plc[0].apli[plbw->iSelected = plbw->iFocus = 0L]->fl |= (LI_FOCUS | LI_SELECTED);
  2336.                    }
  2337.                    else
  2338.                    {
  2339.                    plbw->plc[0].apli[plbw->iFocus]->fl &= ~LI_FOCUS;
  2340.                    plbw->plc[0].apli[plbw->iFocus = 0L]->fl |= LI_FOCUS;
  2341.                    }
  2342.             
  2343.                    if ( fScroll )
  2344.                    {
  2345.                    mrNotifyOwner(plbw, LN_SCROLL);
  2346.                    WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  2347.                           MPFROMSHORT(plbw->iVertScroll = 0), 0L);
  2348.                    WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  2349.                    }
  2350.                    }
  2351.                return(MRFROMLONG(TRUE));
  2352.  
  2353.                case VK_END :
  2354.  
  2355.                /* Get the list box data    pointer    from the window    */
  2356.  
  2357.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2358.  
  2359.                /* Set the current item selected    to the bottom    */
  2360.                /* of the list and update the scroll bar    to    */
  2361.                /* reflect this change before forcing the window    */
  2362.                /* to be    repainted                */
  2363.  
  2364.                if (    (plbw->cItems >    plbw->cLinesPage) &&
  2365.                 (plbw->iVertScroll != plbw->cVertScroll) )
  2366.                    {
  2367.                    if ( plbw->iFocus < plbw->cVertScroll )
  2368.                    fScroll = TRUE;
  2369.                    else
  2370.                    fScroll = FALSE;
  2371.  
  2372.                    if ( (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL))    == 0UL )
  2373.                    {
  2374.                    SaveSelectState(0L, plbw->iFocus);
  2375.                    plbw->plc[0].apli[plbw->iFocus]->fl &= ~(LI_FOCUS | LI_SELECTED);
  2376.                    plbw->plc[0].apli[plbw->iSelected = plbw->iFocus = plbw->cItems - 1L]->fl |=    (LI_FOCUS | LI_SELECTED);
  2377.                    }
  2378.                    else
  2379.                    {
  2380.                    plbw->plc[0].apli[plbw->iFocus]->fl &= ~LI_FOCUS;
  2381.                    plbw->plc[0].apli[plbw->iFocus = plbw->cItems - 1L]->fl |= LI_FOCUS;
  2382.                    }
  2383.  
  2384.                    if ( fScroll )
  2385.                    {
  2386.                    mrNotifyOwner(plbw, LN_SCROLL);
  2387.                    WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  2388.                           MPFROMSHORT(plbw->iVertScroll = plbw->cVertScroll), 0L);
  2389.                    WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  2390.                    }
  2391.                    }
  2392.                return(MRFROMLONG(TRUE));
  2393.  
  2394.                case VK_TAB :
  2395.  
  2396.                /* Get the list box data    pointer    from the window    */
  2397.  
  2398.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2399.  
  2400.                /* TAB key pressed, determine which control is    */
  2401.                /* the next tab stop and    set the    focus on that    */
  2402.                /* control                    */
  2403.  
  2404.                WinSetFocus(HWND_DESKTOP,
  2405.                        WinEnumDlgItem(plbw->hwndParent,
  2406.                               hWnd,
  2407.                               EDI_NEXTTABITEM));
  2408.                return(MRFROMLONG(TRUE));
  2409.  
  2410.                case VK_BACKTAB :
  2411.  
  2412.                /* Get the list box data    pointer    from the window    */
  2413.  
  2414.                plbw    = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2415.  
  2416.                /* Shift+TAB key    pressed, determine which    */
  2417.                /* control is the previous tab stop and set the    */
  2418.                /* focus    on that    control                */
  2419.  
  2420.                WinSetFocus(HWND_DESKTOP,
  2421.                        WinEnumDlgItem(plbw->hwndParent,
  2422.                               hWnd,
  2423.                               EDI_PREVTABITEM));
  2424.                return(MRFROMLONG(TRUE));
  2425.                }
  2426.        return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  2427.  
  2428. /************************************************************************/
  2429. /************************************************************************/
  2430. /*                                    */
  2431. /* Part    5: Scroll bar interface                        */
  2432. /*                                    */
  2433. /************************************************************************/
  2434. /************************************************************************/
  2435.  
  2436.    /*********************************************************************/
  2437.    /*  Horizontal scroll bar                        */
  2438.    /*********************************************************************/
  2439.  
  2440.    case    WM_HSCROLL :
  2441.                /* Get the list box data    pointer    from the window    */
  2442.  
  2443.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2444.  
  2445.                /* Save the current scroll position        */
  2446.  
  2447.        i = plbw->iHorzScroll;
  2448.  
  2449.                /* Determine the    scroll event            */
  2450.  
  2451.        switch (    HIUSHORT(mp2) )
  2452.        {
  2453.                /* Line up request through up scroll button    */
  2454.  
  2455.        case    SB_LINELEFT :
  2456.            plbw->iHorzScroll--;
  2457.            break;
  2458.                /* Line down request through down scroll    button    */
  2459.  
  2460.        case    SB_LINERIGHT :
  2461.            plbw->iHorzScroll++;
  2462.            break;
  2463.                /* Page up request through scroll bar selection    */
  2464.  
  2465.        case    SB_PAGELEFT :
  2466.            plbw->iHorzScroll -= plbw->cCharsPage;
  2467.            break;
  2468.                /* Page down request through scroll bar        */
  2469.                /* selection                    */
  2470.  
  2471.        case    SB_PAGERIGHT :
  2472.            plbw->iHorzScroll += plbw->cCharsPage;
  2473.            break;
  2474.                /* Slider is being dragged            */
  2475.  
  2476.        case    SB_SLIDERTRACK :
  2477.            plbw->iHorzScroll = SHORT1FROMMP(mp2);
  2478.            break;
  2479.                /* Ignore all other scroll bar events        */
  2480.        default :
  2481.            return(0L);
  2482.        }
  2483.                /* Calculate the    proper position    of the scroll    */
  2484.                /* bar such that    it falls within    a valid    range    */
  2485.                /* and set the new scroll bar position and force    */
  2486.                /* the repainting of the    output window        */
  2487.  
  2488.        if (  (plbw->iHorzScroll    = max(0, min(plbw->iHorzScroll,    plbw->cHorzScroll))) - i )
  2489.        {
  2490.                /* Send the scroll notification to the list box    */
  2491.                /* owner                        */
  2492.  
  2493.        mrNotifyOwner(plbw, LN_SCROLL);
  2494.  
  2495.                /* Remove the focus indicator since it will    */
  2496.                /* show the right edge repeatedly along the line    */
  2497.                /* while    scrolling                */
  2498.  
  2499.        RemoveFocus(plbw);
  2500.  
  2501.                /* Update the scroll bar    position and then cause    */
  2502.                /* the list area    to scroll horizontally before    */
  2503.                /* forcing the list box to repaint the area    */
  2504.                /* invalidated                    */
  2505.  
  2506.        WinSendMsg(plbw->hwndScrollBottom, SBM_SETPOS, MPFROMSHORT(plbw->iHorzScroll), 0L);
  2507.        rcl = plbw->rcl;
  2508.        --rcl.xRight;
  2509.        WinScrollWindow(hWnd, -(plbw->iHorzScroll - i) * plbw->xChar, 0L,
  2510.                (PRECTL)&rcl, (PRECTL)&plbw->rcl,
  2511.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  2512.        WinUpdateWindow(hWnd);
  2513.  
  2514.                /* Redisplay the    focus since the    text has been    */
  2515.                /* scrolled properly                */
  2516.  
  2517.        SetFocus(plbw, plbw->iFocus);
  2518.        }
  2519.        break;
  2520.  
  2521.    /*********************************************************************/
  2522.    /*  Vertical    scroll bar                        */
  2523.    /*********************************************************************/
  2524.  
  2525.    case    WM_VSCROLL :
  2526.                /* Get the list box data    pointer    from the window    */
  2527.  
  2528.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2529.  
  2530.                /* Save the current scroll position        */
  2531.  
  2532.        i = plbw->iVertScroll;
  2533.  
  2534.                /* Determine the    scroll event            */
  2535.  
  2536.        switch (    HIUSHORT(mp2) )
  2537.        {
  2538.                /* Line up request through up scroll button    */
  2539.  
  2540.        case    SB_LINEUP :
  2541.            plbw->iVertScroll--;
  2542.            break;
  2543.                /* Line down request through down scroll    button    */
  2544.  
  2545.        case    SB_LINEDOWN :
  2546.            plbw->iVertScroll++;
  2547.            break;
  2548.                /* Page up request through scroll bar selection    */
  2549.  
  2550.        case    SB_PAGEUP :
  2551.            plbw->iVertScroll -= (plbw->cLinesPage -    1);
  2552.            break;
  2553.                /* Page down request through scroll bar        */
  2554.                /* selection                    */
  2555.  
  2556.        case    SB_PAGEDOWN :
  2557.            plbw->iVertScroll += (plbw->cLinesPage -    1);
  2558.            break;
  2559.                /* Slider is being dragged            */
  2560.  
  2561.        case    SB_SLIDERTRACK :
  2562.            plbw->iVertScroll = SHORT1FROMMP(mp2);
  2563.            break;
  2564.                /* Ignore all other scroll bar events        */
  2565.        default :
  2566.            return(0L);
  2567.        }
  2568.                /* Calculate the    proper position    of the scroll    */
  2569.                /* bar such that    it falls within    a valid    range    */
  2570.  
  2571.        if ( (plbw->iVertScroll = max(0,    min(plbw->iVertScroll, plbw->cVertScroll))) - i    )
  2572.        {
  2573.                /* Set the new scroll bar position and force the    */
  2574.                /* repainting of    the output window        */
  2575.  
  2576.        mrNotifyOwner(plbw, LN_SCROLL);
  2577.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS, MPFROMSHORT(plbw->iVertScroll), 0L);
  2578.        WinScrollWindow(hWnd, 0L, (plbw->iVertScroll    - i) * plbw->cyItem,
  2579.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  2580.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  2581.        WinUpdateWindow(hWnd);
  2582.        }
  2583.        break;
  2584.  
  2585. /************************************************************************/
  2586. /************************************************************************/
  2587. /*                                    */
  2588. /* Part    6: Control messages                        */
  2589. /*                                    */
  2590. /************************************************************************/
  2591. /************************************************************************/
  2592.  
  2593.    /*********************************************************************/
  2594.    /*  Base messages                            */
  2595.    /*********************************************************************/
  2596.  
  2597.    case    LM_DELETEALL :
  2598.    case    LM_DELETEITEM :
  2599.    case    LM_INSERTITEM :
  2600.    case    LM_QUERYITEMCOUNT :
  2601.    case    LM_QUERYITEMHANDLE :
  2602.    case    LM_QUERYITEMTEXT :
  2603.    case    LM_QUERYITEMTEXTLENGTH :
  2604.    case    LM_QUERYSELECTION :
  2605.    case    LM_QUERYTOPINDEX :
  2606.    case    LM_SEARCHSTRING    :
  2607.    case    LM_SELECTITEM :
  2608.    case    LM_SETITEMHANDLE :
  2609.    case    LM_SETITEMHEIGHT :
  2610.    case    LM_SETITEMTEXT :
  2611.    case    LM_SETTOPINDEX :
  2612.        return(mrBaseListHandler(hWnd, msg, mp1,    mp2));
  2613.  
  2614.    /*********************************************************************/
  2615.    /*  Extended    messages                        */
  2616.    /*********************************************************************/
  2617.  
  2618.    case    LMX_ADDARRAY :
  2619.    case    LMX_CALCLINECOUNT :
  2620.    case    LMX_CALCSIZE :
  2621.    case    LMX_COPY :
  2622.    case    LMX_CUT    :
  2623.    case    LMX_PASTE :
  2624.    case    LMX_QUERYITEMCOUNT :
  2625.    case    LMX_QUERYITEMRECT :
  2626.    case    LMX_QUERYSELECTLIST :
  2627.    case    LMX_RESETLIST :
  2628.    case    LMX_SELECTALL :
  2629.    case    LMX_SELECTITEMBITMAP :
  2630.    case    LMX_SETARRAY :
  2631.    case    LMX_SETARRAYHANDLES :
  2632.    case    LMX_SETARRAYITEMS :
  2633.    case    LMX_SETITEMBITMAPS :
  2634.    case    LMX_SETITEMCOUNT :
  2635.    case    LMX_SORT :
  2636.        return(mrExtendedListHandler(hWnd, msg, mp1, mp2));
  2637.  
  2638.    /*********************************************************************/
  2639.    /*  Extended    messages                        */
  2640.    /*********************************************************************/
  2641.  
  2642.    case    LMX_SETCHECK :
  2643.    case    LMX_QUERYCHECK :
  2644.    case    LMX_SETCHECKARRAY :
  2645.    case    LMX_QUERYCHECKARRAY :
  2646.        return(mrChkBoxHandler(hWnd, msg, mp1, mp2));
  2647.  
  2648.    /*********************************************************************/
  2649.    /*  Extended    sound messages                        */
  2650.    /*********************************************************************/
  2651.  
  2652.    case    LMXM_SETSOUNDEVENT :
  2653.    case    LMXM_QUERYSOUNDEVENT :
  2654.        return(mrSoundHandler(hWnd, msg,    mp1, mp2));
  2655.  
  2656. /************************************************************************/
  2657. /************************************************************************/
  2658. /*                                    */
  2659. /* Part    7: Painting and    display                        */
  2660. /*                                    */
  2661. /************************************************************************/
  2662. /************************************************************************/
  2663.  
  2664.    /*********************************************************************/
  2665.    /*  System colour/Presentation parameter change            */
  2666.    /*********************************************************************/
  2667.  
  2668.    case    WM_SYSCOLORCHANGE :
  2669.    case    WM_PRESPARAMCHANGED :
  2670.  
  2671.                /* Get the list box data    pointer    from the window    */
  2672.  
  2673.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2674.  
  2675.                /* Presentation parameters or system colours    */
  2676.                /* have changed,    get the    new values for the    */
  2677.                /* colours                    */
  2678.  
  2679.        plbw->lClrText          = lGetPresParam(hWnd,    PP_FOREGROUNDCOLOR,
  2680.                           PP_FOREGROUNDCOLORINDEX,
  2681.                           SYSCLR_OUTPUTTEXT);
  2682.        plbw->lClrList          = lGetPresParam(hWnd,    PP_BACKGROUNDCOLOR,
  2683.                           PP_BACKGROUNDCOLORINDEX,
  2684.                           SYSCLR_ENTRYFIELD);
  2685.        plbw->lClrBorder          = lGetPresParam(hWnd,    PP_BORDERCOLOR,
  2686.                           PP_BORDERCOLORINDEX,
  2687.                           SYSCLR_BUTTONDARK);
  2688.        plbw->lClrBackground      = lGetPresParam(hWnd,    PP_BACKGROUNDCOLOR,
  2689.                           PP_BACKGROUNDCOLORINDEX,
  2690.                           SYSCLR_FIELDBACKGROUND);
  2691.        plbw->lClrHilite          = lGetPresParam(hWnd,    PP_HILITEFOREGROUNDCOLOR,
  2692.                           PP_HILITEFOREGROUNDCOLORINDEX,
  2693.                           SYSCLR_HILITEFOREGROUND);
  2694.        plbw->lClrHiliteBackground = lGetPresParam(hWnd,    PP_HILITEBACKGROUNDCOLOR,
  2695.                           PP_HILITEBACKGROUNDCOLORINDEX,
  2696.                           SYSCLR_HILITEBACKGROUND);
  2697.        if ( !WinQueryPresParam(hWnd, PP_FOREGROUNDCOLORINDEX, 0UL, &ulID, sizeof(LONG),    (PVOID)&plbw->lClrTextIndex,
  2698.                    QPF_NOINHERIT | QPF_ID1COLORINDEX) )
  2699.        plbw->lClrTextIndex = SYSCLR_OUTPUTTEXT;
  2700.        if ( !WinQueryPresParam(hWnd, PP_BACKGROUNDCOLORINDEX, 0UL, &ulID, sizeof(LONG),    (PVOID)&plbw->lClrListIndex,
  2701.                    QPF_NOINHERIT | QPF_ID1COLORINDEX) )
  2702.        plbw->lClrListIndex = SYSCLR_ENTRYFIELD;
  2703.  
  2704.                /* Since    there may be a different font being    */
  2705.                /* used,    determine the new size of the list    */
  2706.                /* box horizontal scroll    bar            */
  2707.  
  2708.        if ( (hPS = WinGetPS(hWnd)) != (HPS)NULL    )
  2709.        {
  2710.        if (    plbw->cItems )
  2711.            for ( i = 0, plbw->cxItem = 0L; i < plbw->cItems; i++ )
  2712.            {
  2713.            GpiQueryTextBox(hPS,    (LONG)plbw->plc[0].apli[i]->cText,
  2714.                    plbw->plc[0].apli[i]->pszText, 5L, rgptl);
  2715.            if (    (plbw->plc[0].apli[i]->cxItem =    rgptl[TXTBOX_CONCAT].x -
  2716.                               rgptl[TXTBOX_BOTTOMLEFT].x) > plbw->cxItem )
  2717.                plbw->cxItem = plbw->plc[0].apli[i]->cxItem;
  2718.            }
  2719.                /* Get the font metrics for the current font to    */
  2720.                /* allow    the sizing of the list box to be    */
  2721.                /* properly calculated                */
  2722.  
  2723.        GpiQueryFontMetrics(hPS, sizeof(FONTMETRICS), &fm);
  2724.        plbw->yAscender = fm.lMaxAscender;
  2725.        MeasureItem(plbw, fm.lMaxBaselineExt);
  2726.        plbw->xChar    = fm.lAveCharWidth;
  2727.  
  2728.                /* Initialize the values    for the    list box    */
  2729.                /* pertaining to    the number of items in the list    */
  2730.                /* box, display line count, etc.            */
  2731.  
  2732.        SizeListBox(plbw);
  2733.  
  2734.                /* Release the presentation space handle    and    */
  2735.                /* force    the repainting of the list area    of the    */
  2736.                /* list box                    */
  2737.  
  2738.        WinReleasePS(hPS);
  2739.        }
  2740.        if ( WinIsWindowShowing(hWnd) )
  2741.        WinInvalidateRect(hWnd, &plbw->rcl, FALSE);
  2742.        break;
  2743.  
  2744.    /*********************************************************************/
  2745.    /*  Paint control                            */
  2746.    /*********************************************************************/
  2747.  
  2748.    case    WM_PAINT :
  2749.                /* Get the address of the control info from the    */
  2750.                /* control's reserved memory                     */
  2751.  
  2752.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2753.  
  2754.                /* Check    to see if the style of the list    box has    */
  2755.                /* changed since    it was last painted and    if the    */
  2756.                /* case,    check to see how it should be changed    */
  2757.                /* in terms of its component parts        */
  2758.  
  2759.        if ( ((flStyle =    WinQueryWindowULong(hWnd, QWL_STYLE)) &    0x0000ffffUL) != (plbw->flStyle    & 0x0000ffffUL)    )
  2760.        if (    (plbw->flStyle & LS_HORZSCROLL)    && ((flStyle & LS_HORZSCROLL) == 0) )
  2761.            {
  2762.                /* Scroll bar being removed, delete the        */
  2763.                /* horizontal scroll bar    and re-jigg the    list    */
  2764.                /* box to allow for the additional space        */
  2765.  
  2766.            WinDestroyWindow(plbw->hwndScrollBottom);
  2767.            plbw->flStyle = flStyle;
  2768.            SizeListBox(plbw);
  2769.            }
  2770.        else
  2771.            if ( flStyle & LS_HORZSCROLL )
  2772.            {
  2773.                /* Horizontal scroll bar    being added, create the    */
  2774.                /* scroll bar and re-jigg the list box to allow    */
  2775.                /* for the reduction in space for the displayed    */
  2776.                /* list                        */
  2777.  
  2778.            if (    fAddHorzScroll(hWnd, plbw) )
  2779.                {
  2780.                hPS = WinGetPS(hWnd);
  2781.  
  2782.                if ( plbw->cItems )
  2783.                for ( i = 0,    plbw->cxItem = 0L; i < plbw->cItems; i++ )
  2784.                    {
  2785.                    GpiQueryTextBox(hPS, (LONG)plbw->plc[0].apli[i]->cText,
  2786.                            plbw->plc[0].apli[i]->pszText, 5L, rgptl);
  2787.                    if ( (plbw->plc[0].apli[i]->cxItem = rgptl[TXTBOX_CONCAT].x -
  2788.                                   rgptl[TXTBOX_BOTTOMLEFT].x) >    plbw->cxItem )
  2789.                    plbw->cxItem    = plbw->plc[0].apli[i]->cxItem;
  2790.                    }
  2791.                GpiQueryFontMetrics(hPS,    sizeof(FONTMETRICS), &fm);
  2792.                WinReleasePS(hPS);
  2793.                MeasureItem(plbw, fm.lMaxBaselineExt);
  2794.                SizeListBox(plbw);
  2795.                UpdateScrollBars(plbw);
  2796.                }
  2797.            }
  2798.            else
  2799.                /* General style    change,    refresh    the list box    */
  2800.                /* sizes    in case    the list box has changed from    */
  2801.                /* no adjust position to    the opposite        */
  2802.            {
  2803.            plbw->flStyle = flStyle;
  2804.            SizeListBox(plbw);
  2805.            UpdateScrollBars(plbw);
  2806.            }
  2807.                /* Check    to see if delayed update in which case    */
  2808.                /* update the limits and    scroll bars        */
  2809.  
  2810.        if ( plbw->fDirty )
  2811.        UpdateScrollBars(plbw);
  2812.  
  2813.                /* Set the colour table to RGB mode        */
  2814.  
  2815.        if ( (hPS = WinBeginPaint(hWnd, (HPS)NULL, &rclPaint)) != (HPS)NULL )
  2816.        {
  2817.        GpiCreateLogColorTable(hPS, 0L, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  2818.  
  2819.                /* Check    to see if the style of the list    box    */
  2820.                /* includes a horizontal    scroll bar in which    */
  2821.                /* case need to paint the corner    left over where    */
  2822.                /* the two scroll bars meet            */
  2823.  
  2824.        if (    plbw->flStyle &    LS_HORZSCROLL )
  2825.            WinFillRect(hPS,    &plbw->rclCorner, plbw->lClrBackground);
  2826.  
  2827.                /* Check    to see if the style of the list    box    */
  2828.                /* allows for the height    of the list box    to be    */
  2829.                /* adjusted to allow only the display of        */
  2830.                /* complete lines within    the list box in    which    */
  2831.                /* case,    need to    paint the left over area at the    */
  2832.                /* top of the window                */
  2833.  
  2834.        if (    ((plbw->flStyle    & LS_NOADJUSTPOS) != LS_NOADJUSTPOS) &&
  2835.         (plbw->rclAdjusted.yTop    > plbw->rclAdjusted.yBottom) )
  2836.            WinFillRect(hPS,    &plbw->rclAdjusted, plbw->lClrBackground);
  2837.  
  2838.                /* Now, draw the    borders    of the non-scroll bar    */
  2839.                /* edges.  First    set the    colour of the border    */
  2840.                /* and then draw    the inside edge    of the border.    */
  2841.                /* The border follows the typical 3D effect of    */
  2842.                /* one line being dark and the second line being    */
  2843.                /* light.                    */
  2844.  
  2845.        GpiSetColor(hPS, RGB_WHITE);
  2846.        GpiMove(hPS,    plbw->aptlInside);
  2847.        GpiPolyLine(hPS, plbw->cptl,    &plbw->aptlInside[1]);
  2848.  
  2849.                /* Having drawn the inside edge,    now draw the    */
  2850.                /* outside edge of the border            */
  2851.  
  2852.        GpiSetColor(hPS, plbw->lClrBorder);
  2853.        GpiMove(hPS,    plbw->aptlOutside);
  2854.        GpiPolyLine(hPS, plbw->cptl,    &plbw->aptlOutside[1]);
  2855.  
  2856.                /* Check    to see if the list box contains    any    */
  2857.                /* items    in which case they need    to be drawn    */
  2858.  
  2859.        if (    plbw->cItems )
  2860.            {
  2861.                /* Initialize the base rectangle            */
  2862.  
  2863.            rcl = plbw->rcl;
  2864.  
  2865.                /* Using    the paint rectangle, determine the last    */
  2866.                /* item that requires to    be painted        */
  2867.  
  2868.            n = plbw->iVertScroll + ((plbw->rcl.yTop    - rclPaint.yBottom) /
  2869.            plbw->cyItem);
  2870.  
  2871.            if ( plbw->rcl.yTop < rclPaint.yTop )
  2872.            i = 0;
  2873.            else
  2874.            i = (plbw->rcl.yTop - rclPaint.yTop)    / plbw->cyItem;
  2875.  
  2876.                /* Using    the paint rectangle, determine the    */
  2877.                /* first    item that requires to be painted and    */
  2878.                /* also form the    final rectangle    for the    text    */
  2879.  
  2880.            rcl.yBottom = (rcl.yTop = plbw->rcl.yTop    -
  2881.                  (i    * plbw->cyItem)) - plbw->cyItem;
  2882.  
  2883.                /* Form the starting display point for the    */
  2884.                /* drawing of the text                */
  2885.  
  2886.            ptl.x = plbw->rcl.xLeft + 2L - (plbw->iHorzScroll * plbw->xChar);
  2887.            ptl.y = rcl.yTop    - plbw->yAscender;
  2888.  
  2889.                /* Since    the entire window is sub-divided    */
  2890.                /* logically into lines,    paint each of the lines    */
  2891.                /* within the window                */
  2892.  
  2893.            for ( i += plbw->iVertScroll; i <= n; i++ )
  2894.            if (    i >= plbw->cItems )
  2895.                {
  2896.                /* No more stream information available,    paint    */
  2897.                /* the remainder    of the window below the    last    */
  2898.                /* logical line in the background colour    and    */
  2899.                /* break    out of the loop                */
  2900.  
  2901.                if ( (rcl.yBottom = plbw->rcl.yBottom) <    rcl.yTop )
  2902.                WinFillRect(hPS, &rcl, plbw->lClrList);
  2903.                break;
  2904.                }
  2905.            else
  2906.                {
  2907.                if ( (fl    = plbw->plc[0].apli[i]->fl) & LI_SELECTED )
  2908.                plbw->plc[0].apli[i]->fl |= LI_SELECTEDPREV;
  2909.  
  2910.                /* Draw the text    for the    list box item        */
  2911.  
  2912.                DrawItem(plbw, i, hPS, &rcl, &ptl);
  2913.                plbw->plc[0].apli[i]->fl    = fl & ~LI_SELECTEDPREV;
  2914.  
  2915.                /* Shift    the line positioning down ready    for the    */
  2916.                /* next line to be drawn                */
  2917.  
  2918.                rcl.yTop    = rcl.yBottom;
  2919.                rcl.yBottom -= plbw->cyItem;
  2920.                ptl.y -=    plbw->cyItem;
  2921.                }
  2922.            }
  2923.        else
  2924.                /* No items contained within the    list box, just    */
  2925.                /* fill it with the list    box background colour    */
  2926.  
  2927.            WinFillRect(hPS,    &plbw->rcl, plbw->lClrList);
  2928.  
  2929.        WinEndPaint(hPS);
  2930.        FocusChange(plbw, plbw->iFocus, TRUE);
  2931.        }
  2932.        break;
  2933.  
  2934. /************************************************************************/
  2935. /************************************************************************/
  2936. /*                                    */
  2937. /* Part    8: Control destruction coding                    */
  2938. /*                                    */
  2939. /************************************************************************/
  2940. /************************************************************************/
  2941.  
  2942.    /*********************************************************************/
  2943.    /*  Control being destroyed,    perform    clean-up            */
  2944.    /*********************************************************************/
  2945.  
  2946.    case    WM_DESTROY :
  2947.                /* Get the address of the control info from the    */
  2948.                /* control's reserved memory                     */
  2949.  
  2950.        plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2951.  
  2952.                /* Release the column heaps            */
  2953.  
  2954.        if ( plbw->cItems )
  2955.        for ( i = 0;    i < plbw->cColumns; i++    )
  2956.            HeapRelease(plbw->plc[i].hHeap);
  2957.  
  2958.                /* Destroy the scroll bars            */
  2959.  
  2960.        if ( plbw->hwndScrollLeft )
  2961.        WinDestroyWindow(plbw->hwndScrollLeft);
  2962.        if ( plbw->hwndScrollRight )
  2963.        WinDestroyWindow(plbw->hwndScrollRight);
  2964.        if ( plbw->hwndScrollTop    )
  2965.        WinDestroyWindow(plbw->hwndScrollTop);
  2966.        if ( plbw->hwndScrollBottom )
  2967.        WinDestroyWindow(plbw->hwndScrollBottom);
  2968.  
  2969.                /* Close    the open .WAV files and    release    the    */
  2970.                /* sound    support    DLL                */
  2971.  
  2972.        UnloadSoundSupport(plbw);
  2973.  
  2974.                /* Delete the check mark    bitmaps            */
  2975.  
  2976.        GpiDeleteBitmap(plbw->hbm);
  2977.  
  2978.                /* Release the heap                */
  2979.  
  2980.        HeapRelease(plbw->hHeap);
  2981.        break;
  2982.                /* Default message processing            */
  2983.    default :
  2984.        return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  2985.    }
  2986. return(0L);
  2987. }
  2988.