/*
==============================================================================
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 - 1998 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.
*/
{ // DrawStatusValue
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.
*/
{ // OnCreate
TCHAR szValue [20] ;
HDC hDC ;
int iLen ;
int i ;
hDC = hVBarDC = GetDC (hWnd) ;
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.
#ifdef JAPAN
iLen = TSPRINTF (szValue, szStatusMediumnValueFormat, -((FLOAT) 9999.999)) ;
#else
iLen = TSPRINTF (szValue, szStatusLargeValueFormat, -eStatusValueMax) ;
#endif
GetTextExtentPoint (hDC, szValue, lstrlen(szValue), &StatusData.sizeValue) ;
for (i = 0 ;
i < StatusNumElts ;
i++)
{ // for
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) ;
} // for
} // OnCreate
void static OnPaint (HWND hWnd)
/*
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, TRANSPARENT) ;
GetClientRect (hWnd, &rectClient) ;
HLine (hDC, GetStockObject (BLACK_PEN),
rectClient.left, rectClient.right,
rectClient.bottom - 1) ;
if ((pGraphs->gOptions.bStatusBarChecked) &&
(pGraphs->gOptions.bLegendChecked))
{ // if
UINT hPrevTextAlign = SetTextAlign (hDC, TA_LEFT | TA_TOP) ;
for (i = 0 ;
i < StatusNumElts ;
i++)
{ // for
// 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 ) ;
} // for
// 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) ;
}
} // if
EndPaint (hWnd, &ps) ;
} // StatusPaint
//==========================================================================//
// Exported Functions //
//==========================================================================//
void StatusDrawTime (HDC hDC, BOOL bForceRedraw)
/*
Called By: StatusTimer, StatusPaint.
*/
{ // StatusDrawTime
FLOAT eTimeSeconds ;
if (PlayingBackLog ())
eTimeSeconds = (FLOAT) PlaybackSelectedSeconds () ;
else
eTimeSeconds = pGraphs->gOptions.eTimeInterval *
(FLOAT) pGraphs->gMaxValues;
DrawStatusValue (hDC, StatusTimeElt, eTimeSeconds, bForceRedraw) ;
} // StatusDrawTime
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) ;
}
#if 0
void StatusDrawAvg (HDC hDC, PLINESTRUCT pLine, BOOL bForceRedraw)
/*
Called By: StatusTimer, StatusPaint.
*/
{
FLOAT eValue ;
if (!pLine)
eValue = (FLOAT) 0.0 ;
else
eValue = pLine->lnAveValue ;
DrawStatusValue (hDC, StatusAvgElt, eValue, bForceRedraw) ;
}
void StatusDrawMax (HDC hDC, PLINESTRUCT pLine, BOOL bForceRedraw)
/*
Called By: StatusTimer, StatusPaint.
*/
{
FLOAT eValue ;
if (!pLine)
eValue = (FLOAT) 0.0 ;
else
eValue = pLine->lnMaxValue ;
DrawStatusValue (hDC, StatusMaxElt, eValue, bForceRedraw) ;
}
void StatusDrawMin (HDC hDC, PLINESTRUCT pLine, BOOL bForceRedraw)
/*
Called By: StatusTimer, StatusPaint.
*/
{
FLOAT eValue ;
if (!pLine)
eValue = (FLOAT) 0.0 ;
else
eValue = pLine->lnMinValue ;
DrawStatusValue (hDC, StatusMinElt, eValue, bForceRedraw) ;
}
#endif
LRESULT APIENTRY GraphStatusWndProc (HWND hWnd,
WORD wMsg,
WPARAM wParam,
LPARAM lParam)
{ // GraphStatusWndProc
BOOL bCallDefProc ;
LRESULT lReturnValue ;
bCallDefProc = FALSE ;
lReturnValue = 0L ;
switch (wMsg)
{ // switch
case WM_CREATE:
//OnCreate (hWnd) ;
OnVBarCreate (hWnd) ;
break ;
case WM_PAINT:
OnPaint (hWnd) ;
break ;
case WM_DESTROY:
ReleaseDC (hWnd, hVBarDC) ;
break ;
default:
bCallDefProc = TRUE ;
} // switch
if (bCallDefProc)
lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;
return (lReturnValue);
} // GraphStatusWndProc
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.
*/
{ // StatusTimer
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) ;
}
} // StatusTimer
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 = (WNDPROC) GraphStatusWndProc ;
wc.hInstance = hInstance ;
wc.cbClsExtra = iGraphStatusClassExtra ;
wc.cbWndExtra = iGraphStatusWindowExtra ;
wc.hIcon = NULL ;
wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wc.hbrBackground = hbLightGray ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = szGraphStatusClass ;
return (RegisterClass (&wc)) ;
}