home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx2.zip / listbox.c < prev    next >
C/C++ Source or Header  |  1994-04-22  |  105KB  |  2,968 lines

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