|
|
/*
==============================================================================
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)) ; }
|