home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / perfmon / intrline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  29.6 KB  |  1,067 lines

  1. /*
  2. ==============================================================================
  3.  
  4.   Application:
  5.  
  6.             Microsoft Windows NT (TM) Performance Monitor
  7.  
  8.   File:
  9.             intrline.c -- IntervalLine custom control.
  10.  
  11.   Copyright 1992-1997, Microsoft Corporation. All Rights Reserved.
  12. ==============================================================================
  13. */
  14.  
  15.  
  16. /*
  17.  
  18.  
  19. Basic Information
  20. -----------------
  21.    
  22. An ILine (Interval Line) control is a horizontally-sliding device; the user 
  23. can slide the start position and end position independently by dragging 
  24. either "grab" bar, or move them simultaneously by dragging the center grab
  25. bar. An ILine control is used in the Input Log dialog of Perfmon, but could
  26. be used anywhere. The control allows the user to specify the start, end and 
  27. duration of playback within the range of previously-logged data.
  28.  
  29.  
  30. ILine Parts
  31. -----------
  32.  
  33.      iBeginValue                                            iEndValue
  34.      |      iStartValue                        iStopValue           |
  35.      |      |                                           |           |
  36.      v      v                                           v           v
  37.      +------+-+---------------------------------------+-+-----------+
  38.      |      |X|                                       |X|           |
  39.      |      |X|                                       |X|           |
  40.      +------+-+---------------------------------------+-+-----------+
  41.              ^                    ^                    ^
  42.              Start grab bar       Center grab bar      Stop grab bar
  43.  
  44.  
  45. ILine Terminology
  46. -----------------
  47.  
  48. All external routines are designated by the prefix ILine-.
  49. Internal routines are designated by the prefix IL-.
  50.  
  51. The suffix -Value represents an integer in the user-supplied domain.
  52. The suffix -Pixel represents an integer location on the screen.
  53.  
  54. Note that the range of the IntervalLine is represented by "Begin" and 
  55. "End", while the the currently selected interval is represented by
  56. "Start" and "Stop".
  57.  
  58.  
  59. Implementation Notes
  60. --------------------
  61.  
  62. ILine is a custom control, but does not have all the messages 
  63. normally associated with a full-fledged control type like "button". 
  64. In particular, it doesn't have a keyboard interface or ask it's parent
  65. for color choices. It also doesn't have the functions needed for interfacing
  66. with the dialog editor custom control menu.
  67.  
  68. An ILine control is designed to work with an integer range of values
  69. specified by the user of the control. These values should have meaning to
  70. the caller. The caller can specify the minimum value of the range 
  71. (iBeginValue), the maximum value of the range (iEndValue), and the current
  72. starting and stopping values (iStartValue and iStopValue). 
  73.  
  74. These values are set with a function-based interface. (ILSetXXX).
  75.  
  76. The code distinguishes between the *values* for the begin, end, start, and
  77. stop, and the *pixels* which represent locations on the control for these
  78. values.
  79.  
  80. Various bits of the control style allow for changing the control's 
  81. behavior.
  82.  
  83. To allow for multiple ILine controls, all data used by each ILine
  84. instance is allocated from the heap and associated with the control.
  85. The allocation is done in OnCreate and the freeing in OnDestroy. The
  86. instance data is contained in the ILINE structure. Each message handler
  87. retrieves this instance data with the ILData function.
  88.  
  89. */      
  90.  
  91.  
  92. //==========================================================================//
  93. //                                  Includes                                //
  94. //==========================================================================//
  95.  
  96.  
  97. #include "perfmon.h"
  98. #include "utils.h"
  99. #include "intrline.h"
  100. #include "pmemory.h"        // for MemoryXXX (mallloc-type) routines
  101.  
  102. BOOL  IntrLineFocus ;
  103.  
  104. //==========================================================================//
  105. //                                  Constants                               //
  106. //==========================================================================//
  107.  
  108.  
  109. #define dwILineClassStyle     (CS_HREDRAW | CS_VREDRAW)
  110. #define iILineClassExtra      (0)
  111. #define iILineWindowExtra     (sizeof (PILINE))
  112. #define dwILineWindowStyle    (WS_CHILD | WS_VISIBLE) 
  113.  
  114.  
  115. #define ILModeNone            0
  116. #define ILModeLeft            1
  117. #define ILModeCenter          2
  118. #define ILModeRight           3
  119.  
  120. #define TO_THE_END            0x7FFFFFFFL
  121.  
  122. //==========================================================================//
  123. //                                  Typedefs                                //
  124. //==========================================================================//
  125.  
  126.  
  127. // The instance data for each IL window.  One of these is allocated for each
  128. // window in the window's OnCreate processing and free'd in OnDestroy.
  129. typedef struct ILINESTRUCT
  130.    {  // ILINE
  131.    int            iBeginValue ;        // user-supplied lowest range
  132.    int            iEndValue ;          // user-supplied highest range
  133.    int            iStartValue ;        // current start of selected interval
  134.    int            iStopValue ;         // current end of selected interval
  135.    int            iGranularityValue ;
  136.    int            iMinimumRangeValue ;
  137.  
  138.    RECT           rectBorder ;
  139.    RECT           rectLeftBk ;
  140.    RECT           rectLeftGrab ;
  141.    RECT           rectCenterGrab ;
  142.    RECT           rectRightGrab ;
  143.    RECT           rectRightBk ;
  144.  
  145.    HBRUSH         hBrushBk ;
  146.  
  147.    POINTS         ptsMouse ;
  148.    int            iMode ;              // who is being tracked?
  149.    } ILINE ;
  150.  
  151. typedef ILINE *PILINE ;
  152.  
  153.  
  154. //==========================================================================//
  155. //                                   Macros                                 //
  156. //==========================================================================//
  157.  
  158.  
  159. // Width of the start and stob grab bars
  160. #define ILGrabWidth()      \
  161.    (xScrollThumbWidth)
  162.  
  163.  
  164. // A rectangle is "drawable" if it has both nonzero width and height
  165. #define RectDrawable(lpRect)           \
  166.    ((lpRect->right - lpRect->left) &&  \
  167.     (lpRect->bottom - lpRect->top))
  168.  
  169.  
  170. //======================================//
  171. // ILine Accessor Macros                //
  172. //======================================//
  173.  
  174. // These macros reference fields in the ILine structure and should be
  175. // used in place of direct reference to the fields. This makes the code
  176. // easier to read and allows modification of the underlying structure.
  177.  
  178. // You can use these macros to both get and set the fields.
  179.  
  180. #define ILBegin(pILine)    \
  181.    (pILine->iBeginValue)
  182.  
  183. #define ILEnd(pILine)      \
  184.    (pILine->iEndValue)
  185.  
  186. #define ILStart(pILine)    \
  187.    (pILine->iStartValue)
  188.  
  189. #define ILStop(pILine)     \
  190.    (pILine->iStopValue)
  191.  
  192. #define ILMode(pILine)     \
  193.    (pILine->iMode)
  194.  
  195.  
  196. //======================================//
  197. // ILine Pseudo-Accessor Macros         //
  198. //======================================//
  199.  
  200. // These macros are used to get values which don't correspond to a single
  201. // field. You can get the value with these macros but can't set it.
  202.  
  203. #define ILWidth(pILine)    \
  204.    (pILine->rectBorder.right)
  205.  
  206. #define ILRange(pILine)    \
  207.    (ILEnd (pILine) - ILBegin (pILine))
  208.  
  209. #define ILStartPixel(pILine) \
  210.    (pILine->rectLeftGrab.left)
  211.  
  212. #define ILStopPixel(pILine)   \
  213.    (pILine->rectRightGrab.right)
  214.  
  215.  
  216. //==========================================================================//
  217. //                              Local Functions                             //
  218. //==========================================================================//
  219.  
  220.  
  221. void static ILNotifyChange (HWND hWnd,
  222.                             PILINE pILine)
  223.    {  // ILNotifyChange
  224.    HWND           hWndParent ;
  225.  
  226.    hWndParent = WindowParent (hWnd) ;
  227.  
  228.    if (hWndParent)
  229.       SendMessage (hWndParent, WM_COMMAND, 
  230.                    (WPARAM) WindowID (hWnd),
  231.                    (LPARAM) hWnd) ;
  232.    }  // ILNotifyChange
  233.  
  234.  
  235. BOOL ILGrabRect (IN PILINE pILine, 
  236.                  OUT LPRECT lpRect)
  237. /*
  238.    Effect:        Return in lpRect the rectangle representing the position
  239.                   of the grab bar currently being tracked.
  240. */
  241.    {  // ILGrabRect
  242.    switch (ILMode (pILine))
  243.       {  // switch
  244.       case ILModeLeft:
  245.          *lpRect = pILine->rectLeftGrab ;
  246.          return (TRUE) ;
  247.          break ;
  248.  
  249.       case ILModeRight:
  250.          *lpRect = pILine->rectRightGrab ;
  251.          return (TRUE) ;
  252.          break ;
  253.  
  254.       case ILModeCenter:
  255.          *lpRect = pILine->rectCenterGrab ;
  256.          return (TRUE) ;
  257.          break ;
  258.  
  259.       case ILModeNone:
  260.          lpRect->left = 0 ;
  261.          lpRect->top = 0 ;
  262.          lpRect->right = 0 ;
  263.          lpRect->bottom = 0 ;
  264.          return (FALSE) ;
  265.          break ;
  266.       }  // switch
  267.    }  // ILGrabRect
  268.  
  269.  
  270. PILINE ILData (HWND hWndIL)
  271.    {
  272.    return ((PILINE) GetWindowLong (hWndIL, 0)) ;
  273.    }
  274.  
  275.  
  276. PILINE AllocateILData (HWND hWndIL)
  277.    {
  278.    PILINE         pILine ;
  279.  
  280.    pILine = MemoryAllocate (sizeof (ILINE)) ;
  281.    SetWindowLong (hWndIL, 0, (LONG) pILine) ;
  282.  
  283.    return (pILine) ;
  284.    }
  285.  
  286.  
  287. void static DrawGrab (HDC hDC,
  288.                       LPRECT lpRectGrab,
  289.                       BOOL bDown)
  290.    {  // DrawGrab
  291.    if (!RectDrawable (lpRectGrab))
  292.       return ;
  293.  
  294.    if (bDown)
  295.       ThreeDConcave1 (hDC, 
  296.                      lpRectGrab->left,
  297.                      lpRectGrab->top,
  298.                      lpRectGrab->right,
  299.                      lpRectGrab->bottom) ;
  300.    else
  301.       ThreeDConvex1 (hDC, 
  302.                     lpRectGrab->left,
  303.                     lpRectGrab->top,
  304.                     lpRectGrab->right,
  305.                     lpRectGrab->bottom) ;
  306.    }  // DrawGrab
  307.  
  308.  
  309. int ILValueToPixel (PILINE pILine,
  310.                     int iValue)
  311.    {
  312.    int            xPixel ;
  313.  
  314.    if (ILRange (pILine))
  315.       xPixel = MulDiv (iValue, ILWidth (pILine), ILRange (pILine)) ;
  316.    else
  317.       xPixel = 0 ;
  318.  
  319.    return (PinExclusive (xPixel, 0, pILine->rectBorder.right)) ;
  320.    }
  321.  
  322.  
  323. int ILPixelToValue (PILINE pILine,
  324.                     int xPixel)
  325.    {
  326.    int            iValue ;
  327.  
  328.    if (ILWidth (pILine))
  329.       iValue = MulDiv (xPixel, ILRange (pILine), ILWidth (pILine)) ;
  330.    else
  331.       iValue = 0 ;
  332.  
  333.    return (PinInclusive (iValue, ILBegin (pILine), ILEnd (pILine))) ;
  334.    }
  335.  
  336.  
  337. void static ILCalcPositions (HWND hWnd,
  338.                              PILINE pILine)
  339. /*
  340.    Effect:        Determine and set all of the physical rectangles of ILine,
  341.                   based on the current size of the ILine window and the 
  342.                   current logical Start, Stop, Begin, and End values.
  343. */
  344.    {  // ILCalcPositions
  345.    int            xStart, xStop ;
  346.    int            yHeight ;
  347.  
  348.    GetClientRect (hWnd, &pILine->rectBorder) ;
  349.    yHeight = pILine->rectBorder.bottom ;
  350.  
  351.    xStart = ILValueToPixel (pILine, ILStart (pILine)) ;
  352.    xStop = ILValueToPixel (pILine, ILStop (pILine)) ;
  353.  
  354.    pILine->rectLeftBk.left = 1 ;
  355.    pILine->rectLeftBk.top = 1 ;
  356.    pILine->rectLeftBk.right = xStart ;
  357.    pILine->rectLeftBk.bottom = yHeight - 1 ;
  358.  
  359.    pILine->rectLeftGrab.left = xStart ;
  360.    pILine->rectLeftGrab.top = 1 ;
  361.    pILine->rectLeftGrab.right = xStart + ILGrabWidth () ;
  362.    pILine->rectLeftGrab.bottom = yHeight - 1 ;
  363.  
  364.    pILine->rectRightBk.left = xStop ;
  365.    pILine->rectRightBk.top = 1 ;
  366.    pILine->rectRightBk.right = pILine->rectBorder.right - 1 ;
  367.    pILine->rectRightBk.bottom = yHeight - 1 ;
  368.  
  369.    pILine->rectRightGrab.left = xStop - ILGrabWidth () ;
  370.    pILine->rectRightGrab.top = 1 ;
  371.    pILine->rectRightGrab.right = xStop ;
  372.    pILine->rectRightGrab.bottom = yHeight - 1 ;
  373.  
  374.    pILine->rectCenterGrab.left = pILine->rectLeftGrab.right ;
  375.    pILine->rectCenterGrab.top = 1 ;
  376.    pILine->rectCenterGrab.right = pILine->rectRightGrab.left ;
  377.    pILine->rectCenterGrab.bottom = yHeight - 1 ;
  378.  
  379.    if (pILine->rectLeftGrab.right > pILine->rectRightGrab.left)
  380.       {
  381.       pILine->rectLeftGrab.right = pILine->rectLeftGrab.left + 
  382.                                    (xStop - xStart) / 2 ;
  383.       pILine->rectRightGrab.left = pILine->rectLeftGrab.right ;
  384.       pILine->rectCenterGrab.left = 0 ;
  385.       pILine->rectCenterGrab.right = 0 ;
  386.       }
  387.    }  // ILCalcPositions
  388.  
  389.  
  390. void static ILDraw (HDC hDC, 
  391.                     PILINE pILine,     
  392.                     LPRECT lpRectUpdate)
  393. /*
  394.    Effect:        Draw the image of pILine on hDC.  Draw at least the 
  395.                   portions within rectUpdate.
  396.  
  397.    Called By:     OnPaint, OnMouseMove.
  398. */
  399.    {  // ILDraw
  400.  
  401.    //=============================//
  402.    // Draw Border                 //
  403.    //=============================//
  404.    
  405.    FrameRect (hDC, &pILine->rectBorder, GetStockObject (BLACK_BRUSH)) ;
  406.  
  407.    //=============================//
  408.    // Draw Background             //
  409.    //=============================//
  410.  
  411.    FillRect (hDC, &pILine->rectLeftBk, pILine->hBrushBk) ;
  412.    FillRect (hDC, &pILine->rectRightBk, pILine->hBrushBk) ;
  413.  
  414.    //=============================//
  415.    // Draw Range Grabs            //
  416.    //=============================//
  417.  
  418.    DrawGrab (hDC, &pILine->rectLeftGrab, 
  419.              ILMode (pILine) == ILModeLeft) ;
  420.    DrawGrab (hDC, &pILine->rectRightGrab,
  421.              ILMode (pILine) == ILModeRight) ;
  422.  
  423.    //=============================//
  424.    // Draw Center Grab            //
  425.    //=============================//
  426.  
  427.    DrawGrab (hDC, &pILine->rectCenterGrab,
  428.              ILMode (pILine) == ILModeCenter) ;
  429.    }  // ILDraw
  430.  
  431. #if 0
  432. void ILPageLeftRight (HWND hWnd,
  433.                       PILINE pILine,
  434.                       BOOL bLeft)
  435.    {  // ILPageLeftRight
  436.    int            iStart, iStop, iMove ;
  437.    HDC            hDC ;
  438.  
  439.    iStart = ILStart (pILine) ;
  440.    iStop = ILStop (pILine) ;
  441.  
  442.    if (ILRange (pILine) >= 10)   
  443.       iMove = ILRange (pILine) / 10 ;
  444.    else
  445.       iMove = 1 ;
  446.  
  447.    if (bLeft)
  448.       iMove = -iMove ;
  449.  
  450.    iStart += iMove ;
  451.    iStop += iMove ;
  452.  
  453.    ILineSetStart (hWnd, iStart) ;
  454.    ILineSetStop (hWnd, iStop) ;
  455.  
  456.    hDC = GetDC (hWnd) ;
  457.    ILDraw (hDC, pILine, &pILine->rectBorder) ;
  458.    ReleaseDC (hWnd, hDC) ;
  459.  
  460.    ILNotifyChange (hWnd, pILine) ;
  461.    }  // ILPageLeftRight
  462. #endif
  463.  
  464. void ILMoveLeftRight (HWND hWnd,
  465.                       BOOL bStart,
  466.                       BOOL bLeft,
  467.                       int  MoveAmt)
  468.    {  // ILPageLeftRight
  469.    int            iStart, iStop, iMove ;
  470.    int            iBegin, iEnd ;
  471.    HDC            hDC ;
  472.    PILINE         pILine ;
  473.  
  474.    pILine = ILData (hWnd) ;
  475.    iStart = ILStart (pILine) ;
  476.    iStop = ILStop (pILine) ;
  477.    iBegin = ILBegin (pILine) ;
  478.    iEnd = ILEnd (pILine) ;
  479.  
  480.    iMove = MoveAmt ;
  481.    if (bLeft)
  482.       iMove = -iMove ;
  483.  
  484.    if (bStart)
  485.       {
  486.       if (MoveAmt == TO_THE_END)
  487.          {
  488.          iStart = iBegin ;
  489.          }
  490.       else
  491.          {
  492.          iStart += iMove ;
  493.          if (iStart >= iStop)
  494.             {
  495.             return;
  496.             }
  497.          }
  498.  
  499.       ILineSetStart (hWnd, iStart) ;
  500.       }
  501.    else
  502.       {
  503.       if (MoveAmt == TO_THE_END)
  504.          {
  505.          iStop = iEnd ;
  506.          }
  507.       else
  508.          {
  509.          iStop += iMove ;
  510.          if (iStart >= iStop)
  511.             {
  512.             return;
  513.             }
  514.          }
  515.  
  516.       ILineSetStop (hWnd, iStop) ;
  517.       }
  518.  
  519.    hDC = GetDC (hWnd) ;
  520.    ILDraw (hDC, pILine, &pILine->rectBorder) ;
  521.    ReleaseDC (hWnd, hDC) ;
  522.  
  523.    ILNotifyChange (hWnd, pILine) ;
  524.    }  // ILMoveLeftRight
  525.  
  526. static BOOL OnKeyDown (HWND hWnd,
  527.                        WPARAM wParam)
  528.    {
  529.    BOOL bHandle = TRUE ;
  530.    BOOL bStart ;
  531.    BOOL bLeftDirection ;
  532.    BOOL bShiftKeyDown ;
  533.  
  534.    if (wParam == VK_LEFT || wParam == VK_RIGHT)
  535.       {
  536.       bShiftKeyDown = (GetKeyState (VK_SHIFT) < 0) ;
  537.  
  538.       if (!bShiftKeyDown)
  539.          {
  540.          if (wParam == VK_LEFT)
  541.             {
  542.             // Left Arrow --> move Start Edge Left
  543.             bStart = TRUE ;
  544.             bLeftDirection = TRUE ;
  545.             }
  546.          else
  547.             {
  548.             // Right Arrow --> move Stop Edge Right
  549.             bStart = FALSE ;
  550.             bLeftDirection = FALSE ;
  551.             }
  552.          }
  553.       else
  554.          {
  555.          if (wParam == VK_LEFT)
  556.             {
  557.             // Shift Left Arrow --> move Stop Edge Left
  558.             bStart = FALSE ;
  559.             bLeftDirection = TRUE ;
  560.             }
  561.          else
  562.             {
  563.             // Shift Right Arrow --> move Start Edge Right
  564.             bStart = TRUE ;
  565.             bLeftDirection = FALSE ;
  566.             }
  567.          }
  568.       ILMoveLeftRight (hWnd, bStart, bLeftDirection, 1) ;
  569.       }
  570.    else if (wParam == VK_HOME)
  571.       {
  572.       // move iStart all the way the Left
  573.       ILMoveLeftRight (hWnd, TRUE, TRUE, TO_THE_END) ;
  574.       }
  575.    else if (wParam == VK_END)
  576.       {
  577.       // move iStop all the way the right
  578.       ILMoveLeftRight (hWnd, FALSE, FALSE, TO_THE_END) ;
  579.       }
  580.    else
  581.       {
  582.       bHandle = FALSE ;
  583.       }
  584.    return (bHandle) ;
  585.  
  586.    }  // OnKeyDown
  587.  
  588. void StartGrab (HWND hWnd,
  589.                 PILINE pILine)
  590.    {  // StartGrab
  591.    RECT           rectUpdate ;
  592.    HDC            hDC ;
  593.  
  594.    SetCapture (hWnd) ;
  595.    ILGrabRect (pILine, &rectUpdate) ;
  596.  
  597.    hDC = GetDC (hWnd) ;
  598.    ILDraw (hDC, pILine, &rectUpdate) ;
  599.    ReleaseDC (hWnd, hDC) ;
  600.    }  // StartGrab
  601.  
  602.  
  603. void EndGrab (HWND hWnd,
  604.               PILINE pILine)
  605. /*
  606.    Internals:     Set the mode to null after getting the grab rectangle
  607.                   so ILGrabRect knows which grab bar to get.
  608. */
  609.    {
  610.    RECT           rectUpdate ;
  611.    HDC            hDC ;
  612.  
  613.    ReleaseCapture () ;
  614.  
  615.    ILGrabRect (pILine, &rectUpdate) ;
  616.    ILMode (pILine) = ILModeNone ;
  617.  
  618.    hDC = GetDC (hWnd) ;
  619.    ILDraw (hDC, pILine, &rectUpdate) ;
  620.    ReleaseDC  (hWnd, hDC) ;
  621.    }
  622.  
  623.    
  624. //==========================================================================//
  625. //                              Message Handlers                            //
  626. //==========================================================================//
  627.  
  628.  
  629. void static OnPaint (HWND hWnd)
  630.    {
  631.    PAINTSTRUCT    ps ;
  632.    HDC            hDC ;
  633.    PILINE         pILine ;
  634.  
  635.    pILine = ILData (hWnd) ;
  636.    hDC = BeginPaint (hWnd, &ps) ;
  637.  
  638.    ILDraw (hDC, pILine, &ps.rcPaint) ;
  639.  
  640.    EndPaint (hWnd, &ps) ;
  641.    }
  642.  
  643.  
  644. void static OnCreate (HWND hWnd)
  645.    {
  646.    PILINE         pILine ;
  647.  
  648.    pILine = AllocateILData (hWnd) ;
  649.    ILBegin (pILine) =  0 ;
  650.    ILEnd (pILine) =  100 ;
  651.    ILStart (pILine) =  0 ;
  652.    ILStop (pILine) = 100 ;
  653.    ILMode (pILine) = ILModeNone ;
  654.  
  655.    pILine->hBrushBk = CreateSolidBrush (crBlue) ;
  656.    ILCalcPositions (hWnd, pILine) ;
  657.    }
  658.  
  659.  
  660. void static OnDestroy (HWND hWnd)
  661.    {
  662.    PILINE         pILine ;
  663.  
  664.    pILine = ILData (hWnd) ;
  665.  
  666.    IntrLineFocus = FALSE ;
  667.    DeleteBrush (pILine->hBrushBk) ;
  668.    MemoryFree (pILine) ;
  669.    }
  670.  
  671.  
  672. void static OnLButtonUp (HWND hWnd)
  673.    {  // OnLButtonUp
  674.    PILINE         pILine ;
  675.  
  676.    pILine = ILData (hWnd) ;
  677.  
  678.    if (ILMode (pILine) == ILModeNone)
  679.       return ;
  680.  
  681.    EndGrab (hWnd, pILine) ;
  682.    }  // OnLButtonUp
  683.  
  684.  
  685. void static OnMouseMove (HWND hWnd,
  686.                          POINTS ptsMouse)
  687. /*
  688.    Effect:        Handle any actions needed when the mouse moves in the
  689.                   ILine hWnd's client area or while the mouse is captured.
  690.                   In particular, if we are tracking one of the grab bars, 
  691.                   determine if the mouse movement represents a logical value 
  692.                   change and move the grab bar accordingly.
  693.  
  694.    Called By:     ILineWndProc, in response to a WM_MOUSEMOVE message.
  695.  
  696.    See Also:      OnLButtonDown, OnLButtonUp.
  697.  
  698.    Note:          This function has multiple return points.
  699.  
  700.    Note:          Since we have captured the mouse, we receive mouse msgs
  701.                   even when the mouse is outside our client area, but still
  702.                   in client coordinates. Thus we can have negative mouse
  703.                   coordinates. That is why we convert the lParam of the
  704.                   mouse msg into a POINTS structure rather than 2 WORDS.
  705.                   
  706.                    
  707.    Internals:     Remember that an IntervalLine can only take on integral
  708.                   values in the user-supplied range. Therefore we do our
  709.                   movement calculation in user values, not pixels. We
  710.                   determine what the logical value would be for the previous
  711.                   (last mouse move) and current mouse position. If these
  712.                   LOGICAL values differ, we attempt an adjustment of the
  713.                   grab bar by that logical amount.  This way the grab 
  714.                   values assume on integral positions and the calculations
  715.                   are simplified. 
  716.  
  717.                   If we calculated by pixel movement, and then shifted the 
  718.                   bar into the nearest integal position, we would encounter 
  719.                   rounding problems. In particular, when tracking the center 
  720.                   grab bar, if we moved both start and stop by the same 
  721.                   amount of PIXELS, then converted to LOGICAL values, we 
  722.                   might find our center bar shrinking and growing while
  723.                   the bar moves.
  724. */
  725.    {
  726.    int            iMousePrevious, iMouseCurrent ;
  727.    int            iMouseMove ;
  728.    PILINE         pILine ;
  729.    HDC            hDC ;
  730.  
  731.    //=============================//
  732.    // Are we tracking?            //
  733.    //=============================//
  734.  
  735.    pILine = ILData (hWnd) ;
  736.    if (ILMode (pILine) == ILModeNone)
  737.       return ;
  738.  
  739.    //=============================//
  740.    // Calc LOGICAL mouse movement //
  741.    //=============================//
  742.  
  743.    ptsMouse.x = PinInclusive ((INT)ptsMouse.x, 
  744.                               (INT)pILine->rectBorder.left, 
  745.                               (INT)pILine->rectBorder.right) ;
  746.  
  747.    iMousePrevious = ILPixelToValue (pILine, pILine->ptsMouse.x) ;
  748.    iMouseCurrent = ILPixelToValue (pILine, ptsMouse.x) ;
  749.  
  750.    iMouseMove = iMouseCurrent - iMousePrevious ;
  751.    if (!iMouseMove)   
  752.       return ;
  753.  
  754.    //=============================//
  755.    // Move grab bar positions     //
  756.    //=============================//
  757.  
  758.    switch (ILMode (pILine))
  759.       {  // switch   
  760.       case ILModeLeft:
  761.          ILStart (pILine) += iMouseMove ;
  762.          ILStart (pILine) = min (ILStart (pILine), ILStop (pILine) - 1) ;
  763.          break ;
  764.  
  765.       case ILModeCenter:
  766.          // Before we slide the center grab bar we need to see if the 
  767.          // desired movement amount would send either end out of bounds,
  768.          // and reduce the movement accordingly.
  769.  
  770.          if (ILStart (pILine) + iMouseMove < ILBegin (pILine))
  771.             iMouseMove = ILBegin (pILine) - ILStart (pILine) ;
  772.          if (ILStop (pILine) + iMouseMove > ILEnd (pILine))
  773.             iMouseMove = ILEnd (pILine) - ILStop (pILine) ;
  774.  
  775.          ILStart (pILine) += iMouseMove ;
  776.          ILStop (pILine) += iMouseMove ;
  777.          break ;
  778.  
  779.       case ILModeRight:
  780.          ILStop (pILine) += iMouseMove ;
  781.          ILStop (pILine) = max (ILStart (pILine) + 1, ILStop (pILine)) ;
  782.          break ;
  783.       }  // switch
  784.  
  785.  
  786.    //=============================//
  787.    // Keep grab bars in range     //
  788.    //=============================//
  789.  
  790.  
  791.    ILStart (pILine) = PinInclusive (ILStart (pILine),
  792.                                     ILBegin (pILine), ILEnd (pILine)) ;
  793.    ILStop (pILine) = PinInclusive (ILStop (pILine),
  794.                                    ILBegin (pILine), ILEnd (pILine)) ;
  795.  
  796.    //=============================//
  797.    // Determine pixel pos, draw   //
  798.    //=============================//
  799.  
  800.    ILCalcPositions (hWnd, pILine) ;
  801.  
  802.    hDC = GetDC (hWnd) ;
  803.    ILDraw (hDC, pILine, &pILine->rectBorder) ;
  804.    ReleaseDC (hWnd, hDC) ;
  805.  
  806.    pILine->ptsMouse = ptsMouse ;
  807.    ILNotifyChange (hWnd, pILine) ;
  808.    }  // OnMouseMove
  809.  
  810.  
  811. void static OnLButtonDown (HWND hWnd, 
  812.                            POINTS ptsMouse)
  813.    {
  814.    PILINE         pILine ;
  815.    POINT          ptMouse ;
  816.  
  817.    pILine = ILData (hWnd) ;
  818.  
  819.    pILine->ptsMouse = ptsMouse ;
  820.    ptMouse.x = ptsMouse.x ;
  821.    ptMouse.y = ptsMouse.y ;
  822.  
  823. #if 0
  824.    // Russ said this is bad, so don't do it
  825.    if (PtInRect (&pILine->rectLeftBk, ptMouse))
  826.       ILPageLeftRight (hWnd, pILine, TRUE) ;
  827.  
  828.    else if (PtInRect (&pILine->rectRightBk, ptMouse))
  829.       ILPageLeftRight (hWnd, pILine, FALSE) ;
  830.  
  831.    else if (PtInRect (&pILine->rectLeftGrab, ptMouse))
  832. #endif
  833.    if (PtInRect (&pILine->rectLeftGrab, ptMouse) ||
  834.        PtInRect (&pILine->rectLeftBk, ptMouse))
  835.       {
  836.       ILMode (pILine) = ILModeLeft ;
  837.       StartGrab (hWnd, pILine) ;
  838.       }
  839.  
  840.    else if (PtInRect (&pILine->rectRightGrab, ptMouse) ||
  841.             PtInRect (&pILine->rectRightBk, ptMouse))
  842.       {
  843.       ILMode (pILine) = ILModeRight ;
  844.       StartGrab (hWnd, pILine) ;
  845.       }
  846.  
  847.    else if (PtInRect (&pILine->rectCenterGrab, ptMouse))
  848.       {
  849.       ILMode (pILine) = ILModeCenter ;
  850.       StartGrab (hWnd, pILine) ;
  851.       }
  852.    }
  853.  
  854.  
  855. void static OnSize (HWND hWnd, WORD xWidth, WORD yHeight)
  856.    {  // OnSize
  857.    PILINE         pILine ;
  858.  
  859.    pILine = ILData (hWnd) ;
  860.  
  861.    ILCalcPositions (hWnd, pILine) ;
  862.    }  // OnSize
  863.  
  864.  
  865. //==========================================================================//
  866. //                             Exported Functions                           //
  867. //==========================================================================//
  868.  
  869.  
  870. LONG FAR PASCAL ILineWndProc (HWND hWnd,
  871.                               unsigned msg,
  872.                               WPARAM wParam,
  873.                               LONG lParam)
  874. /*
  875.    Note:          This function must be declared in the application's
  876.                   linker-definition file, perfmon.def file.
  877. */
  878.    {  // ILineWndProc
  879.    BOOL           bCallDefWindowProc ;
  880.    POINTS         ptsMouse ;
  881.    LONG           lReturnValue ;
  882.  
  883.    bCallDefWindowProc = FALSE ;
  884.    lReturnValue = 0L ;
  885.  
  886.    switch (msg)
  887.       {  // switch
  888.       case WM_CREATE:
  889.          OnCreate (hWnd) ;
  890.          break ;
  891.  
  892.       case WM_DESTROY:
  893.          OnDestroy (hWnd) ;
  894.          break ;
  895.  
  896.       case WM_LBUTTONDOWN:
  897.          // See the note in OnMouseMove for why we are using POINTS
  898.          SetFocus (hWnd) ;
  899.          ptsMouse = MAKEPOINTS (lParam) ;
  900.          OnLButtonDown (hWnd, ptsMouse) ;
  901.          break ;
  902.  
  903.       case WM_LBUTTONUP:
  904.          OnLButtonUp (hWnd) ;
  905.          break ;
  906.  
  907.       case WM_SETFOCUS:
  908.       case WM_KILLFOCUS:
  909.          {
  910.          PILINE         pILine ;
  911.  
  912.          IntrLineFocus = (msg == WM_SETFOCUS) ;
  913.  
  914.          pILine = ILData (hWnd) ;
  915.          ILNotifyChange (hWnd, pILine) ;
  916.          }
  917.          return 0 ;
  918.  
  919.  
  920.       case WM_MOUSEMOVE:
  921.          // See the note in OnMouseMove for why we are using POINTS
  922.          ptsMouse = MAKEPOINTS (lParam) ;
  923.          OnMouseMove (hWnd, ptsMouse) ;
  924.          break ;
  925.  
  926.       case WM_KEYDOWN:
  927.          if (!OnKeyDown (hWnd, wParam))
  928.             {
  929.             bCallDefWindowProc = TRUE ;
  930.             }
  931.          break ;
  932.   
  933.       case WM_GETDLGCODE:
  934.          // We want to handle Arrow keys input.  If we don't specify this
  935.          // the dialog will not pass arrow keys to us.
  936.          return (DLGC_WANTARROWS) ;
  937.          break ;
  938.  
  939.       case WM_PAINT:
  940.          OnPaint (hWnd) ;
  941.          break ;
  942.  
  943.       case WM_SIZE:
  944.          OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
  945.  
  946.       default:
  947.          bCallDefWindowProc = TRUE ;
  948.       }  // switch
  949.  
  950.    if (bCallDefWindowProc)
  951.       lReturnValue = DefWindowProc (hWnd, msg, wParam, lParam) ;
  952.  
  953.    return (lReturnValue) ;
  954.    }  // ILineWndProc
  955.  
  956.  
  957.  
  958. BOOL ILineInitializeApplication (void)
  959. /*
  960.    Effect:        Perform all initializations required before an application
  961.                   can create an IntervalLine. In particular, register the 
  962.                   IntervalLine window class.
  963.  
  964.    Called By:     The application, in its InitializeApplication routine.
  965.  
  966.    Returns:       Whether the class could be registered.
  967. */
  968.    {  // ILineInitializeApplication
  969.    WNDCLASS       wc ;
  970.  
  971.    wc.style =           dwILineClassStyle ;
  972.    wc.lpfnWndProc =     ILineWndProc ;
  973.    wc.cbClsExtra =      iILineClassExtra ;
  974.    wc.cbWndExtra =      iILineWindowExtra ;
  975.    wc.hInstance =       hInstance ;
  976.    wc.hIcon =           NULL ;
  977.    wc.hCursor =         LoadCursor (NULL, IDC_ARROW) ;
  978.    wc.hbrBackground =   NULL ;
  979.    wc.lpszMenuName =    NULL ;
  980.    wc.lpszClassName =   szILineClass ;
  981.  
  982.    return (RegisterClass (&wc)) ;
  983.    }  // ILineInitializeApplication
  984.  
  985.  
  986. void ILineSetRange (HWND hWnd, int iBegin, int iEnd)
  987.    {  // ILineSetRange
  988.    PILINE         pILine ;
  989.  
  990.    pILine = ILData (hWnd) ;
  991.  
  992.    ILBegin (pILine) = iBegin ;
  993.    ILEnd (pILine) = iEnd ;
  994.  
  995.    ILCalcPositions (hWnd, pILine) ;
  996.    }  // ILineSetRange
  997.  
  998.  
  999. void ILineSetStart (HWND hWnd, int iStart)
  1000.    {  // ILineSetStart
  1001.    PILINE         pILine ;
  1002.  
  1003.    pILine = ILData (hWnd) ;
  1004.  
  1005.    iStart = PinInclusive (iStart, ILBegin (pILine), ILEnd (pILine)) ;
  1006.    ILStart (pILine) = iStart ;
  1007.  
  1008.    ILCalcPositions (hWnd, pILine) ;
  1009.    }  // ILineSetStart
  1010.  
  1011.  
  1012.  
  1013. void ILineSetStop (HWND hWnd, int iStop)
  1014.    {  // ILineSetStop
  1015.    PILINE         pILine ;
  1016.  
  1017.    pILine = ILData (hWnd) ;
  1018.  
  1019.    iStop = PinInclusive (iStop, ILBegin (pILine), ILEnd (pILine)) ;
  1020.    ILStop (pILine) = iStop ;
  1021.  
  1022.    ILCalcPositions (hWnd, pILine) ;
  1023.    }  // ILineSetStop
  1024.  
  1025.  
  1026. int ILineXStart (HWND hWnd)
  1027.    {
  1028.    PILINE         pILine ;
  1029.  
  1030.    pILine = ILData (hWnd) ;
  1031.  
  1032.    return (pILine->rectLeftGrab.left) ;
  1033.    }
  1034.  
  1035.  
  1036. int ILineXStop (HWND hWnd)
  1037.    {
  1038.    PILINE         pILine ;
  1039.  
  1040.    pILine = ILData (hWnd) ;
  1041.  
  1042.    return (pILine->rectRightGrab.right) ;
  1043.    }
  1044.  
  1045.  
  1046. int ILineStart (HWND hWnd)
  1047.    {
  1048.    PILINE         pILine ;
  1049.  
  1050.    pILine = ILData (hWnd) ;
  1051.  
  1052.    return  (ILStart (pILine)) ;
  1053.    }
  1054.  
  1055.  
  1056. int ILineStop (HWND hWnd)
  1057.    {
  1058.    PILINE         pILine ;
  1059.  
  1060.    pILine = ILData (hWnd) ;
  1061.  
  1062.    return  (ILStop (pILine)) ;
  1063.    }
  1064.  
  1065.  
  1066.  
  1067.