Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1340 lines
37 KiB

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