home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx4.zip / ListBox.C < prev    next >
C/C++ Source or Header  |  1994-07-05  |  108KB  |  3,031 lines

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