504 lines
16 KiB
C
504 lines
16 KiB
C
/*
|
|
==============================================================================
|
|
|
|
Application:
|
|
|
|
Microsoft Windows NT (TM) Performance Monitor
|
|
|
|
File:
|
|
status.c - Status window procedure and supporting routines.
|
|
|
|
This file contains code creating the status window, which is
|
|
a child of the legend window. The status window shows the
|
|
time duration of the chart, and the last, avg, min and max
|
|
of the currently-selected chart line.
|
|
|
|
|
|
Copyright 1992, Microsoft Corporation. All Rights Reserved.
|
|
==============================================================================
|
|
*/
|
|
|
|
//==========================================================================//
|
|
// Includes //
|
|
//==========================================================================//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h> // for mbstowcs
|
|
|
|
#include "perfmon.h"
|
|
#include "perfmops.h" // for ConvertDecimalPoint
|
|
#include "valuebar.h"
|
|
|
|
#include "grafdata.h" // for CurrentGraphLine
|
|
#include "graph.h"
|
|
#include "playback.h" // for PlayingBackLog
|
|
#include "legend.h"
|
|
#include "utils.h"
|
|
|
|
//==========================================================================//
|
|
// Constants //
|
|
//==========================================================================//
|
|
HDC hVBarDC ;
|
|
|
|
#define szGraphStatusClass TEXT("PerfmonGraphStatusClass")
|
|
#define dwGraphStatusClassStyle (CS_HREDRAW | CS_VREDRAW | CS_OWNDC)
|
|
#define iGraphStatusClassExtra (0)
|
|
#define iGraphStatusWindowExtra (0)
|
|
#define dwGraphStatusWindowStyle (WS_CHILD | WS_VISIBLE)
|
|
|
|
|
|
#define szStatusValueFormat TEXT("%10.3f")
|
|
#define szStatusMediumnValueFormat TEXT("%10.0f")
|
|
#define szStatusLargeValueFormat TEXT("%10.4e")
|
|
#define eStatusValueTooLarge ((FLOAT) 1.0E+20)
|
|
#define eStatusValueMax ((FLOAT) 999999.999)
|
|
#define eStatusLargeValueMax ((FLOAT) 9999999999.0)
|
|
|
|
|
|
#define szValueTooHigh TEXT("+ + + +")
|
|
#define szValueTooLow TEXT("- - - -")
|
|
|
|
#define StatusLastElt 0
|
|
#define StatusAvgElt 1
|
|
#define StatusMinElt 2
|
|
#define StatusMaxElt 3
|
|
#define StatusTimeElt 4
|
|
|
|
#define StatusNumElts 5
|
|
|
|
#define StatusDrawAvg(hDC, eValue, bForceRedraw) \
|
|
DrawStatusValue (hDC, StatusAvgElt, eValue, bForceRedraw)
|
|
|
|
#define StatusDrawMax(hDC, eValue, bForceRedraw) \
|
|
DrawStatusValue (hDC, StatusMaxElt, eValue, bForceRedraw)
|
|
|
|
#define StatusDrawMin(hDC, eValue, bForceRedraw) \
|
|
DrawStatusValue (hDC, StatusMinElt, eValue, bForceRedraw)
|
|
|
|
//==========================================================================//
|
|
// Typedefs //
|
|
//==========================================================================//
|
|
|
|
|
|
typedef struct StatusEltStruct {
|
|
TCHAR szText [20] ;
|
|
int xTextPos ;
|
|
int xValuePos ;
|
|
FLOAT eValue ;
|
|
} StatusEltType ;
|
|
|
|
|
|
// This structure represents the "instance data" for a StatusWindow. The
|
|
// information is collected in a structure to ease the conversion of this
|
|
// code when later adding multiple graph windows. For now, one copy of this
|
|
// struct is defined as local data to this file.
|
|
typedef struct StatusDataStruct {
|
|
StatusEltType aElts [StatusNumElts] ;
|
|
SIZE sizeValue ;
|
|
int yHeight ;
|
|
} StatusDataType ;
|
|
|
|
|
|
|
|
//==========================================================================//
|
|
// Local Data //
|
|
//==========================================================================//
|
|
|
|
|
|
StatusDataType StatusData ;
|
|
|
|
|
|
//==========================================================================//
|
|
// Macros //
|
|
//==========================================================================//
|
|
|
|
|
|
#define StatusTopMargin() (2)
|
|
#define StatusBottomMargin() (4)
|
|
|
|
#define StatusLeftMargin() (3)
|
|
#define StatusTextMargin() (5 + ThreeDPad)
|
|
#define StatusValueMargin() (3 + ThreeDPad)
|
|
|
|
|
|
//==========================================================================//
|
|
// Local Functions //
|
|
//==========================================================================//
|
|
|
|
|
|
void
|
|
DrawStatusValue (
|
|
HDC hDC,
|
|
int iEltOffset,
|
|
FLOAT eValue,
|
|
BOOL bForceRedraw
|
|
)
|
|
/*
|
|
Called By: StatusDrawTime, StatusDrawLast, StatusDrawAvg,
|
|
StatusDrawMin, StatusDrawMax.
|
|
*/
|
|
{
|
|
RECT rectValue ;
|
|
TCHAR szValue [20] ;
|
|
|
|
if (!bForceRedraw && eValue == StatusData.aElts[iEltOffset].eValue)
|
|
return ;
|
|
StatusData.aElts[iEltOffset].eValue = eValue ;
|
|
|
|
rectValue.left = StatusData.aElts[iEltOffset].xValuePos ;
|
|
rectValue.top = StatusTopMargin () + ThreeDPad + 1;
|
|
rectValue.right = rectValue.left + StatusData.sizeValue.cx ;
|
|
rectValue.bottom = rectValue.top + StatusData.sizeValue.cy ;
|
|
|
|
|
|
if (eValue > eStatusValueMax) {
|
|
if (eValue > eStatusValueTooLarge) {
|
|
lstrcpy (szValue, szValueTooHigh) ;
|
|
} else {
|
|
TSPRINTF (szValue,
|
|
(eValue > eStatusLargeValueMax) ? szStatusLargeValueFormat :
|
|
szStatusMediumnValueFormat,
|
|
eValue) ;
|
|
ConvertDecimalPoint (szValue) ;
|
|
}
|
|
} else if (eValue < -eStatusValueMax)
|
|
lstrcpy (szValue, szValueTooLow) ;
|
|
else {
|
|
TSPRINTF (szValue, szStatusValueFormat, eValue) ;
|
|
ConvertDecimalPoint (szValue) ;
|
|
}
|
|
|
|
ExtTextOut (hDC, rectValue.right, rectValue.top, ETO_OPAQUE, &rectValue,
|
|
szValue, lstrlen (szValue), NULL) ;
|
|
} // DrawStatusValue
|
|
|
|
|
|
//==========================================================================//
|
|
// Message Handlers //
|
|
//==========================================================================//
|
|
|
|
|
|
//void static OnCreate (HWND hWnd)
|
|
void
|
|
OnVBarCreate (
|
|
HWND hWnd
|
|
)
|
|
/*
|
|
Effect: Perform any actions needed when a status window is created.
|
|
In particular, set the instance data to initial values,
|
|
determine the size and placement of the various elements
|
|
of the status display.
|
|
|
|
Called By: GraphStatusWndProc only, in response to a WM_CREATE message.
|
|
*/
|
|
{
|
|
TCHAR szValue [20] ;
|
|
HDC hDC ;
|
|
int iLen ;
|
|
int i ;
|
|
|
|
hDC = hVBarDC = GetDC (hWnd) ;
|
|
if (!hDC)
|
|
return;
|
|
SelectFont (hDC, hFontScales) ;
|
|
SetBkColor (hDC, ColorBtnFace) ;
|
|
SetTextAlign (hDC, TA_RIGHT | TA_TOP) ;
|
|
|
|
//=============================//
|
|
// Load Text Labels //
|
|
//=============================//
|
|
|
|
StringLoad (IDS_STATUSLAST, StatusData.aElts[StatusLastElt].szText) ;
|
|
StringLoad (IDS_STATUSAVG, StatusData.aElts[StatusAvgElt].szText) ;
|
|
StringLoad (IDS_STATUSMIN, StatusData.aElts[StatusMinElt].szText) ;
|
|
StringLoad (IDS_STATUSMAX, StatusData.aElts[StatusMaxElt].szText) ;
|
|
StringLoad (IDS_STATUSTIME, StatusData.aElts[StatusTimeElt].szText) ;
|
|
|
|
//=============================//
|
|
// Determine Status Height //
|
|
//=============================//
|
|
|
|
StatusData.yHeight = StatusTopMargin () +
|
|
StatusBottomMargin () +
|
|
FontHeight (hDC, TRUE) +
|
|
2 * ThreeDPad ;
|
|
|
|
//=============================//
|
|
// Set position/size of elts //
|
|
//=============================//
|
|
|
|
// Determine the bounding box for each status value by using a max value.
|
|
iLen = TSPRINTF (szValue, szStatusLargeValueFormat, -eStatusValueMax) ;
|
|
|
|
GetTextExtentPoint (hDC, szValue, lstrlen(szValue), &StatusData.sizeValue) ;
|
|
for (i = 0 ; i < StatusNumElts ; i++) {
|
|
StatusData.aElts[i].eValue = (FLOAT) 0.0 ;
|
|
|
|
if (i)
|
|
StatusData.aElts[i].xTextPos = StatusTextMargin () +
|
|
StatusData.aElts[i - 1].xValuePos +
|
|
StatusData.sizeValue.cx ;
|
|
else
|
|
StatusData.aElts[i].xTextPos = StatusLeftMargin () ;
|
|
StatusData.aElts[i].xValuePos = StatusData.aElts[i].xTextPos +
|
|
StatusValueMargin () +
|
|
TextWidth (hDC, StatusData.aElts[i].szText) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
static
|
|
OnPaint (
|
|
HWND hWnd,
|
|
BOOL bEraseBackground
|
|
)
|
|
/*
|
|
Effect: Paint the invalid surface of hWnd. Draw each label, each
|
|
recessed value box, and each value.
|
|
|
|
Called By: GraphStatusWndProc only, in response to a WM_PAINT message.
|
|
*/
|
|
{
|
|
HDC hDC ;
|
|
PAINTSTRUCT ps ;
|
|
RECT rectClient ;
|
|
int i ;
|
|
PLINESTRUCT pLine;
|
|
|
|
hDC = BeginPaint (hWnd, &ps) ;
|
|
SetBkMode (hDC, (bEraseBackground ? OPAQUE : TRANSPARENT)) ;
|
|
SetBkColor (hDC, ColorBtnFace) ;
|
|
|
|
GetClientRect (hWnd, &rectClient) ;
|
|
HLine (hDC, GetStockObject (BLACK_PEN),
|
|
rectClient.left, rectClient.right,
|
|
rectClient.bottom - 1) ;
|
|
|
|
if ((pGraphs->gOptions.bStatusBarChecked) && (pGraphs->gOptions.bLegendChecked)) {
|
|
UINT hPrevTextAlign = SetTextAlign (hDC, TA_LEFT | TA_TOP) ;
|
|
|
|
for (i = 0; i < StatusNumElts; i++) {
|
|
// Draw the label
|
|
TextOut (hDC, StatusData.aElts[i].xTextPos, StatusTopMargin () + ThreeDPad,
|
|
StatusData.aElts[i].szText,
|
|
lstrlen (StatusData.aElts[i].szText)) ;
|
|
|
|
// Draw the recesed value box
|
|
ThreeDConcave1 (hDC,
|
|
StatusData.aElts[i].xValuePos - ThreeDPad,
|
|
StatusTopMargin (),
|
|
StatusData.aElts[i].xValuePos + StatusData.sizeValue.cx + ThreeDPad,
|
|
StatusTopMargin () + StatusData.sizeValue.cy + 2 * ThreeDPad ) ;
|
|
}
|
|
|
|
// restore TextAlign for drawing values
|
|
SetTextAlign (hDC, hPrevTextAlign) ;
|
|
|
|
// Draw the values themselves
|
|
|
|
pLine = CurrentGraphLine (hWndGraph) ;
|
|
StatusDrawTime (hDC, TRUE) ;
|
|
|
|
StatusDrawLast (hDC, pLine, TRUE) ;
|
|
|
|
if (pLine) {
|
|
StatusDrawAvg (hDC, pLine->lnAveValue, TRUE) ;
|
|
StatusDrawMin (hDC, pLine->lnMinValue, TRUE) ;
|
|
StatusDrawMax (hDC, pLine->lnMaxValue, TRUE) ;
|
|
} else {
|
|
StatusDrawAvg (hVBarDC, (FLOAT)0.0, TRUE) ;
|
|
StatusDrawMax (hVBarDC, (FLOAT)0.0, TRUE) ;
|
|
StatusDrawMin (hVBarDC, (FLOAT)0.0, TRUE) ;
|
|
}
|
|
}
|
|
|
|
EndPaint (hWnd, &ps) ;
|
|
}
|
|
|
|
|
|
//==========================================================================//
|
|
// Exported Functions //
|
|
//==========================================================================//
|
|
|
|
|
|
|
|
void
|
|
StatusDrawTime (
|
|
HDC hDC,
|
|
BOOL bForceRedraw
|
|
)
|
|
/*
|
|
Called By: StatusTimer, StatusPaint.
|
|
*/
|
|
{
|
|
FLOAT eTimeSeconds ;
|
|
|
|
if (PlayingBackLog ())
|
|
eTimeSeconds = (FLOAT) PlaybackSelectedSeconds () ;
|
|
else
|
|
eTimeSeconds = pGraphs->gOptions.eTimeInterval *
|
|
(FLOAT) pGraphs->gMaxValues;
|
|
|
|
DrawStatusValue (hDC, StatusTimeElt, eTimeSeconds, bForceRedraw) ;
|
|
}
|
|
|
|
|
|
void
|
|
StatusDrawLast (
|
|
HDC hDC,
|
|
PLINESTRUCT pLine,
|
|
BOOL bForceRedraw
|
|
)
|
|
/*
|
|
Called By: StatusTimer, StatusPaint.
|
|
*/
|
|
{
|
|
INT iKnownValue ;
|
|
int iMaxValues ;
|
|
FLOAT eValue ;
|
|
|
|
if (!pLine || pGraphs->gKnownValue == -1)
|
|
eValue = (FLOAT) 0.0 ;
|
|
else {
|
|
iKnownValue = pGraphs->gKnownValue ;
|
|
iMaxValues = pGraphs->gMaxValues ;
|
|
eValue = pLine->lnValues [iKnownValue % iMaxValues] ;
|
|
}
|
|
|
|
DrawStatusValue (hDC, StatusLastElt, eValue, bForceRedraw) ;
|
|
}
|
|
|
|
LRESULT
|
|
APIENTRY
|
|
GraphStatusWndProc (
|
|
HWND hWnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
BOOL bCallDefProc ;
|
|
LRESULT lReturnValue ;
|
|
|
|
bCallDefProc = FALSE ;
|
|
lReturnValue = 0L ;
|
|
|
|
switch (wMsg) {
|
|
case WM_CREATE:
|
|
//OnCreate (hWnd) ;
|
|
OnVBarCreate (hWnd) ;
|
|
break ;
|
|
|
|
|
|
case WM_PAINT:
|
|
OnPaint (hWnd, TRUE) ;
|
|
break ;
|
|
|
|
case WM_DESTROY:
|
|
ReleaseDC (hWnd, hVBarDC) ;
|
|
break ;
|
|
|
|
default:
|
|
bCallDefProc = TRUE ;
|
|
}
|
|
|
|
if (bCallDefProc)
|
|
lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;
|
|
|
|
return (lReturnValue);
|
|
}
|
|
|
|
|
|
int
|
|
ValuebarHeight (
|
|
HWND hWnd
|
|
)
|
|
/*
|
|
Effect: A status window has a preferred height, based on the font
|
|
used in its display. Return the preferred height, determined
|
|
when the window was created.
|
|
|
|
Assert: OnCreate has already been called, and it set
|
|
StatusData.yHeight.
|
|
*/
|
|
{
|
|
return (StatusData.yHeight) ;
|
|
}
|
|
|
|
|
|
void
|
|
StatusTimer (
|
|
HWND hWnd,
|
|
BOOL bForceRedraw
|
|
)
|
|
/*
|
|
Effect: Perform any status-window actions necessary when a timer
|
|
tick has been received. In particular, update (redraw)
|
|
any of the changed values in the status bar.
|
|
|
|
Internals: Each of these called functions compares the value to be
|
|
displayed with the previous value and doesn't draw if the
|
|
values are equal.
|
|
*/
|
|
{
|
|
PLINESTRUCT pLine;
|
|
|
|
pLine = CurrentGraphLine (hWndGraph) ;
|
|
|
|
StatusDrawLast (hVBarDC, pLine, bForceRedraw) ;
|
|
|
|
if (pLine) {
|
|
StatusDrawAvg (hVBarDC, pLine->lnAveValue, bForceRedraw) ;
|
|
StatusDrawMin (hVBarDC, pLine->lnMinValue, bForceRedraw) ;
|
|
StatusDrawMax (hVBarDC, pLine->lnMaxValue, bForceRedraw) ;
|
|
} else {
|
|
StatusDrawAvg (hVBarDC, (FLOAT)0.0, bForceRedraw) ;
|
|
StatusDrawMax (hVBarDC, (FLOAT)0.0, bForceRedraw) ;
|
|
StatusDrawMin (hVBarDC, (FLOAT)0.0, bForceRedraw) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HWND
|
|
CreateGraphStatusWindow (
|
|
HWND hWndGraph
|
|
)
|
|
{
|
|
return (CreateWindow (szGraphStatusClass, // class
|
|
NULL, // caption
|
|
dwGraphStatusWindowStyle, // window style
|
|
0, 0, // position
|
|
0, 0, // size
|
|
hWndGraph, // parent window
|
|
NULL, // menu
|
|
hInstance, // program instance
|
|
NULL)) ; // user-supplied data
|
|
}
|
|
|
|
|
|
BOOL
|
|
GraphStatusInitializeApplication (void)
|
|
/*
|
|
Called By: GraphInitializeApplication only
|
|
*/
|
|
{
|
|
WNDCLASS wc ;
|
|
|
|
wc.style = dwGraphStatusClassStyle ;
|
|
wc.lpfnWndProc = GraphStatusWndProc ;
|
|
wc.hInstance = hInstance ;
|
|
wc.cbClsExtra = iGraphStatusClassExtra ;
|
|
wc.cbWndExtra = iGraphStatusWindowExtra ;
|
|
wc.hIcon = NULL ;
|
|
wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
|
|
// wc.hbrBackground = hbLightGray ;
|
|
wc.hbrBackground = hBrushFace;
|
|
wc.lpszMenuName = NULL ;
|
|
wc.lpszClassName = szGraphStatusClass ;
|
|
|
|
return (RegisterClass (&wc)) ;
|
|
}
|