home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx1.zip / TRAFFMGR.C < prev    next >
C/C++ Source or Header  |  1994-01-06  |  38KB  |  1,106 lines

  1. #pragma    title("List Box Replacement  --  Version 1.0 -- (TraffMgr.C)")
  2. #pragma    subtitle("   Traffic Manager - Interface Definitions")
  3.  
  4. /* Program name: Listbox.Dll    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. /*               DISCLAIMER OF WARRANTIES.            */
  24. /************************************************************************/
  25. /************************************************************************/
  26. /*     The following [enclosed]    code is    source code created by the    */
  27. /*     authors.     This source code is  provided to you solely        */
  28. /*     for the purpose of assisting you    in the development of your    */
  29. /*     applications.  The code is provided "AS IS", without        */
  30. /*     warranty    of any kind.  The authors shall    not be liable        */
  31. /*     for any damages arising out of your use of the source code,    */
  32. /*     even if they have been advised of the possibility of such    */
  33. /*     damages.     It is provided    purely for instructional and        */
  34. /*     illustrative purposes.                        */
  35. /************************************************************************/
  36. /************************************************************************/
  37.  
  38. #pragma    info(noext)
  39. #pragma    strings(readonly)
  40.  
  41. #if defined(__ZTC__)
  42.  
  43. #define    _Seg16
  44.  
  45. #endif
  46.  
  47. #define    INCL_GPI           /* Include OS/2 PM GPI Interface    */
  48. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  49.  
  50. #include <os2.h>
  51. #include <stdlib.h>
  52.  
  53. #include "listbox.h"
  54.  
  55. /* This    module contains    the routines that handle the traffic management    */
  56. /* for the list    box.                            */
  57. /*                                    */
  58. /* Equivalent command line invocation of each module using the        */
  59. /* IBM C Set++ Compiler    Version    2.0 is:                    */
  60. /*                                    */
  61. /*     Icc -G3e- -O+ -Rn -C -W3    -FoTraffMgr TraffMgr.C            */
  62.  
  63. /* Filename:   TraffMgr.C                        */
  64.  
  65. /*  Version:   1.0                            */
  66. /*  Created:   1993-10-14                        */
  67. /*  Revised:   1993-11-05                        */
  68.  
  69. /* Routines:   LONG lGetPresParam(HWND hWnd, ULONG ulID1, ULONG    ulID2,    */
  70. /*                  LONG lDefault);            */
  71. /*           VOID SizeListBox(PLISTBOXWIN plbw);            */
  72. /*           VOID FocusChange(PLISTBOXWIN plbw, LONG iFocus,        */
  73. /*                BOOL fSet);                */
  74. /*           VOID SetFocus(PLISTBOXWIN plbw, LONG iFocus);        */
  75. /*           VOID RemoveFocus(PLISTBOXWIN plbw);            */
  76. /*           BOOL fDecodeMouse(PLISTBOXWIN plbw, MPARAM mp1);        */
  77. /*           BOOL fDecodeExtendedMouse(PLISTBOXWIN plbw, MPARAM mp1,    */
  78. /*                     BOOL fBlock);            */
  79. /*           VOID MeasureItem(PLISTBOXWIN plbw, LONG lMaxBaselineExt);*/
  80. /*           BOOL fAddHorzScroll(HWND    hWnd, PLISTBOXWIN plbw);    */
  81. /*           VOID LineUp(PLISTBOXWIN plbw);                */
  82. /*           VOID LineDown(PLISTBOXWIN plbw);                */
  83. /*           VOID DragUp(PLISTBOXWIN plbw);                */
  84. /*           VOID DragDown(PLISTBOXWIN plbw);                */
  85.  
  86.  
  87. /* --------------------------------------------------------------------    */
  88.  
  89. #pragma    subtitle("   Traffic Manager - Presentation Parameter Retrieve Procedure")
  90. #pragma    page( )
  91.  
  92. /* --- lGetPresParam ----------------------------------    [ Private } ---    */
  93. /*                                    */
  94. /*     This function is    used to    retrieve a presentation    parameter    */
  95. /*     that may    be present.  If    the presentation parameter is not,    */
  96. /*     the default colour passed to the    function will be used.    All    */
  97. /*     colours queried for are RGB or their RGB    equivalents.        */
  98. /*                                    */
  99. /*     Upon Entry:                            */
  100. /*                                    */
  101. /*     HWND  hWnd;     = Window    Handle                    */
  102. /*     ULONG ulID1;    = Presentation Parameter    1 ID (RGB)        */
  103. /*     ULONG ulID2;    = Presentation Parameter    2 ID (Index)        */
  104. /*     LONG  lDefault; = Default Colour                    */
  105. /*                                    */
  106. /*     Upon Exit:                            */
  107. /*                                    */
  108. /*     lGetPresParam = Colour to Use (RGB)                */
  109. /*                                    */
  110. /* --------------------------------------------------------------------    */
  111.  
  112. LONG lGetPresParam(HWND    hWnd, ULONG ulID1, ULONG ulID2,    LONG lDefault)
  113.  
  114. {
  115. HPS   hPS;               /* Presentation Space Handle        */
  116. LONG  lClr;               /* Presentation Parameter Colour    */
  117. ULONG ulID;               /* Presentation Parameter ID        */
  118.  
  119.                /* First    try to determine if any    presentation    */
  120.                /* parameters are set for the area requested.    */
  121.                /* The first ID is RGB index and    the second ID    */
  122.                /* is colour index.                */
  123.  
  124. if ( WinQueryPresParam(hWnd, ulID1, ulID2, &ulID, sizeof(LONG),    (PVOID)&lClr,
  125.                QPF_NOINHERIT | QPF_ID2COLORINDEX | QPF_PURERGBCOLOR) )
  126.  
  127.                /* Presentation parameter set for the area,    */
  128.                /* return the RGB colour                */
  129.    return(lClr);
  130. else
  131.                /* No presentation parameters set, check    to see    */
  132.                /* if the default is a system colour in which    */
  133.                /* only need to query the index for the RGB    */
  134.                /* value                        */
  135.  
  136.    if (    (lDefault >= SYSCLR_SHADOWHILITEBGND) &&
  137.     (lDefault <= SYSCLR_HELPHILITE)    )
  138.        return(WinQuerySysColor(HWND_DESKTOP, lDefault, 0L));
  139.    else
  140.                /* Standard colour index, get the RGB equivalent    */
  141.                /* for the index                    */
  142.  
  143.        if ( (hPS = WinGetPS(hWnd)) != (HPS)NULL    )
  144.        if (    (lClr =    GpiQueryRGBColor(hPS, LCOLOPT_REALIZED,    lDefault)) == GPI_ALTERROR )
  145.            {
  146.                /* Colour was not found,    return white as    colour    */
  147.  
  148.            WinReleasePS(hPS);
  149.            return(RGB_WHITE);
  150.            }
  151.        else
  152.            {
  153.                /* Colour found,    return the RGB value        */
  154.  
  155.            WinReleasePS(hPS);
  156.            return(lClr);
  157.            }
  158.        else
  159.        return(RGB_WHITE);
  160. }
  161. #pragma    subtitle("   Traffic Manager - List Box Sizing Procedure")
  162. #pragma    page( )
  163.  
  164. /* --- SizeListBox ------------------------------------    [ Private ] ---    */
  165. /*                                    */
  166. /*     This function is    used to    calculate the positions    of the        */
  167. /*     scroll bars that    are part of the    list box as well as the        */
  168. /*     border points that are to be drawn when the control is        */
  169. /*     painted.                                */
  170. /*                                    */
  171. /*     Upon Entry:                            */
  172. /*                                    */
  173. /*     PLISTBOXWIN plbw; = List    Box Control Information    Pointer        */
  174. /*                                    */
  175. /*     Upon Exit:                            */
  176. /*                                    */
  177. /*     Nothing                                */
  178. /*                                    */
  179. /* --------------------------------------------------------------------    */
  180.  
  181. VOID SizeListBox(PLISTBOXWIN plbw)
  182.  
  183. {
  184. LONG  lMargin;               /* Margin Size            */
  185. ULONG cswp;               /* SWP Array    Count            */
  186.  
  187.                /* Initialize the values    for the    list box    */
  188.                /* pertaining to    the number of items in the list    */
  189.                /* box, display line count, etc.            */
  190.  
  191. plbw->cLinesPage = (plbw->rcl.yTop - plbw->rcl.yBottom)    / plbw->cyItem;
  192. if ( (plbw->rcl.yTop - plbw->rcl.yBottom) % plbw->cyItem )
  193.    ++plbw->cLinesPage;
  194.  
  195. if ( plbw->flStyle & LS_NOADJUSTPOS )
  196.    plbw->cy = plbw->cyWindow;
  197. else
  198.    {
  199.    lMargin = 2L    + (plbw->flStyle & LS_HORZSCROLL ? plbw->cyScroll : 2L);
  200.    plbw->cy = ((plbw->cyWindow - lMargin) / plbw->cyItem) * plbw->cyItem + lMargin;
  201.    plbw->rclAdjusted.yTop    = plbw->cyWindow;
  202.    plbw->rclAdjusted.yBottom = plbw->cy;
  203.    plbw->rclAdjusted.xLeft   = 0L;
  204.    plbw->rclAdjusted.xRight  = plbw->cxWindow;
  205.    }
  206.                /* Calculate the    width of the group such    that it    */
  207.                /* is almost the    width of the window and    also    */
  208.                /* calculate the    width of the list box such that    */
  209.                /* it is    almost the width of the    group box    */
  210.  
  211. plbw->aswp[SWP_VERT].x    = (plbw->cx = plbw->cxWindow) -    plbw->cxScroll;
  212. plbw->aswp[SWP_VERT].cy    = plbw->cy;
  213.  
  214. if ( plbw->flStyle & LS_HORZSCROLL )
  215.    {
  216.                /*                   2        */
  217.                /* 1┌────────────────────────────────┬─┐        */
  218.                /*  │                    │^│        */
  219.                /*  │                    ├─┤        */
  220.                /*  │                    │ │        */
  221.                /*  │                    │ │        */
  222.                /*  │                    ├─┤        */
  223.                /*  │                    │v│        */
  224.                /* 0├─┬────────────────────────────┬─┼─┘        */
  225.                /*  │<│                  │>│        */
  226.                /*  └─┴────────────────────────────┴─┘        */
  227.    plbw->cptl =    2L;
  228.    plbw->aptlOutside[0].x = 0L;
  229.    plbw->aptlOutside[0].y = 1L;
  230.    plbw->aptlOutside[1].x = 0L;
  231.    plbw->aptlOutside[1].y = plbw->cy - 1L;
  232.    plbw->aptlOutside[2].x = plbw->aswp[SWP_VERT].x;
  233.    plbw->aptlOutside[2].y = plbw->cy - 1L;
  234.  
  235.    plbw->aptlInside[0].x = 1L;
  236.    plbw->aptlInside[0].y = 0L;
  237.    plbw->aptlInside[1].x = 1L;
  238.    plbw->aptlInside[1].y = plbw->cy - 2L;
  239.    plbw->aptlInside[2].x = plbw->aswp[SWP_VERT].x;
  240.    plbw->aptlInside[2].y = plbw->cy - 2L;
  241.  
  242.    plbw->rcl.yTop    = plbw->cy    - 2L;
  243.    plbw->rcl.yBottom = plbw->aswp[SWP_HORZ].cy;
  244.    plbw->rcl.xRight  = plbw->aswp[SWP_VERT].x;
  245.    plbw->rcl.xLeft   = 2L;
  246.  
  247.    plbw->aswp[SWP_HORZ].cx = plbw->aswp[SWP_VERT].x;;
  248.    plbw->aswp[SWP_VERT].y  = plbw->cyScroll;
  249.    plbw->aswp[SWP_VERT].cy = plbw->cy -    plbw->cyScroll;
  250.    cswp    = 2UL;
  251.    plbw->rclCorner.xLeft   = plbw->aswp[SWP_VERT].x;
  252.    plbw->rclCorner.xRight  = plbw->cx;
  253.    plbw->rclCorner.yBottom = 0L;
  254.    plbw->rclCorner.yTop       = plbw->aswp[SWP_VERT].y;
  255.    }
  256. else
  257.    {
  258.                /*  2                    3        */
  259.                /* 1┌────────────────────────────────┬─┐        */
  260.                /*  │                    │^│        */
  261.                /*  │                    ├─┤        */
  262.                /*  │                    │ │        */
  263.                /*  │                    │ │        */
  264.                /*  │                    ├─┤        */
  265.                /*  │                    │v│        */
  266.                /*  └────────────────────────────────┴─┘        */
  267.                /*  1                    0        */
  268.    plbw->cptl =    3L;
  269.    plbw->aptlOutside[0].x = plbw->aswp[SWP_VERT].x;
  270.    plbw->aptlOutside[0].y = 1L;
  271.    plbw->aptlOutside[1].x = 0L;
  272.    plbw->aptlOutside[1].y = 1L;
  273.    plbw->aptlOutside[2].x = 0L;
  274.    plbw->aptlOutside[2].y = plbw->cy - 1L;
  275.    plbw->aptlOutside[3].x = plbw->aswp[SWP_VERT].x;
  276.    plbw->aptlOutside[3].y = plbw->cy - 1L;
  277.  
  278.    plbw->aptlInside[0].x = plbw->aswp[SWP_VERT].x;
  279.    plbw->aptlInside[0].y = 0L;
  280.    plbw->aptlInside[1].x = 1L;
  281.    plbw->aptlInside[1].y = 0L;
  282.    plbw->aptlInside[2].x = 1L;
  283.    plbw->aptlInside[2].y = plbw->cy - 2L;
  284.    plbw->aptlInside[3].x = plbw->aswp[SWP_VERT].x;
  285.    plbw->aptlInside[3].y = plbw->cy - 2L;
  286.  
  287.    plbw->rcl.yTop    = plbw->cy    - 2L;
  288.    plbw->rcl.yBottom = 2L;
  289.    plbw->rcl.xRight  = plbw->aswp[SWP_VERT].x;
  290.    plbw->rcl.xLeft   = 2L;
  291.    cswp    = 1UL;
  292.    }
  293.                /* Window has been resized, calculate the new    */
  294.                /* values for the number    of lines displayed and    */
  295.                /* the relative number of characters displayed    */
  296.  
  297. plbw->cLinesPage = (plbw->rcl.yTop - plbw->rcl.yBottom)    / plbw->cyItem;
  298. if ( (plbw->rcl.yTop - plbw->rcl.yBottom) % plbw->cyItem )
  299.     ++plbw->cLinesPage;
  300. plbw->cCharsPage = (plbw->rcl.xRight - plbw->rcl.xLeft)    / plbw->xChar;
  301. if ( (plbw->rcl.xRight - plbw->rcl.xLeft) % plbw->xChar    )
  302.     ++plbw->cCharsPage;
  303.                /* Reposition and resize    the controls        */
  304.  
  305. WinSetMultWindowPos(plbw->hAB, plbw->aswp, cswp);
  306.  
  307. }
  308. #pragma    subtitle("   Traffic Manager - Focus Change Routine")
  309. #pragma    page( )
  310.  
  311. /* --- FocusChange ------------------------------------- [ Public ] ---    */
  312. /*                                    */
  313. /*     This function is    used to    draw the focus indicator around    a    */
  314. /*     list box    item.                            */
  315. /*                                    */
  316. /*     Upon Entry:                            */
  317. /*                                    */
  318. /*     PLISTBOXWIN plbw;   = List Box Data Pointer            */
  319. /*     LONG       iFocus; = Focus Item    Index                */
  320. /*                                    */
  321. /*     Upon Exit:                            */
  322. /*                                    */
  323. /*     Nothing                                */
  324. /*                                    */
  325. /* --------------------------------------------------------------------    */
  326.  
  327. VOID FocusChange(PLISTBOXWIN plbw, LONG    iFocus,    BOOL fSet)
  328.  
  329. {
  330. if ( (iFocus < plbw->cItems) &&    plbw->fFocus )
  331.    if (    fSet )
  332.        {
  333.                /* Check    to see if the item receiving the focus    */
  334.                /* is visible in    which case the focus indicator    */
  335.                /* needs    to be drawn for    it            */
  336.  
  337.        if ( fItemVisible(plbw, iFocus) )
  338.        {
  339.        WinCreateCursor(plbw->hWnd, plbw->rcl.xLeft,
  340.                (plbw->rcl.yTop - (iFocus - plbw->iVertScroll) *
  341.                           plbw->cyItem) - plbw->cyItem,
  342.                0L, 0L, CURSOR_SETPOS, NULL);
  343.        if (    !plbw->fFocusShown )
  344.            WinShowCursor(plbw->hWnd, plbw->fFocusShown = TRUE);
  345.        }
  346.        }
  347.    else
  348.                /* Check    to see if the item losing the focus    */
  349.                /* is visible in    which case the focus indicator    */
  350.                /* needs    to be drawn for    it            */
  351.  
  352.        if ( plbw->fFocusShown )
  353.        WinShowCursor(plbw->hWnd, plbw->fFocusShown = FALSE);
  354. }
  355. #pragma    subtitle("   Traffic Manager - Focus Draw Routine")
  356. #pragma    page( )
  357.  
  358. /* --- SetFocus    ---------------------------------------- [ Public ] ---    */
  359. /*                                    */
  360. /*     This function is    used to    draw the focus indicator around    a    */
  361. /*     list box    item.                            */
  362. /*                                    */
  363. /*     Upon Entry:                            */
  364. /*                                    */
  365. /*     PLISTBOXWIN plbw;   = List Box Data Pointer            */
  366. /*     LONG       iFocus; = Focus Item    Index                */
  367. /*                                    */
  368. /*     Upon Exit:                            */
  369. /*                                    */
  370. /*     Nothing                                */
  371. /*                                    */
  372. /* --------------------------------------------------------------------    */
  373.  
  374. VOID SetFocus(PLISTBOXWIN plbw,    LONG iFocus)
  375.  
  376. {
  377. if ( iFocus < plbw->cItems )
  378.    {
  379.                /* Check    to see if the item receiving the focus    */
  380.                /* is visible in    which case the focus indicator    */
  381.                /* needs    to be drawn for    it            */
  382.  
  383.    if (    WinIsWindowShowing(plbw->hWnd) )
  384.        FocusChange(plbw, iFocus, TRUE);
  385.  
  386.    if (    !(plbw->plc[0].ali[iFocus].fl &    LI_FOCUS) )
  387.        {
  388.                /* Check    to see if a previous item had focus it    */
  389.                /* which    if the case, the item should have its    */
  390.                /* focus    flag cleared                */
  391.  
  392.        if ( plbw->iFocus != LIT_NONE )
  393.        plbw->plc[0].ali[plbw->iFocus].fl &=    ~LI_FOCUS;
  394.  
  395.                /* Set the focus    flag for the item now receiving    */
  396.                /* the focus                    */
  397.  
  398.        plbw->plc[0].ali[plbw->iFocus = iFocus].fl |= LI_FOCUS;
  399.        }
  400.    }
  401. }
  402. #pragma    subtitle("   Traffic Manager - Focus Remove Routine")
  403. #pragma    page( )
  404.  
  405. /* --- RemoveFocus ------------------------------------- [ Public ] ---    */
  406. /*                                    */
  407. /*     This function is    used to    draw the focus indicator around    a    */
  408. /*     list box    item.                            */
  409. /*                                    */
  410. /*     Upon Entry:                            */
  411. /*                                    */
  412. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  413. /*                                    */
  414. /*     Upon Exit:                            */
  415. /*                                    */
  416. /*     Nothing                                */
  417. /*                                    */
  418. /* --------------------------------------------------------------------    */
  419.  
  420. VOID RemoveFocus(PLISTBOXWIN plbw)
  421.  
  422. {
  423.  
  424. if ( plbw->iFocus != LIT_NONE )
  425.    {
  426.    plbw->plc[0].ali[plbw->iFocus].fl &=    ~LI_FOCUS;
  427.    FocusChange(plbw, plbw->iFocus, FALSE);
  428.    }
  429. }
  430. #pragma    subtitle("   Traffic Manager - Mouse Position Decode Routine")
  431. #pragma    page( )
  432.  
  433. /* --- fDecodeMouse -----------------------------------    [ Private ] ---    */
  434. /*                                    */
  435. /*     This function is    used to    determine if the current location of    */
  436. /*     the mouse within    the list box is    over a valid entry and to    */
  437. /*     either select or    deselect the item.                */
  438. /*                                    */
  439. /*     Upon Entry:                            */
  440. /*                                    */
  441. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  442. /*     MPARAM       mp1;     = Message Parameter 1                */
  443. /*                                    */
  444. /*     Upon Exit:                            */
  445. /*                                    */
  446. /*     fDecodeMouse =  TRUE : Mouse Pointer within List    Area        */
  447. /*            = FALSE : Mouse Pointer outside List Area        */
  448. /*                                    */
  449. /* --------------------------------------------------------------------    */
  450.  
  451. BOOL fDecodeMouse(PLISTBOXWIN plbw, MPARAM mp1)
  452.  
  453. {
  454. LONG   iSelected;           /* Selected Item Index        */
  455. POINTL ptl;               /* Display Point            */
  456.  
  457. ptl.x =    (LONG)SHORT1FROMMP(mp1);
  458. ptl.y =    (LONG)SHORT2FROMMP(mp1);
  459. if ( WinPtInRect(plbw->hAB, &plbw->rcl,    &ptl) )
  460.    {
  461.    if (    (iSelected = lItemFromPoint(plbw, (LONG)SHORT2FROMMP(mp1))) != plbw->iFocus )
  462.        RemoveFocus(plbw);
  463.  
  464.    if (    plbw->flStyle &    LS_EXTENDEDSEL )
  465.        {
  466.        if ( plbw->fCapture && (iSelected == plbw->iFocus) )
  467.        return(TRUE);
  468.        else
  469.        if (    plbw->fCapture )
  470.            {
  471.            SelectExtendedItems(plbw, 0L, iSelected);
  472.            SetFocus(plbw, iSelected);
  473.            }
  474.        else
  475.            if ( !(plbw->plc[0].ali[iSelected].fl & LI_SELECTED) &&
  476.             fSelectItem(plbw, 0L, iSelected, TRUE) )
  477.            {
  478.            SetFocus(plbw, iSelected);
  479.            mrNotifyOwner(plbw, LN_SELECT);
  480.            }
  481.  
  482.        if ( !(plbw->plc[0].ali[iSelected].fl & LI_FOCUS) )
  483.        SetFocus(plbw, iSelected);
  484.  
  485.        return(TRUE);
  486.        }
  487.    else
  488.        if ( plbw->flStyle & LS_MULTIPLESEL )
  489.        {
  490.        if (    plbw->fCapture && (iSelected ==    plbw->iFocus) )
  491.            return(TRUE);
  492.        else
  493.            if ( plbw->fCapture )
  494.            SetFocus(plbw, iSelected);
  495.            else
  496.            {
  497.            if (    fSelectItem(plbw, 0L, iSelected,
  498.                     (BOOL)(plbw->plc[0].ali[iSelected].fl & LI_SELECTED    ? FALSE    : TRUE)) )
  499.                {
  500.                SetFocus(plbw, iSelected);
  501.                mrNotifyOwner(plbw, LN_SELECT);
  502.                return(TRUE);
  503.                }
  504.            }
  505.        }
  506.        else
  507.        if (    iSelected != plbw->iSelected )
  508.            {
  509.            fSelectItem(plbw, 0L, iSelected,    TRUE);
  510.            SetFocus(plbw, iSelected);
  511.            mrNotifyOwner(plbw, LN_SELECT);
  512.            return(TRUE);
  513.            }
  514.    }
  515. return(FALSE);
  516. }
  517. #pragma    subtitle("   Traffic Manager - Mouse Position Decode Routine")
  518. #pragma    page( )
  519.  
  520. /* --- fDecodeExtendedMouse ---------------------------    [ Private ] ---    */
  521. /*                                    */
  522. /*     This function is    used to    determine if the current location of    */
  523. /*     the mouse within    the list box is    over a valid entry and to    */
  524. /*     either select or    deselect the item.                */
  525. /*                                    */
  526. /*     Upon Entry:                            */
  527. /*                                    */
  528. /*     PLISTBOXWIN plbw;   = List Box Data Pointer            */
  529. /*     MPARAM       mp1;       = Message Parameter 1            */
  530. /*     BOOL       fBlock; = Block Selected Flag            */
  531. /*                                    */
  532. /*     Upon Exit:                            */
  533. /*                                    */
  534. /*     fDecodeExtendedMouse =  TRUE : Mouse Pointer within List    Area    */
  535. /*                = FALSE : Mouse Pointer outside List Area    */
  536. /*                                    */
  537. /* --------------------------------------------------------------------    */
  538.  
  539. BOOL fDecodeExtendedMouse(PLISTBOXWIN plbw, MPARAM mp1,    BOOL fBlock)
  540.  
  541. {
  542. LONG   iSelected;           /* Selected Item Index        */
  543. POINTL ptl;               /* Display Point            */
  544.  
  545. ptl.x =    (LONG)SHORT1FROMMP(mp1);
  546. ptl.y =    (LONG)SHORT2FROMMP(mp1);
  547. if ( WinPtInRect(plbw->hAB, &plbw->rcl,    &ptl) )
  548.    {
  549.    if (    (iSelected = lItemFromPoint(plbw, (LONG)SHORT2FROMMP(mp1))) != plbw->iFocus )
  550.        RemoveFocus(plbw);
  551.  
  552.    if (    fBlock )
  553.        {
  554.        SelectExtendedItems(plbw, 0L, iSelected);
  555.        SetFocus(plbw, iSelected);
  556.        mrNotifyOwner(plbw, LN_SELECT);
  557.        return(TRUE);
  558.        }
  559.    else
  560.        if ( fSelectMultipleItem(plbw, 0L, iSelected,
  561.                 (BOOL)(plbw->plc[0].ali[iSelected].fl &    LI_SELECTED ? FALSE : TRUE)) )
  562.        {
  563.        if (    (plbw->iFocus == iSelected) && !(plbw->flStyle & LS_OWNERDRAW) )
  564.            plbw->iSelected = iSelected;
  565.        else
  566.            SetFocus(plbw, plbw->iSelected =    iSelected);
  567.        mrNotifyOwner(plbw, LN_SELECT);
  568.        return(TRUE);
  569.        }
  570.    }
  571.  
  572. return(FALSE);
  573. }
  574. #pragma    subtitle("   Traffic Manager - Item Measure Routine")
  575. #pragma    page( )
  576.  
  577. /* --- MeasureItem ----------------------------------- [ Private ] --- */
  578. /*                                    */
  579. /*     This function is    used to    determine if the item is within    the    */
  580. /*     visible portion of the list box.                    */
  581. /*                                    */
  582. /*     Upon Entry:                            */
  583. /*                                    */
  584. /*     PLISTBOXWIN plbw;        = List Box Data Pointer        */
  585. /*     LONG       lMaxBaselineExt; = Maximum Font Height        */
  586. /*                                    */
  587. /*     Upon Exit:                            */
  588. /*                                    */
  589. /*     Nothing                                */
  590. /*                                    */
  591. /* --------------------------------------------------------------------    */
  592.  
  593. VOID MeasureItem(PLISTBOXWIN plbw, LONG    lMaxBaselineExt)
  594.  
  595. {
  596. ULONG ul;               /* Return Value            */
  597.  
  598. if ( plbw->flStyle & LS_OWNERDRAW )
  599.    {
  600.    if (    (plbw->cyItem =    (LONG)SHORT1FROMMR((ul = (ULONG)WinSendMsg(plbw->hwndOwner,
  601.                                    WM_MEASUREITEM,
  602.                                    MPFROMLONG(plbw->id),
  603.                                    MPFROMLONG(0UL))))) < lMaxBaselineExt )
  604.        plbw->cyItem  = lMaxBaselineExt;
  605.  
  606.    if (    plbw->flStyle &    LS_HORZSCROLL )
  607.        plbw->cxItem = (LONG)SHORT2FROMMR(ul);
  608.    }
  609. else
  610.    plbw->cyItem     = lMaxBaselineExt;
  611. }
  612. #pragma    subtitle("   Traffic Manager - Horizontal Scroll Creation Routine")
  613. #pragma    page( )
  614.  
  615. /* --- fAddHorzScroll ---------------------------------    [ Private ] ---    */
  616. /*                                    */
  617. /*     This function is    used to    create the horizontal scroll bar for    */
  618. /*     the list    box.                            */
  619. /*                                    */
  620. /*     Upon Entry:                            */
  621. /*                                    */
  622. /*     HWND       hWnd; = List    Box Window Handle            */
  623. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  624. /*                                    */
  625. /*     Upon Exit:                            */
  626. /*                                    */
  627. /*     fAddHorzScroll =     TRUE :    Scroll Bar Created            */
  628. /*              =    FALSE :    Scroll Bar Creation Error        */
  629. /*                                    */
  630. /* --------------------------------------------------------------------    */
  631.  
  632. BOOL fAddHorzScroll(HWND hWnd, PLISTBOXWIN plbw)
  633.  
  634. {
  635. LONG cxScroll;               /* Scroll Bar Width            */
  636.  
  637.                /* Calculate the    width of the scroll bar    and    */
  638.                /* make sure that it is a valid size otherwise    */
  639.                /* make its initial width zero            */
  640.  
  641. if ( (cxScroll = plbw->cx - plbw->cxScroll) < 0L )
  642.    cxScroll = 0L;
  643.  
  644. if ( (plbw->hwndScrollBottom = WinCreateWindow(hWnd, WC_SCROLLBAR, (PSZ)NULL,
  645.                            SBS_HORZ    | WS_VISIBLE,
  646.                            0L, 0L, cxScroll, plbw->cyScroll,
  647.                            hWnd, HWND_TOP, 0x0000c002UL,
  648.                            (PVOID)NULL, (PVOID)NULL)) != (HWND)NULL    )
  649.     {
  650.                /* Sub-class the    scroll bar to allow the        */
  651.                /* monitoring of    the button up events which will    */
  652.                /* allow    the proper refocusing to the list box    */
  653.  
  654.     WinSetWindowULong(plbw->hwndScrollBottom, QWL_USER,
  655.               (ULONG)WinSubclassWindow(plbw->hwndScrollBottom,
  656.                            (PFNWP)ScrollBarWndProc));
  657.  
  658.     WinQueryWindowPos(plbw->hwndScrollBottom, &plbw->aswp[SWP_HORZ]);
  659.     WinEnableWindow(plbw->hwndScrollBottom, FALSE);
  660.     return(TRUE);
  661.     }
  662. else
  663.     return(FALSE);
  664. }
  665. #pragma    subtitle("   Traffic Manager - Line Up Routine")
  666. #pragma    page( )
  667.  
  668. /* --- LineUp -----------------------------------------    [ Private ] ---    */
  669. /*                                    */
  670. /*     This function is    used to    move the focus one line    up within    */
  671. /*     the list    box.                            */
  672. /*                                    */
  673. /*     Upon Entry:                            */
  674. /*                                    */
  675. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  676. /*                                    */
  677. /*     Upon Exit:                            */
  678. /*                                    */
  679. /*     Nothing                                */
  680. /*                                    */
  681. /* --------------------------------------------------------------------    */
  682.  
  683. VOID LineUp(PLISTBOXWIN    plbw)
  684.  
  685. {
  686.                /* Check    to see if the focus has    been placed on    */
  687.                /* the list box and if it is visible remove the    */
  688.                /* focus    indicator                */
  689. if ( plbw->iFocus > 0L )
  690.    {
  691.                /* Check    to see if the list box is in single    */
  692.                /* select mode which means that the item    which    */
  693.                /* contains the focus also is the current item    */
  694.                /* selected                    */
  695.  
  696.    if (    (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL)) == 0UL )
  697.        {
  698.        SaveSelectState(0L, plbw->iFocus);
  699.        plbw->plc[0].ali[plbw->iFocus].fl &= ~(LI_FOCUS | LI_SELECTED);
  700.        if ( fItemVisible(plbw, plbw->iFocus) )
  701.        {
  702.        FocusChange(plbw, plbw->iFocus, FALSE);
  703.        DrawItemSelection(plbw, plbw->iFocus);
  704.        }
  705.                /* Update the selected item index        */
  706.  
  707.        --plbw->iSelected;
  708.  
  709.                /* Check    to see if the new position calculated    */
  710.                /* will be before the current list top display    */
  711.                /* item,    in which case, the list    will need to be    */
  712.                /* shifted upwards and the list redisplayed    */
  713.  
  714.        if ( --plbw->iFocus < plbw->iVertScroll )
  715.        {
  716.                /* Set the new scroll bar position and force the    */
  717.                /* repainting of    the output window        */
  718.  
  719.        mrNotifyOwner(plbw, LN_SCROLL);
  720.        --plbw->iVertScroll;
  721.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  722.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  723.        WinScrollWindow(plbw->hWnd, 0L, -plbw->cyItem,
  724.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  725.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  726.        WinUpdateWindow(plbw->hWnd);
  727.        }
  728.  
  729.        SaveSelectState(0L, plbw->iFocus);
  730.        plbw->plc[0].ali[plbw->iFocus].fl |= (LI_FOCUS |    LI_SELECTED);
  731.        DrawItemSelection(plbw, plbw->iFocus);
  732.        FocusChange(plbw, plbw->iFocus, TRUE);
  733.        mrNotifyOwner(plbw, LN_SELECT);
  734.        }
  735.    else
  736.        {
  737.        RemoveFocus(plbw);
  738.  
  739.                /* Check    to see if the new position calculated    */
  740.                /* will be before the current list top display    */
  741.                /* item,    in which case, the list    will need to be    */
  742.                /* shifted upwards and the list redisplayed    */
  743.  
  744.        if ( --plbw->iFocus < plbw->iVertScroll )
  745.        {
  746.                /* Set the new scroll bar position and force the    */
  747.                /* repainting of    the output window        */
  748.  
  749.        mrNotifyOwner(plbw, LN_SCROLL);
  750.        --plbw->iVertScroll;
  751.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  752.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  753.        WinScrollWindow(plbw->hWnd, 0L, -plbw->cyItem,
  754.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  755.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  756.        WinUpdateWindow(plbw->hWnd);
  757.        }
  758.        SetFocus(plbw, plbw->iFocus);
  759.        mrNotifyOwner(plbw, LN_SELECT);
  760.        }
  761.    }
  762. }
  763. #pragma    subtitle("   Traffic Manager - Line Down Routine")
  764. #pragma    page( )
  765.  
  766. /* --- LineDown    ---------------------------------------    [ Private ] ---    */
  767. /*                                    */
  768. /*     This function is    used to    move the focus one line    down within    */
  769. /*     the list    box.                            */
  770. /*                                    */
  771. /*     Upon Entry:                            */
  772. /*                                    */
  773. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  774. /*                                    */
  775. /*     Upon Exit:                            */
  776. /*                                    */
  777. /*     Nothing                                */
  778. /*                                    */
  779. /* --------------------------------------------------------------------    */
  780.  
  781. VOID LineDown(PLISTBOXWIN plbw)
  782.  
  783. {
  784.                /* Check    to see if the focus has    been placed on    */
  785.                /* the list box and if it is visible remove the    */
  786.                /* focus    indicator                */
  787.  
  788. if ( (plbw->iFocus != LIT_NONE)    && (plbw->iFocus < (plbw->cItems - 1L))    )
  789.    if (    (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL)) == 0UL )
  790.        {
  791.                /* Remove the focus from    the selected item    */
  792.  
  793.        SaveSelectState(0L, plbw->iFocus);
  794.        FocusChange(plbw, plbw->iFocus, FALSE);
  795.        plbw->plc[0].ali[plbw->iFocus].fl &= ~(LI_FOCUS | LI_SELECTED);
  796.        if ( fItemVisible(plbw, plbw->iFocus) &&    (plbw->iSelected != LIT_NONE) )
  797.        DrawItemSelection(plbw, plbw->iSelected);
  798.  
  799.                /* Check    to see if the new position calculated    */
  800.                /* will be after    the list bottom    display    item,    */
  801.                /* in which case, the list will need to be    */
  802.                /* shifted downwards and    the list redisplayed    */
  803.  
  804.        if ( (plbw->iSelected = ++plbw->iFocus) >= (plbw->iVertScroll + plbw->cLinesPage) )
  805.        {
  806.                /* Set the new scroll bar position and force the    */
  807.                /* repainting of    the output window        */
  808.  
  809.        mrNotifyOwner(plbw, LN_SCROLL);
  810.        ++plbw->iVertScroll;
  811.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  812.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  813.        WinScrollWindow(plbw->hWnd, 0L, plbw->cyItem,
  814.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  815.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  816.        WinUpdateWindow(plbw->hWnd);
  817.        }
  818.  
  819.        SaveSelectState(0L, plbw->iFocus);
  820.        plbw->plc[0].ali[plbw->iFocus].fl |= (LI_FOCUS |    LI_SELECTED);
  821.        FocusChange(plbw, plbw->iFocus, TRUE);
  822.        DrawItemSelection(plbw, plbw->iFocus);
  823.        mrNotifyOwner(plbw, LN_SELECT);
  824.        }
  825.    else
  826.        {
  827.        RemoveFocus(plbw);
  828.                /* Check    to see if the list box is in single    */
  829.                /* select mode which means that the item    which    */
  830.                /* contains the focus also is the current item    */
  831.                /* selected                    */
  832.  
  833.        if ( (plbw->flStyle & LS_MULTIPLESEL) ==    0UL )
  834.        plbw->iSelected = ++plbw->iFocus;
  835.        else
  836.        ++plbw->iFocus;
  837.  
  838.                /* Check    to see if the new position calculated    */
  839.                /* will be after    the list bottom    display    item,    */
  840.                /* in which case, the list will need to be    */
  841.                /* shifted downwards and    the list redisplayed    */
  842.  
  843.        if ( plbw->iFocus >= (plbw->iVertScroll + plbw->cLinesPage) )
  844.        {
  845.                /* Set the new scroll bar position and force the    */
  846.                /* repainting of    the output window        */
  847.  
  848.        mrNotifyOwner(plbw, LN_SCROLL);
  849.        ++plbw->iVertScroll;
  850.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  851.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  852.        WinScrollWindow(plbw->hWnd, 0L, plbw->cyItem,
  853.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  854.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  855.        WinUpdateWindow(plbw->hWnd);
  856.        }
  857.        mrNotifyOwner(plbw, LN_SELECT);
  858.        SetFocus(plbw, plbw->iFocus);
  859.        }
  860. }
  861. #pragma    subtitle("   Traffic Manager - Drag Up Routine")
  862. #pragma    page( )
  863.  
  864. /* --- LineUp -----------------------------------------    [ Private ] ---    */
  865. /*                                    */
  866. /*     This function is    used to    move the focus one line    up within    */
  867. /*     the list    box.                            */
  868. /*                                    */
  869. /*     Upon Entry:                            */
  870. /*                                    */
  871. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  872. /*                                    */
  873. /*     Upon Exit:                            */
  874. /*                                    */
  875. /*     Nothing                                */
  876. /*                                    */
  877. /* --------------------------------------------------------------------    */
  878.  
  879. VOID DragUp(PLISTBOXWIN    plbw)
  880.  
  881. {
  882.                /* Check    to see if the focus has    been placed on    */
  883.                /* the list box and if it is visible remove the    */
  884.                /* focus    indicator                */
  885. if ( plbw->iFocus > 0L )
  886.    {
  887.                /* Check    to see if the list box is in single    */
  888.                /* select mode which means that the item    which    */
  889.                /* contains the focus also is the current item    */
  890.                /* selected                    */
  891.  
  892.    if (    (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL)) == 0UL )
  893.        {
  894.        SaveSelectState(0L, plbw->iFocus);
  895.        FocusChange(plbw, plbw->iFocus, FALSE);
  896.        plbw->plc[0].ali[plbw->iFocus].fl &= ~(LI_FOCUS | LI_SELECTED);
  897.        if ( fItemVisible(plbw, plbw->iFocus) )
  898.        DrawItemSelection(plbw, plbw->iFocus);
  899.  
  900.                /* Check    to see if the new position calculated    */
  901.                /* will be before the current list top display    */
  902.                /* item,    in which case, the list    will need to be    */
  903.                /* shifted upwards and the list redisplayed    */
  904.  
  905.        if ( (plbw->iSelected = --plbw->iFocus) < plbw->iVertScroll )
  906.        {
  907.        SaveSelectState(0L, plbw->iFocus);
  908.        plbw->plc[0].ali[plbw->iFocus].fl |=    (LI_FOCUS | LI_SELECTED);
  909.  
  910.                /* Set the new scroll bar position and force the    */
  911.                /* repainting of    the output window        */
  912.  
  913.        mrNotifyOwner(plbw, LN_SCROLL);
  914.        --plbw->iVertScroll;
  915.        FocusChange(plbw, plbw->iFocus, TRUE);
  916.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  917.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  918.        WinScrollWindow(plbw->hWnd, 0L, -plbw->cyItem,
  919.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  920.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  921.        WinUpdateWindow(plbw->hWnd);
  922.        }
  923.        else
  924.        {
  925.        SaveSelectState(0L, plbw->iFocus);
  926.        plbw->plc[0].ali[plbw->iFocus].fl |=    (LI_FOCUS | LI_SELECTED);
  927.        FocusChange(plbw, plbw->iFocus, TRUE);
  928.        DrawItemSelection(plbw, plbw->iFocus);
  929.        }
  930.        mrNotifyOwner(plbw, LN_SELECT);
  931.        }
  932.    else
  933.        {
  934.        RemoveFocus(plbw);
  935.  
  936.                /* Check    to see if the drag is in an area where    */
  937.                /* the current focus item will be deselected    */
  938.  
  939.        if ( plbw->iFocus > plbw->iAnchor )
  940.        {
  941.                /* In an    area where the drag direction is    */
  942.                /* deselecting items, deselect the current item    */
  943.                /* and redraw it                    */
  944.  
  945.        SaveSelectState(0L, plbw->iFocus);
  946.        plbw->plc[0].ali[plbw->iFocus].fl &=    ~LI_SELECTED;
  947.        DrawItemSelection(plbw, plbw->iFocus);
  948.        }
  949.                /* Check    to see if the new position calculated    */
  950.                /* will be before the current list top display    */
  951.                /* item,    in which case, the list    will need to be    */
  952.                /* shifted upwards and the list redisplayed    */
  953.  
  954.        if ( --plbw->iFocus < plbw->iVertScroll )
  955.        {
  956.        SaveSelectState(0L, plbw->iFocus);
  957.        plbw->plc[0].ali[plbw->iFocus].fl |=    LI_SELECTED;
  958.  
  959.                /* Set the new scroll bar position and force the    */
  960.                /* repainting of    the output window        */
  961.  
  962.        mrNotifyOwner(plbw, LN_SCROLL);
  963.        --plbw->iVertScroll;
  964.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  965.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  966.        WinScrollWindow(plbw->hWnd, 0L, -plbw->cyItem,
  967.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  968.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  969.        WinUpdateWindow(plbw->hWnd);
  970.        }
  971.        else
  972.        {
  973.        SaveSelectState(0L, plbw->iFocus);
  974.        plbw->plc[0].ali[plbw->iFocus].fl |=    LI_SELECTED;
  975.        }
  976.  
  977.        mrNotifyOwner(plbw, LN_SELECT);
  978.        SetFocus(plbw, plbw->iFocus);
  979.        }
  980.    }
  981. }
  982. #pragma    subtitle("   Traffic Manager - Drag Down Routine")
  983. #pragma    page( )
  984.  
  985. /* --- DragDown    ---------------------------------------    [ Private ] ---    */
  986. /*                                    */
  987. /*     This function is    used to    move the focus one line    down within    */
  988. /*     the list    box.                            */
  989. /*                                    */
  990. /*     Upon Entry:                            */
  991. /*                                    */
  992. /*     PLISTBOXWIN plbw; = List    Box Data Pointer            */
  993. /*                                    */
  994. /*     Upon Exit:                            */
  995. /*                                    */
  996. /*     Nothing                                */
  997. /*                                    */
  998. /* --------------------------------------------------------------------    */
  999.  
  1000. VOID DragDown(PLISTBOXWIN plbw)
  1001.  
  1002. {
  1003.                /* Check    to see if the focus has    been placed on    */
  1004.                /* the list box and if it is visible remove the    */
  1005.                /* focus    indicator                */
  1006.  
  1007. if ( (plbw->iFocus != LIT_NONE)    && (plbw->iFocus < (plbw->cItems - 1L))    )
  1008.    if (    (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL)) == 0UL )
  1009.        {
  1010.        SaveSelectState(0L, plbw->iFocus);
  1011.        plbw->plc[0].ali[plbw->iFocus].fl &= ~(LI_FOCUS | LI_SELECTED);
  1012.        if ( fItemVisible(plbw, plbw->iFocus) )
  1013.        DrawItemSelection(plbw, plbw->iFocus);
  1014.  
  1015.                /* Check    to see if the new position calculated    */
  1016.                /* will be after    the list bottom    display    item,    */
  1017.                /* in which case, the list will need to be    */
  1018.                /* shifted downwards and    the list redisplayed    */
  1019.  
  1020.        if ( (plbw->iSelected = ++plbw->iFocus) >= (plbw->iVertScroll + plbw->cLinesPage) )
  1021.        {
  1022.        SaveSelectState(0L, plbw->iFocus);
  1023.        plbw->plc[0].ali[plbw->iFocus].fl |=    (LI_FOCUS | LI_SELECTED);
  1024.        FocusChange(plbw, plbw->iFocus, TRUE);
  1025.  
  1026.                /* Set the new scroll bar position and force the    */
  1027.                /* repainting of    the output window        */
  1028.  
  1029.        mrNotifyOwner(plbw, LN_SCROLL);
  1030.        ++plbw->iVertScroll;
  1031.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  1032.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  1033.        WinScrollWindow(plbw->hWnd, 0L, plbw->cyItem,
  1034.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  1035.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  1036.        WinUpdateWindow(plbw->hWnd);
  1037.        }
  1038.        else
  1039.        {
  1040.        SaveSelectState(0L, plbw->iFocus);
  1041.        plbw->plc[0].ali[plbw->iFocus].fl |=    (LI_FOCUS | LI_SELECTED);
  1042.        FocusChange(plbw, plbw->iFocus, TRUE);
  1043.        DrawItemSelection(plbw, plbw->iFocus);
  1044.        }
  1045.        mrNotifyOwner(plbw, LN_SELECT);
  1046.        }
  1047.    else
  1048.        {
  1049.        RemoveFocus(plbw);
  1050.  
  1051.                /* Check    to see if the drag is in an area where    */
  1052.                /* the current focus item will be deselected    */
  1053.  
  1054.        if ( plbw->iFocus < plbw->iAnchor )
  1055.        {
  1056.                /* In an    area where the drag direction is    */
  1057.                /* deselecting items, deselect the current item    */
  1058.                /* and redraw it                    */
  1059.  
  1060.        SaveSelectState(0L, plbw->iFocus);
  1061.        plbw->plc[0].ali[plbw->iFocus].fl &=    ~LI_SELECTED;
  1062.        DrawItemSelection(plbw, plbw->iFocus);
  1063.        }
  1064.                /* Check    to see if the list box is in single    */
  1065.                /* select mode which means that the item    which    */
  1066.                /* contains the focus also is the current item    */
  1067.                /* selected                    */
  1068.  
  1069.        if ( (plbw->flStyle & LS_MULTIPLESEL) ==    0UL )
  1070.        plbw->iSelected = ++plbw->iFocus;
  1071.        else
  1072.        ++plbw->iFocus;
  1073.  
  1074.                /* Check    to see if the new position calculated    */
  1075.                /* will be after    the list bottom    display    item,    */
  1076.                /* in which case, the list will need to be    */
  1077.                /* shifted downwards and    the list redisplayed    */
  1078.  
  1079.        if ( plbw->iFocus >= (plbw->iVertScroll + plbw->cLinesPage) )
  1080.        {
  1081.        SaveSelectState(0L, plbw->iFocus);
  1082.        plbw->plc[0].ali[plbw->iFocus].fl |=    LI_SELECTED;
  1083.  
  1084.                /* Set the new scroll bar position and force the    */
  1085.                /* repainting of    the output window        */
  1086.  
  1087.        mrNotifyOwner(plbw, LN_SCROLL);
  1088.        ++plbw->iVertScroll;
  1089.        WinSendMsg(plbw->hwndScrollRight, SBM_SETPOS,
  1090.               MPFROMSHORT(plbw->iVertScroll = max(0, min(plbw->iVertScroll, plbw->cVertScroll))), 0L);
  1091.        WinScrollWindow(plbw->hWnd, 0L, plbw->cyItem,
  1092.                (PRECTL)&plbw->rcl, (PRECTL)&plbw->rcl,
  1093.                (HRGN)NULL, (PRECTL)NULL, SW_INVALIDATERGN);
  1094.        WinUpdateWindow(plbw->hWnd);
  1095.        }
  1096.        else
  1097.        {
  1098.        SaveSelectState(0L, plbw->iFocus);
  1099.        plbw->plc[0].ali[plbw->iFocus].fl |=    LI_SELECTED;
  1100.        }
  1101.  
  1102.        mrNotifyOwner(plbw, LN_SELECT);
  1103.        SetFocus(plbw, plbw->iFocus);
  1104.        }
  1105. }
  1106.