1085 lines
29 KiB
C
1085 lines
29 KiB
C
|
/*
|
||
|
==============================================================================
|
||
|
|
||
|
Application:
|
||
|
|
||
|
Microsoft Windows NT (TM) Performance Monitor
|
||
|
|
||
|
File:
|
||
|
intrline.c -- IntervalLine custom control.
|
||
|
|
||
|
Copyright 1992, Microsoft Corporation. All Rights Reserved.
|
||
|
==============================================================================
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
|
||
|
Basic Information
|
||
|
-----------------
|
||
|
|
||
|
An ILine (Interval Line) control is a horizontally-sliding device; the user
|
||
|
can slide the start position and end position independently by dragging
|
||
|
either "grab" bar, or move them simultaneously by dragging the center grab
|
||
|
bar. An ILine control is used in the Input Log dialog of Perfmon, but could
|
||
|
be used anywhere. The control allows the user to specify the start, end and
|
||
|
duration of playback within the range of previously-logged data.
|
||
|
|
||
|
|
||
|
ILine Parts
|
||
|
-----------
|
||
|
|
||
|
iBeginValue iEndValue
|
||
|
| iStartValue iStopValue |
|
||
|
| | | |
|
||
|
v v v v
|
||
|
+------+-+---------------------------------------+-+-----------+
|
||
|
| |X| |X| |
|
||
|
| |X| |X| |
|
||
|
+------+-+---------------------------------------+-+-----------+
|
||
|
^ ^ ^
|
||
|
Start grab bar Center grab bar Stop grab bar
|
||
|
|
||
|
|
||
|
ILine Terminology
|
||
|
-----------------
|
||
|
|
||
|
All external routines are designated by the prefix ILine-.
|
||
|
Internal routines are designated by the prefix IL-.
|
||
|
|
||
|
The suffix -Value represents an integer in the user-supplied domain.
|
||
|
The suffix -Pixel represents an integer location on the screen.
|
||
|
|
||
|
Note that the range of the IntervalLine is represented by "Begin" and
|
||
|
"End", while the the currently selected interval is represented by
|
||
|
"Start" and "Stop".
|
||
|
|
||
|
|
||
|
Implementation Notes
|
||
|
--------------------
|
||
|
|
||
|
ILine is a custom control, but does not have all the messages
|
||
|
normally associated with a full-fledged control type like "button".
|
||
|
In particular, it doesn't have a keyboard interface or ask it's parent
|
||
|
for color choices. It also doesn't have the functions needed for interfacing
|
||
|
with the dialog editor custom control menu.
|
||
|
|
||
|
An ILine control is designed to work with an integer range of values
|
||
|
specified by the user of the control. These values should have meaning to
|
||
|
the caller. The caller can specify the minimum value of the range
|
||
|
(iBeginValue), the maximum value of the range (iEndValue), and the current
|
||
|
starting and stopping values (iStartValue and iStopValue).
|
||
|
|
||
|
These values are set with a function-based interface. (ILSetXXX).
|
||
|
|
||
|
The code distinguishes between the *values* for the begin, end, start, and
|
||
|
stop, and the *pixels* which represent locations on the control for these
|
||
|
values.
|
||
|
|
||
|
Various bits of the control style allow for changing the control's
|
||
|
behavior.
|
||
|
|
||
|
To allow for multiple ILine controls, all data used by each ILine
|
||
|
instance is allocated from the heap and associated with the control.
|
||
|
The allocation is done in OnCreate and the freeing in OnDestroy. The
|
||
|
instance data is contained in the ILINE structure. Each message handler
|
||
|
retrieves this instance data with the ILData function.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Includes //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
#include "perfmon.h"
|
||
|
#include "utils.h"
|
||
|
#include "intrline.h"
|
||
|
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
|
||
|
|
||
|
BOOL IntrLineFocus ;
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Constants //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
#define dwILineClassStyle (CS_HREDRAW | CS_VREDRAW)
|
||
|
#define iILineClassExtra (0)
|
||
|
#define iILineWindowExtra (sizeof (PILINE))
|
||
|
#define dwILineWindowStyle (WS_CHILD | WS_VISIBLE)
|
||
|
|
||
|
|
||
|
#define ILModeNone 0
|
||
|
#define ILModeLeft 1
|
||
|
#define ILModeCenter 2
|
||
|
#define ILModeRight 3
|
||
|
|
||
|
#define TO_THE_END 0x7FFFFFFFL
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Typedefs //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
// The instance data for each IL window. One of these is allocated for each
|
||
|
// window in the window's OnCreate processing and free'd in OnDestroy.
|
||
|
typedef struct ILINESTRUCT
|
||
|
{ // ILINE
|
||
|
int iBeginValue ; // user-supplied lowest range
|
||
|
int iEndValue ; // user-supplied highest range
|
||
|
int iStartValue ; // current start of selected interval
|
||
|
int iStopValue ; // current end of selected interval
|
||
|
int iGranularityValue ;
|
||
|
int iMinimumRangeValue ;
|
||
|
|
||
|
RECT rectBorder ;
|
||
|
RECT rectLeftBk ;
|
||
|
RECT rectLeftGrab ;
|
||
|
RECT rectCenterGrab ;
|
||
|
RECT rectRightGrab ;
|
||
|
RECT rectRightBk ;
|
||
|
|
||
|
HBRUSH hBrushBk ;
|
||
|
|
||
|
POINTS ptsMouse ;
|
||
|
int iMode ; // who is being tracked?
|
||
|
} ILINE ;
|
||
|
|
||
|
typedef ILINE *PILINE ;
|
||
|
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Macros //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
// Width of the start and stob grab bars
|
||
|
#define ILGrabWidth() \
|
||
|
(xScrollThumbWidth)
|
||
|
|
||
|
|
||
|
// A rectangle is "drawable" if it has both nonzero width and height
|
||
|
#define RectDrawable(lpRect) \
|
||
|
((lpRect->right - lpRect->left) && \
|
||
|
(lpRect->bottom - lpRect->top))
|
||
|
|
||
|
|
||
|
//======================================//
|
||
|
// ILine Accessor Macros //
|
||
|
//======================================//
|
||
|
|
||
|
// These macros reference fields in the ILine structure and should be
|
||
|
// used in place of direct reference to the fields. This makes the code
|
||
|
// easier to read and allows modification of the underlying structure.
|
||
|
|
||
|
// You can use these macros to both get and set the fields.
|
||
|
|
||
|
#define ILBegin(pILine) \
|
||
|
(pILine->iBeginValue)
|
||
|
|
||
|
#define ILEnd(pILine) \
|
||
|
(pILine->iEndValue)
|
||
|
|
||
|
#define ILStart(pILine) \
|
||
|
(pILine->iStartValue)
|
||
|
|
||
|
#define ILStop(pILine) \
|
||
|
(pILine->iStopValue)
|
||
|
|
||
|
#define ILMode(pILine) \
|
||
|
(pILine->iMode)
|
||
|
|
||
|
|
||
|
//======================================//
|
||
|
// ILine Pseudo-Accessor Macros //
|
||
|
//======================================//
|
||
|
|
||
|
// These macros are used to get values which don't correspond to a single
|
||
|
// field. You can get the value with these macros but can't set it.
|
||
|
|
||
|
#define ILWidth(pILine) \
|
||
|
(pILine->rectBorder.right)
|
||
|
|
||
|
#define ILRange(pILine) \
|
||
|
(ILEnd (pILine) - ILBegin (pILine))
|
||
|
|
||
|
#define ILStartPixel(pILine) \
|
||
|
(pILine->rectLeftGrab.left)
|
||
|
|
||
|
#define ILStopPixel(pILine) \
|
||
|
(pILine->rectRightGrab.right)
|
||
|
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Local Functions //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
void static ILNotifyChange (HWND hWnd,
|
||
|
PILINE pILine)
|
||
|
{ // ILNotifyChange
|
||
|
HWND hWndParent ;
|
||
|
|
||
|
hWndParent = WindowParent (hWnd) ;
|
||
|
|
||
|
if (hWndParent)
|
||
|
SendMessage (hWndParent, WM_COMMAND,
|
||
|
(WPARAM) WindowID (hWnd),
|
||
|
(LPARAM) hWnd) ;
|
||
|
} // ILNotifyChange
|
||
|
|
||
|
|
||
|
BOOL ILGrabRect (IN PILINE pILine,
|
||
|
OUT LPRECT lpRect)
|
||
|
/*
|
||
|
Effect: Return in lpRect the rectangle representing the position
|
||
|
of the grab bar currently being tracked.
|
||
|
*/
|
||
|
{ // ILGrabRect
|
||
|
switch (ILMode (pILine))
|
||
|
{ // switch
|
||
|
case ILModeLeft:
|
||
|
*lpRect = pILine->rectLeftGrab ;
|
||
|
return (TRUE) ;
|
||
|
break ;
|
||
|
|
||
|
case ILModeRight:
|
||
|
*lpRect = pILine->rectRightGrab ;
|
||
|
return (TRUE) ;
|
||
|
break ;
|
||
|
|
||
|
case ILModeCenter:
|
||
|
*lpRect = pILine->rectCenterGrab ;
|
||
|
return (TRUE) ;
|
||
|
break ;
|
||
|
|
||
|
case ILModeNone:
|
||
|
lpRect->left = 0 ;
|
||
|
lpRect->top = 0 ;
|
||
|
lpRect->right = 0 ;
|
||
|
lpRect->bottom = 0 ;
|
||
|
return (FALSE) ;
|
||
|
break ;
|
||
|
} // switch
|
||
|
|
||
|
// return FALSE if it falls through to here
|
||
|
return FALSE;
|
||
|
} // ILGrabRect
|
||
|
|
||
|
|
||
|
PILINE ILData (HWND hWndIL)
|
||
|
{
|
||
|
return ((PILINE) GetWindowLongPtr (hWndIL, 0)) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
PILINE AllocateILData (HWND hWndIL)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = MemoryAllocate (sizeof (ILINE)) ;
|
||
|
SetWindowLongPtr (hWndIL, 0, (LONG_PTR) pILine) ;
|
||
|
|
||
|
return (pILine) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
void static DrawGrab (HDC hDC,
|
||
|
LPRECT lpRectGrab,
|
||
|
BOOL bDown)
|
||
|
{ // DrawGrab
|
||
|
if (!RectDrawable (lpRectGrab))
|
||
|
return ;
|
||
|
|
||
|
if (bDown)
|
||
|
ThreeDConcave1 (hDC,
|
||
|
lpRectGrab->left,
|
||
|
lpRectGrab->top,
|
||
|
lpRectGrab->right,
|
||
|
lpRectGrab->bottom) ;
|
||
|
else
|
||
|
ThreeDConvex1 (hDC,
|
||
|
lpRectGrab->left,
|
||
|
lpRectGrab->top,
|
||
|
lpRectGrab->right,
|
||
|
lpRectGrab->bottom) ;
|
||
|
} // DrawGrab
|
||
|
|
||
|
|
||
|
int ILValueToPixel (PILINE pILine,
|
||
|
int iValue)
|
||
|
{
|
||
|
int xPixel ;
|
||
|
|
||
|
if (ILRange (pILine))
|
||
|
xPixel = MulDiv (iValue, ILWidth (pILine), ILRange (pILine)) ;
|
||
|
else
|
||
|
xPixel = 0 ;
|
||
|
|
||
|
return (PinExclusive (xPixel, 0, pILine->rectBorder.right)) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ILPixelToValue (PILINE pILine,
|
||
|
int xPixel)
|
||
|
{
|
||
|
int iValue ;
|
||
|
|
||
|
if (ILWidth (pILine))
|
||
|
iValue = MulDiv (xPixel, ILRange (pILine), ILWidth (pILine)) ;
|
||
|
else
|
||
|
iValue = 0 ;
|
||
|
|
||
|
return (PinInclusive (iValue, ILBegin (pILine), ILEnd (pILine))) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
void static ILCalcPositions (HWND hWnd,
|
||
|
PILINE pILine)
|
||
|
/*
|
||
|
Effect: Determine and set all of the physical rectangles of ILine,
|
||
|
based on the current size of the ILine window and the
|
||
|
current logical Start, Stop, Begin, and End values.
|
||
|
*/
|
||
|
{ // ILCalcPositions
|
||
|
int xStart, xStop ;
|
||
|
int yHeight ;
|
||
|
|
||
|
GetClientRect (hWnd, &pILine->rectBorder) ;
|
||
|
yHeight = pILine->rectBorder.bottom ;
|
||
|
|
||
|
xStart = ILValueToPixel (pILine, ILStart (pILine)) ;
|
||
|
xStop = ILValueToPixel (pILine, ILStop (pILine)) ;
|
||
|
|
||
|
pILine->rectLeftBk.left = 1 ;
|
||
|
pILine->rectLeftBk.top = 1 ;
|
||
|
pILine->rectLeftBk.right = xStart ;
|
||
|
pILine->rectLeftBk.bottom = yHeight - 1 ;
|
||
|
|
||
|
pILine->rectLeftGrab.left = xStart ;
|
||
|
pILine->rectLeftGrab.top = 1 ;
|
||
|
pILine->rectLeftGrab.right = xStart + ILGrabWidth () ;
|
||
|
pILine->rectLeftGrab.bottom = yHeight - 1 ;
|
||
|
|
||
|
pILine->rectRightBk.left = xStop ;
|
||
|
pILine->rectRightBk.top = 1 ;
|
||
|
pILine->rectRightBk.right = pILine->rectBorder.right - 1 ;
|
||
|
pILine->rectRightBk.bottom = yHeight - 1 ;
|
||
|
|
||
|
pILine->rectRightGrab.left = xStop - ILGrabWidth () ;
|
||
|
pILine->rectRightGrab.top = 1 ;
|
||
|
pILine->rectRightGrab.right = xStop ;
|
||
|
pILine->rectRightGrab.bottom = yHeight - 1 ;
|
||
|
|
||
|
pILine->rectCenterGrab.left = pILine->rectLeftGrab.right ;
|
||
|
pILine->rectCenterGrab.top = 1 ;
|
||
|
pILine->rectCenterGrab.right = pILine->rectRightGrab.left ;
|
||
|
pILine->rectCenterGrab.bottom = yHeight - 1 ;
|
||
|
|
||
|
if (pILine->rectLeftGrab.right > pILine->rectRightGrab.left)
|
||
|
{
|
||
|
pILine->rectLeftGrab.right = pILine->rectLeftGrab.left +
|
||
|
(xStop - xStart) / 2 ;
|
||
|
pILine->rectRightGrab.left = pILine->rectLeftGrab.right ;
|
||
|
pILine->rectCenterGrab.left = 0 ;
|
||
|
pILine->rectCenterGrab.right = 0 ;
|
||
|
}
|
||
|
} // ILCalcPositions
|
||
|
|
||
|
|
||
|
void static ILDraw (HDC hDC,
|
||
|
PILINE pILine,
|
||
|
LPRECT lpRectUpdate)
|
||
|
/*
|
||
|
Effect: Draw the image of pILine on hDC. Draw at least the
|
||
|
portions within rectUpdate.
|
||
|
|
||
|
Called By: OnPaint, OnMouseMove.
|
||
|
*/
|
||
|
{ // ILDraw
|
||
|
HBRUSH hBrush = GetStockObject (BLACK_BRUSH);
|
||
|
|
||
|
if (!hBrush)
|
||
|
return;
|
||
|
//=============================//
|
||
|
// Draw Border //
|
||
|
//=============================//
|
||
|
|
||
|
FrameRect (hDC, &pILine->rectBorder, hBrush);
|
||
|
|
||
|
//=============================//
|
||
|
// Draw Background //
|
||
|
//=============================//
|
||
|
|
||
|
FillRect (hDC, &pILine->rectLeftBk, pILine->hBrushBk) ;
|
||
|
FillRect (hDC, &pILine->rectRightBk, pILine->hBrushBk) ;
|
||
|
|
||
|
//=============================//
|
||
|
// Draw Range Grabs //
|
||
|
//=============================//
|
||
|
|
||
|
DrawGrab (hDC, &pILine->rectLeftGrab,
|
||
|
ILMode (pILine) == ILModeLeft) ;
|
||
|
DrawGrab (hDC, &pILine->rectRightGrab,
|
||
|
ILMode (pILine) == ILModeRight) ;
|
||
|
|
||
|
//=============================//
|
||
|
// Draw Center Grab //
|
||
|
//=============================//
|
||
|
|
||
|
DrawGrab (hDC, &pILine->rectCenterGrab,
|
||
|
ILMode (pILine) == ILModeCenter) ;
|
||
|
} // ILDraw
|
||
|
|
||
|
#if 0
|
||
|
void ILPageLeftRight (HWND hWnd,
|
||
|
PILINE pILine,
|
||
|
BOOL bLeft)
|
||
|
{ // ILPageLeftRight
|
||
|
int iStart, iStop, iMove ;
|
||
|
HDC hDC ;
|
||
|
|
||
|
iStart = ILStart (pILine) ;
|
||
|
iStop = ILStop (pILine) ;
|
||
|
|
||
|
if (ILRange (pILine) >= 10)
|
||
|
iMove = ILRange (pILine) / 10 ;
|
||
|
else
|
||
|
iMove = 1 ;
|
||
|
|
||
|
if (bLeft)
|
||
|
iMove = -iMove ;
|
||
|
|
||
|
iStart += iMove ;
|
||
|
iStop += iMove ;
|
||
|
|
||
|
ILineSetStart (hWnd, iStart) ;
|
||
|
ILineSetStop (hWnd, iStop) ;
|
||
|
|
||
|
hDC = GetDC (hWnd) ;
|
||
|
ILDraw (hDC, pILine, &pILine->rectBorder) ;
|
||
|
ReleaseDC (hWnd, hDC) ;
|
||
|
|
||
|
ILNotifyChange (hWnd, pILine) ;
|
||
|
} // ILPageLeftRight
|
||
|
#endif
|
||
|
|
||
|
void ILMoveLeftRight (HWND hWnd,
|
||
|
BOOL bStart,
|
||
|
BOOL bLeft,
|
||
|
int MoveAmt)
|
||
|
{ // ILPageLeftRight
|
||
|
int iStart, iStop, iMove ;
|
||
|
int iBegin, iEnd ;
|
||
|
HDC hDC ;
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
iStart = ILStart (pILine) ;
|
||
|
iStop = ILStop (pILine) ;
|
||
|
iBegin = ILBegin (pILine) ;
|
||
|
iEnd = ILEnd (pILine) ;
|
||
|
|
||
|
iMove = MoveAmt ;
|
||
|
if (bLeft)
|
||
|
iMove = -iMove ;
|
||
|
|
||
|
if (bStart)
|
||
|
{
|
||
|
if (MoveAmt == TO_THE_END)
|
||
|
{
|
||
|
iStart = iBegin ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iStart += iMove ;
|
||
|
if (iStart >= iStop)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ILineSetStart (hWnd, iStart) ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (MoveAmt == TO_THE_END)
|
||
|
{
|
||
|
iStop = iEnd ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iStop += iMove ;
|
||
|
if (iStart >= iStop)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ILineSetStop (hWnd, iStop) ;
|
||
|
}
|
||
|
|
||
|
hDC = GetDC (hWnd) ;
|
||
|
if (hDC) {
|
||
|
ILDraw (hDC, pILine, &pILine->rectBorder) ;
|
||
|
ReleaseDC (hWnd, hDC) ;
|
||
|
}
|
||
|
|
||
|
ILNotifyChange (hWnd, pILine) ;
|
||
|
} // ILMoveLeftRight
|
||
|
|
||
|
static BOOL OnKeyDown (HWND hWnd,
|
||
|
WPARAM wParam)
|
||
|
{
|
||
|
BOOL bHandle = TRUE ;
|
||
|
BOOL bStart ;
|
||
|
BOOL bLeftDirection ;
|
||
|
BOOL bShiftKeyDown ;
|
||
|
|
||
|
if (wParam == VK_LEFT || wParam == VK_RIGHT)
|
||
|
{
|
||
|
bShiftKeyDown = (GetKeyState (VK_SHIFT) < 0) ;
|
||
|
|
||
|
if (!bShiftKeyDown)
|
||
|
{
|
||
|
if (wParam == VK_LEFT)
|
||
|
{
|
||
|
// Left Arrow --> move Start Edge Left
|
||
|
bStart = TRUE ;
|
||
|
bLeftDirection = TRUE ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Right Arrow --> move Stop Edge Right
|
||
|
bStart = FALSE ;
|
||
|
bLeftDirection = FALSE ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (wParam == VK_LEFT)
|
||
|
{
|
||
|
// Shift Left Arrow --> move Stop Edge Left
|
||
|
bStart = FALSE ;
|
||
|
bLeftDirection = TRUE ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Shift Right Arrow --> move Start Edge Right
|
||
|
bStart = TRUE ;
|
||
|
bLeftDirection = FALSE ;
|
||
|
}
|
||
|
}
|
||
|
ILMoveLeftRight (hWnd, bStart, bLeftDirection, 1) ;
|
||
|
}
|
||
|
else if (wParam == VK_HOME)
|
||
|
{
|
||
|
// move iStart all the way the Left
|
||
|
ILMoveLeftRight (hWnd, TRUE, TRUE, TO_THE_END) ;
|
||
|
}
|
||
|
else if (wParam == VK_END)
|
||
|
{
|
||
|
// move iStop all the way the right
|
||
|
ILMoveLeftRight (hWnd, FALSE, FALSE, TO_THE_END) ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bHandle = FALSE ;
|
||
|
}
|
||
|
return (bHandle) ;
|
||
|
|
||
|
} // OnKeyDown
|
||
|
|
||
|
void StartGrab (HWND hWnd,
|
||
|
PILINE pILine)
|
||
|
{ // StartGrab
|
||
|
RECT rectUpdate ;
|
||
|
HDC hDC ;
|
||
|
|
||
|
SetCapture (hWnd) ;
|
||
|
ILGrabRect (pILine, &rectUpdate) ;
|
||
|
|
||
|
hDC = GetDC (hWnd) ;
|
||
|
if (hDC) {
|
||
|
ILDraw (hDC, pILine, &rectUpdate) ;
|
||
|
ReleaseDC (hWnd, hDC) ;
|
||
|
} // StartGrab
|
||
|
}
|
||
|
|
||
|
void EndGrab (HWND hWnd,
|
||
|
PILINE pILine)
|
||
|
/*
|
||
|
Internals: Set the mode to null after getting the grab rectangle
|
||
|
so ILGrabRect knows which grab bar to get.
|
||
|
*/
|
||
|
{
|
||
|
RECT rectUpdate ;
|
||
|
HDC hDC ;
|
||
|
|
||
|
ReleaseCapture () ;
|
||
|
|
||
|
ILGrabRect (pILine, &rectUpdate) ;
|
||
|
ILMode (pILine) = ILModeNone ;
|
||
|
|
||
|
hDC = GetDC (hWnd) ;
|
||
|
if (hDC) {
|
||
|
ILDraw (hDC, pILine, &rectUpdate) ;
|
||
|
ReleaseDC (hWnd, hDC) ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Message Handlers //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
void static OnPaint (HWND hWnd)
|
||
|
{
|
||
|
PAINTSTRUCT ps ;
|
||
|
HDC hDC ;
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
hDC = BeginPaint (hWnd, &ps) ;
|
||
|
|
||
|
ILDraw (hDC, pILine, &ps.rcPaint) ;
|
||
|
|
||
|
EndPaint (hWnd, &ps) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
void static OnCreate (HWND hWnd)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = AllocateILData (hWnd) ;
|
||
|
ILBegin (pILine) = 0 ;
|
||
|
ILEnd (pILine) = 100 ;
|
||
|
ILStart (pILine) = 0 ;
|
||
|
ILStop (pILine) = 100 ;
|
||
|
ILMode (pILine) = ILModeNone ;
|
||
|
|
||
|
pILine->hBrushBk = CreateSolidBrush (crBlue) ;
|
||
|
ILCalcPositions (hWnd, pILine) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
void static OnDestroy (HWND hWnd)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
IntrLineFocus = FALSE ;
|
||
|
DeleteBrush (pILine->hBrushBk) ;
|
||
|
MemoryFree (pILine) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
void static OnLButtonUp (HWND hWnd)
|
||
|
{ // OnLButtonUp
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
if (ILMode (pILine) == ILModeNone)
|
||
|
return ;
|
||
|
|
||
|
EndGrab (hWnd, pILine) ;
|
||
|
} // OnLButtonUp
|
||
|
|
||
|
|
||
|
void static OnMouseMove (HWND hWnd,
|
||
|
POINTS ptsMouse)
|
||
|
/*
|
||
|
Effect: Handle any actions needed when the mouse moves in the
|
||
|
ILine hWnd's client area or while the mouse is captured.
|
||
|
In particular, if we are tracking one of the grab bars,
|
||
|
determine if the mouse movement represents a logical value
|
||
|
change and move the grab bar accordingly.
|
||
|
|
||
|
Called By: ILineWndProc, in response to a WM_MOUSEMOVE message.
|
||
|
|
||
|
See Also: OnLButtonDown, OnLButtonUp.
|
||
|
|
||
|
Note: This function has multiple return points.
|
||
|
|
||
|
Note: Since we have captured the mouse, we receive mouse msgs
|
||
|
even when the mouse is outside our client area, but still
|
||
|
in client coordinates. Thus we can have negative mouse
|
||
|
coordinates. That is why we convert the lParam of the
|
||
|
mouse msg into a POINTS structure rather than 2 WORDS.
|
||
|
|
||
|
|
||
|
Internals: Remember that an IntervalLine can only take on integral
|
||
|
values in the user-supplied range. Therefore we do our
|
||
|
movement calculation in user values, not pixels. We
|
||
|
determine what the logical value would be for the previous
|
||
|
(last mouse move) and current mouse position. If these
|
||
|
LOGICAL values differ, we attempt an adjustment of the
|
||
|
grab bar by that logical amount. This way the grab
|
||
|
values assume on integral positions and the calculations
|
||
|
are simplified.
|
||
|
|
||
|
If we calculated by pixel movement, and then shifted the
|
||
|
bar into the nearest integal position, we would encounter
|
||
|
rounding problems. In particular, when tracking the center
|
||
|
grab bar, if we moved both start and stop by the same
|
||
|
amount of PIXELS, then converted to LOGICAL values, we
|
||
|
might find our center bar shrinking and growing while
|
||
|
the bar moves.
|
||
|
*/
|
||
|
{
|
||
|
int iMousePrevious, iMouseCurrent ;
|
||
|
int iMouseMove ;
|
||
|
PILINE pILine ;
|
||
|
HDC hDC ;
|
||
|
|
||
|
//=============================//
|
||
|
// Are we tracking? //
|
||
|
//=============================//
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
if (ILMode (pILine) == ILModeNone)
|
||
|
return ;
|
||
|
|
||
|
//=============================//
|
||
|
// Calc LOGICAL mouse movement //
|
||
|
//=============================//
|
||
|
|
||
|
ptsMouse.x = PinInclusive ((INT)ptsMouse.x,
|
||
|
(INT)pILine->rectBorder.left,
|
||
|
(INT)pILine->rectBorder.right) ;
|
||
|
|
||
|
iMousePrevious = ILPixelToValue (pILine, pILine->ptsMouse.x) ;
|
||
|
iMouseCurrent = ILPixelToValue (pILine, ptsMouse.x) ;
|
||
|
|
||
|
iMouseMove = iMouseCurrent - iMousePrevious ;
|
||
|
if (!iMouseMove)
|
||
|
return ;
|
||
|
|
||
|
//=============================//
|
||
|
// Move grab bar positions //
|
||
|
//=============================//
|
||
|
|
||
|
switch (ILMode (pILine))
|
||
|
{ // switch
|
||
|
case ILModeLeft:
|
||
|
ILStart (pILine) += iMouseMove ;
|
||
|
ILStart (pILine) = min (ILStart (pILine), ILStop (pILine) - 1) ;
|
||
|
break ;
|
||
|
|
||
|
case ILModeCenter:
|
||
|
// Before we slide the center grab bar we need to see if the
|
||
|
// desired movement amount would send either end out of bounds,
|
||
|
// and reduce the movement accordingly.
|
||
|
|
||
|
if (ILStart (pILine) + iMouseMove < ILBegin (pILine))
|
||
|
iMouseMove = ILBegin (pILine) - ILStart (pILine) ;
|
||
|
if (ILStop (pILine) + iMouseMove > ILEnd (pILine))
|
||
|
iMouseMove = ILEnd (pILine) - ILStop (pILine) ;
|
||
|
|
||
|
ILStart (pILine) += iMouseMove ;
|
||
|
ILStop (pILine) += iMouseMove ;
|
||
|
break ;
|
||
|
|
||
|
case ILModeRight:
|
||
|
ILStop (pILine) += iMouseMove ;
|
||
|
ILStop (pILine) = max (ILStart (pILine) + 1, ILStop (pILine)) ;
|
||
|
break ;
|
||
|
} // switch
|
||
|
|
||
|
|
||
|
//=============================//
|
||
|
// Keep grab bars in range //
|
||
|
//=============================//
|
||
|
|
||
|
|
||
|
ILStart (pILine) = PinInclusive (ILStart (pILine),
|
||
|
ILBegin (pILine), ILEnd (pILine)) ;
|
||
|
ILStop (pILine) = PinInclusive (ILStop (pILine),
|
||
|
ILBegin (pILine), ILEnd (pILine)) ;
|
||
|
|
||
|
//=============================//
|
||
|
// Determine pixel pos, draw //
|
||
|
//=============================//
|
||
|
|
||
|
ILCalcPositions (hWnd, pILine) ;
|
||
|
|
||
|
hDC = GetDC (hWnd) ;
|
||
|
if (hDC) {
|
||
|
ILDraw (hDC, pILine, &pILine->rectBorder) ;
|
||
|
ReleaseDC (hWnd, hDC) ;
|
||
|
}
|
||
|
|
||
|
pILine->ptsMouse = ptsMouse ;
|
||
|
ILNotifyChange (hWnd, pILine) ;
|
||
|
} // OnMouseMove
|
||
|
|
||
|
|
||
|
void static OnLButtonDown (HWND hWnd,
|
||
|
POINTS ptsMouse)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
POINT ptMouse ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
pILine->ptsMouse = ptsMouse ;
|
||
|
ptMouse.x = ptsMouse.x ;
|
||
|
ptMouse.y = ptsMouse.y ;
|
||
|
|
||
|
#if 0
|
||
|
// Russ said this is bad, so don't do it
|
||
|
if (PtInRect (&pILine->rectLeftBk, ptMouse))
|
||
|
ILPageLeftRight (hWnd, pILine, TRUE) ;
|
||
|
|
||
|
else if (PtInRect (&pILine->rectRightBk, ptMouse))
|
||
|
ILPageLeftRight (hWnd, pILine, FALSE) ;
|
||
|
|
||
|
else if (PtInRect (&pILine->rectLeftGrab, ptMouse))
|
||
|
#endif
|
||
|
if (PtInRect (&pILine->rectLeftGrab, ptMouse) ||
|
||
|
PtInRect (&pILine->rectLeftBk, ptMouse))
|
||
|
{
|
||
|
ILMode (pILine) = ILModeLeft ;
|
||
|
StartGrab (hWnd, pILine) ;
|
||
|
}
|
||
|
|
||
|
else if (PtInRect (&pILine->rectRightGrab, ptMouse) ||
|
||
|
PtInRect (&pILine->rectRightBk, ptMouse))
|
||
|
{
|
||
|
ILMode (pILine) = ILModeRight ;
|
||
|
StartGrab (hWnd, pILine) ;
|
||
|
}
|
||
|
|
||
|
else if (PtInRect (&pILine->rectCenterGrab, ptMouse))
|
||
|
{
|
||
|
ILMode (pILine) = ILModeCenter ;
|
||
|
StartGrab (hWnd, pILine) ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void static OnSize (HWND hWnd, WORD xWidth, WORD yHeight)
|
||
|
{ // OnSize
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
ILCalcPositions (hWnd, pILine) ;
|
||
|
} // OnSize
|
||
|
|
||
|
|
||
|
//==========================================================================//
|
||
|
// Exported Functions //
|
||
|
//==========================================================================//
|
||
|
|
||
|
|
||
|
LRESULT
|
||
|
FAR
|
||
|
PASCAL
|
||
|
ILineWndProc (
|
||
|
HWND hWnd,
|
||
|
unsigned msg,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
/*
|
||
|
Note: This function must be declared in the application's
|
||
|
linker-definition file, perfmon.def file.
|
||
|
*/
|
||
|
{ // ILineWndProc
|
||
|
BOOL bCallDefWindowProc ;
|
||
|
POINTS ptsMouse ;
|
||
|
LRESULT lReturnValue ;
|
||
|
|
||
|
bCallDefWindowProc = FALSE ;
|
||
|
lReturnValue = 0L ;
|
||
|
|
||
|
switch (msg)
|
||
|
{ // switch
|
||
|
case WM_CREATE:
|
||
|
OnCreate (hWnd) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
OnDestroy (hWnd) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_LBUTTONDOWN:
|
||
|
// See the note in OnMouseMove for why we are using POINTS
|
||
|
SetFocus (hWnd) ;
|
||
|
ptsMouse = MAKEPOINTS (lParam) ;
|
||
|
OnLButtonDown (hWnd, ptsMouse) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_LBUTTONUP:
|
||
|
OnLButtonUp (hWnd) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_SETFOCUS:
|
||
|
case WM_KILLFOCUS:
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
IntrLineFocus = (msg == WM_SETFOCUS) ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
ILNotifyChange (hWnd, pILine) ;
|
||
|
}
|
||
|
return 0 ;
|
||
|
|
||
|
|
||
|
case WM_MOUSEMOVE:
|
||
|
// See the note in OnMouseMove for why we are using POINTS
|
||
|
ptsMouse = MAKEPOINTS (lParam) ;
|
||
|
OnMouseMove (hWnd, ptsMouse) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_KEYDOWN:
|
||
|
if (!OnKeyDown (hWnd, wParam))
|
||
|
{
|
||
|
bCallDefWindowProc = TRUE ;
|
||
|
}
|
||
|
break ;
|
||
|
|
||
|
case WM_GETDLGCODE:
|
||
|
// We want to handle Arrow keys input. If we don't specify this
|
||
|
// the dialog will not pass arrow keys to us.
|
||
|
return (DLGC_WANTARROWS) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
OnPaint (hWnd) ;
|
||
|
break ;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
|
||
|
|
||
|
default:
|
||
|
bCallDefWindowProc = TRUE ;
|
||
|
} // switch
|
||
|
|
||
|
if (bCallDefWindowProc)
|
||
|
lReturnValue = DefWindowProc (hWnd, msg, wParam, lParam) ;
|
||
|
|
||
|
return (lReturnValue) ;
|
||
|
} // ILineWndProc
|
||
|
|
||
|
|
||
|
|
||
|
BOOL ILineInitializeApplication (void)
|
||
|
/*
|
||
|
Effect: Perform all initializations required before an application
|
||
|
can create an IntervalLine. In particular, register the
|
||
|
IntervalLine window class.
|
||
|
|
||
|
Called By: The application, in its InitializeApplication routine.
|
||
|
|
||
|
Returns: Whether the class could be registered.
|
||
|
*/
|
||
|
{ // ILineInitializeApplication
|
||
|
WNDCLASS wc ;
|
||
|
|
||
|
wc.style = dwILineClassStyle ;
|
||
|
wc.lpfnWndProc = ILineWndProc ;
|
||
|
wc.cbClsExtra = iILineClassExtra ;
|
||
|
wc.cbWndExtra = iILineWindowExtra ;
|
||
|
wc.hInstance = hInstance ;
|
||
|
wc.hIcon = NULL ;
|
||
|
wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
|
||
|
wc.hbrBackground = NULL ;
|
||
|
wc.lpszMenuName = NULL ;
|
||
|
wc.lpszClassName = szILineClass ;
|
||
|
|
||
|
return (RegisterClass (&wc)) ;
|
||
|
} // ILineInitializeApplication
|
||
|
|
||
|
|
||
|
void ILineSetRange (HWND hWnd, int iBegin, int iEnd)
|
||
|
{ // ILineSetRange
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
ILBegin (pILine) = iBegin ;
|
||
|
ILEnd (pILine) = iEnd ;
|
||
|
|
||
|
ILCalcPositions (hWnd, pILine) ;
|
||
|
} // ILineSetRange
|
||
|
|
||
|
|
||
|
void ILineSetStart (HWND hWnd, int iStart)
|
||
|
{ // ILineSetStart
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
iStart = PinInclusive (iStart, ILBegin (pILine), ILEnd (pILine)) ;
|
||
|
ILStart (pILine) = iStart ;
|
||
|
|
||
|
ILCalcPositions (hWnd, pILine) ;
|
||
|
} // ILineSetStart
|
||
|
|
||
|
|
||
|
|
||
|
void ILineSetStop (HWND hWnd, int iStop)
|
||
|
{ // ILineSetStop
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
iStop = PinInclusive (iStop, ILBegin (pILine), ILEnd (pILine)) ;
|
||
|
ILStop (pILine) = iStop ;
|
||
|
|
||
|
ILCalcPositions (hWnd, pILine) ;
|
||
|
} // ILineSetStop
|
||
|
|
||
|
|
||
|
int ILineXStart (HWND hWnd)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
return (pILine->rectLeftGrab.left) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ILineXStop (HWND hWnd)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
return (pILine->rectRightGrab.right) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ILineStart (HWND hWnd)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
return (ILStart (pILine)) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ILineStop (HWND hWnd)
|
||
|
{
|
||
|
PILINE pILine ;
|
||
|
|
||
|
pILine = ILData (hWnd) ;
|
||
|
|
||
|
return (ILStop (pILine)) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|