|
|
1.1 root 1: //==========================================================================//
2: // Includes //
3: //==========================================================================//
4:
5:
6: #include <stdio.h>
7: #include "perfmon.h"
8: #include "grafdisp.h" // external declarations for this file
9:
10: #include "grafdata.h" // for InsertGraph, et al.
11: #include "graph.h"
12: #include "legend.h"
13: #include "line.h" // for LineCreatePen
14: #include "perfmops.h" // for DoWindowDrag
15: #include "playback.h" // for PlayingBackLog
16: #include "valuebar.h"
17: #include "utils.h"
18: #include "timeline.h" // for IsTLineWindowUp & TLineRedraw
19:
20: //==========================================================================//
21: // Constants //
22: //==========================================================================//
23:
24: // this macro is used in doing a simple DDA (Digital Differential Analyzer)
25: // * 10 + 5 is to make the result round up with .5
26: #define DDA_DISTRIBUTE(TotalTics, numOfData) \
27: ((TotalTics * 10 / numOfData) + 5) / 10
28:
29: HDC hGraphDisplayDC ;
30: //=============================//
31: // GraphDisplay Class //
32: //=============================//
33:
34:
35: TCHAR szGraphDisplayWindowClass[] = TEXT("PerfmonGraphDisplayClass") ;
36: #define dwGraphDisplayClassStyle (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC)
37: #define iGraphDisplayClassExtra (0)
38: #define iGraphDisplayWindowExtra (0)
39: #define dwGraphDisplayWindowStyle (WS_CHILD | WS_VISIBLE)
40:
41:
42:
43: //==========================================================================//
44: // Local Functions //
45: //==========================================================================//
46: BOOL UpdateTimeLine (HDC hDC, PGRAPHSTRUCT pGraph, BOOL getLastTimeLocation) ;
47:
48: #if 0
49: PGRAPHSTRUCT GraphData (HWND hWndGraphDisplay)
50: /*
51: Effect: Return the graph associated with graph display window
52: hWndGraphData. At the present time, we only have one
53: graph data window and one graph structure. In the
54: future, we may have several of each. The graph structure
55: is conceptually instance data of the graph display
56: window. Use of this function allows for easier additions
57: to the code.
58: */
59: {
60: return (pGraphs) ;
61: }
62: #endif
63:
64: INT ScaleAndInvertY (FLOAT ey,
65: PLINESTRUCT pLineStruct,
66: PGRAPHSTRUCT pGraph)
67: /*
68: Effect: Given data value ey, scale and fit the value to fit
69: within the graph data area of the window, considering
70: the scale set for the line and the current size of the
71: data rectangle.
72: */
73: { // ScaleAndInvertY
74: INT yGraphDataHeight, // Height of graph area
75: yInverted ; // Scaled & Inverted Y.
76: FLOAT eppd,
77: eyScaled ;
78:
79:
80: // Take care of any scaling now, at output time.
81: ey *= pLineStruct->eScale ;
82:
83: // Calculate the Cy of the graph area.
84: yGraphDataHeight = pGraph->rectData.bottom - pGraph->rectData.top ;
85:
86: // Calculate the pixels per data point.
87: eppd = (FLOAT) ((FLOAT) yGraphDataHeight / (FLOAT) pGraph->gOptions.iVertMax) ;
88: eyScaled = eppd * ey ;
89: yInverted = (INT) (((FLOAT) yGraphDataHeight) - eyScaled) ;
90:
91: yInverted += pGraph->rectData.top ;
92:
93: // Clamp the range to fit with in the graph portion of the windows
94: yInverted = PinInclusive (yInverted,
95: pGraph->rectData.top, pGraph->rectData.bottom) ;
96: return (yInverted) ;
97: } // ScaleAndInvertY
98:
99:
100:
101: BOOL DrawGrid (HDC hDC,
102: PGRAPHSTRUCT pGraph,
103: LPRECT lpRect,
104: BOOL bForPaint)
105: /*
106: Effect: Draw the grid lines in the graph display window.
107: These grid lines are in the graph data area only,
108: which is indicated by pGraph->rectData.
109:
110: Called By: OnPaint only.
111: */
112: { // DrawGrid
113: int iGrid, iLines ;
114: int xGrid, yGrid ;
115: POINT aPoints [4 * iGraphMaxTics] ;
116: DWORD aCounts [2 * iGraphMaxTics] ;
117: HPEN hPenPrevious ;
118: int bottomAdjust ;
119:
120: if (!pGraph->gOptions.bHorzGridChecked &&
121: !pGraph->gOptions.bVertGridChecked)
122: return (FALSE) ;
123:
124:
125: hPenPrevious = SelectPen (hDC, IsPrinterDC (hDC) ?
126: GetStockObject (BLACK_PEN) : pGraph->hGridPen) ;
127:
128: iLines = 0 ;
129:
130: if (pGraph->gOptions.bHorzGridChecked)
131: {
132: for (iGrid = 1 ;
133: iGrid < pGraph->yNumTics ;
134: iGrid++)
135: { // for
136: yGrid = pGraph->ayTics[iGrid] + pGraph->rectData.top ;
137: if (yGrid >= lpRect->top &&
138: yGrid <= lpRect->bottom)
139: { // if
140: aPoints[2 * iLines].x = lpRect->left ;
141: aPoints[2 * iLines].y = yGrid ;
142: aPoints[2 * iLines + 1].x = lpRect->right ;
143: aPoints[2 * iLines + 1].y = yGrid ;
144:
145: aCounts[iLines] = 2 ;
146: iLines++ ;
147: } // if
148: } // for
149: } // if
150:
151: if (pGraph->gOptions.bVertGridChecked)
152: {
153: bottomAdjust = lpRect->bottom + (bForPaint ? 1 : 0) ;
154: for (iGrid = 1 ;
155: iGrid < pGraph->xNumTics ;
156: iGrid++)
157: { // for
158: xGrid = pGraph->axTics[iGrid] + pGraph->rectData.left ;
159: if (xGrid >= lpRect->left &&
160: xGrid <= lpRect->right)
161: { // if
162: aPoints[2 * iLines].x = xGrid ;
163: aPoints[2 * iLines].y = lpRect->top ;
164: aPoints[2 * iLines + 1].x = xGrid ;
165: aPoints[2 * iLines + 1].y = bottomAdjust ;
166:
167: aCounts[iLines] = 2 ;
168: iLines++ ;
169: } // if
170: } // for
171: } // if
172:
173: if (iLines)
174: PolyPolyline (hDC, aPoints, aCounts, iLines) ;
175:
176: SelectPen (hDC, hPenPrevious) ;
177:
178: return (TRUE) ;
179: } // DrawGrid
180:
181:
182:
183: BOOL DrawBarChartData (HDC hDC,
184: PGRAPHSTRUCT pGraph)
185: { // DrawBarChartData
186: PLINESTRUCT pLineStruct ;
187: PFLOAT pDataPoints ;
188: INT nLegendItems,
189: cx,
190: cxBar,
191: xDataPoint,
192: y ;
193: RECT rectBar ;
194: RECT rectBkgrnd ;
195: HBRUSH hOldBrush ;
196: FLOAT eValue ;
197: PLINESTRUCT pCurrentLine ;
198:
199: // Determine how many items are in the legend.
200:
201: nLegendItems = 0 ;
202:
203: for (pLineStruct = pGraph->pLineFirst ;
204: pLineStruct ;
205: pLineStruct = pLineStruct->pLineNext)
206: { // for
207: nLegendItems++ ;
208: } // for
209:
210: if (nLegendItems == 0)
211: return(FALSE) ;
212:
213: // get current select line for highlighting
214: if (pGraph->HighLightOnOff)
215: {
216: pCurrentLine = CurrentGraphLine (hWndGraph) ;
217: }
218: else
219: {
220: pCurrentLine = NULL ;
221: }
222:
223: // Determine the width of each bar.
224: cx = pGraph->rectData.right - pGraph->rectData.left ;
225:
226:
227: if (PlayingBackLog())
228: {
229: // get the average using the start and stop data point
230: // from the log file
231: PlaybackLines (pGraph->pSystemFirst,
232: pGraph->pLineFirst,
233: PlaybackLog.StartIndexPos.iPosition) ;
234: PlaybackLines (pGraph->pSystemFirst,
235: pGraph->pLineFirst,
236: PlaybackLog.StopIndexPos.iPosition) ;
237: }
238: else
239: {
240: // Loop through all the DataLines and draw a bar for
241: // it's last value.
242: xDataPoint = pGraph->gKnownValue % pGraph->gMaxValues ;
243: }
244:
245: rectBar.bottom = pGraph->rectData.bottom + 1 ;
246:
247: rectBkgrnd = pGraph->rectData ;
248:
249: hOldBrush = SelectBrush (hDC, hBrushFace) ;
250:
251: PatBlt (hDC,
252: rectBkgrnd.left, rectBkgrnd.top,
253: rectBkgrnd.right - rectBkgrnd.left,
254: rectBkgrnd.bottom - rectBkgrnd.top + 1,
255: PATCOPY) ;
256: DrawGrid(hDC, pGraph, &(rectBkgrnd), FALSE) ;
257:
258: rectBar.right = pGraph->rectData.left ;
259: for (pLineStruct = pGraph->pLineFirst ;
260: pLineStruct ;
261: pLineStruct = pLineStruct->pLineNext)
262: { // for
263: pDataPoints = pLineStruct->lnValues ;
264:
265: if (PlayingBackLog())
266: {
267: eValue = (*(pLineStruct->valNext))(pLineStruct) ;
268: }
269: else
270: {
271: eValue = pDataPoints[xDataPoint] ;
272: }
273:
274:
275: y = ScaleAndInvertY (eValue,
276: pLineStruct,
277: pGraph) ;
278:
279: rectBar.left = rectBar.right ;
280: rectBar.top = y ;
281:
282: // nomore line to draw
283: if (nLegendItems == 0 )
284: {
285: break ;
286: }
287:
288: cxBar = DDA_DISTRIBUTE (cx, nLegendItems) ;
289: rectBar.right = rectBar.left + cxBar ;
290:
291: // setup for next DDA
292: nLegendItems-- ;
293: cx -= cxBar ;
294:
295: // NOTE: this handle creation should be moved to line
296: // create time.
297:
298: if (pCurrentLine == pLineStruct)
299: {
300: SetBkColor (hDC, crWhite) ;
301: }
302: else
303: {
304: SetBkColor (hDC, pLineStruct->Visual.crColor) ;
305: }
306: ExtTextOut (hDC, rectBar.right, rectBar.top, ETO_OPAQUE,
307: &rectBar, NULL, 0, NULL) ;
308: } // for
309:
310: return (TRUE) ;
311: }
312:
313:
314: /***************************************************************************
315: * DrawTLGraphData - Draw Time Line Graph Data.
316: *
317: * Some notes about drawing the DataPoint graphs.
318: *
319: * 1] It's real expensive to make a GDI call. So, we do not
320: * make a MoveToEx and LineTo call for each point. Instead
321: * we create a polyline and send it down to GDI.
322: *
323: * 2] The X coordinates for each point in the polyline is generated
324: * from our favorite xDataPoint to xWindows DDA.
325: *
326: * 3] The Y coordinate is generated from the pLineStruct->lnValues[x]
327: * data associated with each line.
328: ***************************************************************************/
329: BOOL DrawTLGraphData (HDC hDC,
330: BOOL bForPaint,
331: PRECT prctPaint,
332: PGRAPHSTRUCT pGraph)
333: /*
334: Called By: UpdateGraphDisplay only.
335: */
336: {
337: PLINESTRUCT pLineStruct ;
338: HPEN hPen = 0 ;
339: HPEN hOldPen ;
340: PFLOAT pDataPoints ;
341: INT i, j,
342: iValidValues,
343: xDispDataPoint,
344: xLeftLimit,
345: xRightLimit ;
346: PPOINT pptDataPoints ;
347: INT numOfData, rectWidth, xPos ;
348: PLINESTRUCT pCurrentLine ;
349: INT DrawZeroPoint = 0 ;
350:
351: // SetBkColor (hDC, crLightGray) ;
352:
353: if (!IsPrinterDC (hDC))
354: {
355: if (bForPaint)
356: {
357: IntersectClipRect (hDC,
358: pGraph->rectData.left,
359: pGraph->rectData.top,
360: pGraph->rectData.right,
361: pGraph->rectData.bottom + 1) ;
362: }
363: else
364: {
365: IntersectClipRect (hDC,
366: pGraph->rectData.left,
367: pGraph->rectData.top,
368: PlayingBackLog () ?
369: pGraph->rectData.right :
370: min (pGraph->rectData.right,
371: pGraph->gTimeLine.xLastTime + 2),
372: pGraph->rectData.bottom + 1) ;
373: }
374: }
375:
376: xLeftLimit = prctPaint->left - pGraph->gTimeLine.ppd - 1 ;
377: // xRightLimit = prctPaint->right + pGraph->gTimeLine.ppd ;
378: xRightLimit = prctPaint->right ;
379: pptDataPoints = pGraph->pptDataPoints ;
380:
381: iValidValues = pGraph->gTimeLine.iValidValues ;
382:
383: if (!PlayingBackLog() &&
384: pGraph->gOptions.iGraphOrHistogram == LINE_GRAPH)
385: {
386: // drawing the 0th at the end of the chart.
387: DrawZeroPoint = 1 ;
388: if (iValidValues == pGraph->gMaxValues)
389: {
390: iValidValues++ ;
391: }
392: }
393:
394: // get current select line for highlighting
395: if (pGraph->HighLightOnOff)
396: {
397: pCurrentLine = CurrentGraphLine (hWndGraph) ;
398: }
399: else
400: {
401: pCurrentLine = NULL ;
402: }
403:
404: // loop through lines to plot
405: for (pLineStruct = pGraph->pLineFirst ;
406: pLineStruct || pCurrentLine;
407: pLineStruct = pLineStruct->pLineNext)
408: { // for
409:
410: if (pLineStruct == NULL)
411: {
412: // now draw the current line
413: pLineStruct = pCurrentLine ;
414: }
415: else if (pLineStruct == pCurrentLine)
416: {
417: // skip this line and draw it later
418: continue ;
419: }
420:
421: // "Localize" some variables from the line data structure.
422: pDataPoints = pLineStruct->lnValues ;
423:
424:
425: rectWidth = pGraph->rectData.right - pGraph->rectData.left ;
426: numOfData = pGraph->gMaxValues - 1 + DrawZeroPoint ;
427:
428: // Generate the polyline data.
429: xDispDataPoint = pGraph->rectData.left ;
430:
431: // Only process points that lie within the update region.
432: // Also only process points that have valid data.
433: j = 0 ;
434:
435: for (i = 0 ; i < iValidValues ; i++)
436: { // for
437: if (xDispDataPoint > xRightLimit)
438: {
439: // we are done!
440: break ;
441: }
442: if (xDispDataPoint >= xLeftLimit)
443: {
444: // It is within the limits, plot the point
445: pptDataPoints[j].x = xDispDataPoint ;
446: pptDataPoints[j].y = ScaleAndInvertY (
447: (i == pGraph->gMaxValues) ? pDataPoints[0] : pDataPoints[i],
448: pLineStruct,
449: pGraph) ;
450: j++ ;
451: } // if
452:
453: // setup for the next point
454: if (!numOfData)
455: {
456: // no more points to go
457: break ;
458: }
459:
460: xPos = DDA_DISTRIBUTE (rectWidth, numOfData) ;
461: xDispDataPoint += xPos ;
462: numOfData-- ;
463: rectWidth -= xPos ;
464: } // for i
465:
466: // only need to draw the line if there is point to draw.
467: if (j > 0)
468: {
469: // Set the pen color and draw the polyline.
470: if (IsPrinterDC (hDC))
471: {
472: hPen = LineCreatePen (hDC, &(pLineStruct->Visual), TRUE) ;
473: hOldPen = SelectObject (hDC, hPen) ;
474: }
475: else
476: {
477: if (pCurrentLine == pLineStruct)
478: {
479: // highlight this line by turning it into White color
480: hOldPen = SelectObject (hDC, hWhitePen) ;
481: }
482: else
483: {
484: SelectObject (hDC, pLineStruct->hPen) ;
485: }
486: }
487:
488: Polyline(hDC, pptDataPoints, j) ;
489:
490: if (hPen)
491: {
492: SelectObject (hDC, hOldPen) ;
493:
494: if (hPen != hWhitePen)
495: {
496: DeletePen (hPen) ;
497: }
498: hPen = 0 ;
499: }
500: }
501:
502: if (pCurrentLine == pLineStruct)
503: {
504: // We are done...
505: break ;
506: }
507: } // for pLine
508:
509: if (IsTLineWindowUp())
510: {
511: // re-draw the timelines if need
512: TLineRedraw (hDC, pGraph) ;
513: }
514:
515: // reset the clipping region
516: SelectClipRgn (hDC, pGraph->hGraphRgn) ;
517:
518: return (TRUE) ;
519: } // DrawTLGraphData
520:
521:
522:
523: /***************************************************************************
524: * bInitTimeLine - Initialize the fields of the time line structure.
525: ***************************************************************************/
526: BOOL bInitTimeLine(PGRAPHSTRUCT pGraph)
527: {
528:
529: pGraph->gTimeLine.xLastTime = 0 ;
530: pGraph->gTimeLine.ppd = 0 ;
531: pGraph->gTimeLine.rppd = 0 ;
532: pGraph->gTimeLine.iValidValues = 1 ;
533:
534: return (TRUE) ;
535:
536: }
537:
538:
539: /***************************************************************************
540: * Scale Time Line
541: *
542: * This routine should be called from the WM_SIZE message.
543: * It does the scaling from the number of data points to the
544: * size of the window.
545: ***************************************************************************/
546: void ScaleTimeLine (PGRAPHSTRUCT pGraph)
547: {
548: INT nDataPoints,
549: cxClient ;
550:
551: // Calculate the pels per data point.
552: nDataPoints = pGraph->gMaxValues - 1 ;
553: cxClient = pGraph->rectData.right - pGraph->rectData.left ;
554:
555: // ppd = Pixels per DataPoint.
556: // rppd = Remaining Pixels per DataPoint.
557: pGraph->gTimeLine.ppd = cxClient / nDataPoints ;
558: pGraph->gTimeLine.rppd = cxClient % nDataPoints ;
559: }
560:
561:
562: void DisplayTimeLine(HDC hDC, PGRAPHSTRUCT pGraph)
563: /*
564: Called By: OnPaint only.
565:
566: Assert: xDisplayPoint has been set by UpdateTimeLine on this
567: same timer tick.
568: */
569: { // DisplayTimeLine
570: INT xDisplayPoint ;
571: RECT rect ;
572:
573: if (pGraph->gTimeLine.xLastTime == -1)
574: {
575: UpdateTimeLine (hGraphDisplayDC, pGraph, TRUE) ;
576: }
577:
578: // xDisplayPoint is X coordinate to display the time line at.
579: if ((xDisplayPoint = pGraph->gTimeLine.xLastTime) == 0)
580: return ;
581:
582: SelectBrush (hDC, pGraph->hbRed) ;
583:
584: if (xDisplayPoint >= pGraph->rectData.right)
585: {
586: rect.left = pGraph->rectData.left ;
587: }
588: else
589: {
590: // rect.left = xDisplayPoint++ ;
591: rect.left = xDisplayPoint ;
592: }
593: rect.top = pGraph->rectData.top ;
594: rect.right = rect.left + 2 ;
595: rect.bottom = pGraph->rectData.bottom ;
596:
597: // IntersectRect (&rect, &rect, &pGraph->rectData) ;
598: if (rect.right > pGraph->rectData.right)
599: {
600: rect.right = pGraph->rectData.right ;
601: }
602: PatBlt (hDC,
603: rect.left, rect.top,
604: rect.right - rect.left,
605: rect.bottom - rect.top + 1 ,
606: PATCOPY) ;
607:
608: } // DisplayTimeLine
609:
610:
611:
612: int SuggestedNumTics (int iRange)
613: /*
614: Effect: Return an appropriate number of tic marks to display
615: within iRange pixels.
616:
617: These numbers are empirically chosen for pleasing
618: results.
619: */
620: { // SuggestedNumTics
621: if (iRange < 20)
622: return (0) ;
623:
624: if (iRange < 50)
625: return (2) ;
626:
627: if (iRange < 100)
628: return (4) ;
629:
630: if (iRange < 150)
631: return (5) ;
632:
633: if (iRange < 300)
634: return (10) ;
635:
636: if (iRange < 500)
637: return (20) ;
638:
639: return (25) ;
640: } // SuggestedNumTics
641:
642:
643:
644: void SetGridPositions (PGRAPHSTRUCT pGraph)
645: { // SetGridPositions
646: int xDataWidth ;
647: int yDataHeight ;
648:
649: int iCurrentTicPixels ;
650: int iNumTics ;
651:
652: int i ;
653:
654:
655: //=============================//
656: // Set number of Tics //
657: //=============================//
658:
659: xDataWidth = pGraph->rectData.right - pGraph->rectData.left ;
660: yDataHeight = pGraph->rectData.bottom - pGraph->rectData.top ;
661:
662: pGraph->xNumTics = PinInclusive (SuggestedNumTics (xDataWidth),
663: 0, iGraphMaxTics) ;
664: pGraph->yNumTics = PinInclusive (SuggestedNumTics (yDataHeight),
665: 0, iGraphMaxTics) ;
666:
667: // if we have more tics than possible integral values, reduce the number
668: // of tics.
669: if (pGraph->gOptions.iVertMax < pGraph->yNumTics)
670: pGraph->yNumTics = pGraph->gOptions.iVertMax ;
671:
672:
673: //=============================//
674: // Set X Tic Positions //
675: //=============================//
676:
677: if (pGraph->xNumTics)
678: {
679: iNumTics = pGraph->xNumTics ;
680:
681: pGraph->axTics[0] = 0 ;
682: for (i = 1 ;
683: i < pGraph->xNumTics ;
684: i++)
685: { // for
686: if (iNumTics == 0)
687: {
688: break ;
689: }
690: iCurrentTicPixels = DDA_DISTRIBUTE (xDataWidth, iNumTics) ;
691: pGraph->axTics [i] = pGraph->axTics [i - 1] + iCurrentTicPixels ;
692:
693: xDataWidth -= iCurrentTicPixels ;
694: iNumTics-- ;
695: } // for
696: } // if
697:
698:
699: //=============================//
700: // Set Y Tic Positions //
701: //=============================//
702:
703: if (pGraph->yNumTics)
704: {
705: iNumTics = pGraph->yNumTics ;
706:
707: pGraph->ayTics[0] = 0 ;
708: for (i = 1 ;
709: i < pGraph->yNumTics ;
710: i++)
711: { // for
712: if (iNumTics == 0)
713: {
714: break ;
715: }
716: iCurrentTicPixels = DDA_DISTRIBUTE (yDataHeight, iNumTics) ;
717: pGraph->ayTics [i] = pGraph->ayTics [i- 1] + iCurrentTicPixels ;
718:
719: yDataHeight -= iCurrentTicPixels ;
720: iNumTics-- ;
721: } // for
722: } // if
723: } // SetGridPositions
724:
725:
726:
727: int GraphVerticalScaleWidth (HDC hDC,
728: PGRAPHSTRUCT pGraph)
729: {
730: TCHAR szMaxValue [20] ;
731: int xWidth ;
732:
733: if (!pGraph->gOptions.bLabelsChecked)
734: return (0) ;
735:
736:
737: // SelectFont (hDC, IsPrinterDC (hDC) ? hFontPrinterScales : hFontScales) ;
738:
739:
740: TSPRINTF (szMaxValue, TEXT(" %1d "),
741: pGraph->gOptions.iVertMax * 10 ) ;
742:
743: xWidth = TextWidth (hDC, szMaxValue) ;
744:
745: return (xWidth) ;
746: }
747:
748:
749:
750: void DrawGraphScale (HDC hDC,
751: PGRAPHSTRUCT pGraph)
752: {
753: TCHAR szScale [20] ;
754:
755: INT len,
756: i,
757: nLines,
758: iUnitsPerLine ;
759: FLOAT ePercentOfTotal ;
760: FLOAT eDiff ;
761: BOOL bUseFloatingPt = FALSE ;
762:
763: //=============================//
764: // Draw Vertical Scale? //
765: //=============================//
766:
767: if (!pGraph->gOptions.bLabelsChecked)
768: return ;
769:
770: // Get the number of lines.
771: nLines = pGraph->yNumTics ;
772:
773: // Calculate what percentage of the total each line represents.
774: ePercentOfTotal = ((FLOAT) 1.0) / ((FLOAT) nLines) ;
775:
776: // Calculate the amount (number of units) of the Vertical max each
777: // each line in the graph represents.
778: iUnitsPerLine = (INT) ((FLOAT) pGraph->gOptions.iVertMax * ePercentOfTotal) ;
779: ePercentOfTotal *= (FLOAT) pGraph->gOptions.iVertMax ;
780: eDiff = (FLOAT)iUnitsPerLine - ePercentOfTotal ;
781: if (eDiff < (FLOAT) 0.0)
782: eDiff = -eDiff ;
783:
784: if (eDiff > (FLOAT) 0.1)
785: bUseFloatingPt = TRUE ;
786:
787: //=============================//
788: // Set Drawing Attributes //
789: //=============================//
790:
791: // SelectFont (hDC, IsPrinterDC (hDC) ? hFontPrinterScales : hFontScales) ;
792: SetBkMode(hDC, TRANSPARENT) ;
793: SetTextAlign (hDC, TA_TOP | TA_RIGHT) ;
794: SelectObject(hDC, GetStockObject (BLACK_PEN)) ;
795:
796: // Set the background color to gray
797: if (!IsPrinterDC (hDC))
798: FillRect (hDC, &(pGraph->rectVertScale), hbLightGray) ;
799:
800: // Now Output each string.
801: for (i = 0 ;
802: i < nLines ;
803: i++)
804: { // for
805: if (bUseFloatingPt)
806: {
807: len = TSPRINTF (szScale, TEXT("%1.1f"),
808: (FLOAT)pGraph->gOptions.iVertMax - ((FLOAT)i *
809: ePercentOfTotal)) ;
810: TextOut (hDC,
811: pGraph->rectVertScale.right,
812: pGraph->ayTics[i] +
813: pGraph->rectData.top - HalfTextHeight,
814: szScale,
815: lstrlen(szScale)) ;
816: }
817: else
818: {
819: len = TSPRINTF (szScale, TEXT("%d"),
820: pGraph->gOptions.iVertMax - (i * iUnitsPerLine)) ;
821: TextOut (hDC,
822: pGraph->rectVertScale.right,
823: pGraph->ayTics[i] +
824: pGraph->rectData.top - HalfTextHeight,
825: szScale,
826: lstrlen(szScale)) ;
827: }
828: } // for
829:
830: // Output the "min value" separately.
831: TextOut (hDC,
832: pGraph->rectVertScale.right,
833: pGraph->rectData.bottom - HalfTextHeight,
834: TEXT("0"),
835: 1) ;
836: } // DrawGraphScale
837:
838:
839:
840: void SizeGraphDisplayComponentsRect (HDC hDC,
841: PGRAPHSTRUCT pGraph,
842: RECT rectDisplay)
843: { // SizeGraphDisplayComponentsRect
844: int xScaleWidth ;
845:
846: if (!rectDisplay.right || !rectDisplay.bottom)
847: return ;
848:
849: //=============================//
850: // Size the Vertical Scale //
851: //=============================//
852:
853: xScaleWidth = GraphVerticalScaleWidth (hDC, pGraph) ;
854: pGraph->rectVertScale.left = rectDisplay.left ;
855: pGraph->rectVertScale.top = rectDisplay.top ;
856: pGraph->rectVertScale.right = rectDisplay.left + xScaleWidth ;
857: pGraph->rectVertScale.bottom = rectDisplay.bottom ;
858:
859: //=============================//
860: // Size the Horizontal Scale //
861: //=============================//
862:
863: pGraph->rectHorzScale.left = 0 ;
864: pGraph->rectHorzScale.top = 0 ;
865: pGraph->rectHorzScale.right = 0 ;
866: pGraph->rectHorzScale.bottom = 0 ;
867:
868: //=============================//
869: // Size the Data Area //
870: //=============================//
871:
872: pGraph->rectData.left = pGraph->rectVertScale.right + 3 + ThreeDPad ;
873: pGraph->rectData.right = rectDisplay.right - 5 - ThreeDPad ;
874: pGraph->rectData.top = rectDisplay.top + 5 + ThreeDPad ;
875: pGraph->rectData.bottom = rectDisplay.bottom - 5 - ThreeDPad ;
876:
877: SetGridPositions (pGraph) ;
878: ScaleTimeLine (pGraph) ;
879:
880: //==========================================//
881: // Invalidate the last time line poisition //
882: //==========================================//
883: pGraph->gTimeLine.xLastTime = -1 ;
884:
885: if (pGraph->hGraphRgn)
886: {
887: DeleteObject (pGraph->hGraphRgn) ;
888: }
889:
890: pGraph->hGraphRgn = CreateRectRgn (rectDisplay.left,
891: rectDisplay.top,
892: rectDisplay.right,
893: rectDisplay.bottom) ;
894:
895: SelectClipRgn (hDC, pGraph->hGraphRgn) ;
896:
897: } // SizeGraphDisplayComponentsRect
898:
899:
900: void SizeGraphDisplayComponents (HWND hWnd)
901: /*
902: Effect: Given the graph display window hWnd, of size
903: (xWidth x yHeight), determine the size and position
904: of the various graph display components: the vertical
905: scale, the horizontal scale, and the data area.
906:
907: Called By: OnSize, any other routine that changes the visibility
908: of a vertical or horizontal scale.
909:
910: Note: This function has multiple return points.
911: */
912: { // SizeGraphDisplayComponents
913: PGRAPHSTRUCT pGraph ;
914: RECT rectClient ;
915:
916: pGraph = GraphData (hWnd) ;
917: GetClientRect (hWnd, &rectClient) ;
918:
919: SizeGraphDisplayComponentsRect (hGraphDisplayDC, pGraph, rectClient) ;
920: }
921:
922:
923: void UpdateGraphDisplay (HDC hDC,
924: BOOL bForPaint,
925: LPRECT lpRect,
926: PGRAPHSTRUCT pGraph)
927: /*
928: Effect: Draw the portions of the graph that change as the
929: graph's values change. This includes the background,
930: the grid, the lines, and the timeline.
931: */
932: { // UpdateGraphDisplay
933: RECT rectUpdate ;
934:
935: if (!bForPaint && !IsPrinterDC (hDC) &&
936: pGraph->gOptions.iGraphOrHistogram == LINE_GRAPH)
937: {
938: HBRUSH hOldBrush ;
939:
940: rectUpdate = pGraph->rectData ;
941: rectUpdate.bottom += 1 ;
942:
943: IntersectRect (&rectUpdate, lpRect, &rectUpdate) ;
944: hOldBrush = SelectBrush (hDC, hBrushFace) ;
945:
946: PatBlt (hDC,
947: rectUpdate.left, rectUpdate.top,
948: rectUpdate.right - rectUpdate.left,
949: rectUpdate.bottom - rectUpdate.top,
950: PATCOPY) ;
951: }
952: else
953: {
954: IntersectRect (&rectUpdate, lpRect, &pGraph->rectData) ;
955: }
956:
957: if (pGraph->gOptions.iGraphOrHistogram == LINE_GRAPH)
958: {
959: DrawGrid(hDC, pGraph, &rectUpdate, bForPaint) ;
960: if (pGraph->pLineFirst != NULL)
961: {
962: DrawTLGraphData(hDC, bForPaint, &rectUpdate, pGraph) ;
963: if (!PlayingBackLog ())
964: DisplayTimeLine(hDC, pGraph) ;
965: }
966: }
967: else
968: {
969: DrawBarChartData (hDC, pGraph) ;
970: }
971: } // UpdateGraphDisplay
972:
973:
974: BOOL UpdateTimeLine (HDC hDC,
975: PGRAPHSTRUCT pGraph,
976: BOOL getLastTimeLocation)
977: /*
978: Called By: GraphTimer only.
979:
980: See Also: UpdateGraphDisplay.
981: */
982: {
983: INT i,
984: xDisplayPoint,
985: xDataPoint ;
986: RECT rctUpdate ;
987: INT xLastTime ;
988: INT rectWidth,
989: xPos,
990: numOfPoints ;
991:
992:
993: if ((xLastTime = pGraph->gTimeLine.xLastTime) != 0)
994: {
995: if ((pGraph->gKnownValue % pGraph->gMaxValues) == 1)
996: {
997: // Data wrap around case
998: rctUpdate.left = pGraph->rectData.left ;
999: rctUpdate.right = pGraph->rectData.left +
1000: pGraph->gTimeLine.ppd + 1 ;
1001: }
1002: else
1003: {
1004: rctUpdate.left = xLastTime - pGraph->gTimeLine.ppd ;
1005: rctUpdate.right = xLastTime +
1006: pGraph->gTimeLine.ppd + 1 ;
1007: }
1008: rctUpdate.top = pGraph->rectData.top ;
1009: rctUpdate.bottom = pGraph->rectData.bottom + 1 ;
1010: }
1011:
1012: // Calculate where to draw the time line.
1013: // This is done by running a simple DDA (Digital Differential Analyzer)
1014: // We have to position the time depending upon the size of the
1015: // graph window. In essence we need to calculate the x display
1016: // coordinate.
1017:
1018: // Note we should wrap Known Value in UpdateGLData.
1019: // We should also use a data buffer of 256 bytes so we can
1020: // wrap with and AND.
1021:
1022: // xDataPoint = pGraph->gKnownValue ;
1023: xDataPoint = pGraph->gKnownValue % pGraph->gMaxValues ;
1024:
1025: xDisplayPoint = pGraph->rectData.left ;
1026:
1027: numOfPoints = pGraph->gMaxValues - 1 ;
1028:
1029: if (!PlayingBackLog() &&
1030: pGraph->gOptions.iGraphOrHistogram == LINE_GRAPH)
1031: {
1032: // drawing the 0th at the end of the chart.
1033: // So, we do have gMaxValues points
1034: numOfPoints++ ;
1035: if ((pGraph->gKnownValue % pGraph->gMaxValues) == 0)
1036: {
1037: xDataPoint = pGraph->gMaxValues ;
1038: }
1039: }
1040:
1041: rectWidth = pGraph->rectData.right - pGraph->rectData.left ;
1042:
1043: for (i = 0 ; i < xDataPoint ; i++)
1044: {
1045: if (numOfPoints == 0)
1046: {
1047: break ;
1048: }
1049: xPos = DDA_DISTRIBUTE (rectWidth, numOfPoints) ;
1050: xDisplayPoint += xPos ;
1051: rectWidth -= xPos ;
1052: numOfPoints-- ;
1053: } // for
1054:
1055: pGraph->gTimeLine.xLastTime = xDisplayPoint ;
1056:
1057: if (!getLastTimeLocation && iPerfmonView == IDM_VIEWCHART && !bPerfmonIconic)
1058: {
1059: UpdateGraphDisplay (hDC, FALSE, &rctUpdate, pGraph) ;
1060: }
1061:
1062: return(TRUE) ;
1063: }
1064:
1065:
1066: //==========================================================================//
1067: // Message Handlers //
1068: //==========================================================================//
1069:
1070:
1071: void /*static*/ OnCreate (HWND hWnd)
1072: /*
1073: Effect: Perform all actions needed when a GraphDisplay window is
1074: created.
1075: In particular, initialize the graph instance data and
1076: create the child windows.
1077:
1078: Called By: GraphDisplayWndProc, in response to a WM_CREATE message.
1079: */
1080: { // OnCreate
1081: LOGBRUSH LogBrush ;
1082: TEXTMETRIC tmScales ;
1083:
1084: hGraphDisplayDC = GetDC(hWnd) ;
1085:
1086: SelectFont(hGraphDisplayDC, hFontScales) ;
1087: GetTextMetrics(hGraphDisplayDC, &tmScales) ;
1088: HalfTextHeight = tmScales.tmHeight / 2 ;
1089:
1090: SetBkColor (hGraphDisplayDC, crLightGray) ;
1091:
1092:
1093: InsertGraph(hWnd) ;
1094: bInitTimeLine(pGraphs) ;
1095:
1096: pGraphs->hWnd = hWnd ;
1097:
1098: // Create the brush and pen used by the time line.
1099: // We don't want to create these on every timer tick.
1100:
1101: LogBrush.lbStyle = BS_SOLID ;
1102: LogBrush.lbColor = RGB(0xff, 0, 0) ;
1103: LogBrush.lbHatch = 0 ;
1104:
1105: // Now get the system resources we use "all the time"
1106: pGraphs->hbRed = CreateBrushIndirect(&LogBrush) ;
1107: pGraphs->hGridPen = CreatePen (PS_SOLID, 1, crGray) ;
1108:
1109: pGraphs->xNumTics = 0 ;
1110: pGraphs->yNumTics = 0 ;
1111: } // OnCreate
1112:
1113:
1114: void /*static*/ OnSize (HWND hWnd,
1115: WORD xWidth,
1116: WORD yHeight)
1117: { // OnSize
1118: PGRAPHSTRUCT pGraph ;
1119:
1120: pGraph = GraphData (hWnd) ;
1121:
1122: SizeGraphDisplayComponents (hWnd) ;
1123: } // OnSize
1124:
1125:
1126: void /*static*/ OnPaint (HWND hWnd)
1127: {
1128: HDC hDC ;
1129: PAINTSTRUCT ps ;
1130: PGRAPHSTRUCT pGraph ;
1131:
1132: pGraph = GraphData (hWnd) ;
1133: hDC = BeginPaint(hWnd, &ps) ;
1134:
1135: DrawGraphDisplay (hDC, ps.rcPaint, pGraph) ;
1136:
1137: EndPaint(hWnd, &ps) ;
1138: } // OnPaint
1139:
1140:
1141: //==========================================================================//
1142: // Exported Functions //
1143: //==========================================================================//
1144:
1145: #ifdef KEEP_PRINT
1146: void PrintGraphDisplay (HDC hDC,
1147: PGRAPHSTRUCT pGraph)
1148: {
1149: DrawGraphScale (hDC, pGraph) ;
1150:
1151:
1152: //!! UpdateGraphDisplay (hDC, TRUE, &(pGraph->rectData), pGraph) ;
1153:
1154: IntersectClipRect (hDC, 0, 0, 10000, 10000) ;
1155: SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
1156: SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
1157: Rectangle (hDC,
1158: pGraph->rectData.left,
1159: pGraph->rectData.top,
1160: pGraph->rectData.right,
1161: pGraph->rectData.bottom) ;
1162: } // PrintGraphDisplay
1163: #endif
1164:
1165:
1166:
1167: void DrawGraphDisplay (HDC hDC,
1168: RECT rectDraw,
1169: PGRAPHSTRUCT pGraph)
1170: {
1171: BOOL bPaintScale ;
1172: INT LocalThreeDPad = ThreeDPad - 1 ;
1173:
1174: // Only draw the vertical labels if the paint rectangle
1175: // any portion of the window to the left of the graph area.
1176:
1177: bPaintScale = (rectDraw.left <= pGraph->rectVertScale.right) ;
1178: if (bPaintScale)
1179: DrawGraphScale (hDC, pGraph) ;
1180: if (IsPrinterDC (hDC))
1181: Rectangle (hDC,
1182: pGraph->rectData.left,
1183: pGraph->rectData.top,
1184: pGraph->rectData.right,
1185: pGraph->rectData.bottom) ;
1186: else
1187: ThreeDConcave1 (hDC,
1188: pGraph->rectData.left - LocalThreeDPad,
1189: pGraph->rectData.top - LocalThreeDPad,
1190: pGraph->rectData.right + LocalThreeDPad,
1191: pGraph->rectData.bottom + LocalThreeDPad + 1) ;
1192:
1193: UpdateGraphDisplay (hDC, TRUE, &(rectDraw), pGraph) ;
1194: } // DrawGraphDisplay
1195:
1196:
1197: LRESULT APIENTRY GraphDisplayWndProc (HWND hWnd,
1198: UINT uMsg,
1199: WPARAM wParam,
1200: LPARAM lParam)
1201: { // GraphDisplayWndProc
1202: LONG lret = 0L ;
1203: BOOL bCallDefProc = FALSE ;
1204:
1205: switch (LOWORD (uMsg))
1206: {
1207: case WM_LBUTTONDOWN:
1208: DoWindowDrag (lParam) ;
1209: break ;
1210:
1211: case WM_LBUTTONDBLCLK:
1212: SendMessage (hWndMain, uMsg, wParam, lParam) ;
1213: break ;
1214:
1215: case WM_CREATE:
1216: OnCreate (hWnd) ;
1217: break ;
1218:
1219: case WM_SIZE:
1220: OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
1221: break ;
1222:
1223: case WM_DESTROY:
1224: KillTimer(hWndMain, GRAPH_TIMER_ID) ;
1225: break ;
1226:
1227: case WM_PAINT:
1228: OnPaint (hWnd) ;
1229: break ;
1230:
1231: case WM_TIMER:
1232: GraphTimer (hWnd, FALSE) ;
1233: break ;
1234:
1235: default:
1236: bCallDefProc = TRUE ;
1237: break ;
1238: } // switch
1239:
1240:
1241: if (bCallDefProc)
1242: {
1243: lret = DefWindowProc(hWnd, uMsg, wParam, lParam) ;
1244: }
1245: return (lret) ;
1246: }
1247:
1248:
1249: BOOL GraphDisplayInitializeApplication (void)
1250: { // GraphDisplayInitializeApplication
1251: WNDCLASS wc ;
1252:
1253: wc.style = dwGraphDisplayClassStyle ;
1254: wc.lpfnWndProc = (WNDPROC) GraphDisplayWndProc ;
1255: wc.hInstance = hInstance ;
1256: wc.cbClsExtra = iGraphDisplayWindowExtra ;
1257: wc.cbWndExtra = iGraphDisplayClassExtra ;
1258: wc.hIcon = NULL ;
1259: wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
1260: wc.hbrBackground = hbLightGray ;
1261: wc.lpszMenuName = NULL ;
1262: wc.lpszClassName = (LPTSTR) szGraphDisplayWindowClass ;
1263:
1264: return (RegisterClass (&wc)) ;
1265: } // GraphDisplayInitializeApplication
1266:
1267:
1268:
1269: HWND CreateGraphDisplayWindow (HWND hWndGraph)
1270: {
1271: return (CreateWindow (szGraphDisplayWindowClass, // class
1272: NULL, // caption
1273: dwGraphDisplayWindowStyle, // window style
1274: 0, 0, // position
1275: 0, 0, // size
1276: hWndGraph, // parent window
1277: NULL, // menu
1278: hInstance, // program instance
1279: NULL)) ; // user-supplied data
1280: }
1281:
1282:
1283:
1284: BOOL ToggleGraphRefresh (HWND hWnd)
1285: { // ToggleGraphRefresh
1286: PGRAPHSTRUCT pGraph ;
1287:
1288: pGraph = GraphData (hWnd) ;
1289:
1290: if (pGraph->bManualRefresh)
1291: SetGraphTimer (pGraph) ;
1292: else
1293: ClearGraphTimer (pGraph) ;
1294:
1295: pGraph->bManualRefresh = !pGraph->bManualRefresh ;
1296: return (pGraph->bManualRefresh) ;
1297: } // ToggleGraphRefresh
1298:
1299: BOOL GraphRefresh (HWND hWnd)
1300: { // GraphRefresh
1301: PGRAPHSTRUCT pGraph ;
1302:
1303: pGraph = GraphData (hWnd) ;
1304:
1305: return (pGraph->bManualRefresh) ;
1306: } // GraphRefresh
1307:
1308:
1309: void GraphTimer (HWND hWnd,
1310: BOOL bForce)
1311: /*
1312: Effect: Handle any actions necessary when the graph display
1313: window hWnd receives a timer tick. In particular,
1314: update the graph display and update the status bar
1315: if it is showing.
1316:
1317: Called By: GraphDisplayWndProc, in response to a WM_TIMER message.
1318: */
1319: { // GraphTimer
1320: PGRAPHSTRUCT pGraph ;
1321:
1322: pGraph = GraphData (hWnd) ;
1323:
1324: if (!pGraph->pLineFirst)
1325: return ;
1326:
1327:
1328: if (bForce || !pGraph->bManualRefresh)
1329: {
1330:
1331:
1332: HandleGraphTimer () ;
1333:
1334: // If we are displaying a time-line graph then do the
1335: // calculations for the minimal update region.
1336: // If were doing a bar graph, then draw the
1337: // whole graph area.
1338:
1339: if (pGraph->gOptions.iGraphOrHistogram == LINE_GRAPH)
1340: UpdateTimeLine (hGraphDisplayDC, pGraph, FALSE) ;
1341: else
1342: DrawBarChartData (hGraphDisplayDC, pGraph) ;
1343:
1344: // Take care of the status bar window
1345: StatusTimer (hWndGraphStatus, FALSE) ;
1346:
1347: } // if
1348: } // GraphTimer
1349:
1350: // this routine set/reset the line highlight mode
1351: void ChartHighlight (void)
1352: {
1353: PGRAPHSTRUCT pGraph ;
1354:
1355:
1356: if (pGraph = GraphData (hWndGraph))
1357: {
1358: if (pGraph->pLineFirst)
1359: {
1360: // toggle the HightlightOnOff mode
1361: pGraph->HighLightOnOff = !pGraph->HighLightOnOff ;
1362: WindowInvalidate (hWndGraphDisplay) ;
1363: }
1364: else
1365: {
1366: // no line availble, just turn it off
1367: pGraph->HighLightOnOff = FALSE ;
1368: }
1369: }
1370: } // ChartHighlight
1371:
1372:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.