windows-nt/Source/XPSP1/NT/sdktools/perfmon/legend.c
2020-09-26 16:20:57 +08:00

1343 lines
37 KiB
C

/*
==============================================================================
Application:
Microsoft Windows NT (TM) Performance Monitor
File:
legend.c - legend window routines.
This file contains code creating the legend window, which is
a child of the graph windows. The legend window displays a
legend line for each line in the associated graph. It also
includes an area called the label, which are headers for those
lines.
Copyright 1992, Microsoft Corporation. All Rights Reserved.
==============================================================================
*/
//==========================================================================//
// Includes //
//==========================================================================//
#include <stdio.h> // for sprintf
#include "perfmon.h"
#include "legend.h" // external declarations for this file
#include "owndraw.h"
#include "alert.h" // for EditAlert
#include "grafdata.h" // for EditChart
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
#include "utils.h"
#include "valuebar.h" // for StatusTimer
#include "playback.h" // for PlayingBackLog()
#include "perfmops.h" // for COnvertDecimalPoint
#define eScaleValueSpace TEXT(">9999999999.0")
//==========================================================================//
// Constants //
//==========================================================================//
#define dwGraphLegendClassStyle (CS_HREDRAW | CS_VREDRAW)
#define iGraphLegendClassExtra (0)
#define iGraphLegendWindowExtra (sizeof (PLEGEND))
#define dwGraphLegendWindowStyle (WS_CHILD | WS_VISIBLE)
#define xLegendBorderWidth (xDlgBorderWidth)
#define yLegendBorderHeight (yDlgBorderHeight)
#define iLabelLen 30
#define iLegendColMax 1000
#define LEFTORIENTATION 1
#define CENTERORIENTATION 2
#define RIGHTORIENTATION 3
#define LegendColorCol 0
#define LegendScaleCol 1
#define LegendCounterCol 2
#define LegendInstanceCol 3
#define LegendParentCol 4
#define LegendObjectCol 5
#define LegendSystemCol 6
#define iLegendNumCols 7
#define iLegendMaxVisibleItems 8
#define dwGraphLegendItemsWindowClass TEXT("ListBox")
#define dwGraphLegendItemsWindowStyle \
(LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | \
WS_VISIBLE | WS_CHILD | WS_VSCROLL)
//==========================================================================//
// Typedefs //
//==========================================================================//
typedef struct LEGENDCOLSTRUCT {
TCHAR szLabel [iLabelLen] ;
int xMinWidth ;
int xMaxWidth ;
int xWidth ;
int xPos ;
int iOrientation ;
} LEGENDCOL ;
typedef LEGENDCOL *PLEGENDCOL ;
typedef struct LEGENDTRUCT {
HWND hWndItems ;
HFONT hFontItems ;
HFONT hFontLabels ;
int xMinWidth ;
int yLabelHeight ;
int yItemHeight ;
int iNumItemsVisible ;
LEGENDCOL aCols [iLegendNumCols] ;
int iLineType ;
PLINE pCurrentLine ; // current selected line
} LEGEND ;
typedef LEGEND *PLEGEND ;
//==========================================================================//
// Macros //
//==========================================================================//
#define LabelTopMargin() (2)
#define LegendLeftMargin() (3 + ThreeDPad)
#define LegendItemTopMargin() (yBorderHeight)
#define IsLegendLabelVisible() (TRUE)
#define ColCanGrow(pCol) \
(pCol->xMaxWidth > pCol->xWidth)
#define LegendHorzMargin() (3)
//==========================================================================//
// Local Data //
//==========================================================================//
PLEGEND pGraphLegendData ;
PLEGEND pAlertLegendData ;
#define LegendData(hWnd) \
((hWnd == hWndGraphLegend) ? pGraphLegendData : pAlertLegendData )
//==========================================================================//
// Local Functions //
//==========================================================================//
void
LegendSetCurrentLine (
PLEGEND pLegend,
int iIndex
)
{
pLegend->pCurrentLine =
(PLINESTRUCT) LBData (pLegend->hWndItems, iIndex) ;
if (pLegend->pCurrentLine == (PLINESTRUCT) LB_ERR) {
pLegend->pCurrentLine = NULL ;
}
}
PLEGEND
AllocateLegendData (
HWND hWnd,
BOOL bChartLegend
)
{
PLEGEND pLegend ;
pLegend = MemoryAllocate (sizeof (LEGEND)) ;
if (bChartLegend) {
hWndGraphLegend = hWnd ;
pGraphLegendData = pLegend ;
} else {
hWndAlertLegend = hWnd ;
pAlertLegendData = pLegend ;
}
return (pLegend) ;
}
void
DrawLegendLabel (
PLEGEND pLegend,
HDC hDC,
HWND hWnd
)
{
int i ;
int xPos ;
RECT rect ;
RECT rectLB ;
INT LocalThreeDPad = ThreeDPad - 1 ;
// SetBkColor (hDC, crLightGray) ;
SetBkColor (hDC, ColorBtnFace) ;
SelectFont (hDC, pLegend->hFontLabels) ;
GetClientRect (hWnd, &rect) ;
// Fill (hDC, crLightGray, &rect) ;
ExtTextOut (hDC, rect.left, rect.top,
ETO_OPAQUE, &(rect), NULL, 0, NULL ) ;
GetWindowRect (pLegend->hWndItems, &rectLB) ;
ScreenRectToClient (hWnd, &rectLB) ;
ThreeDConcave1 (hDC,
rectLB.left - LocalThreeDPad,
rectLB.top - LocalThreeDPad,
rectLB.right + LocalThreeDPad,
rectLB.bottom + LocalThreeDPad) ;
for (i = 0; i < iLegendNumCols; i++) {
rect.left = pLegend->aCols[i].xPos ;
rect.top = yBorderHeight ;
rect.right = rect.left + pLegend->aCols[i].xWidth - LegendHorzMargin () ;
rect.bottom = pLegend->yLabelHeight ;
switch (pLegend->aCols[i].iOrientation) {
case LEFTORIENTATION:
SetTextAlign (hDC, TA_LEFT) ;
xPos = rect.left ;
break ;
case CENTERORIENTATION:
SetTextAlign (hDC, TA_CENTER) ;
xPos = (rect.left + rect.right) / 2 ;
break ;
case RIGHTORIENTATION:
SetTextAlign (hDC, TA_RIGHT) ;
xPos = rect.right ;
break ;
default:
xPos = rect.left ;
break ;
}
ExtTextOut (hDC,
xPos, rect.top,
ETO_OPAQUE,
&rect,
pLegend->aCols[i].szLabel,
lstrlen (pLegend->aCols[i].szLabel),
NULL) ;
}
}
void
DrawColorCol (
PLEGEND pLegend,
PLINE pLine,
int iCol,
HDC hDC,
int yPos
)
/*
Effect: Draw the "color" column of a legend entry. The color
column displays a small sample of the line drawing.
For charts, the sample is a line of the correct style,
color, and width. Since we are using wide lines,
the round endcaps of the lines will breach the column.
Therefore we need to set the clip region. We could
remove this clipping if we find a way to change the
end cap design.
For alerts, the sample is a small circle which echos
the design in the alert log itself.
*/
{
HBRUSH hBrush, hBrushPrevious ;
RECT rect ;
int yMiddle ;
int iCircle ;
rect.left = pLegend->aCols[iCol].xPos - LegendLeftMargin () + 2 ;
rect.top = yPos + 1 ;
rect.right = rect.left + pLegend->aCols[iCol].xWidth - LegendHorzMargin () ;
rect.bottom = yPos + pLegend->yItemHeight - 1 ;
yMiddle = rect.top + (rect.bottom - rect.top) / 2 ;
iCircle = rect.bottom - rect.top - 2 ;
switch (pLegend->iLineType) {
case LineTypeChart:
if (pLine->Visual.iWidth == 1) {
// simple case with thin pen
// hBrush = SelectBrush (hDC, hbLightGray) ;
hBrush = SelectBrush (hDC, hBrushFace) ;
Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom) ;
HLine (hDC, pLine->hPen,
rect.left + 1, rect.right - 1, yMiddle) ;
SelectBrush (hDC, hBrush) ;
} else {
// thicker pen width, have to set ClipRect so
// it will not draw otherside the rect.
SaveDC (hDC) ;
// hBrush = SelectBrush (hDC, hbLightGray) ;
hBrush = SelectBrush (hDC, hBrushFace) ;
Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom) ;
IntersectClipRect (hDC,
rect.left + 1,
rect.top + 1,
rect.right - 1,
rect.bottom - 1) ;
HLine (hDC, pLine->hPen,
rect.left + 1, rect.right - 1, yMiddle) ;
SelectBrush (hDC, hBrush) ;
RestoreDC (hDC, -1) ;
}
break ;
case LineTypeAlert:
hBrushPrevious = SelectBrush (hDC, pLine->hBrush) ;
Ellipse (hDC,
rect.left + 2,
rect.top + 2,
rect.left + 2 + iCircle,
rect.top + 2 + iCircle) ;
SelectBrush (hDC, hBrushPrevious) ;
break ;
}
}
void
DrawLegendCol (
PLEGEND pLegend,
int iCol,
HDC hDC,
int yPos,
LPTSTR lpszValue
)
/*
Effect: Draw the value lpszValue for the column iCol on hDC.
Assert: The foreground and background text colors of hDC are
properly set.
*/
{
RECT rect ;
int xPos ;
rect.left = pLegend->aCols[iCol].xPos - LegendLeftMargin () ;
rect.top = yPos ;
rect.right = rect.left + pLegend->aCols[iCol].xWidth - LegendHorzMargin () ;
rect.bottom = yPos + pLegend->yItemHeight ;
// SetTextAlign (hDC, TA_TOP) ;
switch (pLegend->aCols[iCol].iOrientation) {
case LEFTORIENTATION:
SetTextAlign (hDC, TA_LEFT) ;
xPos = rect.left ;
break ;
case CENTERORIENTATION:
SetTextAlign (hDC, TA_CENTER) ;
xPos = (rect.left + rect.right) / 2 ;
break ;
case RIGHTORIENTATION:
SetTextAlign (hDC, TA_RIGHT) ;
xPos = rect.right ;
break ;
default:
xPos = rect.left ;
break ;
}
ExtTextOut (hDC,
xPos, rect.top + LegendItemTopMargin (),
ETO_OPAQUE | ETO_CLIPPED,
&rect,
lpszValue,
lstrlen (lpszValue),
NULL) ;
}
void
DrawLegendItem (
PLEGEND pLegend,
PLINESTRUCT pLine,
int yPos,
HDC hDC
)
{
TCHAR szValue [256] ;
TCHAR szInstance [256] ;
TCHAR szParent [256] ;
TCHAR szNoName[4] ;
szNoName[0] = szNoName[1] = szNoName[2] = TEXT('-') ;
szNoName[3] = TEXT('\0') ;
//=============================//
// Determine Instance, Parent //
//=============================//
// It's possible that there will be no instance, therefore
// the lnInstanceName would be NULL.
if (pLine->lnObject.NumInstances > 0) {
// Test for the parent object instance name title index.
// If there is one, it implies that there will be a valid
// Parent Object Name and a valid Parent Object Instance Name.
// If the Parent Object title index is 0 then
// just display the instance name.
lstrcpy (szInstance, pLine->lnInstanceName) ;
if (pLine->lnInstanceDef.ParentObjectTitleIndex &&
pLine->lnPINName) {
// Get the Parent Object Name.
lstrcpy (szParent, pLine->lnPINName) ;
} else {
lstrcpy (szParent, szNoName) ;
}
} else {
lstrcpy (szInstance, szNoName) ;
lstrcpy (szParent, szNoName) ;
}
//=============================//
// Draw Color //
//=============================//
DrawColorCol (pLegend, pLine, LegendColorCol, hDC, yPos) ;
//=============================//
// Draw Scale/Value //
//=============================//
if (pLegend->iLineType == LineTypeChart) {
if (pLine->eScale < (FLOAT) 1.0) {
TSPRINTF (szValue, TEXT("%7.7f"), pLine->eScale) ;
} else {
TSPRINTF (szValue, TEXT("%10.3f"), pLine->eScale) ;
}
ConvertDecimalPoint (szValue) ;
} else {
FLOAT tempAlertValue ;
tempAlertValue = pLine->eAlertValue ;
if (tempAlertValue < (FLOAT) 0.0) {
tempAlertValue = -tempAlertValue ;
}
if (tempAlertValue >= (FLOAT) 10000.0) {
if (tempAlertValue < (FLOAT) 1.0E+8) {
TSPRINTF (szValue, TEXT("%c%10.0f"),
pLine->bAlertOver ? TEXT('>') : TEXT('<'),
pLine->eAlertValue) ;
} else {
TSPRINTF (szValue, TEXT("%c%10.3e"),
pLine->bAlertOver ? TEXT('>') : TEXT('<'),
pLine->eAlertValue) ;
}
ConvertDecimalPoint (szValue) ;
} else {
TSPRINTF (szValue, TEXT("%c%10.4f"),
pLine->bAlertOver ? TEXT('>') : TEXT('<'),
pLine->eAlertValue) ;
ConvertDecimalPoint (szValue) ;
}
}
SetTextAlign (hDC, TA_TOP) ;
DrawLegendCol (pLegend, LegendScaleCol,
hDC, yPos, szValue) ;
//=============================//
// Draw Counter //
//=============================//
DrawLegendCol (pLegend, LegendCounterCol,
hDC, yPos, pLine->lnCounterName) ;
//=============================//
// Draw Instance //
//=============================//
DrawLegendCol (pLegend, LegendInstanceCol,
hDC, yPos, szInstance) ;
//=============================//
// Draw Parent //
//=============================//
DrawLegendCol (pLegend, LegendParentCol,
hDC, yPos, szParent) ;
//=============================//
// Draw Object //
//=============================//
DrawLegendCol (pLegend, LegendObjectCol,
hDC, yPos, pLine->lnObjectName) ;
//=============================//
// Draw System //
//=============================//
DrawLegendCol (pLegend, LegendSystemCol,
hDC, yPos, pLine->lnSystemName) ;
}
//==========================================================================//
// Message Handlers //
//==========================================================================//
BOOL
OnLegendCreate (
HWND hWnd,
LPCREATESTRUCT lpCS
)
{
PLEGEND pLegend ;
HDC hDC ;
int iCol ;
BOOL bChartLegend ;
bChartLegend = (lpCS->lpCreateParams) == (LPVOID) TRUE ;
pLegend = AllocateLegendData (hWnd, bChartLegend) ;
if (!pLegend)
return (FALSE) ;
if (bChartLegend) {
pLegend->iLineType = LineTypeChart ;
} else {
pLegend->iLineType = LineTypeAlert ;
}
pLegend->hFontItems = hFontScales ;
pLegend->hFontLabels = hFontScalesBold ;
hDC = GetDC (hWnd) ;
if (!hDC)
return (FALSE);
//=============================//
// Load Labels //
//=============================//
StringLoad (IDS_LABELCOLOR, pLegend->aCols[LegendColorCol].szLabel) ;
if (pLegend->iLineType == LineTypeChart)
StringLoad (IDS_LABELSCALE,
pLegend->aCols[LegendScaleCol].szLabel) ;
else
StringLoad (IDS_LABELVALUE,
pLegend->aCols[LegendScaleCol].szLabel) ;
StringLoad (IDS_LABELCOUNTER, pLegend->aCols[LegendCounterCol].szLabel) ;
StringLoad (IDS_LABELINSTANCE, pLegend->aCols[LegendInstanceCol].szLabel) ;
StringLoad (IDS_LABELPARENT, pLegend->aCols[LegendParentCol].szLabel) ;
StringLoad (IDS_LABELOBJECT, pLegend->aCols[LegendObjectCol].szLabel) ;
StringLoad (IDS_LABELSYSTEM, pLegend->aCols[LegendSystemCol].szLabel) ;
//=============================//
// Label dimensions //
//=============================//
SelectFont (hDC, pLegend->hFontLabels) ;
pLegend->yLabelHeight = FontHeight (hDC, TRUE) + 2 * LabelTopMargin () ;
//=============================//
// Column dimensions //
//=============================//
for (iCol = 0; iCol < iLegendNumCols; iCol++) {
pLegend->aCols[iCol].iOrientation = LEFTORIENTATION ;
pLegend->aCols[iCol].xMinWidth =
TextWidth (hDC, pLegend->aCols[iCol].szLabel) + LegendHorzMargin () ;
}
SelectFont (hDC, pLegend->hFontItems) ;
pLegend->yItemHeight = FontHeight (hDC, TRUE) + 2 * LegendItemTopMargin () ;
pLegend->aCols[LegendColorCol].xMaxWidth = max (3 * xScrollWidth,
pLegend->aCols[LegendColorCol].xMinWidth) ;
pLegend->aCols[LegendScaleCol].xMaxWidth = TextWidth (hDC, eScaleValueSpace) ;
pLegend->aCols[LegendCounterCol].xMaxWidth = iLegendColMax ;
pLegend->aCols[LegendInstanceCol].xMaxWidth = iLegendColMax ;
pLegend->aCols[LegendParentCol].xMaxWidth = iLegendColMax ;
pLegend->aCols[LegendObjectCol].xMaxWidth = iLegendColMax ;
pLegend->aCols[LegendSystemCol].xMaxWidth = iLegendColMax ;
pLegend->aCols[LegendColorCol].iOrientation = LEFTORIENTATION ;
pLegend->aCols[LegendScaleCol].iOrientation = RIGHTORIENTATION ;
ReleaseDC (hWnd, hDC) ;
//=============================//
// Create Legend Items Listbox //
//=============================//
pLegend->hWndItems =
CreateWindow (TEXT("ListBox"), // window class
NULL, // window caption
dwGraphLegendItemsWindowStyle, // window style
0, 0, 0, 0, // window size and pos
hWnd, // parent window
NULL, // menu
hInstance, // program instance
(LPVOID) TRUE) ; // user-supplied data
return TRUE;
}
void
static
OnSize (
HWND hWnd,
int xWidth,
int yHeight
)
/*
Effect: Perform all actions necessary when the legend window is
being resized. In particular, set the width and starting
position for each column of the legend list and labels.
Internals: What we do is determine the amount of space in the
width that is greater than the minimum, and allocate
that space among each of the columns that is willing to
be larger than minimum. If there is not enough room for
the minimum, don't bother with calculations.
*/
{
PLEGEND pLegend ;
PLEGENDCOL pCol ;
int xMin ;
int xSlack ;
int iColsToGrow ;
int iCol ;
pLegend = LegendData (hWnd) ;
//=============================//
// Resize Legend Items //
//=============================//
if (IsLegendLabelVisible ())
MoveWindow (pLegend->hWndItems,
LegendLeftMargin (), pLegend->yLabelHeight + ThreeDPad,
xWidth - 2 * LegendLeftMargin (),
yHeight - pLegend->yLabelHeight - yLegendBorderHeight,
TRUE) ;
else
MoveWindow (pLegend->hWndItems,
0, 0,
xWidth, yHeight,
TRUE) ;
//=============================//
// Allocate width to Columns //
//=============================//
xMin = LegendMinWidth (hWnd) ;
xSlack = max (xWidth - xMin, 0) ;
iColsToGrow = 0 ;
for (iCol = 0; iCol < iLegendNumCols; iCol++) {
pCol = &(pLegend->aCols[iCol]) ;
pCol->xWidth = pCol->xMinWidth ;
if (ColCanGrow (pCol))
iColsToGrow++ ;
}
for (iCol = 0; iCol < iLegendNumCols; iCol++) {
pCol = &(pLegend->aCols[iCol]) ;
if (ColCanGrow (pCol)) {
if ((pCol->xWidth + xSlack / iColsToGrow) > pCol->xMaxWidth) {
pCol->xWidth = pCol->xMaxWidth ;
xSlack -= (pCol->xMaxWidth - pCol->xMinWidth) ;
iColsToGrow-- ;
}
}
}
for (iCol = 0; iCol < iLegendNumCols; iCol++) {
pCol = &(pLegend->aCols[iCol]) ;
if (ColCanGrow (pCol))
pCol->xWidth += xSlack / iColsToGrow ;
}
if (pLegend->aCols[LegendCounterCol].xWidth <
pLegend->aCols[LegendCounterCol].xMaxWidth) {
// cut some from the other columns and give them to CounterCol
if (pLegend->aCols[LegendColorCol].xWidth - xScrollWidth >=
pLegend->aCols[LegendColorCol].xMinWidth) {
pLegend->aCols[LegendColorCol].xWidth -= xScrollWidth ;
pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
}
if (pLegend->aCols[LegendInstanceCol].xWidth - xScrollWidth >=
pLegend->aCols[LegendInstanceCol].xMinWidth) {
pLegend->aCols[LegendInstanceCol].xWidth -= xScrollWidth ;
pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
}
if (pLegend->aCols[LegendParentCol].xWidth - xScrollWidth >=
pLegend->aCols[LegendParentCol].xMinWidth) {
pLegend->aCols[LegendParentCol].xWidth -= xScrollWidth ;
pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
}
}
//=============================//
// Set Column positions //
//=============================//
pLegend->aCols[0].xPos = LegendLeftMargin () ;
for (iCol = 1; iCol < iLegendNumCols; iCol++) {
pLegend->aCols[iCol].xPos =
pLegend->aCols[iCol - 1].xPos + pLegend->aCols[iCol - 1].xWidth ;
if (iCol == LegendCounterCol) {
// add some space between Scale/Value col & Counter col
pLegend->aCols[LegendCounterCol].xPos += LegendLeftMargin () ;
}
}
}
void
static
OnPaint (
HWND hWnd
)
{
PLEGEND pLegend ;
HDC hDC ;
PAINTSTRUCT ps ;
hDC = BeginPaint (hWnd, &ps) ;
if (IsLegendLabelVisible ()) {
pLegend = LegendData (hWnd) ;
DrawLegendLabel (pLegend, hDC, hWnd) ;
}
if (LBNumItems (pLegend->hWndItems) == 0) {
WindowInvalidate(pLegend->hWndItems) ;
}
EndPaint (hWnd, &ps) ;
}
void
OnDrawLegendItem (
HWND hWnd,
LPDRAWITEMSTRUCT lpDI
)
{
HFONT hFontPrevious ;
HDC hDC ;
PLEGEND pLegend ;
PLINESTRUCT pLine ;
int iLBIndex ;
COLORREF preBkColor = 0;
COLORREF preTextColor = 0;
BOOL ResetColor = FALSE ;
hDC = lpDI->hDC ;
iLBIndex = DIIndex (lpDI) ;
pLegend = LegendData (hWnd) ;
if (iLBIndex == -1)
pLine = NULL ;
else
pLine = (PLINESTRUCT) LBData (pLegend->hWndItems, iLBIndex) ;
//=============================//
// Set DC attributes //
//=============================//
if (DISelected (lpDI) || pLine == NULL) {
preTextColor = SetTextColor (hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)) ;
preBkColor = SetBkColor (hDC, GetSysColor (COLOR_HIGHLIGHT)) ;
ResetColor = TRUE ;
}
ExtTextOut (hDC, lpDI->rcItem.left, lpDI->rcItem.top,
ETO_OPAQUE, &(lpDI->rcItem), NULL, 0, NULL ) ;
//=============================//
// Draw Legend Item //
//=============================//
hFontPrevious = SelectFont (hDC, pLegend->hFontItems) ;
if (pLine)
DrawLegendItem (pLegend, pLine, lpDI->rcItem.top, hDC) ;
SelectFont (hDC, hFontPrevious) ;
//=============================//
// Draw Focus //
//=============================//
if (DIFocus (lpDI))
DrawFocusRect (hDC, &(lpDI->rcItem)) ;
if (ResetColor == TRUE) {
preTextColor = SetTextColor (hDC, preTextColor) ;
preBkColor = SetBkColor (hDC, preBkColor) ;
}
}
void
static
OnMeasureItem (
HWND hWnd,
LPMEASUREITEMSTRUCT lpMI
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWnd) ;
lpMI->itemHeight = pLegend->yItemHeight ;
}
void
static
OnDestroy (
HWND hWnd
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWnd) ;
MemoryFree (pLegend) ;
}
void
static
OnDoubleClick (
HWND hWnd
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWnd) ;
if (!pLegend)
return ;
switch (pLegend->iLineType) {
case LineTypeChart:
EditChart (hWndMain) ;
break ;
case LineTypeAlert:
EditAlert (hWndAlert) ;
break ;
}
}
void
static
OnSetFocus (
HWND hWnd
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWnd) ;
SetFocus (pLegend->hWndItems) ;
}
void
static
OnSelectionChanged (
HWND hWnd
)
{
PLEGEND pLegend ;
PGRAPHSTRUCT pGraph ;
int iIndex ;
pLegend = LegendData (hWnd) ;
// set the new selected line
iIndex = (int)LBSelection (pLegend->hWndItems) ;
if (iIndex == LB_ERR)
return ;
LegendSetCurrentLine (pLegend, iIndex) ;
if (pLegend->iLineType == LineTypeChart) {
pGraph = GraphData (hWndGraph) ;
if (!PlayingBackLog()) {
// update the min, max, & avg of the current line
UpdateValueBarData (pGraph) ;
}
// update the valuebar display
StatusTimer (hWndGraphStatus, TRUE) ;
// change the Current highlighted line if necessary
if (pGraph && pGraph->HighLightOnOff) {
WindowInvalidate (hWndGraphDisplay) ;
}
}
}
//==========================================================================//
// Exported Functions //
//==========================================================================//
LRESULT
APIENTRY
GraphLegendWndProc (
HWND hWnd,
UINT wMsg,
WPARAM wParam,
LPARAM lParam
)
{
BOOL bCallDefProc ;
LRESULT lReturnValue ;
bCallDefProc = FALSE ;
lReturnValue = 0L ;
switch (wMsg) {
case WM_DELETEITEM:
break ;
case WM_COMMAND:
switch (HIWORD (wParam)) { // switch
case LBN_DBLCLK:
OnDoubleClick (hWnd) ;
break ;
case LBN_SELCHANGE:
OnSelectionChanged (hWnd) ;
break ;
default:
break ;
} // switch
break ;
case WM_CREATE:
OnLegendCreate (hWnd, (LPCREATESTRUCT) lParam) ;
break ;
case WM_DESTROY:
OnDestroy (hWnd) ;
break ;
case WM_DRAWITEM:
OnDrawLegendItem (hWnd, (LPDRAWITEMSTRUCT) lParam) ;
break ;
case WM_MEASUREITEM:
OnMeasureItem (hWnd, (LPMEASUREITEMSTRUCT) lParam) ;
break ;
case WM_PAINT:
OnPaint (hWnd) ;
break ;
case WM_SIZE:
OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
break ;
case WM_SETFOCUS:
OnSetFocus (hWnd) ;
break ;
default:
bCallDefProc = TRUE ;
}
if (bCallDefProc)
lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;
return (lReturnValue);
}
int
LegendMinWidth (
HWND hWnd
)
{
PLEGEND pLegend ;
int iCol ;
int xMinWidth ;
pLegend = LegendData (hWnd) ;
xMinWidth = 0 ;
for (iCol = 0; iCol < iLegendNumCols; iCol++) {
xMinWidth += pLegend->aCols[iCol].xMinWidth ;
}
return (xMinWidth) ;
}
int
LegendMinHeight (
HWND hWnd
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWnd) ;
if (IsLegendLabelVisible ())
return (pLegend->yLabelHeight + pLegend->yItemHeight) ;
else
return (pLegend->yItemHeight) ;
}
int
LegendHeight (
HWND hWnd,
int yGraphHeight
)
/*
Effect: Return the best height for the Legend window given the
number of items and label visibility of the legend, as
well as the overall height of the graph.
*/
{
PLEGEND pLegend ;
int yPreferredHeight ;
pLegend = LegendData (hWnd) ;
yPreferredHeight = yLegendBorderHeight +
pLegend->yItemHeight *
PinInclusive (LBNumItems (pLegend->hWndItems),
1, iLegendMaxVisibleItems) ;
if (IsLegendLabelVisible ())
yPreferredHeight += pLegend->yLabelHeight ;
return (min (yPreferredHeight, yGraphHeight / 2)) ;
}
int
LegendFullHeight (
HWND hWnd,
HDC hDC
)
/*
Effect: Return the best height for the Legend window given the
number of items and label visibility of the legend, as
well as the overall height of the graph.
*/
{
PLEGEND pLegend ;
int yPreferredHeight ;
pLegend = LegendData (hWnd) ;
yPreferredHeight = yLegendBorderHeight +
pLegend->yItemHeight *
LBNumItems (pLegend->hWndItems) ;
if (IsLegendLabelVisible ())
yPreferredHeight += pLegend->yLabelHeight ;
return (yPreferredHeight) ;
}
HWND
CreateGraphLegendWindow (
HWND hWndGraph
)
{
return (CreateWindow (szGraphLegendClass, // class
NULL, // caption
dwGraphLegendWindowStyle, // window style
0, 0, // position
0, 0, // size
hWndGraph, // parent window
NULL, // menu
hInstance, // program instance
(LPVOID) TRUE)) ; // user-supplied data
}
BOOL
GraphLegendInitializeApplication (void)
/*
Called By: GraphInitializeApplication only
*/
{
WNDCLASS wc ;
wc.style = dwGraphLegendClassStyle ;
wc.lpfnWndProc = GraphLegendWndProc ;
wc.hInstance = hInstance ;
wc.cbClsExtra = iGraphLegendClassExtra ;
wc.cbWndExtra = iGraphLegendWindowExtra ;
wc.hIcon = NULL ;
wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
// wc.hbrBackground = hbLightGray ;
wc.hbrBackground = hBrushFace ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = szGraphLegendClass ;
return (RegisterClass (&wc)) ;
}
BOOL
LegendAddItem (
HWND hWnd,
PLINESTRUCT pLine
)
/*
Effect: Add a legend entry for the line pLine. Don't select
the line as current entry here, because this will cause
the scroll bar to unneccesarily appear for a moment.
If you want this line to be the current line, resize
the legend first, then set as current line.
See Also: ChartInsertLine, AlertInsertLine.
*/
{
PLEGEND pLegend ;
pLegend = LegendData (hWnd) ;
LBAdd (pLegend->hWndItems, pLine) ;
return (TRUE) ;
}
void
LegendDeleteItem (
HWND hWndLegend,
PLINE pLine
)
{
PLEGEND pLegend ;
int iIndex ;
int iNextIndex ;
int iNumItems ;
PGRAPHSTRUCT pGraph ;
pLegend = LegendData (hWndLegend) ;
if (!pLegend)
return ;
iNumItems = LBNumItems (pLegend->hWndItems) ;
iIndex = (int)LBFind (pLegend->hWndItems, pLine) ;
if (iIndex != LB_ERR) {
LBDelete (pLegend->hWndItems, iIndex) ;
}
// no need to do anything if iNumItems is 1 to begin with
if (iNumItems != LB_ERR && iNumItems > 1) {
if (iIndex == iNumItems - 1) {
// deleting the last line, then set selection
// to the previous legend line
iNextIndex = iIndex - 1 ;
} else {
// set the selection to the next legend line
iNextIndex = iIndex ;
}
LBSetSelection (pLegend->hWndItems, iNextIndex) ;
LegendSetCurrentLine (pLegend, iNextIndex) ;
if (pLegend->iLineType == LineTypeChart) {
// update the min, max, & avg of the current line
pGraph = GraphData (hWndGraph) ;
if (!PlayingBackLog()) {
// update the min, max, & avg of the current line
UpdateValueBarData (pGraph) ;
}
// update the valuebar display
StatusTimer (hWndGraphStatus, TRUE) ;
}
}
}
PLINE
LegendCurrentLine (
HWND hWndLegend
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWndLegend) ;
if (!pLegend)
return (NULL) ;
return (pLegend->pCurrentLine) ;
}
int
LegendNumItems (
HWND hWndLegend
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWndLegend) ;
return (LBNumItems (pLegend->hWndItems)) ;
}
void
LegendSetSelection (
HWND hWndLegend,
int iIndex
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWndLegend) ;
LBSetSelection (pLegend->hWndItems, iIndex) ;
LegendSetCurrentLine (pLegend, iIndex) ;
}
#ifdef KEEP_PRINT
void
PrintLegend (
HDC hDC,
PGRAPHSTRUCT pGraph,
HWND hWndLegend,
RECT rectLegend
)
{
PLEGEND pLegend ;
int yItemHeight ;
HFONT hFontItems ;
PLINE pLine ;
int iIndex ;
int iIndexNum ;
pLegend = LegendData (hWndLegend) ;
yItemHeight = pLegend->yItemHeight ;
hFontItems = pLegend->hFontItems ;
pLegend->hFontItems = hFontPrinterScales ;
SelectFont (hDC, pLegend->hFontItems) ;
pLegend->yItemHeight = FontHeight (hDC, TRUE) ;
iIndexNum = LBNumItems (pLegend->hWndItems) ;
for (iIndex = 0; iIndex < iIndexNum; iIndex++) {
pLine = (PLINE) LBData (pLegend->hWndItems, iIndex) ;
DrawLegendItem (pLegend, pLine, iIndex * pLegend->yItemHeight, hDC) ;
}
pLegend->hFontItems = hFontItems ;
pLegend->yItemHeight = yItemHeight ;
SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
Rectangle (hDC, 0, 0,
rectLegend.right - rectLegend.left,
rectLegend.bottom - rectLegend.top) ;
}
#endif
void
ClearLegend (
HWND hWndLegend
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWndLegend) ;
if (!pLegend)
return ;
LBReset (pLegend->hWndItems) ;
pLegend->pCurrentLine = NULL ;
}
void
LegendSetRedraw (
HWND hWndLegend,
BOOL bRedraw
)
{
PLEGEND pLegend ;
pLegend = LegendData (hWndLegend) ;
if (!pLegend)
return ;
LBSetRedraw (pLegend->hWndItems, bRedraw) ;
}