Leaked source code of windows server 2003
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.

1356 lines
43 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. grphdsp.cpp
  5. Abstract:
  6. <abstract>
  7. --*/
  8. #include "polyline.h"
  9. #include <limits.h>
  10. #include "grphdsp.h"
  11. #include "grphitem.h"
  12. #include "winhelpr.h"
  13. #define ThreeDPad 1
  14. #define BORDER ThreeDPad
  15. #define TEXT_MARGIN (ThreeDPad + 2)
  16. static HPEN hPenWhite;
  17. static HPEN hPenBlack;
  18. INT
  19. CGraphDisp::RGBToLightness ( COLORREF clrValue )
  20. {
  21. INT iLightness;
  22. INT iRed;
  23. INT iGreen;
  24. INT iBlue;
  25. INT iMax;
  26. INT iMin;
  27. // The complete algorithm for computing lightness is:
  28. // Lightness = (Max(R,G,B)+ Min(R,G,B))/2*225.
  29. // Only need to compute enought to determine whether to draw black or white highlight.
  30. iRed = GetRValue( clrValue );
  31. iGreen = GetGValue (clrValue );
  32. iBlue = GetBValue (clrValue );
  33. if ( iRed > iGreen ) {
  34. iMax = iRed;
  35. iMin = iGreen;
  36. } else {
  37. iMax = iGreen;
  38. iMin = iRed;
  39. }
  40. if ( iBlue > iMax ) {
  41. iMax = iBlue;
  42. } else if ( iBlue < iMin ) {
  43. iMin = iBlue;
  44. }
  45. iLightness = iMin + iMax;
  46. return iLightness;
  47. }
  48. CGraphDisp::CGraphDisp ( void )
  49. : m_pCtrl ( NULL ),
  50. m_pGraph ( NULL ),
  51. m_pHiliteItem ( NULL ),
  52. m_hFontVertical ( NULL ),
  53. m_bBarConfigChanged ( TRUE )
  54. {
  55. }
  56. CGraphDisp::~CGraphDisp ( void )
  57. {
  58. if (m_hFontVertical != NULL)
  59. DeleteObject(m_hFontVertical);
  60. if (m_hPenTimeBar != 0) {
  61. DeleteObject ( m_hPenTimeBar );
  62. m_hPenTimeBar = 0;
  63. }
  64. if (m_hPenGrid != 0) {
  65. DeleteObject ( m_hPenGrid );
  66. m_hPenGrid = 0;
  67. }
  68. }
  69. BOOL
  70. CGraphDisp::Init (
  71. CSysmonControl *pCtrl,
  72. PGRAPHDATA pGraph
  73. )
  74. {
  75. BOOL bRetStatus = TRUE;
  76. m_pCtrl = pCtrl;
  77. m_pGraph = pGraph;
  78. m_clrCurrentGrid = m_pCtrl->clrGrid();
  79. m_clrCurrentTimeBar = m_pCtrl->clrTimeBar();
  80. // Create the highlight, timebar and grid pens.
  81. m_hPenTimeBar = CreatePen(PS_SOLID, 2, m_clrCurrentTimeBar );
  82. // if can't do it, use a stock object (this can't fail)
  83. if (m_hPenTimeBar == NULL)
  84. m_hPenTimeBar = (HPEN)GetStockObject(BLACK_PEN);
  85. m_hPenGrid = CreatePen(PS_SOLID, 1, m_clrCurrentGrid );
  86. // if can't do it, use a stock object (this can't fail)
  87. if (m_hPenGrid == NULL)
  88. m_hPenGrid = (HPEN)GetStockObject(BLACK_PEN);
  89. // Highlight pens are shared among all Sysmon instances.
  90. BEGIN_CRITICAL_SECTION
  91. if (hPenWhite == 0) {
  92. hPenWhite = CreatePen(PS_SOLID, 3, RGB(255,255,255));
  93. hPenBlack = CreatePen(PS_SOLID, 3, RGB(0,0,0));
  94. }
  95. END_CRITICAL_SECTION
  96. return bRetStatus;
  97. }
  98. void CGraphDisp::HiliteItem( PCGraphItem pItem )
  99. {
  100. m_pHiliteItem = pItem;
  101. }
  102. VOID
  103. CGraphDisp::Draw(
  104. HDC hDC,
  105. HDC hAttribDC,
  106. BOOL fMetafile,
  107. BOOL fEntire,
  108. PRECT /* prcUpdate */ )
  109. {
  110. RECT rectFrame;
  111. RECT rectTitle;
  112. CStepper locStepper;
  113. DWORD dwPrevLayout = 0;
  114. DWORD dwNewLayout = 0;
  115. if ( ( m_rect.right > m_rect.left ) && ( m_rect.bottom > m_rect.top ) ) {
  116. if ( NULL != hDC ) {
  117. dwPrevLayout = GetLayout ( hDC );
  118. dwNewLayout = dwPrevLayout;
  119. if ( dwNewLayout & LAYOUT_RTL ) {
  120. dwNewLayout &= ~LAYOUT_RTL;
  121. SetLayout (hDC, dwNewLayout);
  122. }
  123. // Fill plot area
  124. Fill(hDC, m_pCtrl->clrBackPlot(), &m_rectPlot);
  125. rectFrame = m_rectPlot;
  126. // Draw 3D border around plot area
  127. if ( eAppear3D == m_pCtrl->Appearance() ) {
  128. InflateRect(&rectFrame,BORDER,BORDER);
  129. DrawEdge(hDC, &rectFrame, BDR_SUNKENOUTER, BF_RECT);
  130. }
  131. // Select colors for all text
  132. SetBkMode(hDC, TRANSPARENT);
  133. SetTextColor(hDC, m_pCtrl->clrFgnd());
  134. // Draw the scale
  135. if (m_pGraph->Options.bLabelsChecked) {
  136. SelectFont(hDC, m_pCtrl->Font()) ;
  137. m_pGraph->Scale.Draw(hDC);
  138. }
  139. // Draw the main title
  140. if (m_pGraph->Options.pszGraphTitle != NULL) {
  141. SelectFont(hDC, m_pCtrl->Font()) ;
  142. SetTextAlign(hDC, TA_TOP|TA_CENTER);
  143. rectTitle = rectFrame;
  144. rectTitle.top = m_rect.top;
  145. FitTextOut(
  146. hDC,
  147. hAttribDC,
  148. 0,
  149. &rectTitle,
  150. m_pGraph->Options.pszGraphTitle,
  151. lstrlen(m_pGraph->Options.pszGraphTitle),
  152. TA_CENTER,
  153. FALSE );
  154. }
  155. // Draw the Y axis title
  156. if (m_pGraph->Options.pszYaxisTitle != NULL && m_hFontVertical != NULL) {
  157. SelectFont(hDC, m_hFontVertical) ;
  158. SetTextAlign(hDC, TA_TOP|TA_CENTER);
  159. rectTitle = rectFrame;
  160. rectTitle.left = m_rect.left;
  161. FitTextOut(
  162. hDC,
  163. hAttribDC,
  164. 0,
  165. &rectTitle,
  166. m_pGraph->Options.pszYaxisTitle,
  167. lstrlen(m_pGraph->Options.pszYaxisTitle),
  168. TA_CENTER,
  169. TRUE);
  170. }
  171. // setup stepper reset to start
  172. locStepper = m_pGraph->TimeStepper;
  173. locStepper.Reset();
  174. // Set clipping area. Fill executed above, so bFill= FALSE.
  175. StartUpdate(hDC, fMetafile, fEntire, 0, (m_rectPlot.right - m_rectPlot.left), FALSE );
  176. // draw the grid lines
  177. DrawGrid(hDC, 0, m_rectPlot.right - m_rectPlot.left);
  178. m_pCtrl->LockCounterData();
  179. switch (m_pGraph->Options.iDisplayType) {
  180. case LINE_GRAPH:
  181. // Finish and restart update so that wide lines are cropped at the timeline.
  182. FinishUpdate(hDC, fMetafile);
  183. StartUpdate(
  184. hDC,
  185. fMetafile,
  186. FALSE,
  187. 0,
  188. m_pGraph->TimeStepper.Position(),
  189. FALSE );
  190. // Plot points from start of graph to time line
  191. PlotData(hDC, m_pGraph->TimeStepper.StepNum() + m_pGraph->History.nBacklog,
  192. m_pGraph->TimeStepper.StepNum(), &locStepper);
  193. FinishUpdate(hDC, fMetafile);
  194. // Plot points from time line to end of graph
  195. locStepper = m_pGraph->TimeStepper;
  196. // Restart update. Left-hand ends and internal gaps of wide lines are not cropped.
  197. StartUpdate(
  198. hDC,
  199. fMetafile,
  200. FALSE,
  201. locStepper.Position(),
  202. m_rectPlot.right - m_rectPlot.left,
  203. FALSE );
  204. PlotData(hDC, m_pGraph->TimeStepper.StepCount() + m_pGraph->History.nBacklog,
  205. m_pGraph->TimeStepper.StepCount() - m_pGraph->TimeStepper.StepNum(),
  206. &locStepper);
  207. DrawTimeLine(hDC, m_pGraph->TimeStepper.Position());
  208. if ( MIN_TIME_VALUE != m_pGraph->LogViewTempStart )
  209. DrawStartStopLine(hDC, m_pGraph->LogViewStartStepper.Position());
  210. if ( MAX_TIME_VALUE != m_pGraph->LogViewTempStop )
  211. DrawStartStopLine(hDC, m_pGraph->LogViewStopStepper.Position());
  212. break;
  213. case BAR_GRAPH:
  214. PlotBarGraph(hDC, FALSE);
  215. break;
  216. }
  217. FinishUpdate(hDC, fMetafile);
  218. if ( dwNewLayout != dwPrevLayout ) {
  219. SetLayout (hDC, dwPrevLayout);
  220. }
  221. m_pCtrl->UnlockCounterData();
  222. }
  223. }
  224. }
  225. VOID
  226. CGraphDisp::UpdateTimeBar(
  227. HDC hDC,
  228. BOOL bPlotData )
  229. {
  230. INT nBacklog;
  231. INT iUpdateCnt;
  232. INT i;
  233. CStepper locStepper;
  234. nBacklog = m_pGraph->History.nBacklog;
  235. // Work off backlogged sample intervals
  236. while ( nBacklog > 0) {
  237. // If we are going to wrap around, update in two steps
  238. if (nBacklog > m_pGraph->TimeStepper.StepCount()
  239. - m_pGraph->TimeStepper.StepNum()) {
  240. iUpdateCnt = m_pGraph->TimeStepper.StepCount()
  241. - m_pGraph->TimeStepper.StepNum();
  242. } else {
  243. iUpdateCnt = nBacklog;
  244. }
  245. // step to position of current data
  246. locStepper = m_pGraph->TimeStepper;
  247. for (i=0; i<iUpdateCnt; i++)
  248. m_pGraph->TimeStepper.NextPosition();
  249. if ( bPlotData ) {
  250. StartUpdate(
  251. hDC,
  252. FALSE,
  253. FALSE,
  254. locStepper.Position(),
  255. m_pGraph->TimeStepper.Position(),
  256. TRUE );
  257. DrawGrid(hDC, locStepper.Position(), m_pGraph->TimeStepper.Position());
  258. PlotData(hDC, nBacklog, iUpdateCnt, &locStepper);
  259. FinishUpdate ( hDC, FALSE );
  260. }
  261. if (m_pGraph->TimeStepper.StepNum() >= m_pGraph->TimeStepper.StepCount())
  262. m_pGraph->TimeStepper.Reset();
  263. nBacklog -= iUpdateCnt;
  264. }
  265. if ( bPlotData ) {
  266. DrawTimeLine(hDC, m_pGraph->TimeStepper.Position());
  267. }
  268. m_pGraph->History.nBacklog = 0;
  269. }
  270. VOID
  271. CGraphDisp::Update( HDC hDC )
  272. {
  273. DWORD dwPrevLayout = 0;
  274. DWORD dwNewLayout = 0;
  275. m_pCtrl->LockCounterData();
  276. if ( NULL != hDC ) {
  277. dwPrevLayout = GetLayout ( hDC );
  278. dwNewLayout = dwPrevLayout;
  279. if ( dwNewLayout & LAYOUT_RTL ) {
  280. dwNewLayout &= ~LAYOUT_RTL;
  281. SetLayout (hDC, dwNewLayout);
  282. }
  283. if ( ( m_rect.right > m_rect.left ) && ( m_rect.bottom > m_rect.top ) ) {
  284. switch (m_pGraph->Options.iDisplayType) {
  285. case LINE_GRAPH:
  286. // Update the line graph and time bar based on history
  287. // backlog. Reset history backlog to 0, signalling collection
  288. // thread to post another WM_GRAPH_UPDATE message.
  289. UpdateTimeBar ( hDC, TRUE );
  290. break;
  291. case BAR_GRAPH:
  292. PlotBarGraph(hDC, TRUE);
  293. break;
  294. }
  295. }
  296. // If updating histogram or report, update thetimebar step based on
  297. // history backlog. Reset history backlog to 0, signalling collection
  298. // thread to post another WM_GRAPH_UPDATE message.
  299. UpdateTimeBar ( hDC, FALSE );
  300. if ( dwNewLayout != dwPrevLayout ) {
  301. SetLayout (hDC, dwPrevLayout);
  302. }
  303. }
  304. m_pCtrl->UnlockCounterData();
  305. }
  306. void
  307. CGraphDisp::StartUpdate(
  308. HDC hDC,
  309. BOOL fMetafile,
  310. BOOL fEntire,
  311. INT xLeft,
  312. INT xRight,
  313. BOOL bFill )
  314. {
  315. RECT rect;
  316. // Preserve clipping region
  317. if ( FALSE == fMetafile ) {
  318. m_rgnClipSave = CreateRectRgn(0,0,0,0);
  319. if (m_rgnClipSave != NULL) {
  320. if (GetClipRgn(hDC, m_rgnClipSave) != 1) {
  321. DeleteObject(m_rgnClipSave);
  322. m_rgnClipSave = NULL;
  323. }
  324. }
  325. xLeft += m_rectPlot.left;
  326. xRight += m_rectPlot.left;
  327. IntersectClipRect (
  328. hDC,
  329. max ( m_rectPlot.left, xLeft ),
  330. m_rectPlot.top,
  331. min (m_rectPlot.right, xRight + 1), // Extra pixel for TimeBar
  332. m_rectPlot.bottom ) ;
  333. } else if( TRUE == fEntire ){
  334. m_rgnClipSave = NULL;
  335. IntersectClipRect (
  336. hDC,
  337. m_rectPlot.left,
  338. m_rectPlot.top,
  339. m_rectPlot.right,
  340. m_rectPlot.bottom ) ;
  341. }
  342. // Fill performed before this method for metafiles and complete draw.
  343. if ( !fMetafile && bFill ) {
  344. SetRect(
  345. &rect,
  346. max ( m_rectPlot.left, xLeft - 1 ),
  347. m_rectPlot.top - 1,
  348. min (m_rectPlot.right, xRight + 1),
  349. m_rectPlot.bottom);
  350. Fill(hDC, m_pCtrl->clrBackPlot(), &rect);
  351. }
  352. }
  353. void CGraphDisp::FinishUpdate( HDC hDC, BOOL fMetafile )
  354. {
  355. // Restore saved clip region
  356. if ( !fMetafile ) {
  357. SelectClipRgn(hDC, m_rgnClipSave);
  358. if (m_rgnClipSave != NULL) {
  359. DeleteObject(m_rgnClipSave);
  360. m_rgnClipSave = NULL;
  361. }
  362. }
  363. }
  364. void CGraphDisp::DrawGrid(HDC hDC, INT xLeft, INT xRight)
  365. {
  366. INT xPos;
  367. INT nTics;
  368. INT *piScaleTic;
  369. INT i;
  370. if ( (m_pGraph->Options.bVertGridChecked)
  371. || (m_pGraph->Options.bHorzGridChecked) ) {
  372. if ( m_clrCurrentGrid != m_pCtrl->clrGrid() ) {
  373. m_clrCurrentGrid = m_pCtrl->clrGrid();
  374. DeleteObject ( m_hPenGrid );
  375. m_hPenGrid = CreatePen(PS_SOLID, 1, m_clrCurrentGrid );
  376. // if can't do it, use a stock object (this can't fail)
  377. if (m_hPenGrid == NULL)
  378. m_hPenGrid = (HPEN)GetStockObject(BLACK_PEN);
  379. }
  380. }
  381. if (m_pGraph->Options.bVertGridChecked) {
  382. SelectObject(hDC, m_hPenGrid);
  383. m_GridStepper.Reset();
  384. xPos = m_GridStepper.NextPosition();
  385. while (xPos < xLeft)
  386. xPos =m_GridStepper.NextPosition();
  387. while (xPos < xRight) {
  388. MoveToEx(hDC, xPos + m_rectPlot.left, m_rectPlot.bottom, NULL);
  389. LineTo(hDC, xPos + m_rectPlot.left, m_rectPlot.top - 1);
  390. xPos = m_GridStepper.NextPosition();
  391. }
  392. }
  393. if (m_pGraph->Options.bHorzGridChecked) {
  394. xLeft += m_rectPlot.left;
  395. xRight += m_rectPlot.left;
  396. SelectObject(hDC,m_hPenGrid);
  397. nTics = m_pGraph->Scale.GetTicPositions(&piScaleTic);
  398. for (i=1; i<nTics; i++) {
  399. MoveToEx(hDC, xLeft, m_rectPlot.top + piScaleTic[i], NULL);
  400. LineTo(hDC, xRight + 1, m_rectPlot.top + piScaleTic[i]);
  401. }
  402. }
  403. }
  404. BOOL
  405. CGraphDisp::CalcYPosition (
  406. PCGraphItem pItem,
  407. INT iHistIndex,
  408. BOOL bLog,
  409. INT y[3] )
  410. {
  411. BOOL bReturn; // True = good, False = bad.
  412. PDH_STATUS stat;
  413. DWORD dwCtrStat;
  414. double dValue[3];
  415. double dTemp;
  416. INT iVal;
  417. INT nVals = bLog ? 3 : 1;
  418. if (bLog)
  419. stat = pItem->GetLogEntry(iHistIndex, &dValue[1], &dValue[2], &dValue[0], &dwCtrStat);
  420. else
  421. stat = pItem->HistoryValue(iHistIndex, &dValue[0], &dwCtrStat);
  422. if (ERROR_SUCCESS == stat && IsSuccessSeverity(dwCtrStat)) {
  423. for (iVal = 0; iVal < nVals; iVal++) {
  424. dTemp = dValue[iVal] * pItem->Scale();
  425. if (dTemp > m_dMax)
  426. dTemp = m_dMax;
  427. else if (dTemp < m_dMin)
  428. dTemp = m_dMin;
  429. // Plot minimum value as 1 pixel above the bottom of the plot area, since
  430. // clipping and fill regions crop the bottom and right pixels.
  431. y[iVal] = m_rectPlot.bottom - (INT)((dTemp - m_dMin) * m_dPixelScale);
  432. if ( y[iVal] == m_rectPlot.bottom ) {
  433. y[iVal] = m_rectPlot.bottom - 1;
  434. }
  435. }
  436. bReturn = TRUE;
  437. } else {
  438. bReturn = FALSE;
  439. }
  440. return bReturn;
  441. }
  442. void CGraphDisp::PlotData(HDC hDC, INT iHistIndx, INT nSteps, CStepper *pStepper)
  443. {
  444. INT i;
  445. INT x;
  446. INT y[3];
  447. PCGraphItem pItem;
  448. CStepper locStepper;
  449. BOOL bSkip;
  450. BOOL bPrevGood;
  451. BOOL bLog;
  452. BOOL bLogMultiVal;
  453. if (m_pGraph->Options.iVertMax <= m_pGraph->Options.iVertMin)
  454. return;
  455. bSkip = TRUE;
  456. bLog = m_pCtrl->IsLogSource();
  457. bLogMultiVal = bLog && !DisplaySingleLogSampleValue();
  458. // If possible, back up to redraw previous segment
  459. if (pStepper->StepNum() > 0) {
  460. iHistIndx++;
  461. nSteps++;
  462. pStepper->PrevPosition();
  463. }
  464. // Set background color, in case of dashed lines
  465. SetBkMode(hDC, TRANSPARENT);
  466. pItem = m_pCtrl->FirstCounter();
  467. while (pItem != NULL) {
  468. locStepper = *pStepper;
  469. // Skip hilited item the first time
  470. if (!(pItem == m_pHiliteItem && bSkip)) {
  471. INT iPolyIndex = 0;
  472. POINT arrptDataPoints[MAX_GRAPH_SAMPLES] ;
  473. if ( pItem == m_pHiliteItem) {
  474. // Arbitrary 450 (out of 510) chosen as cutoff for white vs. black
  475. if ( 450 > RGBToLightness( m_pCtrl->clrBackPlot() ) )
  476. SelectObject(hDC, hPenWhite);
  477. else
  478. SelectObject(hDC, hPenBlack);
  479. } else {
  480. SelectObject(hDC,pItem->Pen());
  481. }
  482. bPrevGood = FALSE;
  483. // For each GOOD current value:
  484. // If the previous value is good, draw line from previous value to current value.
  485. // If the previous value is bad, MoveTo the current value point.
  486. //
  487. // For the first step, the previous value is false by definition, so the first operation
  488. // is a MoveTo.
  489. //
  490. // Polyline code:
  491. // For each GOOD current value:
  492. // Add the current (good) point to the polyline point array.
  493. // For each BAD current value:
  494. // If the polyline index is > 1 (2 points), draw the polyline and reset the polyline index to 0.
  495. // After all values:
  496. // If the polyline index is > 1 (2 points), draw the polyline.
  497. for (i = 0; i <= nSteps; i++) {
  498. // True = Good current value
  499. if ( CalcYPosition ( pItem, iHistIndx - i, bLog, y ) ) {
  500. x = m_rectPlot.left + locStepper.Position();
  501. // Add point to polyline, since the current value is good.
  502. arrptDataPoints[iPolyIndex].x = x;
  503. arrptDataPoints[iPolyIndex].y = y[0];
  504. iPolyIndex++;
  505. // No polyline optimization for extra Max and Min log points.
  506. if (bLogMultiVal) {
  507. MoveToEx(hDC, x, y[1], NULL);
  508. LineTo(hDC, x, y[2]);
  509. MoveToEx(hDC, x, y[0], NULL);
  510. }
  511. bPrevGood = TRUE;
  512. } else {
  513. // Current value is not good.
  514. bPrevGood = FALSE;
  515. // Current value is not good, so don't add to polyline point array.
  516. if ( iPolyIndex > 1 ) {
  517. // Draw polyline for any existing good points.
  518. Polyline(hDC, arrptDataPoints, iPolyIndex) ;
  519. }
  520. // Reset polyline point index to 0.
  521. iPolyIndex = 0;
  522. }
  523. locStepper.NextPosition();
  524. }
  525. // Draw the final line.
  526. if ( iPolyIndex > 1 ) {
  527. // Draw polyline
  528. Polyline(hDC, arrptDataPoints, iPolyIndex) ;
  529. }
  530. // Exit loop after plotting hilited item
  531. if (pItem == m_pHiliteItem)
  532. break;
  533. }
  534. pItem = pItem->Next();
  535. // After last item, go back to highlighted item
  536. if (pItem == NULL) {
  537. pItem = m_pHiliteItem;
  538. bSkip = FALSE;
  539. }
  540. }
  541. }
  542. void CGraphDisp::PlotBarGraph(HDC hDC, BOOL fUpdate)
  543. {
  544. if ( (m_pGraph->CounterTree.NumCounters() > 0 )
  545. && (m_pGraph->Options.iVertMax > m_pGraph->Options.iVertMin) ) {
  546. CStepper BarStepper;
  547. PCGraphItem pItem;
  548. RECT rectBar;
  549. INT iValue,iPrevValue;
  550. HRESULT hr;
  551. LONG lCtrStat;
  552. double dValue = 0.0;
  553. double dMax;
  554. double dMin;
  555. double dAvg;
  556. double dTemp;
  557. HRGN hrgnRedraw,hrgnTemp;
  558. eReportValueTypeConstant eValueType;
  559. BOOL bLog;
  560. INT iNumCounters = m_pGraph->CounterTree.NumCounters();
  561. BOOL bSkip = TRUE;
  562. INT iHighlightStepNum = 0;
  563. BOOL bLocalUpdate;
  564. HANDLE hPenSave;
  565. bLocalUpdate = fUpdate;
  566. hrgnRedraw = NULL;
  567. eValueType = m_pCtrl->ReportValueType();
  568. // Todo: Move DisplaySingleLogSampleValue() to CSystemMonitor.
  569. bLog = m_pCtrl->IsLogSource();
  570. // Force total redraw if the number of counters has changed in case
  571. // Update is called immediately after.
  572. if ( m_bBarConfigChanged ) {
  573. SetBarConfigChanged ( FALSE );
  574. if ( bLocalUpdate ) {
  575. bLocalUpdate = FALSE;
  576. }
  577. // Clear and fill the entire plot region.
  578. hrgnRedraw = CreateRectRgn(
  579. m_rectPlot.left,
  580. m_rectPlot.top,
  581. m_rectPlot.right,
  582. m_rectPlot.bottom);
  583. if (hrgnRedraw) {
  584. SelectClipRgn(hDC, hrgnRedraw);
  585. Fill(hDC, m_pCtrl->clrBackPlot(), &m_rectPlot);
  586. DrawGrid(hDC, 0, (m_rectPlot.right - m_rectPlot.left));
  587. DeleteObject(hrgnRedraw);
  588. hrgnRedraw = NULL;
  589. }
  590. }
  591. // Intialize stepper for number of bars to plot
  592. BarStepper.Init ( ( m_rectPlot.right - m_rectPlot.left), iNumCounters );
  593. hPenSave = SelectPen ( hDC, GetStockObject(NULL_PEN) );
  594. // Do for all counters
  595. pItem = m_pGraph->CounterTree.FirstCounter();
  596. while ( NULL != pItem ) {
  597. hr = ERROR_SUCCESS;
  598. // Skip highlighted item the first time through
  599. if (!(pItem == m_pHiliteItem && bSkip)) {
  600. // Get display value
  601. if ( sysmonDefaultValue == eValueType ) {
  602. if (bLog) {
  603. hr = pItem->GetStatistics(&dMax, &dMin, &dAvg, &lCtrStat);
  604. dValue = dAvg;
  605. }
  606. else {
  607. hr = pItem->GetValue(&dValue, &lCtrStat);
  608. }
  609. } else {
  610. if ( sysmonCurrentValue == eValueType ) {
  611. hr = pItem->GetValue(&dValue, &lCtrStat);
  612. }
  613. else {
  614. hr = pItem->GetStatistics(&dMax, &dMin, &dAvg, &lCtrStat);
  615. switch ( eValueType ) {
  616. case sysmonAverage:
  617. dValue = dAvg;
  618. break;
  619. case sysmonMinimum:
  620. dValue = dMin;
  621. break;
  622. case sysmonMaximum:
  623. dValue = dMax;
  624. break;
  625. default:
  626. assert (FALSE);
  627. }
  628. }
  629. }
  630. // Erase bar if the counter value is invalid.
  631. if (SUCCEEDED(hr) && IsSuccessSeverity(lCtrStat)) {
  632. // Convert value to pixel units
  633. dTemp = dValue * pItem->Scale();
  634. if (dTemp > m_dMax)
  635. dTemp = m_dMax;
  636. else if (dTemp < m_dMin)
  637. dTemp = m_dMin;
  638. iValue = m_rectPlot.bottom - (INT)((dTemp - m_dMin) * m_dPixelScale);
  639. if ( iValue == m_rectPlot.bottom ) {
  640. // Draw single pixel for screen visibility.
  641. iValue--;
  642. }
  643. } else {
  644. // The current value is 0. Draw single pixel for screen visibility.
  645. iValue = m_rectPlot.bottom - 1;
  646. }
  647. if ( !bSkip ) {
  648. assert ( pItem == m_pHiliteItem );
  649. BarStepper.StepTo ( iHighlightStepNum );
  650. }
  651. // Setup left and right edges of bar
  652. rectBar.left = m_rectPlot.left + BarStepper.Position();
  653. rectBar.right = m_rectPlot.left + BarStepper.NextPosition();
  654. // If doing an update (never called for log sources) and not drawing the highlighted item
  655. if ( bLocalUpdate && !( ( pItem == m_pHiliteItem ) && !bSkip) ) {
  656. assert ( !m_bBarConfigChanged );
  657. // Get previous plot value
  658. iPrevValue = 0;
  659. hr = pItem->HistoryValue(1, &dValue, (ULONG*)&lCtrStat);
  660. if (SUCCEEDED(hr) && IsSuccessSeverity(lCtrStat)) {
  661. // Convert value to pixel units
  662. dTemp = dValue * pItem->Scale();
  663. if (dTemp > m_dMax)
  664. dTemp = m_dMax;
  665. else if (dTemp < m_dMin)
  666. dTemp = m_dMin;
  667. iPrevValue = m_rectPlot.bottom - (INT)((dTemp - m_dMin) * m_dPixelScale);
  668. if ( iPrevValue == m_rectPlot.bottom ) {
  669. // Single pixel was drawn for screen visibility.
  670. iPrevValue--;
  671. }
  672. } else {
  673. // The previous value was 0. Single pixel was drawn for screen visibility.
  674. iPrevValue = m_rectPlot.bottom - 1;
  675. }
  676. // If bar has grown (smaller y coord)
  677. if (iPrevValue > iValue) {
  678. // Draw the new part
  679. rectBar.bottom = iPrevValue;
  680. rectBar.top = iValue;
  681. if ( pItem == m_pHiliteItem) {
  682. // Arbitrary 450 (out of 510) chosen as cutoff for white vs. black
  683. if ( 450 > RGBToLightness( m_pCtrl->clrBackPlot() ) )
  684. SelectBrush(hDC, GetStockObject(WHITE_BRUSH));
  685. else
  686. SelectBrush(hDC, GetStockObject(BLACK_BRUSH));
  687. } else {
  688. SelectBrush(hDC, pItem->Brush());
  689. }
  690. // Bars are drawn with Null pen, so bottom and right are cropped by 1 pixel.
  691. // Add 1 pixel to compensate.
  692. Rectangle(hDC, rectBar.left, rectBar.top, rectBar.right + 1, rectBar.bottom + 1);
  693. } else if (iPrevValue < iValue) {
  694. // Else if bar has shrunk
  695. // Add part to be erased to redraw region
  696. // Erase to the top of the grid, to eliminate random pixels left over.
  697. rectBar.bottom = iValue;
  698. rectBar.top = m_rectPlot.top; // set to stop of grid rather than to prevValue
  699. hrgnTemp = CreateRectRgn(rectBar.left, rectBar.top, rectBar.right, rectBar.bottom);
  700. if (hrgnRedraw && hrgnTemp) {
  701. CombineRgn(hrgnRedraw,hrgnRedraw,hrgnTemp,RGN_OR);
  702. DeleteObject(hrgnTemp);
  703. } else {
  704. hrgnRedraw = hrgnTemp;
  705. }
  706. }
  707. } else {
  708. // Erase and redraw complete bar
  709. // Erase top first
  710. // Add part to be erased to redraw region
  711. // Erase to the top of the grid, to eliminate random pixels left over.
  712. if ( iValue != m_rectPlot.top ) {
  713. rectBar.bottom = iValue;
  714. rectBar.top = m_rectPlot.top; // set to stop of grid rather than to prevValue
  715. hrgnTemp = CreateRectRgn(rectBar.left, rectBar.top, rectBar.right, rectBar.bottom);
  716. if (hrgnRedraw && hrgnTemp) {
  717. CombineRgn(hrgnRedraw,hrgnRedraw,hrgnTemp,RGN_OR);
  718. DeleteObject(hrgnTemp);
  719. } else {
  720. hrgnRedraw = hrgnTemp;
  721. }
  722. }
  723. // Then draw the bar.
  724. rectBar.bottom = m_rectPlot.bottom;
  725. rectBar.top = iValue;
  726. if ( pItem == m_pHiliteItem) {
  727. // Arbitrary 450 (out of 510) chosen as cutoff for white vs. black
  728. if ( 450 > RGBToLightness( m_pCtrl->clrBackPlot() ) )
  729. SelectBrush(hDC, GetStockObject(WHITE_BRUSH));
  730. else
  731. SelectBrush(hDC, GetStockObject(BLACK_BRUSH));
  732. } else {
  733. SelectBrush(hDC, pItem->Brush());
  734. }
  735. // Bars are drawn with Null pen, so bottom and right are cropped by 1 pixel.
  736. // Add 1 pixel to compensate.
  737. Rectangle(hDC, rectBar.left, rectBar.top, rectBar.right + 1, rectBar.bottom + 1);
  738. } // Update
  739. // Exit loop after plotting highlighted item
  740. if (pItem == m_pHiliteItem)
  741. break;
  742. } else {
  743. if ( bSkip ) {
  744. // Save position of highlighted item the first time through
  745. iHighlightStepNum = BarStepper.StepNum();
  746. }
  747. BarStepper.NextPosition();
  748. }
  749. pItem = pItem->Next();
  750. // After last item, go back to highlighted item
  751. if ( NULL == pItem && NULL != m_pHiliteItem ) {
  752. pItem = m_pHiliteItem;
  753. bSkip = FALSE;
  754. }
  755. } // Do for all counters
  756. // If redraw region accumulated, erase and draw grid lines
  757. if (hrgnRedraw) {
  758. SelectClipRgn(hDC, hrgnRedraw);
  759. Fill(hDC, m_pCtrl->clrBackPlot(), &m_rectPlot);
  760. DrawGrid(hDC, 0, (m_rectPlot.right - m_rectPlot.left));
  761. DeleteObject(hrgnRedraw);
  762. }
  763. SelectObject(hDC, hPenSave);
  764. }
  765. }
  766. void CGraphDisp::SizeComponents(HDC hDC, PRECT pRect)
  767. {
  768. INT iStepNum;
  769. INT iScaleWidth;
  770. INT iTitleHeight;
  771. INT iAxisTitleWidth;
  772. RECT rectScale;
  773. SIZE size;
  774. INT iWidth;
  775. INT i;
  776. static INT aiWidthTable[] = {20,50,100,150,300,500,1000000};
  777. static INT aiTicTable[] = {0,2,4,5,10,20,25};
  778. m_rect = *pRect;
  779. // if no space, return
  780. if (m_rect.right <= m_rect.left || m_rect.bottom - m_rect.top <= 0)
  781. return;
  782. // For now use the horizontal font height for both horizontal and vertical text
  783. // because the GetTextExtentPoint32 is returning the wrong height for vertical text
  784. SelectFont(hDC, m_pCtrl->Font());
  785. GetTextExtentPoint32(hDC, TEXT("Sample"), 6, &size);
  786. if (m_pGraph->Options.pszGraphTitle != NULL) {
  787. //SelectFont(hDC, m_pCtrl->Font()) ;
  788. //GetTextExtentPoint32(hDC, m_pGraph->Options.pszGraphTitle,
  789. // lstrlen(m_pGraph->Options.pszGraphTitle), &size);
  790. iTitleHeight = size.cy + TEXT_MARGIN;
  791. } else
  792. iTitleHeight = 0;
  793. if (m_pGraph->Options.pszYaxisTitle != NULL && m_hFontVertical != NULL) {
  794. //SelectFont(hDC, m_hFontVertical);
  795. //GetTextExtentPoint32(hDC, m_pGraph->Options.pszYaxisTitle,
  796. // lstrlen(m_pGraph->Options.pszYaxisTitle), &size);
  797. iAxisTitleWidth = size.cy + TEXT_MARGIN;
  798. } else
  799. iAxisTitleWidth = 0;
  800. if (m_pGraph->Options.bLabelsChecked) {
  801. //SelectFont(hDC, m_pCtrl->Font());
  802. iScaleWidth = m_pGraph->Scale.GetWidth(hDC);
  803. } else
  804. iScaleWidth = 0;
  805. SetRect(&rectScale, pRect->left + iAxisTitleWidth,
  806. pRect->top + iTitleHeight,
  807. pRect->left + iAxisTitleWidth + iScaleWidth,
  808. pRect->bottom);
  809. m_pGraph->Scale.SetRect(&rectScale); // Just to set grid line positions
  810. SetRect(&m_rectPlot, pRect->left + iScaleWidth + iAxisTitleWidth + BORDER,
  811. pRect->top + iTitleHeight + BORDER,
  812. pRect->right - BORDER,
  813. pRect->bottom - BORDER);
  814. // Reinitialize steppers for new width
  815. iWidth = m_rectPlot.right - m_rectPlot.left;
  816. iStepNum = m_pGraph->TimeStepper.StepNum();
  817. m_pGraph->TimeStepper.Init(iWidth, m_pGraph->History.nMaxSamples - 2);
  818. m_pGraph->TimeStepper.StepTo(iStepNum);
  819. iStepNum = m_pGraph->LogViewStartStepper.StepNum();
  820. m_pGraph->LogViewStartStepper.Init(iWidth, m_pGraph->History.nMaxSamples - 2);
  821. m_pGraph->LogViewStartStepper.StepTo(iStepNum);
  822. iStepNum = m_pGraph->LogViewStopStepper.StepNum();
  823. m_pGraph->LogViewStopStepper.Init(iWidth, m_pGraph->History.nMaxSamples - 2);
  824. m_pGraph->LogViewStopStepper.StepTo(iStepNum);
  825. // Find best grid count for this width
  826. for (i=0; iWidth > aiWidthTable[i]; i++) {};
  827. m_GridStepper.Init(iWidth, aiTicTable[i]);
  828. // Compute conversion factors for plot, hit test.
  829. m_dMin = (double)m_pGraph->Options.iVertMin;
  830. m_dMax = (double)m_pGraph->Options.iVertMax;
  831. m_dPixelScale = (double)(m_rectPlot.bottom - m_rectPlot.top) / (m_dMax - m_dMin);
  832. }
  833. void CGraphDisp::DrawTimeLine(HDC hDC, INT x)
  834. {
  835. HPEN hPenSave;
  836. // No time line for log playback
  837. if (m_pCtrl->IsLogSource())
  838. return;
  839. x += m_rectPlot.left + 1;
  840. if ( m_clrCurrentTimeBar != m_pCtrl->clrTimeBar() ) {
  841. LOGBRUSH lbrush;
  842. m_clrCurrentTimeBar = m_pCtrl->clrTimeBar();
  843. DeleteObject ( m_hPenTimeBar );
  844. // When called from Update(), DrawTimeLine is called after the clipping region
  845. // is deactivated. Create a geometric pen in order to specify flat end cap style.
  846. // This eliminates any extra pixels drawn at the end.
  847. lbrush.lbStyle = BS_SOLID;
  848. lbrush.lbColor = m_clrCurrentTimeBar;
  849. lbrush.lbHatch = 0;
  850. m_hPenTimeBar = ExtCreatePen (
  851. PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, 2, &lbrush, 0, NULL );
  852. // if can't do it, use a stock object (this can't fail)
  853. if (m_hPenTimeBar == NULL)
  854. m_hPenTimeBar = (HPEN)GetStockObject(BLACK_PEN);
  855. }
  856. hPenSave = SelectPen ( hDC, m_hPenTimeBar );
  857. MoveToEx ( hDC, x, m_rectPlot.top, NULL );
  858. // Specify 1 less pixel. All fills and clip regions clip bottom and
  859. // right pixels, so match their behavior.
  860. LineTo ( hDC, x, m_rectPlot.bottom - 1 );
  861. SelectObject(hDC, hPenSave);
  862. }
  863. void CGraphDisp::DrawStartStopLine(HDC hDC, INT x)
  864. {
  865. HPEN hPenSave;
  866. // Log view start/stop lines only for log playback
  867. if (!m_pCtrl->IsLogSource())
  868. return;
  869. if ( x > 0 && x < ( m_rectPlot.right - m_rectPlot.left ) ) {
  870. x += m_rectPlot.left;
  871. if ( m_clrCurrentGrid != m_pCtrl->clrGrid() ) {
  872. m_clrCurrentGrid = m_pCtrl->clrGrid();
  873. DeleteObject ( m_hPenGrid );
  874. m_hPenGrid = CreatePen(PS_SOLID, 1, m_clrCurrentGrid );
  875. // if can't do it, use a stock object (this can't fail)
  876. if (m_hPenGrid == NULL)
  877. m_hPenGrid = (HPEN)GetStockObject(BLACK_PEN);
  878. }
  879. hPenSave = SelectPen(hDC, m_hPenGrid);
  880. MoveToEx(hDC, x, m_rectPlot.top, NULL);
  881. LineTo(hDC, x, m_rectPlot.bottom);
  882. SelectObject(hDC, hPenSave);
  883. }
  884. }
  885. void CGraphDisp::ChangeFont( HDC hDC )
  886. {
  887. TEXTMETRIC TextMetrics, newTextMetrics;
  888. LOGFONT LogFont;
  889. HFONT hFontOld;
  890. // Select the new font
  891. hFontOld = SelectFont(hDC, m_pCtrl->Font());
  892. // Get attributes
  893. GetTextMetrics(hDC, &TextMetrics);
  894. // Create LOGFONT for vertical font with same attributes
  895. LogFont.lfHeight = TextMetrics.tmHeight;
  896. LogFont.lfWidth = 0;
  897. LogFont.lfOrientation = LogFont.lfEscapement = 90*10;
  898. LogFont.lfWeight = TextMetrics.tmWeight;
  899. LogFont.lfStrikeOut = TextMetrics.tmStruckOut;
  900. LogFont.lfUnderline = TextMetrics.tmUnderlined;
  901. LogFont.lfItalic = TextMetrics.tmItalic;
  902. LogFont.lfCharSet = TextMetrics.tmCharSet;
  903. LogFont.lfPitchAndFamily = (BYTE)(TextMetrics.tmPitchAndFamily & 0xF0);
  904. GetTextFace(hDC, LF_FACESIZE, LogFont.lfFaceName);
  905. // Force a truetype font, because raster fonts can't rotate
  906. LogFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  907. LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  908. LogFont.lfQuality = DEFAULT_QUALITY;
  909. // Release the current font
  910. if (m_hFontVertical != NULL)
  911. DeleteObject(m_hFontVertical);
  912. // Create the font and save handle locally
  913. m_hFontVertical = CreateFontIndirect(&LogFont);
  914. SelectFont(hDC, m_hFontVertical);
  915. GetTextMetrics(hDC, &newTextMetrics);
  916. SelectFont(hDC, hFontOld);
  917. }
  918. PCGraphItem
  919. CGraphDisp::GetItemInLineGraph ( SHORT xPos, SHORT yPos )
  920. {
  921. PCGraphItem pItem = NULL;
  922. PCGraphItem pReturn = NULL;
  923. INT iPrevStepNum;
  924. POINT ptPrev;
  925. POINT ptNext;
  926. POINTS ptMouse;
  927. CStepper locStepper;
  928. INT iHistIndex;
  929. BOOL bLog;
  930. BOOL bLogMultiVal;
  931. BOOL bFound = FALSE;
  932. INT yPosPrev[3];
  933. INT yPosNext[3];
  934. pItem = m_pCtrl->FirstCounter();
  935. bLog = m_pCtrl->IsLogSource();
  936. bLogMultiVal = bLog && !DisplaySingleLogSampleValue();
  937. // Items exist?
  938. if (pItem != NULL) {
  939. locStepper = m_pGraph->TimeStepper;
  940. locStepper.Reset();
  941. iPrevStepNum = locStepper.PrevStepNum(xPos - m_rectPlot.left);
  942. locStepper.StepTo(iPrevStepNum);
  943. ptPrev.x = m_rectPlot.left + locStepper.Position();
  944. ptNext.x = m_rectPlot.left + locStepper.NextPosition();
  945. ptMouse.x = xPos;
  946. ptMouse.y = yPos;
  947. // Item within rectangle?
  948. if ( iPrevStepNum > -1 ) {
  949. // Determine the history index of the preceding step.
  950. if ( iPrevStepNum <= m_pGraph->TimeStepper.StepNum() ) {
  951. iHistIndex = m_pGraph->TimeStepper.StepNum() - iPrevStepNum;
  952. } else {
  953. iHistIndex = m_pGraph->TimeStepper.StepNum()
  954. + (m_pGraph->TimeStepper.StepCount() - iPrevStepNum);
  955. }
  956. while ( (pItem != NULL) && !bFound ) {
  957. // Calculate y position of this value to compare against
  958. // y position of hit point.
  959. if ( CalcYPosition ( pItem, iHistIndex, bLog, yPosPrev ) ) {
  960. if ( iPrevStepNum < locStepper.StepCount() ) {
  961. if ( CalcYPosition ( pItem, iHistIndex - 1, bLog, yPosNext ) ) {
  962. ptPrev.y = yPosPrev[0];
  963. ptNext.y = yPosNext[0];
  964. bFound = HitTestLine( ptPrev, ptNext, ptMouse, eHitRegion );
  965. // For log files, also check the vertical line from min to max
  966. // for the closest step.
  967. if ( !bFound && bLogMultiVal ) {
  968. INT iTemp = ptNext.x - ptPrev.x;
  969. iTemp = iTemp / 2;
  970. if ( ptMouse.x <= ( ptPrev.x + iTemp/2 ) ) {
  971. bFound = (( yPosPrev[2] - eHitRegion < yPos )
  972. && ( yPos < yPosPrev[1] + eHitRegion ));
  973. } else {
  974. bFound = (( yPosNext[2] - eHitRegion < yPos )
  975. && ( yPos < yPosNext[1] + eHitRegion ));
  976. }
  977. }
  978. }
  979. } else {
  980. // At the end, so just check the final point.
  981. if ( !bLogMultiVal ) {
  982. bFound = (( yPosPrev[0] - eHitRegion < yPos )
  983. && ( yPos < yPosPrev[0] + eHitRegion ));
  984. } else {
  985. bFound = (( yPosPrev[2] - eHitRegion < yPos )
  986. && ( yPos < yPosPrev[1] + eHitRegion ));
  987. }
  988. }
  989. }
  990. if ( bFound )
  991. pReturn = pItem;
  992. else
  993. pItem = pItem->Next();
  994. }
  995. }
  996. }
  997. return pReturn;
  998. }
  999. PCGraphItem
  1000. CGraphDisp::GetItemInBarGraph ( SHORT xPos, SHORT /* yPos */ )
  1001. {
  1002. PCGraphItem pItem = NULL;
  1003. pItem = m_pCtrl->FirstCounter();
  1004. // Items exist?
  1005. if (pItem != NULL) {
  1006. CStepper BarStepper;
  1007. INT iNumCounters = m_pGraph->CounterTree.NumCounters();
  1008. INT iCount;
  1009. INT iHitStep;
  1010. // Intialize stepper for number of bars in plot
  1011. BarStepper.Init ( ( m_rectPlot.right - m_rectPlot.left), iNumCounters );
  1012. iHitStep = BarStepper.PrevStepNum ( xPos - m_rectPlot.left );
  1013. assert ( -1 != iHitStep );
  1014. // Find the counter displayed in the hit step.
  1015. for ( iCount = 0;
  1016. ( iCount < iHitStep ) && ( pItem != NULL );
  1017. iCount++ ) {
  1018. pItem = pItem->Next();
  1019. }
  1020. }
  1021. return pItem;
  1022. }
  1023. PCGraphItem
  1024. CGraphDisp::GetItem( INT xPos, INT yPos )
  1025. {
  1026. PCGraphItem pReturn = NULL;
  1027. if ( ( m_pGraph->Options.iVertMax > m_pGraph->Options.iVertMin)
  1028. && ( yPos >= m_rectPlot.top ) && ( yPos <= m_rectPlot.bottom )
  1029. && ( xPos >= m_rectPlot.left ) && ( xPos <= m_rectPlot.right ) ) {
  1030. m_pCtrl->LockCounterData();
  1031. if ( LINE_GRAPH == m_pGraph->Options.iDisplayType ) {
  1032. assert ( SHRT_MAX >= xPos );
  1033. assert ( SHRT_MAX >= yPos );
  1034. pReturn = GetItemInLineGraph( (SHORT)xPos, (SHORT)yPos );
  1035. } else if ( BAR_GRAPH == m_pGraph->Options.iDisplayType ) {
  1036. assert ( SHRT_MAX >= xPos );
  1037. assert ( SHRT_MAX >= yPos );
  1038. pReturn = GetItemInBarGraph( (SHORT)xPos, (SHORT)yPos );
  1039. }
  1040. m_pCtrl->UnlockCounterData();
  1041. }
  1042. return pReturn;
  1043. }