home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx1.zip / LISTBOX.C < prev    next >
C/C++ Source or Header  |  1994-01-07  |  97KB  |  2,710 lines

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